]>
Dogcows Code - chaz/tar/blob - src/rmt.c
1 /* Remote connection server.
3 Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free Software
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
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.
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. */
20 /* Copyright (C) 1983 Regents of the University of California.
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. */
36 #include <localedir.h>
37 #include <safe-read.h>
38 #include <full-write.h>
41 #include <sys/socket.h>
44 # define EXIT_FAILURE 1
47 # define EXIT_SUCCESS 0
50 /* Maximum size of a string from the requesting program. */
51 #define STRING_SIZE 64
53 /* Name of executing program. */
54 const char *program_name
;
56 /* File descriptor of the tape device, or negative if none open. */
59 /* Buffer containing transferred data, and its allocated size. */
60 static char *record_buffer
;
61 static size_t allocated_size
;
63 /* Buffer for constructing the reply. */
64 static char reply_buffer
[BUFSIZ
];
66 /* Debugging tools. */
68 static FILE *debug_file
;
71 if (debug_file) fprintf(debug_file, File)
73 #define DEBUG1(File, Arg) \
74 if (debug_file) fprintf(debug_file, File, Arg)
76 #define DEBUG2(File, Arg1, Arg2) \
77 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
79 /* Return an error string, given an error number. */
86 private_strerror (int errnum
)
88 extern char *sys_errlist
[];
91 if (errnum
> 0 && errnum
<= sys_nerr
)
92 return _(sys_errlist
[errnum
]);
93 return _("Unknown system error");
95 # define strerror private_strerror
99 report_error_message (const char *string
)
101 DEBUG1 ("rmtd: E 0 (%s)\n", string
);
103 sprintf (reply_buffer
, "E0\n%s\n", string
);
104 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
108 report_numbered_error (int num
)
110 DEBUG2 ("rmtd: E %d (%s)\n", num
, strerror (num
));
112 sprintf (reply_buffer
, "E%d\n%s\n", num
, strerror (num
));
113 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
117 get_string (char *string
)
121 for (counter
= 0; counter
< STRING_SIZE
; counter
++)
123 if (safe_read (STDIN_FILENO
, string
+ counter
, 1) != 1)
126 if (string
[counter
] == '\n')
129 string
[counter
] = '\0';
133 prepare_record_buffer (size_t size
)
135 if (size
<= allocated_size
)
139 free (record_buffer
);
141 record_buffer
= malloc (size
);
145 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
147 report_error_message (N_("Cannot allocate buffer space"));
148 exit (EXIT_FAILURE
); /* exit status used to be 4 */
151 allocated_size
= size
;
154 while (size
> 1024 &&
155 (setsockopt (STDIN_FILENO
, SOL_SOCKET
, SO_RCVBUF
,
156 (char *) &size
, sizeof size
)
160 /* FIXME: I do not see any purpose to the following line... Sigh! */
161 size
= 1 + ((size
- 1) % 1024);
165 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
166 OFLAG_STRING should contain an optional integer, followed by an optional
167 symbolic representation of an open flag using only '|' to separate its
168 components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
169 representation if available, falling back on the numeric
170 representation, or to zero if both formats are absent.
172 This function should be the inverse of encode_oflag. The numeric
173 representation is not portable from one host to another, but it is
174 for backward compatibility with old-fashioned clients that do not
175 emit symbolic open flags. */
178 decode_oflag (char const *oflag_string
)
181 int numeric_oflag
= strtol (oflag_string
, &oflag_num_end
, 10);
182 int symbolic_oflag
= 0;
184 oflag_string
= oflag_num_end
;
185 while (ISSPACE ((unsigned char) *oflag_string
))
190 struct name_value_pair
{ char const *name
; int value
; };
191 static struct name_value_pair
const table
[] =
194 {"APPEND", O_APPEND
},
202 {"LARGEFILE", O_LARGEFILE
}, /* LFS extension for opening large files */
205 {"NOCTTY", O_NOCTTY
},
208 {"NONBLOCK", O_NONBLOCK
},
210 {"RDONLY", O_RDONLY
},
221 struct name_value_pair
const *t
;
224 if (*oflag_string
++ != 'O' || *oflag_string
++ != '_')
225 return numeric_oflag
;
228 (strncmp (oflag_string
, t
->name
, s
= strlen (t
->name
)) != 0
230 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
233 if (t
== table
+ sizeof table
/ sizeof *table
- 1)
234 return numeric_oflag
;
236 symbolic_oflag
|= t
->value
;
239 while (*oflag_string
++ == '|');
241 return symbolic_oflag
;
244 static struct option
const long_opts
[] =
246 {"help", no_argument
, 0, 'h'},
247 {"version", no_argument
, 0, 'v'},
254 if (status
!= EXIT_SUCCESS
)
255 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
260 Usage: %s [OPTION]\n\
261 Manipulate a tape drive, accepting commands from a remote process.\n\
263 --version Output version info.\n\
264 --help Output this help.\n"),
266 fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout
);
273 main (int argc
, char *const *argv
)
278 /* FIXME: Localization is meaningless, unless --help and --version are
279 locally used. Localization would be best accomplished by the calling
280 tar, on messages found within error packets. */
282 program_name
= argv
[0];
283 setlocale (LC_ALL
, "");
284 bindtextdomain (PACKAGE
, LOCALEDIR
);
285 textdomain (PACKAGE
);
287 switch (getopt_long (argc
, argv
, "", long_opts
, NULL
))
290 usage (EXIT_FAILURE
);
293 usage (EXIT_SUCCESS
);
297 char buf
[MB_LEN_MAX
+ 1];
298 printf ("rmt (GNU %s) %s\n", PACKAGE
, VERSION
);
299 printf ("Copyright %s 2001 Free Software Foundation, Inc.\n",
300 copyright_symbol (buf
, sizeof buf
));
302 This program comes with NO WARRANTY, to the extent permitted by law.\n\
303 You may redistribute it under the terms of the GNU General Public License;\n\
304 see the file named COPYING for details."));
314 if (optind
!= argc
- 1)
315 usage (EXIT_FAILURE
);
316 debug_file
= fopen (argv
[optind
], "w");
319 report_numbered_error (errno
);
322 setbuf (debug_file
, 0);
328 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
333 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
337 char device_string
[STRING_SIZE
];
338 char oflag_string
[STRING_SIZE
];
340 get_string (device_string
);
341 get_string (oflag_string
);
342 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
347 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
355 char device_string
[STRING_SIZE
];
357 get_string (device_string
); /* discard */
360 if (close (tape
) < 0)
368 char count_string
[STRING_SIZE
];
369 char position_string
[STRING_SIZE
];
375 get_string (count_string
);
376 get_string (position_string
);
377 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
379 /* Parse count_string, taking care to check for overflow.
380 We can't use standard functions,
381 since off_t might be longer than long. */
383 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
386 negative
= *p
== '-';
387 p
+= negative
|| *p
== '+';
391 int digit
= *p
++ - '0';
392 if (9 < (unsigned) digit
)
396 off_t c10
= 10 * count
;
397 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
398 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
400 report_error_message (N_("Seek offset out of range"));
407 switch (atoi (position_string
))
409 case 0: whence
= SEEK_SET
; break;
410 case 1: whence
= SEEK_CUR
; break;
411 case 2: whence
= SEEK_END
; break;
413 report_error_message (N_("Seek direction out of range"));
416 count
= lseek (tape
, count
, whence
);
420 /* Convert count back to string for reply.
421 We can't use sprintf, since off_t might be longer than long. */
422 p
= count_string
+ sizeof count_string
;
425 *--p
= '0' + (int) (count
% 10);
426 while ((count
/= 10) != 0);
428 DEBUG1 ("rmtd: A %s\n", p
);
430 sprintf (reply_buffer
, "A%s\n", p
);
431 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
437 char count_string
[STRING_SIZE
];
441 get_string (count_string
);
442 size
= atol (count_string
);
443 DEBUG1 ("rmtd: W %s\n", count_string
);
445 prepare_record_buffer (size
);
446 for (counter
= 0; counter
< size
; counter
+= status
)
448 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
452 DEBUG (_("rmtd: Premature eof\n"));
454 report_error_message (N_("Premature end of file"));
455 exit (EXIT_FAILURE
); /* exit status used to be 2 */
458 status
= full_write (tape
, record_buffer
, size
);
466 char count_string
[STRING_SIZE
];
469 get_string (count_string
);
470 DEBUG1 ("rmtd: R %s\n", count_string
);
472 size
= atol (count_string
);
473 prepare_record_buffer (size
);
474 status
= safe_read (tape
, record_buffer
, size
);
477 sprintf (reply_buffer
, "A%ld\n", (long) status
);
478 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
479 full_write (STDOUT_FILENO
, record_buffer
, status
);
485 char operation_string
[STRING_SIZE
];
486 char count_string
[STRING_SIZE
];
488 get_string (operation_string
);
489 get_string (count_string
);
490 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
499 /* Parse count_string, taking care to check for overflow.
500 We can't use standard functions,
501 since off_t might be longer than long. */
503 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
506 negative
= *p
== '-';
507 p
+= negative
|| *p
== '+';
511 int digit
= *p
++ - '0';
512 if (9 < (unsigned) digit
)
516 off_t c10
= 10 * count
;
517 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
518 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
520 report_error_message (N_("Seek offset out of range"));
527 mtop
.mt_count
= count
;
528 if (mtop
.mt_count
!= count
)
530 report_error_message (N_("Seek offset out of range"));
533 mtop
.mt_op
= atoi (operation_string
);
535 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
542 case 'S': /* status */
548 struct mtget operation
;
550 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
552 status
= sizeof operation
;
553 sprintf (reply_buffer
, "A%ld\n", (long) status
);
554 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
555 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
562 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
564 report_error_message (N_("Garbage command"));
565 exit (EXIT_FAILURE
); /* exit status used to be 3 */
569 DEBUG1 ("rmtd: A %ld\n", (long) status
);
571 sprintf (reply_buffer
, "A%ld\n", (long) status
);
572 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
576 report_numbered_error (errno
);
This page took 0.060396 seconds and 4 git commands to generate.