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