]> Dogcows Code - chaz/tar/blob - src/rmt.c
(to_chars): Fix typo in decl.
[chaz/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 }
This page took 0.057053 seconds and 4 git commands to generate.