+ if (status != EXIT_SUCCESS)
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ else
+ {
+ printf (_("\
+Usage: %s [OPTION]\n\
+Manipulate a tape drive, accepting commands from a remote process.\n\
+\n\
+ --version Output version info.\n\
+ --help Output this help.\n"),
+ program_name);
+ fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
+ }
+
+ exit (status);
+}
+
+int
+main (int argc, char *const *argv)
+{
+ char command;
+ ssize_t status;
+
+ /* FIXME: Localization is meaningless, unless --help and --version are
+ locally used. Localization would be best accomplished by the calling
+ tar, on messages found within error packets. */
+
+ program_name = argv[0];
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ switch (getopt_long (argc, argv, "", long_opts, NULL))
+ {
+ default:
+ usage (EXIT_FAILURE);
+
+ case 'h':
+ usage (EXIT_SUCCESS);
+
+ case 'v':
+ {
+ char buf[MB_LEN_MAX + 1];
+ printf ("rmt (GNU %s) %s\n", PACKAGE, VERSION);
+ printf ("Copyright %s 2001 Free Software Foundation, Inc.\n",
+ copyright_symbol (buf, sizeof buf));
+ puts (_("\
+This program comes with NO WARRANTY, to the extent permitted by law.\n\
+You may redistribute it under the terms of the GNU General Public License;\n\
+see the file named COPYING for details."));
+ }
+ return EXIT_SUCCESS;
+
+ case -1:
+ break;
+ }
+
+ if (optind < argc)
+ {
+ if (optind != argc - 1)
+ usage (EXIT_FAILURE);
+ debug_file = fopen (argv[optind], "w");
+ if (debug_file == 0)
+ {
+ report_numbered_error (errno);
+ exit (EXIT_FAILURE);
+ }
+ setbuf (debug_file, 0);
+ }
+
+top:
+ errno = 0;
+ status = 0;
+ if (safe_read (STDIN_FILENO, &command, 1) != 1)
+ return EXIT_SUCCESS;
+
+ switch (command)
+ {
+ /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
+
+ case 'O':
+ {
+ char device_string[STRING_SIZE];
+ char oflag_string[STRING_SIZE];
+
+ get_string (device_string);
+ get_string (oflag_string);
+ DEBUG2 ("rmtd: O %s %s\n", device_string, oflag_string);
+
+ if (tape >= 0)
+ close (tape);
+
+ tape = open (device_string, decode_oflag (oflag_string), MODE_RW);
+ if (tape < 0)
+ goto ioerror;
+ goto respond;
+ }
+
+ case 'C':
+ {
+ char device_string[STRING_SIZE];
+
+ get_string (device_string); /* discard */
+ DEBUG ("rmtd: C\n");
+
+ if (close (tape) < 0)
+ goto ioerror;
+ tape = -1;
+ goto respond;
+ }
+
+ case 'L':
+ {
+ char count_string[STRING_SIZE];
+ char position_string[STRING_SIZE];
+ off_t count = 0;
+ int negative;
+ int whence;
+ char *p;
+
+ get_string (count_string);
+ get_string (position_string);
+ DEBUG2 ("rmtd: L %s %s\n", count_string, position_string);
+
+ /* Parse count_string, taking care to check for overflow.
+ We can't use standard functions,
+ since off_t might be longer than long. */
+
+ for (p = count_string; *p == ' ' || *p == '\t'; p++)
+ continue;
+
+ negative = *p == '-';
+ p += negative || *p == '+';
+
+ for (;;)
+ {
+ int digit = *p++ - '0';
+ if (9 < (unsigned) digit)
+ break;
+ else
+ {
+ off_t c10 = 10 * count;
+ off_t nc = negative ? c10 - digit : c10 + digit;
+ if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
+ {
+ report_error_message (N_("Seek offset out of range"));
+ exit (EXIT_FAILURE);
+ }
+ count = nc;
+ }
+ }
+
+ switch (atoi (position_string))
+ {
+ case 0: whence = SEEK_SET; break;
+ case 1: whence = SEEK_CUR; break;
+ case 2: whence = SEEK_END; break;
+ default:
+ report_error_message (N_("Seek direction out of range"));
+ exit (EXIT_FAILURE);
+ }
+ count = lseek (tape, count, whence);
+ if (count < 0)
+ goto ioerror;
+
+ /* Convert count back to string for reply.
+ We can't use sprintf, since off_t might be longer than long. */
+ p = count_string + sizeof count_string;
+ *--p = '\0';
+ do
+ *--p = '0' + (int) (count % 10);
+ while ((count /= 10) != 0);
+
+ DEBUG1 ("rmtd: A %s\n", p);
+
+ sprintf (reply_buffer, "A%s\n", p);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ goto top;
+ }