]>
Dogcows Code - chaz/tar/blob - rmt.c
e4e8f44bc23e1eb8e99ecbe3420ebdd178220d6d
1 /* Remote connection server.
2 Copyright 1994, 1995, 1996, 1997, 1999 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 "safe-read.h"
36 #include <sys/socket.h>
39 # define EXIT_FAILURE 1
42 # define EXIT_SUCCESS 0
45 /* Maximum size of a string from the requesting program. */
46 #define STRING_SIZE 64
48 /* Name of executing program. */
49 const char *program_name
;
51 /* File descriptor of the tape device, or negative if none open. */
54 /* Buffer containing transferred data, and its allocated size. */
55 static char *record_buffer
;
56 static size_t allocated_size
;
58 /* Buffer for constructing the reply. */
59 static char reply_buffer
[BUFSIZ
];
61 /* Debugging tools. */
63 static FILE *debug_file
;
66 if (debug_file) fprintf(debug_file, File)
68 #define DEBUG1(File, Arg) \
69 if (debug_file) fprintf(debug_file, File, Arg)
71 #define DEBUG2(File, Arg1, Arg2) \
72 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
74 /*------------------------------------------------.
75 | Return an error string, given an error number. |
76 `------------------------------------------------*/
84 private_strerror (int errnum
)
86 extern char *sys_errlist
[];
89 if (errnum
> 0 && errnum
<= sys_nerr
)
90 return _(sys_errlist
[errnum
]);
91 return _("Unknown system error");
93 # define strerror private_strerror
101 report_error_message (const char *string
)
103 DEBUG1 ("rmtd: E 0 (%s)\n", string
);
105 sprintf (reply_buffer
, "E0\n%s\n", string
);
106 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
114 report_numbered_error (int num
)
116 DEBUG2 ("rmtd: E %d (%s)\n", num
, strerror (num
));
118 sprintf (reply_buffer
, "E%d\n%s\n", num
, strerror (num
));
119 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
127 get_string (char *string
)
131 for (counter
= 0; counter
< STRING_SIZE
; counter
++)
133 if (safe_read (STDIN_FILENO
, string
+ counter
, 1) != 1)
136 if (string
[counter
] == '\n')
139 string
[counter
] = '\0';
147 prepare_record_buffer (size_t size
)
149 if (size
<= allocated_size
)
153 free (record_buffer
);
155 record_buffer
= malloc (size
);
159 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
161 report_error_message (N_("Cannot allocate buffer space"));
162 exit (EXIT_FAILURE
); /* exit status used to be 4 */
165 allocated_size
= size
;
168 while (size
> 1024 &&
169 (setsockopt (STDIN_FILENO
, SOL_SOCKET
, SO_RCVBUF
,
170 (char *) &size
, sizeof size
)
174 /* FIXME: I do not see any purpose to the following line... Sigh! */
175 size
= 1 + ((size
- 1) % 1024);
179 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
180 OFLAG_STRING should contain an optional integer, followed by an optional
181 symbolic representation of an open flag using only '|' to separate its
182 components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
183 representation if available, falling back on the numeric
184 representation, or to zero if both formats are absent.
186 This function should be the inverse of encode_oflag. The numeric
187 representation is not portable from one host to another, but it is
188 for backward compatibility with old-fashioned clients that do not
189 emit symbolic open flags. */
192 decode_oflag (char const *oflag_string
)
195 int numeric_oflag
= strtol (oflag_string
, &oflag_num_end
, 10);
196 int symbolic_oflag
= 0;
198 oflag_string
= oflag_num_end
;
199 while (ISSPACE ((unsigned char) *oflag_string
))
204 struct name_value_pair
{ char const *name
; int value
; };
205 static struct name_value_pair
const table
[] =
208 {"APPEND", O_APPEND
},
216 {"LARGEFILE", O_LARGEFILE
}, /* LFS extension for opening large files */
219 {"NOCTTY", O_NOCTTY
},
222 {"NONBLOCK", O_NONBLOCK
},
224 {"RDONLY", O_RDONLY
},
235 struct name_value_pair
const *t
;
238 if (*oflag_string
++ != 'O' || *oflag_string
++ != '_')
239 return numeric_oflag
;
242 (strncmp (oflag_string
, t
->name
, s
= strlen (t
->name
)) != 0
244 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
247 if (t
== table
+ sizeof table
/ sizeof *table
- 1)
248 return numeric_oflag
;
250 symbolic_oflag
|= t
->value
;
253 while (*oflag_string
++ == '|');
255 return symbolic_oflag
;
258 static struct option
const long_opts
[] =
260 {"help", no_argument
, 0, 'h'},
261 {"version", no_argument
, 0, 'v'},
268 if (status
!= EXIT_SUCCESS
)
269 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
274 Usage: %s [OPTION]\n\
275 Manipulate a tape drive, accepting commands from a remote process.\n\
277 --version Output version info.\n\
278 --help Output this help.\n"),
280 fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout
);
291 main (int argc
, char *const *argv
)
296 /* FIXME: Localization is meaningless, unless --help and --version are
297 locally used. Localization would be best accomplished by the calling
298 tar, on messages found within error packets. */
300 program_name
= argv
[0];
301 setlocale (LC_ALL
, "");
302 bindtextdomain (PACKAGE
, LOCALEDIR
);
303 textdomain (PACKAGE
);
305 switch (getopt_long (argc
, argv
, "", long_opts
, NULL
))
308 usage (EXIT_FAILURE
);
311 usage (EXIT_SUCCESS
);
314 printf ("rmt (GNU %s) %s\n%s\n%s\n", PACKAGE
, VERSION
,
315 "Copyright 1999 Free Software Foundation, Inc.",
317 This program comes with NO WARRANTY, to the extent permitted by law.\n\
318 You may redistribute it under the terms of the GNU General Public License;\n\
319 see the file named COPYING for details."));
328 if (optind
!= argc
- 1)
329 usage (EXIT_FAILURE
);
330 debug_file
= fopen (argv
[optind
], "w");
333 report_numbered_error (errno
);
336 setbuf (debug_file
, 0);
342 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
347 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
351 char device_string
[STRING_SIZE
];
352 char oflag_string
[STRING_SIZE
];
354 get_string (device_string
);
355 get_string (oflag_string
);
356 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
361 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
369 char device_string
[STRING_SIZE
];
371 get_string (device_string
); /* discard */
374 if (close (tape
) < 0)
382 char count_string
[STRING_SIZE
];
383 char position_string
[STRING_SIZE
];
389 get_string (count_string
);
390 get_string (position_string
);
391 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
393 /* Parse count_string, taking care to check for overflow.
394 We can't use standard functions,
395 since off_t might be longer than long. */
397 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
400 negative
= *p
== '-';
401 p
+= negative
|| *p
== '+';
405 int digit
= *p
++ - '0';
406 if (9 < (unsigned) digit
)
410 off_t c10
= 10 * count
;
411 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
412 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
414 report_error_message (N_("Seek offset out of range"));
421 switch (atoi (position_string
))
423 case 0: whence
= SEEK_SET
; break;
424 case 1: whence
= SEEK_CUR
; break;
425 case 2: whence
= SEEK_END
; break;
427 report_error_message (N_("Seek direction out of range"));
430 count
= lseek (tape
, count
, whence
);
434 /* Convert count back to string for reply.
435 We can't use sprintf, since off_t might be longer than long. */
436 p
= count_string
+ sizeof count_string
;
439 *--p
= '0' + (int) (count
% 10);
440 while ((count
/= 10) != 0);
442 DEBUG1 ("rmtd: A %s\n", p
);
444 sprintf (reply_buffer
, "A%s\n", p
);
445 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
451 char count_string
[STRING_SIZE
];
455 get_string (count_string
);
456 size
= atol (count_string
);
457 DEBUG1 ("rmtd: W %s\n", count_string
);
459 prepare_record_buffer (size
);
460 for (counter
= 0; counter
< size
; counter
+= status
)
462 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
466 DEBUG (_("rmtd: Premature eof\n"));
468 report_error_message (N_("Premature end of file"));
469 exit (EXIT_FAILURE
); /* exit status used to be 2 */
472 status
= full_write (tape
, record_buffer
, size
);
480 char count_string
[STRING_SIZE
];
483 get_string (count_string
);
484 DEBUG1 ("rmtd: R %s\n", count_string
);
486 size
= atol (count_string
);
487 prepare_record_buffer (size
);
488 status
= safe_read (tape
, record_buffer
, size
);
491 sprintf (reply_buffer
, "A%ld\n", (long) status
);
492 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
493 full_write (STDOUT_FILENO
, record_buffer
, status
);
499 char operation_string
[STRING_SIZE
];
500 char count_string
[STRING_SIZE
];
502 get_string (operation_string
);
503 get_string (count_string
);
504 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
513 /* Parse count_string, taking care to check for overflow.
514 We can't use standard functions,
515 since off_t might be longer than long. */
517 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
520 negative
= *p
== '-';
521 p
+= negative
|| *p
== '+';
525 int digit
= *p
++ - '0';
526 if (9 < (unsigned) digit
)
530 off_t c10
= 10 * count
;
531 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
532 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
534 report_error_message (N_("Seek offset out of range"));
541 mtop
.mt_count
= count
;
542 if (mtop
.mt_count
!= count
)
544 report_error_message (N_("Seek offset out of range"));
547 mtop
.mt_op
= atoi (operation_string
);
549 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
556 case 'S': /* status */
562 struct mtget operation
;
564 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
566 status
= sizeof operation
;
567 sprintf (reply_buffer
, "A%ld\n", (long) status
);
568 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
569 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
576 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
578 report_error_message (N_("Garbage command"));
579 exit (EXIT_FAILURE
); /* exit status used to be 3 */
583 DEBUG1 ("rmtd: A %ld\n", (long) status
);
585 sprintf (reply_buffer
, "A%ld\n", (long) status
);
586 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
590 report_numbered_error (errno
);
This page took 0.054424 seconds and 3 git commands to generate.