]>
Dogcows Code - chaz/tar/blob - src/rmt.c
1 /* Remote connection server.
2 Copyright 1994, 1995, 1996, 1997, 1999, 2000 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 <localedir.h>
34 #include <safe-read.h>
37 #include <sys/socket.h>
40 # define EXIT_FAILURE 1
43 # define EXIT_SUCCESS 0
46 /* Maximum size of a string from the requesting program. */
47 #define STRING_SIZE 64
49 /* Name of executing program. */
50 const char *program_name
;
52 /* File descriptor of the tape device, or negative if none open. */
55 /* Buffer containing transferred data, and its allocated size. */
56 static char *record_buffer
;
57 static size_t allocated_size
;
59 /* Buffer for constructing the reply. */
60 static char reply_buffer
[BUFSIZ
];
62 /* Debugging tools. */
64 static FILE *debug_file
;
67 if (debug_file) fprintf(debug_file, File)
69 #define DEBUG1(File, Arg) \
70 if (debug_file) fprintf(debug_file, File, Arg)
72 #define DEBUG2(File, Arg1, Arg2) \
73 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
75 /* Return an error string, given an error number. */
82 private_strerror (int errnum
)
84 extern char *sys_errlist
[];
87 if (errnum
> 0 && errnum
<= sys_nerr
)
88 return _(sys_errlist
[errnum
]);
89 return _("Unknown system error");
91 # define strerror private_strerror
95 report_error_message (const char *string
)
97 DEBUG1 ("rmtd: E 0 (%s)\n", string
);
99 sprintf (reply_buffer
, "E0\n%s\n", string
);
100 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
104 report_numbered_error (int num
)
106 DEBUG2 ("rmtd: E %d (%s)\n", num
, strerror (num
));
108 sprintf (reply_buffer
, "E%d\n%s\n", num
, strerror (num
));
109 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
113 get_string (char *string
)
117 for (counter
= 0; counter
< STRING_SIZE
; counter
++)
119 if (safe_read (STDIN_FILENO
, string
+ counter
, 1) != 1)
122 if (string
[counter
] == '\n')
125 string
[counter
] = '\0';
129 prepare_record_buffer (size_t size
)
131 if (size
<= allocated_size
)
135 free (record_buffer
);
137 record_buffer
= malloc (size
);
141 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
143 report_error_message (N_("Cannot allocate buffer space"));
144 exit (EXIT_FAILURE
); /* exit status used to be 4 */
147 allocated_size
= size
;
150 while (size
> 1024 &&
151 (setsockopt (STDIN_FILENO
, SOL_SOCKET
, SO_RCVBUF
,
152 (char *) &size
, sizeof size
)
156 /* FIXME: I do not see any purpose to the following line... Sigh! */
157 size
= 1 + ((size
- 1) % 1024);
161 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
162 OFLAG_STRING should contain an optional integer, followed by an optional
163 symbolic representation of an open flag using only '|' to separate its
164 components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
165 representation if available, falling back on the numeric
166 representation, or to zero if both formats are absent.
168 This function should be the inverse of encode_oflag. The numeric
169 representation is not portable from one host to another, but it is
170 for backward compatibility with old-fashioned clients that do not
171 emit symbolic open flags. */
174 decode_oflag (char const *oflag_string
)
177 int numeric_oflag
= strtol (oflag_string
, &oflag_num_end
, 10);
178 int symbolic_oflag
= 0;
180 oflag_string
= oflag_num_end
;
181 while (ISSPACE ((unsigned char) *oflag_string
))
186 struct name_value_pair
{ char const *name
; int value
; };
187 static struct name_value_pair
const table
[] =
190 {"APPEND", O_APPEND
},
198 {"LARGEFILE", O_LARGEFILE
}, /* LFS extension for opening large files */
201 {"NOCTTY", O_NOCTTY
},
204 {"NONBLOCK", O_NONBLOCK
},
206 {"RDONLY", O_RDONLY
},
217 struct name_value_pair
const *t
;
220 if (*oflag_string
++ != 'O' || *oflag_string
++ != '_')
221 return numeric_oflag
;
224 (strncmp (oflag_string
, t
->name
, s
= strlen (t
->name
)) != 0
226 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
229 if (t
== table
+ sizeof table
/ sizeof *table
- 1)
230 return numeric_oflag
;
232 symbolic_oflag
|= t
->value
;
235 while (*oflag_string
++ == '|');
237 return symbolic_oflag
;
240 static struct option
const long_opts
[] =
242 {"help", no_argument
, 0, 'h'},
243 {"version", no_argument
, 0, 'v'},
250 if (status
!= EXIT_SUCCESS
)
251 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
256 Usage: %s [OPTION]\n\
257 Manipulate a tape drive, accepting commands from a remote process.\n\
259 --version Output version info.\n\
260 --help Output this help.\n"),
262 fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout
);
269 main (int argc
, char *const *argv
)
274 /* FIXME: Localization is meaningless, unless --help and --version are
275 locally used. Localization would be best accomplished by the calling
276 tar, on messages found within error packets. */
278 program_name
= argv
[0];
279 setlocale (LC_ALL
, "");
280 bindtextdomain (PACKAGE
, LOCALEDIR
);
281 textdomain (PACKAGE
);
283 switch (getopt_long (argc
, argv
, "", long_opts
, NULL
))
286 usage (EXIT_FAILURE
);
289 usage (EXIT_SUCCESS
);
292 printf ("rmt (GNU %s) %s\n%s\n%s\n", PACKAGE
, VERSION
,
293 "Copyright 2000 Free Software Foundation, Inc.",
295 This program comes with NO WARRANTY, to the extent permitted by law.\n\
296 You may redistribute it under the terms of the GNU General Public License;\n\
297 see the file named COPYING for details."));
306 if (optind
!= argc
- 1)
307 usage (EXIT_FAILURE
);
308 debug_file
= fopen (argv
[optind
], "w");
311 report_numbered_error (errno
);
314 setbuf (debug_file
, 0);
320 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
325 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
329 char device_string
[STRING_SIZE
];
330 char oflag_string
[STRING_SIZE
];
332 get_string (device_string
);
333 get_string (oflag_string
);
334 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
339 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
347 char device_string
[STRING_SIZE
];
349 get_string (device_string
); /* discard */
352 if (close (tape
) < 0)
360 char count_string
[STRING_SIZE
];
361 char position_string
[STRING_SIZE
];
367 get_string (count_string
);
368 get_string (position_string
);
369 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
371 /* Parse count_string, taking care to check for overflow.
372 We can't use standard functions,
373 since off_t might be longer than long. */
375 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
378 negative
= *p
== '-';
379 p
+= negative
|| *p
== '+';
383 int digit
= *p
++ - '0';
384 if (9 < (unsigned) digit
)
388 off_t c10
= 10 * count
;
389 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
390 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
392 report_error_message (N_("Seek offset out of range"));
399 switch (atoi (position_string
))
401 case 0: whence
= SEEK_SET
; break;
402 case 1: whence
= SEEK_CUR
; break;
403 case 2: whence
= SEEK_END
; break;
405 report_error_message (N_("Seek direction out of range"));
408 count
= lseek (tape
, count
, whence
);
412 /* Convert count back to string for reply.
413 We can't use sprintf, since off_t might be longer than long. */
414 p
= count_string
+ sizeof count_string
;
417 *--p
= '0' + (int) (count
% 10);
418 while ((count
/= 10) != 0);
420 DEBUG1 ("rmtd: A %s\n", p
);
422 sprintf (reply_buffer
, "A%s\n", p
);
423 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
429 char count_string
[STRING_SIZE
];
433 get_string (count_string
);
434 size
= atol (count_string
);
435 DEBUG1 ("rmtd: W %s\n", count_string
);
437 prepare_record_buffer (size
);
438 for (counter
= 0; counter
< size
; counter
+= status
)
440 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
444 DEBUG (_("rmtd: Premature eof\n"));
446 report_error_message (N_("Premature end of file"));
447 exit (EXIT_FAILURE
); /* exit status used to be 2 */
450 status
= full_write (tape
, record_buffer
, size
);
458 char count_string
[STRING_SIZE
];
461 get_string (count_string
);
462 DEBUG1 ("rmtd: R %s\n", count_string
);
464 size
= atol (count_string
);
465 prepare_record_buffer (size
);
466 status
= safe_read (tape
, record_buffer
, size
);
469 sprintf (reply_buffer
, "A%ld\n", (long) status
);
470 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
471 full_write (STDOUT_FILENO
, record_buffer
, status
);
477 char operation_string
[STRING_SIZE
];
478 char count_string
[STRING_SIZE
];
480 get_string (operation_string
);
481 get_string (count_string
);
482 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
491 /* Parse count_string, taking care to check for overflow.
492 We can't use standard functions,
493 since off_t might be longer than long. */
495 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
498 negative
= *p
== '-';
499 p
+= negative
|| *p
== '+';
503 int digit
= *p
++ - '0';
504 if (9 < (unsigned) digit
)
508 off_t c10
= 10 * count
;
509 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
510 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
512 report_error_message (N_("Seek offset out of range"));
519 mtop
.mt_count
= count
;
520 if (mtop
.mt_count
!= count
)
522 report_error_message (N_("Seek offset out of range"));
525 mtop
.mt_op
= atoi (operation_string
);
527 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
534 case 'S': /* status */
540 struct mtget operation
;
542 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
544 status
= sizeof operation
;
545 sprintf (reply_buffer
, "A%ld\n", (long) status
);
546 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
547 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
554 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
556 report_error_message (N_("Garbage command"));
557 exit (EXIT_FAILURE
); /* exit status used to be 3 */
561 DEBUG1 ("rmtd: A %ld\n", (long) status
);
563 sprintf (reply_buffer
, "A%ld\n", (long) status
);
564 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
568 report_numbered_error (errno
);
This page took 0.061125 seconds and 4 git commands to generate.