]>
Dogcows Code - chaz/tar/blob - src/rmt.c
1 /* Remote connection server.
3 Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free
4 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
< STRING_SIZE
; counter
++)
122 if (safe_read (STDIN_FILENO
, string
+ counter
, 1) != 1)
125 if (string
[counter
] == '\n')
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'},
253 if (status
!= EXIT_SUCCESS
)
254 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
259 Usage: %s [OPTION]\n\
260 Manipulate a tape drive, accepting commands from a remote process.\n\
262 --version Output version info.\n\
263 --help Output this help.\n"),
265 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
272 main (int argc
, char *const *argv
)
277 /* FIXME: Localization is meaningless, unless --help and --version are
278 locally used. Localization would be best accomplished by the calling
279 tar, on messages found within error packets. */
281 program_name
= argv
[0];
282 setlocale (LC_ALL
, "");
283 bindtextdomain (PACKAGE
, LOCALEDIR
);
284 textdomain (PACKAGE
);
286 switch (getopt_long (argc
, argv
, "", long_opts
, NULL
))
289 usage (EXIT_FAILURE
);
292 usage (EXIT_SUCCESS
);
296 printf ("rmt (%s) %s\n%s\n", PACKAGE_NAME
, PACKAGE_VERSION
,
297 "Copyright (C) 2003 Free Software Foundation, Inc.");
299 This program comes with NO WARRANTY, to the extent permitted by law.\n\
300 You may redistribute it under the terms of the GNU General Public License;\n\
301 see the file named COPYING for details."));
311 if (optind
!= argc
- 1)
312 usage (EXIT_FAILURE
);
313 debug_file
= fopen (argv
[optind
], "w");
316 report_numbered_error (errno
);
319 setbuf (debug_file
, 0);
325 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
330 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
334 char device_string
[STRING_SIZE
];
335 char oflag_string
[STRING_SIZE
];
337 get_string (device_string
);
338 get_string (oflag_string
);
339 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
344 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
352 char device_string
[STRING_SIZE
];
354 get_string (device_string
); /* discard */
357 if (close (tape
) < 0)
365 char count_string
[STRING_SIZE
];
366 char position_string
[STRING_SIZE
];
372 get_string (count_string
);
373 get_string (position_string
);
374 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
376 /* Parse count_string, taking care to check for overflow.
377 We can't use standard functions,
378 since off_t might be longer than long. */
380 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
383 negative
= *p
== '-';
384 p
+= negative
|| *p
== '+';
388 int digit
= *p
++ - '0';
389 if (9 < (unsigned) digit
)
393 off_t c10
= 10 * count
;
394 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
395 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
397 report_error_message (N_("Seek offset out of range"));
404 switch (atoi (position_string
))
406 case 0: whence
= SEEK_SET
; break;
407 case 1: whence
= SEEK_CUR
; break;
408 case 2: whence
= SEEK_END
; break;
410 report_error_message (N_("Seek direction out of range"));
413 count
= lseek (tape
, count
, whence
);
417 /* Convert count back to string for reply.
418 We can't use sprintf, since off_t might be longer than long. */
419 p
= count_string
+ sizeof count_string
;
422 *--p
= '0' + (int) (count
% 10);
423 while ((count
/= 10) != 0);
425 DEBUG1 ("rmtd: A %s\n", p
);
427 sprintf (reply_buffer
, "A%s\n", p
);
428 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
434 char count_string
[STRING_SIZE
];
438 get_string (count_string
);
439 size
= atol (count_string
);
440 DEBUG1 ("rmtd: W %s\n", count_string
);
442 prepare_input_buffer (STDIN_FILENO
, size
);
443 for (counter
= 0; counter
< size
; counter
+= status
)
445 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
449 DEBUG (_("rmtd: Premature eof\n"));
451 report_error_message (N_("Premature end of file"));
452 return EXIT_FAILURE
; /* exit status used to be 2 */
455 status
= full_write (tape
, record_buffer
, size
);
463 char count_string
[STRING_SIZE
];
466 get_string (count_string
);
467 DEBUG1 ("rmtd: R %s\n", count_string
);
469 size
= atol (count_string
);
470 prepare_input_buffer (-1, size
);
471 status
= safe_read (tape
, record_buffer
, size
);
474 sprintf (reply_buffer
, "A%ld\n", (long) status
);
475 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
476 full_write (STDOUT_FILENO
, record_buffer
, status
);
482 char operation_string
[STRING_SIZE
];
483 char count_string
[STRING_SIZE
];
485 get_string (operation_string
);
486 get_string (count_string
);
487 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
496 /* Parse count_string, taking care to check for overflow.
497 We can't use standard functions,
498 since off_t might be longer than long. */
500 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
503 negative
= *p
== '-';
504 p
+= negative
|| *p
== '+';
508 int digit
= *p
++ - '0';
509 if (9 < (unsigned) digit
)
513 off_t c10
= 10 * count
;
514 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
515 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
517 report_error_message (N_("Seek offset out of range"));
524 mtop
.mt_count
= count
;
525 if (mtop
.mt_count
!= count
)
527 report_error_message (N_("Seek offset out of range"));
530 mtop
.mt_op
= atoi (operation_string
);
532 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
539 case 'S': /* status */
545 struct mtget operation
;
547 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
549 status
= sizeof operation
;
550 sprintf (reply_buffer
, "A%ld\n", (long) status
);
551 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
552 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
559 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
561 report_error_message (N_("Garbage command"));
562 return EXIT_FAILURE
; /* exit status used to be 3 */
566 DEBUG1 ("rmtd: A %ld\n", (long) status
);
568 sprintf (reply_buffer
, "A%ld\n", (long) status
);
569 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
573 report_numbered_error (errno
);
This page took 0.060941 seconds and 4 git commands to generate.