]>
Dogcows Code - chaz/tar/blob - src/rmt.c
1 /* Remote connection server.
2 Copyright 1994,95,96,97,99,2000, 2001 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any later
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Copyright (C) 1983 Regents of the University of California.
21 Redistribution and use in source and binary forms are permitted provided
22 that the above copyright notice and this paragraph are duplicated in all
23 such forms and that any documentation, advertising materials, and other
24 materials related to such distribution and use acknowledge that the
25 software was developed by the University of California, Berkeley. The
26 name of the University may not be used to endorse or promote products
27 derived from this software without specific prior written permission.
28 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
29 WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
30 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
33 #include <localedir.h>
34 #include <safe-read.h>
35 #include <full-write.h>
38 #include <sys/socket.h>
41 # define EXIT_FAILURE 1
44 # define EXIT_SUCCESS 0
47 /* Maximum size of a string from the requesting program. */
48 #define STRING_SIZE 64
50 /* Name of executing program. */
51 const char *program_name
;
53 /* File descriptor of the tape device, or negative if none open. */
56 /* Buffer containing transferred data, and its allocated size. */
57 static char *record_buffer
;
58 static size_t allocated_size
;
60 /* Buffer for constructing the reply. */
61 static char reply_buffer
[BUFSIZ
];
63 /* Debugging tools. */
65 static FILE *debug_file
;
68 if (debug_file) fprintf(debug_file, File)
70 #define DEBUG1(File, Arg) \
71 if (debug_file) fprintf(debug_file, File, Arg)
73 #define DEBUG2(File, Arg1, Arg2) \
74 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
76 /* Return an error string, given an error number. */
83 private_strerror (int errnum
)
85 extern char *sys_errlist
[];
88 if (errnum
> 0 && errnum
<= sys_nerr
)
89 return _(sys_errlist
[errnum
]);
90 return _("Unknown system error");
92 # define strerror private_strerror
96 report_error_message (const char *string
)
98 DEBUG1 ("rmtd: E 0 (%s)\n", string
);
100 sprintf (reply_buffer
, "E0\n%s\n", string
);
101 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
105 report_numbered_error (int num
)
107 DEBUG2 ("rmtd: E %d (%s)\n", num
, strerror (num
));
109 sprintf (reply_buffer
, "E%d\n%s\n", num
, strerror (num
));
110 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
114 get_string (char *string
)
118 for (counter
= 0; counter
< STRING_SIZE
; counter
++)
120 if (safe_read (STDIN_FILENO
, string
+ counter
, 1) != 1)
123 if (string
[counter
] == '\n')
126 string
[counter
] = '\0';
130 prepare_record_buffer (size_t size
)
132 if (size
<= allocated_size
)
136 free (record_buffer
);
138 record_buffer
= malloc (size
);
142 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
144 report_error_message (N_("Cannot allocate buffer space"));
145 exit (EXIT_FAILURE
); /* exit status used to be 4 */
148 allocated_size
= size
;
151 while (size
> 1024 &&
152 (setsockopt (STDIN_FILENO
, SOL_SOCKET
, SO_RCVBUF
,
153 (char *) &size
, sizeof size
)
157 /* FIXME: I do not see any purpose to the following line... Sigh! */
158 size
= 1 + ((size
- 1) % 1024);
162 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
163 OFLAG_STRING should contain an optional integer, followed by an optional
164 symbolic representation of an open flag using only '|' to separate its
165 components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
166 representation if available, falling back on the numeric
167 representation, or to zero if both formats are absent.
169 This function should be the inverse of encode_oflag. The numeric
170 representation is not portable from one host to another, but it is
171 for backward compatibility with old-fashioned clients that do not
172 emit symbolic open flags. */
175 decode_oflag (char const *oflag_string
)
178 int numeric_oflag
= strtol (oflag_string
, &oflag_num_end
, 10);
179 int symbolic_oflag
= 0;
181 oflag_string
= oflag_num_end
;
182 while (ISSPACE ((unsigned char) *oflag_string
))
187 struct name_value_pair
{ char const *name
; int value
; };
188 static struct name_value_pair
const table
[] =
191 {"APPEND", O_APPEND
},
199 {"LARGEFILE", O_LARGEFILE
}, /* LFS extension for opening large files */
202 {"NOCTTY", O_NOCTTY
},
205 {"NONBLOCK", O_NONBLOCK
},
207 {"RDONLY", O_RDONLY
},
218 struct name_value_pair
const *t
;
221 if (*oflag_string
++ != 'O' || *oflag_string
++ != '_')
222 return numeric_oflag
;
225 (strncmp (oflag_string
, t
->name
, s
= strlen (t
->name
)) != 0
227 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
230 if (t
== table
+ sizeof table
/ sizeof *table
- 1)
231 return numeric_oflag
;
233 symbolic_oflag
|= t
->value
;
236 while (*oflag_string
++ == '|');
238 return symbolic_oflag
;
241 static struct option
const long_opts
[] =
243 {"help", no_argument
, 0, 'h'},
244 {"version", no_argument
, 0, 'v'},
251 if (status
!= EXIT_SUCCESS
)
252 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
257 Usage: %s [OPTION]\n\
258 Manipulate a tape drive, accepting commands from a remote process.\n\
260 --version Output version info.\n\
261 --help Output this help.\n"),
263 fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout
);
270 main (int argc
, char *const *argv
)
275 /* FIXME: Localization is meaningless, unless --help and --version are
276 locally used. Localization would be best accomplished by the calling
277 tar, on messages found within error packets. */
279 program_name
= argv
[0];
280 setlocale (LC_ALL
, "");
281 bindtextdomain (PACKAGE
, LOCALEDIR
);
282 textdomain (PACKAGE
);
284 switch (getopt_long (argc
, argv
, "", long_opts
, NULL
))
287 usage (EXIT_FAILURE
);
290 usage (EXIT_SUCCESS
);
293 printf ("rmt (GNU %s) %s\n%s\n%s\n", PACKAGE
, VERSION
,
294 "Copyright 2001 Free Software Foundation, Inc.",
296 This program comes with NO WARRANTY, to the extent permitted by law.\n\
297 You may redistribute it under the terms of the GNU General Public License;\n\
298 see the file named COPYING for details."));
307 if (optind
!= argc
- 1)
308 usage (EXIT_FAILURE
);
309 debug_file
= fopen (argv
[optind
], "w");
312 report_numbered_error (errno
);
315 setbuf (debug_file
, 0);
321 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
326 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
330 char device_string
[STRING_SIZE
];
331 char oflag_string
[STRING_SIZE
];
333 get_string (device_string
);
334 get_string (oflag_string
);
335 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
340 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
348 char device_string
[STRING_SIZE
];
350 get_string (device_string
); /* discard */
353 if (close (tape
) < 0)
361 char count_string
[STRING_SIZE
];
362 char position_string
[STRING_SIZE
];
368 get_string (count_string
);
369 get_string (position_string
);
370 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
372 /* Parse count_string, taking care to check for overflow.
373 We can't use standard functions,
374 since off_t might be longer than long. */
376 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
379 negative
= *p
== '-';
380 p
+= negative
|| *p
== '+';
384 int digit
= *p
++ - '0';
385 if (9 < (unsigned) digit
)
389 off_t c10
= 10 * count
;
390 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
391 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
393 report_error_message (N_("Seek offset out of range"));
400 switch (atoi (position_string
))
402 case 0: whence
= SEEK_SET
; break;
403 case 1: whence
= SEEK_CUR
; break;
404 case 2: whence
= SEEK_END
; break;
406 report_error_message (N_("Seek direction out of range"));
409 count
= lseek (tape
, count
, whence
);
413 /* Convert count back to string for reply.
414 We can't use sprintf, since off_t might be longer than long. */
415 p
= count_string
+ sizeof count_string
;
418 *--p
= '0' + (int) (count
% 10);
419 while ((count
/= 10) != 0);
421 DEBUG1 ("rmtd: A %s\n", p
);
423 sprintf (reply_buffer
, "A%s\n", p
);
424 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
430 char count_string
[STRING_SIZE
];
434 get_string (count_string
);
435 size
= atol (count_string
);
436 DEBUG1 ("rmtd: W %s\n", count_string
);
438 prepare_record_buffer (size
);
439 for (counter
= 0; counter
< size
; counter
+= status
)
441 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
445 DEBUG (_("rmtd: Premature eof\n"));
447 report_error_message (N_("Premature end of file"));
448 exit (EXIT_FAILURE
); /* exit status used to be 2 */
451 status
= full_write (tape
, record_buffer
, size
);
459 char count_string
[STRING_SIZE
];
462 get_string (count_string
);
463 DEBUG1 ("rmtd: R %s\n", count_string
);
465 size
= atol (count_string
);
466 prepare_record_buffer (size
);
467 status
= safe_read (tape
, record_buffer
, size
);
470 sprintf (reply_buffer
, "A%ld\n", (long) status
);
471 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
472 full_write (STDOUT_FILENO
, record_buffer
, status
);
478 char operation_string
[STRING_SIZE
];
479 char count_string
[STRING_SIZE
];
481 get_string (operation_string
);
482 get_string (count_string
);
483 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
492 /* Parse count_string, taking care to check for overflow.
493 We can't use standard functions,
494 since off_t might be longer than long. */
496 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
499 negative
= *p
== '-';
500 p
+= negative
|| *p
== '+';
504 int digit
= *p
++ - '0';
505 if (9 < (unsigned) digit
)
509 off_t c10
= 10 * count
;
510 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
511 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
513 report_error_message (N_("Seek offset out of range"));
520 mtop
.mt_count
= count
;
521 if (mtop
.mt_count
!= count
)
523 report_error_message (N_("Seek offset out of range"));
526 mtop
.mt_op
= atoi (operation_string
);
528 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
535 case 'S': /* status */
541 struct mtget operation
;
543 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
545 status
= sizeof operation
;
546 sprintf (reply_buffer
, "A%ld\n", (long) status
);
547 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
548 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
555 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
557 report_error_message (N_("Garbage command"));
558 exit (EXIT_FAILURE
); /* exit status used to be 3 */
562 DEBUG1 ("rmtd: A %ld\n", (long) status
);
564 sprintf (reply_buffer
, "A%ld\n", (long) status
);
565 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
569 report_numbered_error (errno
);
This page took 0.063902 seconds and 4 git commands to generate.