+ case 'W':
+ {
+ char count_string[STRING_SIZE];
+ size_t size;
+ size_t counter;
+
+ get_string (count_string);
+ size = atol (count_string);
+ DEBUG1 ("rmtd: W %s\n", count_string);
+
+ prepare_input_buffer (STDIN_FILENO, size);
+ for (counter = 0; counter < size; counter += status)
+ {
+ status = safe_read (STDIN_FILENO, &record_buffer[counter],
+ size - counter);
+ if (status == SAFE_READ_ERROR || status == 0)
+ {
+ DEBUG (_("rmtd: Premature eof\n"));
+
+ report_error_message (N_("Premature end of file"));
+ return EXIT_FAILURE; /* exit status used to be 2 */
+ }
+ }
+ status = full_write (tape, record_buffer, size);
+ if (status != size)
+ goto ioerror;
+ goto respond;
+ }
+
+ case 'R':
+ {
+ char count_string[STRING_SIZE];
+ size_t size;
+
+ get_string (count_string);
+ DEBUG1 ("rmtd: R %s\n", count_string);
+
+ size = atol (count_string);
+ prepare_input_buffer (-1, size);
+ status = safe_read (tape, record_buffer, size);
+ if (status == SAFE_READ_ERROR)
+ goto ioerror;
+ sprintf (reply_buffer, "A%lu\n", (unsigned long int) status);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ full_write (STDOUT_FILENO, record_buffer, status);
+ goto top;
+ }
+
+ case 'I':
+ {
+ char operation_string[STRING_SIZE];
+ char count_string[STRING_SIZE];
+
+ get_string (operation_string);
+ get_string (count_string);
+ DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string);
+
+#ifdef MTIOCTOP
+ {
+ struct mtop mtop;
+ const char *p;
+ off_t count = 0;
+ int negative;
+
+ /* 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"));
+ return EXIT_FAILURE;
+ }
+ count = nc;
+ }
+ }
+
+ mtop.mt_count = count;
+ if (mtop.mt_count != count)
+ {
+ report_error_message (N_("Seek offset out of range"));
+ return EXIT_FAILURE;
+ }
+ mtop.mt_op = atoi (operation_string);
+
+ if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
+ goto ioerror;
+ }
+#endif
+ goto respond;
+ }
+
+ case 'S': /* status */
+ {
+ DEBUG ("rmtd: S\n");
+
+#ifdef MTIOCGET
+ {
+ struct mtget operation;
+
+ if (ioctl (tape, MTIOCGET, (char *) &operation) < 0)
+ goto ioerror;
+ status = sizeof operation;
+ sprintf (reply_buffer, "A%ld\n", (long) status);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ full_write (STDOUT_FILENO, (char *) &operation, sizeof operation);
+ }
+#endif
+ goto top;
+ }
+
+ default:
+ DEBUG1 (_("rmtd: Garbage command %c\n"), command);
+
+ report_error_message (N_("Garbage command"));
+ return EXIT_FAILURE; /* exit status used to be 3 */
+ }
+
+respond:
+ DEBUG1 ("rmtd: A %ld\n", (long) status);
+
+ sprintf (reply_buffer, "A%ld\n", (long) status);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ goto top;
+
+ioerror:
+ report_numbered_error (errno);
+ goto top;