1 /* Remote connection server.
3 Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004,
4 2005, 2006, 2007 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any later
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20 /* Copyright (C) 1983 Regents of the University of California.
23 Redistribution and use in source and binary forms are permitted provided
24 that the above copyright notice and this paragraph are duplicated in all
25 such forms and that any documentation, advertising materials, and other
26 materials related to such distribution and use acknowledge that the
27 software was developed by the University of California, Berkeley. The
28 name of the University may not be used to endorse or promote products
29 derived from this software without specific prior written permission.
30 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
31 WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
32 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
35 #include "system-ioctl.h"
37 #include <configmake.h>
38 #include <safe-read.h>
39 #include <full-write.h>
40 #include <version-etc.h>
41 #define obstack_chunk_alloc malloc
42 #define obstack_chunk_free free
45 #include <sys/socket.h>
48 # define EXIT_FAILURE 1
51 # define EXIT_SUCCESS 0
54 /* Maximum size of a string from the requesting program.
55 It must hold enough for any integer, possibly with a sign. */
56 #define STRING_SIZE (UINTMAX_STRSIZE_BOUND + 1)
58 const char *program_name;
60 /* File descriptor of the tape device, or negative if none open. */
63 /* Buffer containing transferred data, and its allocated size. */
64 static char *record_buffer;
65 static size_t allocated_size;
67 /* Buffer for constructing the reply. */
68 static char reply_buffer[BUFSIZ];
70 /* Obstack for arbitrary-sized strings */
71 struct obstack string_stk;
73 /* Debugging tools. */
75 static FILE *debug_file;
78 if (debug_file) fprintf(debug_file, File)
80 #define DEBUG1(File, Arg) \
81 if (debug_file) fprintf(debug_file, File, Arg)
83 #define DEBUG2(File, Arg1, Arg2) \
84 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
87 report_error_message (const char *string)
89 DEBUG1 ("rmtd: E 0 (%s)\n", string);
91 sprintf (reply_buffer, "E0\n%s\n", string);
92 full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
96 report_numbered_error (int num)
98 DEBUG2 ("rmtd: E %d (%s)\n", num, strerror (num));
100 sprintf (reply_buffer, "E%d\n%s\n", num, strerror (num));
101 full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
110 if (safe_read (STDIN_FILENO, &c, 1) != 1)
116 obstack_1grow (&string_stk, c);
118 obstack_1grow (&string_stk, 0);
119 return obstack_finish (&string_stk);
123 free_string (char *string)
125 obstack_free (&string_stk, string);
129 get_string_n (char *string)
133 for (counter = 0; ; counter++)
135 if (safe_read (STDIN_FILENO, string + counter, 1) != 1)
138 if (string[counter] == '\n')
141 if (counter == STRING_SIZE - 1)
142 report_error_message (N_("Input string too long"));
144 string[counter] = '\0';
148 get_long (char const *string)
153 n = strtol (string, &p, 10);
156 report_numbered_error (errno);
161 report_error_message (N_("Number syntax error"));
168 prepare_input_buffer (int fd, size_t size)
170 if (size <= allocated_size)
174 free (record_buffer);
176 record_buffer = malloc (size);
180 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
182 report_error_message (N_("Cannot allocate buffer space"));
183 exit (EXIT_FAILURE); /* exit status used to be 4 */
186 allocated_size = size;
191 int isize = size < INT_MAX ? size : INT_MAX;
192 while (setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
193 (char *) &isize, sizeof isize)
200 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
201 OFLAG_STRING should contain an optional integer, followed by an optional
202 symbolic representation of an open flag using only '|' to separate its
203 components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
204 representation if available, falling back on the numeric
205 representation, or to zero if both formats are absent.
207 This function should be the inverse of encode_oflag. The numeric
208 representation is not portable from one host to another, but it is
209 for backward compatibility with old-fashioned clients that do not
210 emit symbolic open flags. */
213 decode_oflag (char const *oflag_string)
216 int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10);
217 int symbolic_oflag = 0;
219 oflag_string = oflag_num_end;
220 while (ISSPACE ((unsigned char) *oflag_string))
225 struct name_value_pair { char const *name; int value; };
226 static struct name_value_pair const table[] =
229 {"APPEND", O_APPEND},
237 {"LARGEFILE", O_LARGEFILE}, /* LFS extension for opening large files */
240 {"NOCTTY", O_NOCTTY},
243 {"NONBLOCK", O_NONBLOCK},
245 {"RDONLY", O_RDONLY},
256 struct name_value_pair const *t;
259 if (*oflag_string++ != 'O' || *oflag_string++ != '_')
260 return numeric_oflag;
263 (strncmp (oflag_string, t->name, s = strlen (t->name)) != 0
265 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
268 if (t == table + sizeof table / sizeof *table - 1)
269 return numeric_oflag;
271 symbolic_oflag |= t->value;
274 while (*oflag_string++ == '|');
276 return symbolic_oflag;
279 static struct option const long_opts[] =
281 {"help", no_argument, 0, 'h'},
282 {"version", no_argument, 0, 'v'},
286 /* In-line localization is used only if --help or --version are
287 locally used. Otherwise, the localization burden lies with tar. */
291 setlocale (LC_ALL, "");
292 bindtextdomain (PACKAGE, LOCALEDIR);
293 textdomain (PACKAGE);
296 static void usage (int) __attribute__ ((noreturn));
303 if (status != EXIT_SUCCESS)
304 fprintf (stderr, _("Try `%s --help' for more information.\n"),
309 Usage: %s [OPTION]\n\
310 Manipulate a tape drive, accepting commands from a remote process.\n\
312 --version Output version info.\n\
313 --help Output this help.\n"),
315 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
323 respond (long int status)
325 DEBUG1 ("rmtd: A %ld\n", status);
327 sprintf (reply_buffer, "A%ld\n", status);
328 full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
336 char *device_string = get_string ();
337 char *oflag_string = get_string ();
339 DEBUG2 ("rmtd: O %s %s\n", device_string, oflag_string);
344 tape = open (device_string, decode_oflag (oflag_string), MODE_RW);
346 report_numbered_error (errno);
349 free_string (device_string);
350 free_string (oflag_string);
356 free_string (get_string ()); /* discard */
359 if (close (tape) < 0)
360 report_numbered_error (errno);
371 char count_string[STRING_SIZE];
372 char position_string[STRING_SIZE];
378 get_string_n (count_string);
379 get_string_n (position_string);
380 DEBUG2 ("rmtd: L %s %s\n", count_string, position_string);
382 /* Parse count_string, taking care to check for overflow.
383 We can't use standard functions,
384 since off_t might be longer than long. */
386 for (p = count_string; *p == ' ' || *p == '\t'; p++)
389 negative = *p == '-';
390 p += negative || *p == '+';
394 int digit = *p - '0';
395 if (9 < (unsigned) digit)
397 report_error_message (N_("Seek offset error"));
402 off_t c10 = 10 * count;
403 off_t nc = negative ? c10 - digit : c10 + digit;
404 if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
406 report_error_message (N_("Seek offset out of range"));
413 switch (get_long (position_string))
428 report_error_message (N_("Seek direction out of range"));
432 count = lseek (tape, count, whence);
434 report_numbered_error (errno);
437 /* Convert count back to string for reply.
438 We can't use sprintf, since off_t might be longer
440 p = count_string + sizeof count_string;
443 *--p = '0' + (int) (count % 10);
444 while ((count /= 10) != 0);
446 DEBUG1 ("rmtd: A %s\n", p);
448 sprintf (reply_buffer, "A%s\n", p);
449 full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
456 char count_string[STRING_SIZE];
461 get_string_n (count_string);
462 size = get_long (count_string);
463 DEBUG1 ("rmtd: W %s\n", count_string);
465 prepare_input_buffer (STDIN_FILENO, size);
466 for (counter = 0; counter < size; counter += status)
468 status = safe_read (STDIN_FILENO, &record_buffer[counter],
470 if (status == SAFE_READ_ERROR || status == 0)
472 DEBUG (_("rmtd: Premature eof\n"));
474 report_error_message (N_("Premature end of file"));
475 exit (EXIT_FAILURE); /* exit status used to be 2 */
478 status = full_write (tape, record_buffer, size);
480 report_numbered_error (errno);
488 char count_string[STRING_SIZE];
492 get_string_n (count_string);
493 DEBUG1 ("rmtd: R %s\n", count_string);
495 size = get_long (count_string);
496 prepare_input_buffer (-1, size);
497 status = safe_read (tape, record_buffer, size);
498 if (status == SAFE_READ_ERROR)
499 report_numbered_error (errno);
502 sprintf (reply_buffer, "A%lu\n", (unsigned long int) status);
503 full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
504 full_write (STDOUT_FILENO, record_buffer, status);
511 char operation_string[STRING_SIZE];
512 char count_string[STRING_SIZE];
514 get_string_n (operation_string);
515 get_string_n (count_string);
516 DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string);
525 /* Parse count_string, taking care to check for overflow.
526 We can't use standard functions,
527 since off_t might be longer than long. */
529 for (p = count_string; *p == ' ' || *p == '\t'; p++)
532 negative = *p == '-';
533 p += negative || *p == '+';
537 int digit = *p++ - '0';
538 if (9 < (unsigned) digit)
542 off_t c10 = 10 * count;
543 off_t nc = negative ? c10 - digit : c10 + digit;
544 if (c10 / 10 != count
545 || (negative ? c10 < nc : nc < c10))
547 report_error_message (N_("Seek offset out of range"));
554 mtop.mt_count = count;
555 if (mtop.mt_count != count)
557 report_error_message (N_("Seek offset out of range"));
560 mtop.mt_op = get_long (operation_string);
562 if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
564 report_numbered_error (errno);
579 struct mtget operation;
581 if (ioctl (tape, MTIOCGET, (char *) &operation) < 0)
582 report_numbered_error (errno);
585 respond (sizeof operation);
586 full_write (STDOUT_FILENO, (char *) &operation, sizeof operation);
593 main (int argc, char **argv)
597 program_name = argv[0];
599 obstack_init (&string_stk);
601 switch (getopt_long (argc, argv, "", long_opts, NULL))
604 usage (EXIT_FAILURE);
607 usage (EXIT_SUCCESS);
611 version_etc (stdout, "rmt", PACKAGE_NAME, PACKAGE_VERSION,
612 "John Gilmore", "Jay Fenlason", (char *) NULL);
622 if (optind != argc - 1)
623 usage (EXIT_FAILURE);
624 debug_file = fopen (argv[optind], "w");
627 report_numbered_error (errno);
630 setbuf (debug_file, 0);
637 if (safe_read (STDIN_FILENO, &command, 1) != 1)
671 DEBUG1 ("rmtd: Garbage command %c\n", command);
672 report_error_message (N_("Garbage command"));
673 return EXIT_FAILURE; /* exit status used to be 3 */