]>
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. */
35 #include <print-copyr.h>
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 printf ("rmt (GNU %s) %s\n", PACKAGE
, VERSION
);
298 print_copyright ("2001 Free Software Foundation, Inc.");
300 This program comes with NO WARRANTY, to the extent permitted by law.\n\
301 You may redistribute it under the terms of the GNU General Public License;\n\
302 see the file named COPYING for details."));
312 if (optind
!= argc
- 1)
313 usage (EXIT_FAILURE
);
314 debug_file
= fopen (argv
[optind
], "w");
317 report_numbered_error (errno
);
320 setbuf (debug_file
, 0);
326 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
331 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
335 char device_string
[STRING_SIZE
];
336 char oflag_string
[STRING_SIZE
];
338 get_string (device_string
);
339 get_string (oflag_string
);
340 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
345 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
353 char device_string
[STRING_SIZE
];
355 get_string (device_string
); /* discard */
358 if (close (tape
) < 0)
366 char count_string
[STRING_SIZE
];
367 char position_string
[STRING_SIZE
];
373 get_string (count_string
);
374 get_string (position_string
);
375 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
377 /* Parse count_string, taking care to check for overflow.
378 We can't use standard functions,
379 since off_t might be longer than long. */
381 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
384 negative
= *p
== '-';
385 p
+= negative
|| *p
== '+';
389 int digit
= *p
++ - '0';
390 if (9 < (unsigned) digit
)
394 off_t c10
= 10 * count
;
395 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
396 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
398 report_error_message (N_("Seek offset out of range"));
405 switch (atoi (position_string
))
407 case 0: whence
= SEEK_SET
; break;
408 case 1: whence
= SEEK_CUR
; break;
409 case 2: whence
= SEEK_END
; break;
411 report_error_message (N_("Seek direction out of range"));
414 count
= lseek (tape
, count
, whence
);
418 /* Convert count back to string for reply.
419 We can't use sprintf, since off_t might be longer than long. */
420 p
= count_string
+ sizeof count_string
;
423 *--p
= '0' + (int) (count
% 10);
424 while ((count
/= 10) != 0);
426 DEBUG1 ("rmtd: A %s\n", p
);
428 sprintf (reply_buffer
, "A%s\n", p
);
429 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
435 char count_string
[STRING_SIZE
];
439 get_string (count_string
);
440 size
= atol (count_string
);
441 DEBUG1 ("rmtd: W %s\n", count_string
);
443 prepare_record_buffer (size
);
444 for (counter
= 0; counter
< size
; counter
+= status
)
446 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
450 DEBUG (_("rmtd: Premature eof\n"));
452 report_error_message (N_("Premature end of file"));
453 exit (EXIT_FAILURE
); /* exit status used to be 2 */
456 status
= full_write (tape
, record_buffer
, size
);
464 char count_string
[STRING_SIZE
];
467 get_string (count_string
);
468 DEBUG1 ("rmtd: R %s\n", count_string
);
470 size
= atol (count_string
);
471 prepare_record_buffer (size
);
472 status
= safe_read (tape
, record_buffer
, size
);
475 sprintf (reply_buffer
, "A%ld\n", (long) status
);
476 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
477 full_write (STDOUT_FILENO
, record_buffer
, status
);
483 char operation_string
[STRING_SIZE
];
484 char count_string
[STRING_SIZE
];
486 get_string (operation_string
);
487 get_string (count_string
);
488 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
497 /* Parse count_string, taking care to check for overflow.
498 We can't use standard functions,
499 since off_t might be longer than long. */
501 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
504 negative
= *p
== '-';
505 p
+= negative
|| *p
== '+';
509 int digit
= *p
++ - '0';
510 if (9 < (unsigned) digit
)
514 off_t c10
= 10 * count
;
515 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
516 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
518 report_error_message (N_("Seek offset out of range"));
525 mtop
.mt_count
= count
;
526 if (mtop
.mt_count
!= count
)
528 report_error_message (N_("Seek offset out of range"));
531 mtop
.mt_op
= atoi (operation_string
);
533 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
540 case 'S': /* status */
546 struct mtget operation
;
548 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
550 status
= sizeof operation
;
551 sprintf (reply_buffer
, "A%ld\n", (long) status
);
552 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
553 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
560 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
562 report_error_message (N_("Garbage command"));
563 exit (EXIT_FAILURE
); /* exit status used to be 3 */
567 DEBUG1 ("rmtd: A %ld\n", (long) status
);
569 sprintf (reply_buffer
, "A%ld\n", (long) status
);
570 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
574 report_numbered_error (errno
);
This page took 0.060786 seconds and 4 git commands to generate.