(to_chars): Fix base-256 output.
[debian/tar] / src / rmt.c
1 /* Remote connection server.
2    Copyright 1994, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
3
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
7    version.
8
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.
13
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.  */
17
18 /* Copyright (C) 1983 Regents of the University of California.
19    All rights reserved.
20
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.  */
31
32 #include "system.h"
33 #include "safe-read.h"
34
35 #include <sys/socket.h>
36
37 #ifndef EXIT_FAILURE
38 # define EXIT_FAILURE 1
39 #endif
40 #ifndef EXIT_SUCCESS
41 # define EXIT_SUCCESS 0
42 #endif
43
44 /* Maximum size of a string from the requesting program.  */
45 #define STRING_SIZE 64
46
47 /* Name of executing program.  */
48 const char *program_name;
49
50 /* File descriptor of the tape device, or negative if none open.  */
51 static int tape = -1;
52
53 /* Buffer containing transferred data, and its allocated size.  */
54 static char *record_buffer;
55 static size_t allocated_size;
56
57 /* Buffer for constructing the reply.  */
58 static char reply_buffer[BUFSIZ];
59
60 /* Debugging tools.  */
61
62 static FILE *debug_file;
63
64 #define DEBUG(File) \
65   if (debug_file) fprintf(debug_file, File)
66
67 #define DEBUG1(File, Arg) \
68   if (debug_file) fprintf(debug_file, File, Arg)
69
70 #define DEBUG2(File, Arg1, Arg2) \
71   if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
72
73 /*------------------------------------------------.
74 | Return an error string, given an error number.  |
75 `------------------------------------------------*/
76
77 #if HAVE_STRERROR
78 # ifndef strerror
79 char *strerror ();
80 # endif
81 #else
82 static char *
83 private_strerror (int errnum)
84 {
85   extern char *sys_errlist[];
86   extern int sys_nerr;
87
88   if (errnum > 0 && errnum <= sys_nerr)
89     return _(sys_errlist[errnum]);
90   return _("Unknown system error");
91 }
92 # define strerror private_strerror
93 #endif
94
95 /*---.
96 | ?  |
97 `---*/
98
99 static void
100 report_error_message (const char *string)
101 {
102   DEBUG1 ("rmtd: E 0 (%s)\n", string);
103
104   sprintf (reply_buffer, "E0\n%s\n", string);
105   full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
106 }
107
108 /*---.
109 | ?  |
110 `---*/
111
112 static void
113 report_numbered_error (int num)
114 {
115   DEBUG2 ("rmtd: E %d (%s)\n", num, strerror (num));
116
117   sprintf (reply_buffer, "E%d\n%s\n", num, strerror (num));
118   full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
119 }
120
121 /*---.
122 | ?  |
123 `---*/
124
125 static void
126 get_string (char *string)
127 {
128   int counter;
129
130   for (counter = 0; counter < STRING_SIZE; counter++)
131     {
132       if (safe_read (STDIN_FILENO, string + counter, 1) != 1)
133         exit (EXIT_SUCCESS);
134
135       if (string[counter] == '\n')
136         break;
137     }
138   string[counter] = '\0';
139 }
140
141 /*---.
142 | ?  |
143 `---*/
144
145 static void
146 prepare_record_buffer (size_t size)
147 {
148   if (size <= allocated_size)
149     return;
150
151   if (record_buffer)
152     free (record_buffer);
153
154   record_buffer = malloc (size);
155
156   if (! record_buffer)
157     {
158       DEBUG (_("rmtd: Cannot allocate buffer space\n"));
159
160       report_error_message (N_("Cannot allocate buffer space"));
161       exit (EXIT_FAILURE);      /* exit status used to be 4 */
162     }
163
164   allocated_size = size;
165
166 #ifdef SO_RCVBUF
167   while (size > 1024 &&
168          (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_RCVBUF,
169                       (char *) &size, sizeof size)
170           < 0))
171     size -= 1024;
172 #else
173   /* FIXME: I do not see any purpose to the following line...  Sigh! */
174   size = 1 + ((size - 1) % 1024);
175 #endif
176 }
177
178 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
179    OFLAG_STRING should contain an optional integer, followed by an optional
180    symbolic representation of an open flag using only '|' to separate its
181    components (e.g. "O_WRONLY|O_CREAT|O_TRUNC").  Prefer the symbolic
182    representation if available, falling back on the numeric
183    representation, or to zero if both formats are absent.
184
185    This function should be the inverse of encode_oflag.  The numeric
186    representation is not portable from one host to another, but it is
187    for backward compatibility with old-fashioned clients that do not
188    emit symbolic open flags.  */
189
190 static int
191 decode_oflag (char const *oflag_string)
192 {
193   char *oflag_num_end;
194   int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10);
195   int symbolic_oflag = 0;
196   
197   oflag_string = oflag_num_end;
198   while (ISSPACE ((unsigned char) *oflag_string))
199     oflag_string++;
200     
201   do
202     {
203       struct name_value_pair { char const *name; int value; };
204       static struct name_value_pair const table[] =
205       {
206         {"APPEND", O_APPEND},
207         {"CREAT", O_CREAT},
208 #ifdef O_DSYNC
209         {"DSYNC", O_DSYNC},
210 #endif
211         {"EXCL", O_EXCL},
212 #ifdef O_LARGEFILE
213         {"LARGEFILE", O_LARGEFILE}, /* LFS extension for opening large files */
214 #endif
215 #ifdef O_NOCTTY
216         {"NOCTTY", O_NOCTTY},
217 #endif
218 #ifdef O_NONBLOCK
219         {"NONBLOCK", O_NONBLOCK},
220 #endif
221         {"RDONLY", O_RDONLY},
222         {"RDWR", O_RDWR},
223 #ifdef O_RSYNC
224         {"RSYNC", O_RSYNC},
225 #endif
226 #ifdef O_SYNC
227         {"SYNC", O_SYNC},
228 #endif
229         {"TRUNC", O_TRUNC},
230         {"WRONLY", O_WRONLY}
231       };
232       struct name_value_pair const *t;
233       size_t s;
234
235       if (*oflag_string++ != 'O' || *oflag_string++ != '_')
236         return numeric_oflag;
237
238       for (t = table;
239            (strncmp (oflag_string, t->name, s = strlen (t->name)) != 0
240             || (oflag_string[s]
241                 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
242                            oflag_string[s])));
243            t++)
244         if (t == table + sizeof table / sizeof *table - 1)
245           return numeric_oflag;
246
247       symbolic_oflag |= t->value;
248       oflag_string += s;
249     }
250   while (*oflag_string++ == '|');
251
252   return symbolic_oflag;
253 }
254
255 /*---.
256 | ?  |
257 `---*/
258
259 int
260 main (int argc, char *const *argv)
261 {
262   char command;
263   ssize_t status;
264
265   /* FIXME: Localization is meaningless, unless --help and --version are
266      locally used.  Localization would be best accomplished by the calling
267      tar, on messages found within error packets.  */
268
269   program_name = argv[0];
270   setlocale (LC_ALL, "");
271   bindtextdomain (PACKAGE, LOCALEDIR);
272   textdomain (PACKAGE);
273
274   /* FIXME: Implement --help and --version as for any other GNU program.  */
275
276   argc--, argv++;
277   if (argc > 0)
278     {
279       debug_file = fopen (*argv, "w");
280       if (debug_file == 0)
281         {
282           report_numbered_error (errno);
283           exit (EXIT_FAILURE);
284         }
285       setbuf (debug_file, 0);
286     }
287
288 top:
289   errno = 0;                    /* FIXME: errno should be read-only */
290   status = 0;
291   if (safe_read (STDIN_FILENO, &command, 1) != 1)
292     exit (EXIT_SUCCESS);
293
294   switch (command)
295     {
296       /* FIXME: Maybe 'H' and 'V' for --help and --version output?  */
297
298     case 'O':
299       {
300         char device_string[STRING_SIZE];
301         char oflag_string[STRING_SIZE];
302
303         get_string (device_string);
304         get_string (oflag_string);
305         DEBUG2 ("rmtd: O %s %s\n", device_string, oflag_string);
306
307         if (tape >= 0)
308           close (tape);
309
310         tape = open (device_string, decode_oflag (oflag_string), MODE_RW);
311         if (tape < 0)
312           goto ioerror;
313         goto respond;
314       }
315
316     case 'C':
317       {
318         char device_string[STRING_SIZE];
319
320         get_string (device_string); /* discard */
321         DEBUG ("rmtd: C\n");
322
323         if (close (tape) < 0)
324           goto ioerror;
325         tape = -1;
326         goto respond;
327       }
328
329     case 'L':
330       {
331         char count_string[STRING_SIZE];
332         char position_string[STRING_SIZE];
333         off_t count = 0;
334         int negative;
335         int whence;
336         char *p;
337
338         get_string (count_string);
339         get_string (position_string);
340         DEBUG2 ("rmtd: L %s %s\n", count_string, position_string);
341
342         /* Parse count_string, taking care to check for overflow.
343            We can't use standard functions,
344            since off_t might be longer than long.  */
345
346         for (p = count_string;  *p == ' ' || *p == '\t';  p++)
347           continue;
348
349         negative = *p == '-';
350         p += negative || *p == '+';
351
352         for (;;)
353           {
354             int digit = *p++ - '0';
355             if (9 < (unsigned) digit)
356               break;
357             else
358               {
359                 off_t c10 = 10 * count;
360                 off_t nc = negative ? c10 - digit : c10 + digit;
361                 if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
362                   {
363                     report_error_message (N_("Seek offset out of range"));
364                     exit (EXIT_FAILURE);
365                   }
366                 count = nc;
367               }
368           }
369
370         switch (atoi (position_string))
371           {
372           case 0: whence = SEEK_SET; break;
373           case 1: whence = SEEK_CUR; break;
374           case 2: whence = SEEK_END; break;
375           default:
376             report_error_message (N_("Seek direction out of range"));
377             exit (EXIT_FAILURE);
378           }
379         count = lseek (tape, count, whence);
380         if (count < 0)
381           goto ioerror;
382
383         /* Convert count back to string for reply.
384            We can't use sprintf, since off_t might be longer than long.  */
385         p = count_string + sizeof count_string;
386         *--p = '\0';
387         do
388           *--p = '0' + (int) (count % 10);
389         while ((count /= 10) != 0);
390         
391         DEBUG1 ("rmtd: A %s\n", p);
392
393         sprintf (reply_buffer, "A%s\n", p);
394         full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
395         goto top;
396       }
397
398     case 'W':
399       {
400         char count_string[STRING_SIZE];
401         size_t size;
402         size_t counter;
403
404         get_string (count_string);
405         size = atol (count_string);
406         DEBUG1 ("rmtd: W %s\n", count_string);
407
408         prepare_record_buffer (size);
409         for (counter = 0; counter < size; counter += status)
410           {
411             status = safe_read (STDIN_FILENO, &record_buffer[counter],
412                                 size - counter);
413             if (status <= 0)
414               {
415                 DEBUG (_("rmtd: Premature eof\n"));
416
417                 report_error_message (N_("Premature end of file"));
418                 exit (EXIT_FAILURE); /* exit status used to be 2 */
419               }
420           }
421         status = full_write (tape, record_buffer, size);
422         if (status < 0)
423           goto ioerror;
424         goto respond;
425       }
426
427     case 'R':
428       {
429         char count_string[STRING_SIZE];
430         size_t size;
431
432         get_string (count_string);
433         DEBUG1 ("rmtd: R %s\n", count_string);
434
435         size = atol (count_string);
436         prepare_record_buffer (size);
437         status = safe_read (tape, record_buffer, size);
438         if (status < 0)
439           goto ioerror;
440         sprintf (reply_buffer, "A%ld\n", (long) status);
441         full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
442         full_write (STDOUT_FILENO, record_buffer, status);
443         goto top;
444       }
445
446     case 'I':
447       {
448         char operation_string[STRING_SIZE];
449         char count_string[STRING_SIZE];
450
451         get_string (operation_string);
452         get_string  (count_string);
453         DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string);
454
455 #ifdef MTIOCTOP
456         {
457           struct mtop mtop;
458           const char *p;
459           off_t count = 0;
460           int negative;
461
462           /* Parse count_string, taking care to check for overflow.
463              We can't use standard functions,
464              since off_t might be longer than long.  */
465           
466           for (p = count_string;  *p == ' ' || *p == '\t';  p++)
467             continue;
468           
469           negative = *p == '-';
470           p += negative || *p == '+';
471           
472           for (;;)
473             {
474               int digit = *p++ - '0';
475               if (9 < (unsigned) digit)
476                 break;
477               else
478                 {
479                   off_t c10 = 10 * count;
480                   off_t nc = negative ? c10 - digit : c10 + digit;
481                   if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
482                     {
483                       report_error_message (N_("Seek offset out of range"));
484                       exit (EXIT_FAILURE);
485                     }
486                   count = nc;
487                 }
488             }
489
490           mtop.mt_count = count;
491           if (mtop.mt_count != count)
492             {
493               report_error_message (N_("Seek offset out of range"));
494               exit (EXIT_FAILURE);
495             }
496           mtop.mt_op = atoi (operation_string);
497
498           if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
499             goto ioerror;
500         }
501 #endif
502         goto respond;
503       }
504
505     case 'S':                   /* status */
506       {
507         DEBUG ("rmtd: S\n");
508
509 #ifdef MTIOCGET
510         {
511           struct mtget operation;
512
513           if (ioctl (tape, MTIOCGET, (char *) &operation) < 0)
514             goto ioerror;
515           status = sizeof operation;
516           sprintf (reply_buffer, "A%ld\n", (long) status);
517           full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
518           full_write (STDOUT_FILENO, (char *) &operation, sizeof operation);
519         }
520 #endif
521         goto top;
522       }
523
524     default:
525       DEBUG1 (_("rmtd: Garbage command %c\n"), command);
526
527       report_error_message (N_("Garbage command"));
528       exit (EXIT_FAILURE);      /* exit status used to be 3 */
529     }
530
531 respond:
532   DEBUG1 ("rmtd: A %ld\n", (long) status);
533
534   sprintf (reply_buffer, "A%ld\n", (long) status);
535   full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
536   goto top;
537
538 ioerror:
539   report_numbered_error (errno);
540   goto top;
541 }