]>
Dogcows Code - chaz/tar/blob - src/rmt.c
1 /* Remote connection server.
3 Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004
4 Free Software Foundation, Inc.
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 <localedir.h>
36 #include <safe-read.h>
37 #include <full-write.h>
40 #include <sys/socket.h>
43 # define EXIT_FAILURE 1
46 # define EXIT_SUCCESS 0
49 /* Maximum size of a string from the requesting program. */
50 #define STRING_SIZE 64
52 /* Name of executing program. */
53 const char *program_name
;
55 /* File descriptor of the tape device, or negative if none open. */
58 /* Buffer containing transferred data, and its allocated size. */
59 static char *record_buffer
;
60 static size_t allocated_size
;
62 /* Buffer for constructing the reply. */
63 static char reply_buffer
[BUFSIZ
];
65 /* Debugging tools. */
67 static FILE *debug_file
;
70 if (debug_file) fprintf(debug_file, File)
72 #define DEBUG1(File, Arg) \
73 if (debug_file) fprintf(debug_file, File, Arg)
75 #define DEBUG2(File, Arg1, Arg2) \
76 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
78 /* Return an error string, given an error number. */
85 private_strerror (int errnum
)
87 extern char *sys_errlist
[];
90 if (errnum
> 0 && errnum
<= sys_nerr
)
91 return _(sys_errlist
[errnum
]);
92 return _("Unknown system error");
94 # define strerror private_strerror
98 report_error_message (const char *string
)
100 DEBUG1 ("rmtd: E 0 (%s)\n", string
);
102 sprintf (reply_buffer
, "E0\n%s\n", string
);
103 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
107 report_numbered_error (int num
)
109 DEBUG2 ("rmtd: E %d (%s)\n", num
, strerror (num
));
111 sprintf (reply_buffer
, "E%d\n%s\n", num
, strerror (num
));
112 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
116 get_string (char *string
)
120 for (counter
= 0; ; counter
++)
122 if (safe_read (STDIN_FILENO
, string
+ counter
, 1) != 1)
125 if (string
[counter
] == '\n' || counter
== STRING_SIZE
- 1)
128 string
[counter
] = '\0';
132 prepare_input_buffer (int fd
, size_t size
)
134 if (size
<= allocated_size
)
138 free (record_buffer
);
140 record_buffer
= malloc (size
);
144 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
146 report_error_message (N_("Cannot allocate buffer space"));
147 exit (EXIT_FAILURE
); /* exit status used to be 4 */
150 allocated_size
= size
;
155 int isize
= size
< INT_MAX
? size
: INT_MAX
;
156 while (setsockopt (fd
, SOL_SOCKET
, SO_RCVBUF
,
157 (char *) &isize
, sizeof isize
)
164 /* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
165 OFLAG_STRING should contain an optional integer, followed by an optional
166 symbolic representation of an open flag using only '|' to separate its
167 components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
168 representation if available, falling back on the numeric
169 representation, or to zero if both formats are absent.
171 This function should be the inverse of encode_oflag. The numeric
172 representation is not portable from one host to another, but it is
173 for backward compatibility with old-fashioned clients that do not
174 emit symbolic open flags. */
177 decode_oflag (char const *oflag_string
)
180 int numeric_oflag
= strtol (oflag_string
, &oflag_num_end
, 10);
181 int symbolic_oflag
= 0;
183 oflag_string
= oflag_num_end
;
184 while (ISSPACE ((unsigned char) *oflag_string
))
189 struct name_value_pair
{ char const *name
; int value
; };
190 static struct name_value_pair
const table
[] =
193 {"APPEND", O_APPEND
},
201 {"LARGEFILE", O_LARGEFILE
}, /* LFS extension for opening large files */
204 {"NOCTTY", O_NOCTTY
},
207 {"NONBLOCK", O_NONBLOCK
},
209 {"RDONLY", O_RDONLY
},
220 struct name_value_pair
const *t
;
223 if (*oflag_string
++ != 'O' || *oflag_string
++ != '_')
224 return numeric_oflag
;
227 (strncmp (oflag_string
, t
->name
, s
= strlen (t
->name
)) != 0
229 && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
232 if (t
== table
+ sizeof table
/ sizeof *table
- 1)
233 return numeric_oflag
;
235 symbolic_oflag
|= t
->value
;
238 while (*oflag_string
++ == '|');
240 return symbolic_oflag
;
243 static struct option
const long_opts
[] =
245 {"help", no_argument
, 0, 'h'},
246 {"version", no_argument
, 0, 'v'},
250 static void usage (int) __attribute__ ((noreturn
));
255 if (status
!= EXIT_SUCCESS
)
256 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
261 Usage: %s [OPTION]\n\
262 Manipulate a tape drive, accepting commands from a remote process.\n\
264 --version Output version info.\n\
265 --help Output this help.\n"),
267 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
274 main (int argc
, char *const *argv
)
279 /* FIXME: Localization is meaningless, unless --help and --version are
280 locally used. Localization would be best accomplished by the calling
281 tar, on messages found within error packets. */
283 program_name
= argv
[0];
284 setlocale (LC_ALL
, "");
285 bindtextdomain (PACKAGE
, LOCALEDIR
);
286 textdomain (PACKAGE
);
288 switch (getopt_long (argc
, argv
, "", long_opts
, NULL
))
291 usage (EXIT_FAILURE
);
294 usage (EXIT_SUCCESS
);
298 printf ("rmt (%s) %s\n%s\n", PACKAGE_NAME
, PACKAGE_VERSION
,
299 "Copyright (C) 2004 Free Software Foundation, Inc.");
301 This program comes with NO WARRANTY, to the extent permitted by law.\n\
302 You may redistribute it under the terms of the GNU General Public License;\n\
303 see the file named COPYING for details."));
313 if (optind
!= argc
- 1)
314 usage (EXIT_FAILURE
);
315 debug_file
= fopen (argv
[optind
], "w");
318 report_numbered_error (errno
);
321 setbuf (debug_file
, 0);
327 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
332 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
336 char device_string
[STRING_SIZE
];
337 char oflag_string
[STRING_SIZE
];
339 get_string (device_string
);
340 get_string (oflag_string
);
341 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
346 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
354 char device_string
[STRING_SIZE
];
356 get_string (device_string
); /* discard */
359 if (close (tape
) < 0)
367 char count_string
[STRING_SIZE
];
368 char position_string
[STRING_SIZE
];
374 get_string (count_string
);
375 get_string (position_string
);
376 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
378 /* Parse count_string, taking care to check for overflow.
379 We can't use standard functions,
380 since off_t might be longer than long. */
382 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
385 negative
= *p
== '-';
386 p
+= negative
|| *p
== '+';
390 int digit
= *p
++ - '0';
391 if (9 < (unsigned) digit
)
395 off_t c10
= 10 * count
;
396 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
397 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
399 report_error_message (N_("Seek offset out of range"));
406 switch (atoi (position_string
))
408 case 0: whence
= SEEK_SET
; break;
409 case 1: whence
= SEEK_CUR
; break;
410 case 2: whence
= SEEK_END
; break;
412 report_error_message (N_("Seek direction out of range"));
415 count
= lseek (tape
, count
, whence
);
419 /* Convert count back to string for reply.
420 We can't use sprintf, since off_t might be longer than long. */
421 p
= count_string
+ sizeof count_string
;
424 *--p
= '0' + (int) (count
% 10);
425 while ((count
/= 10) != 0);
427 DEBUG1 ("rmtd: A %s\n", p
);
429 sprintf (reply_buffer
, "A%s\n", p
);
430 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
436 char count_string
[STRING_SIZE
];
440 get_string (count_string
);
441 size
= atol (count_string
);
442 DEBUG1 ("rmtd: W %s\n", count_string
);
444 prepare_input_buffer (STDIN_FILENO
, size
);
445 for (counter
= 0; counter
< size
; counter
+= status
)
447 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
449 if (status
== SAFE_READ_ERROR
|| status
== 0)
451 DEBUG (_("rmtd: Premature eof\n"));
453 report_error_message (N_("Premature end of file"));
454 return EXIT_FAILURE
; /* exit status used to be 2 */
457 status
= full_write (tape
, record_buffer
, size
);
465 char count_string
[STRING_SIZE
];
468 get_string (count_string
);
469 DEBUG1 ("rmtd: R %s\n", count_string
);
471 size
= atol (count_string
);
472 prepare_input_buffer (-1, size
);
473 status
= safe_read (tape
, record_buffer
, size
);
474 if (status
== SAFE_READ_ERROR
)
476 sprintf (reply_buffer
, "A%lu\n", (unsigned long int) status
);
477 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
478 full_write (STDOUT_FILENO
, record_buffer
, status
);
484 char operation_string
[STRING_SIZE
];
485 char count_string
[STRING_SIZE
];
487 get_string (operation_string
);
488 get_string (count_string
);
489 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
498 /* Parse count_string, taking care to check for overflow.
499 We can't use standard functions,
500 since off_t might be longer than long. */
502 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
505 negative
= *p
== '-';
506 p
+= negative
|| *p
== '+';
510 int digit
= *p
++ - '0';
511 if (9 < (unsigned) digit
)
515 off_t c10
= 10 * count
;
516 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
517 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
519 report_error_message (N_("Seek offset out of range"));
526 mtop
.mt_count
= count
;
527 if (mtop
.mt_count
!= count
)
529 report_error_message (N_("Seek offset out of range"));
532 mtop
.mt_op
= atoi (operation_string
);
534 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
541 case 'S': /* status */
547 struct mtget operation
;
549 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
551 status
= sizeof operation
;
552 sprintf (reply_buffer
, "A%ld\n", (long) status
);
553 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
554 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
561 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
563 report_error_message (N_("Garbage command"));
564 return EXIT_FAILURE
; /* exit status used to be 3 */
568 DEBUG1 ("rmtd: A %ld\n", (long) status
);
570 sprintf (reply_buffer
, "A%ld\n", (long) status
);
571 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
575 report_numbered_error (errno
);
This page took 0.066521 seconds and 4 git commands to generate.