]>
Dogcows Code - chaz/tar/blob - src/rmt.c
1 /* Remote connection server.
2 Copyright 1994, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
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
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.
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. */
18 /* Copyright (C) 1983 Regents of the University of California.
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. */
33 #include "safe-read.h"
36 #include <sys/socket.h>
39 # define EXIT_FAILURE 1
42 # define EXIT_SUCCESS 0
45 /* Maximum size of a string from the requesting program. */
46 #define STRING_SIZE 64
48 /* Name of executing program. */
49 const char *program_name
;
51 /* File descriptor of the tape device, or negative if none open. */
54 /* Buffer containing transferred data, and its allocated size. */
55 static char *record_buffer
;
56 static size_t allocated_size
;
58 /* Buffer for constructing the reply. */
59 static char reply_buffer
[BUFSIZ
];
61 /* Debugging tools. */
63 static FILE *debug_file
;
66 if (debug_file) fprintf(debug_file, File)
68 #define DEBUG1(File, Arg) \
69 if (debug_file) fprintf(debug_file, File, Arg)
71 #define DEBUG2(File, Arg1, Arg2) \
72 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
74 /*------------------------------------------------.
75 | Return an error string, given an error number. |
76 `------------------------------------------------*/
84 private_strerror (int errnum
)
86 extern char *sys_errlist
[];
89 if (errnum
> 0 && errnum
<= sys_nerr
)
90 return _(sys_errlist
[errnum
]);
91 return _("Unknown system error");
93 # define strerror private_strerror
101 report_error_message (const char *string
)
103 DEBUG1 ("rmtd: E 0 (%s)\n", string
);
105 sprintf (reply_buffer
, "E0\n%s\n", string
);
106 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
114 report_numbered_error (int num
)
116 DEBUG2 ("rmtd: E %d (%s)\n", num
, strerror (num
));
118 sprintf (reply_buffer
, "E%d\n%s\n", num
, strerror (num
));
119 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
127 get_string (char *string
)
131 for (counter
= 0; counter
< STRING_SIZE
; counter
++)
133 if (safe_read (STDIN_FILENO
, string
+ counter
, 1) != 1)
136 if (string
[counter
] == '\n')
139 string
[counter
] = '\0';
147 prepare_record_buffer (size_t size
)
149 if (size
<= allocated_size
)
153 free (record_buffer
);
155 record_buffer
= malloc (size
);
159 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
161 report_error_message (N_("Cannot allocate buffer space"));
162 exit (EXIT_FAILURE
); /* exit status used to be 4 */
165 allocated_size
= size
;
168 while (size
> 1024 &&
169 (setsockopt (STDIN_FILENO
, SOL_SOCKET
, SO_RCVBUF
,
170 (char *) &size
, sizeof size
)
174 /* FIXME: I do not see any purpose to the following line... Sigh! */
175 size
= 1 + ((size
- 1) % 1024);
179 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
180 OFLAG_STRING should contain an optional integer, followed by an optional
181 symbolic representation of an open flag using only '|' to separate its
182 components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
183 representation if available, falling back on the numeric
184 representation, or to zero if both formats are absent.
186 This function should be the inverse of encode_oflag. The numeric
187 representation is not portable from one host to another, but it is
188 for backward compatibility with old-fashioned clients that do not
189 emit symbolic open flags. */
192 decode_oflag (char const *oflag_string
)
195 int numeric_oflag
= strtol (oflag_string
, &oflag_num_end
, 10);
196 int symbolic_oflag
= 0;
198 oflag_string
= oflag_num_end
;
199 while (ISSPACE ((unsigned char) *oflag_string
))
204 struct name_value_pair
{ char const *name
; int value
; };
205 static struct name_value_pair
const table
[] =
207 {"APPEND", O_APPEND
},
214 {"LARGEFILE", O_LARGEFILE
}, /* LFS extension for opening large files */
217 {"NOCTTY", O_NOCTTY
},
220 {"NONBLOCK", O_NONBLOCK
},
222 {"RDONLY", O_RDONLY
},
233 struct name_value_pair
const *t
;
236 if (*oflag_string
++ != 'O' || *oflag_string
++ != '_')
237 return numeric_oflag
;
240 (strncmp (oflag_string
, t
->name
, s
= strlen (t
->name
)) != 0
242 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
245 if (t
== table
+ sizeof table
/ sizeof *table
- 1)
246 return numeric_oflag
;
248 symbolic_oflag
|= t
->value
;
251 while (*oflag_string
++ == '|');
253 return symbolic_oflag
;
256 static struct option
const long_opts
[] =
258 {"help", no_argument
, 0, 'h'},
259 {"version", no_argument
, 0, 'v'},
266 if (status
!= EXIT_SUCCESS
)
267 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
272 Usage: %s [OPTION]\n\
273 Manipulate a tape drive, accepting commands from a remote process.\n\
275 --version Output version info.\n\
276 --help Output this help.\n"),
278 fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout
);
289 main (int argc
, char *const *argv
)
294 /* FIXME: Localization is meaningless, unless --help and --version are
295 locally used. Localization would be best accomplished by the calling
296 tar, on messages found within error packets. */
298 program_name
= argv
[0];
299 setlocale (LC_ALL
, "");
300 bindtextdomain (PACKAGE
, LOCALEDIR
);
301 textdomain (PACKAGE
);
303 switch (getopt_long (argc
, argv
, "", long_opts
, NULL
))
306 usage (EXIT_FAILURE
);
309 usage (EXIT_SUCCESS
);
312 printf ("rmt (GNU %s) %s\n%s\n%s\n", PACKAGE
, VERSION
,
313 "Copyright 1999 Free Software Foundation, Inc.",
315 This program comes with NO WARRANTY, to the extent permitted by law.\n\
316 You may redistribute it under the terms of the GNU General Public License;\n\
317 see the file named COPYING for details."));
326 if (optind
!= argc
- 1)
327 usage (EXIT_FAILURE
);
328 debug_file
= fopen (argv
[optind
], "w");
331 report_numbered_error (errno
);
334 setbuf (debug_file
, 0);
338 errno
= 0; /* FIXME: errno should be read-only */
340 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
345 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
349 char device_string
[STRING_SIZE
];
350 char oflag_string
[STRING_SIZE
];
352 get_string (device_string
);
353 get_string (oflag_string
);
354 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
359 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
367 char device_string
[STRING_SIZE
];
369 get_string (device_string
); /* discard */
372 if (close (tape
) < 0)
380 char count_string
[STRING_SIZE
];
381 char position_string
[STRING_SIZE
];
387 get_string (count_string
);
388 get_string (position_string
);
389 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
391 /* Parse count_string, taking care to check for overflow.
392 We can't use standard functions,
393 since off_t might be longer than long. */
395 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
398 negative
= *p
== '-';
399 p
+= negative
|| *p
== '+';
403 int digit
= *p
++ - '0';
404 if (9 < (unsigned) digit
)
408 off_t c10
= 10 * count
;
409 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
410 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
412 report_error_message (N_("Seek offset out of range"));
419 switch (atoi (position_string
))
421 case 0: whence
= SEEK_SET
; break;
422 case 1: whence
= SEEK_CUR
; break;
423 case 2: whence
= SEEK_END
; break;
425 report_error_message (N_("Seek direction out of range"));
428 count
= lseek (tape
, count
, whence
);
432 /* Convert count back to string for reply.
433 We can't use sprintf, since off_t might be longer than long. */
434 p
= count_string
+ sizeof count_string
;
437 *--p
= '0' + (int) (count
% 10);
438 while ((count
/= 10) != 0);
440 DEBUG1 ("rmtd: A %s\n", p
);
442 sprintf (reply_buffer
, "A%s\n", p
);
443 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
449 char count_string
[STRING_SIZE
];
453 get_string (count_string
);
454 size
= atol (count_string
);
455 DEBUG1 ("rmtd: W %s\n", count_string
);
457 prepare_record_buffer (size
);
458 for (counter
= 0; counter
< size
; counter
+= status
)
460 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
464 DEBUG (_("rmtd: Premature eof\n"));
466 report_error_message (N_("Premature end of file"));
467 exit (EXIT_FAILURE
); /* exit status used to be 2 */
470 status
= full_write (tape
, record_buffer
, size
);
478 char count_string
[STRING_SIZE
];
481 get_string (count_string
);
482 DEBUG1 ("rmtd: R %s\n", count_string
);
484 size
= atol (count_string
);
485 prepare_record_buffer (size
);
486 status
= safe_read (tape
, record_buffer
, size
);
489 sprintf (reply_buffer
, "A%ld\n", (long) status
);
490 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
491 full_write (STDOUT_FILENO
, record_buffer
, status
);
497 char operation_string
[STRING_SIZE
];
498 char count_string
[STRING_SIZE
];
500 get_string (operation_string
);
501 get_string (count_string
);
502 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
511 /* Parse count_string, taking care to check for overflow.
512 We can't use standard functions,
513 since off_t might be longer than long. */
515 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
518 negative
= *p
== '-';
519 p
+= negative
|| *p
== '+';
523 int digit
= *p
++ - '0';
524 if (9 < (unsigned) digit
)
528 off_t c10
= 10 * count
;
529 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
530 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
532 report_error_message (N_("Seek offset out of range"));
539 mtop
.mt_count
= count
;
540 if (mtop
.mt_count
!= count
)
542 report_error_message (N_("Seek offset out of range"));
545 mtop
.mt_op
= atoi (operation_string
);
547 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
554 case 'S': /* status */
560 struct mtget operation
;
562 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
564 status
= sizeof operation
;
565 sprintf (reply_buffer
, "A%ld\n", (long) status
);
566 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
567 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
574 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
576 report_error_message (N_("Garbage command"));
577 exit (EXIT_FAILURE
); /* exit status used to be 3 */
581 DEBUG1 ("rmtd: A %ld\n", (long) status
);
583 sprintf (reply_buffer
, "A%ld\n", (long) status
);
584 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
588 report_numbered_error (errno
);
This page took 0.058823 seconds and 4 git commands to generate.