]>
Dogcows Code - chaz/tar/blob - src/rmt.c
74f6e3555ca2ac11d82db769926b99e4b52c631b
1 /* Remote connection server.
3 Copyright 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 <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_record_buffer (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
;
153 while (size
> 1024 &&
154 (setsockopt (STDIN_FILENO
, SOL_SOCKET
, SO_RCVBUF
,
155 (char *) &size
, sizeof size
)
159 /* FIXME: I do not see any purpose to the following line... Sigh! */
160 size
= 1 + ((size
- 1) % 1024);
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 fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout
);
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
);
295 printf ("rmt (GNU %s) %s\n", PACKAGE
, VERSION
);
297 /* Note to translator: Please translate "Copyright " to "©"
298 (C-in-a-circle) if available in the translation's character
300 printf (_("Copyright %d Free Software Foundation, Inc."), 2001);
304 This program comes with NO WARRANTY, to the extent permitted by law.\n\
305 You may redistribute it under the terms of the GNU General Public License;\n\
306 see the file named COPYING for details."));
316 if (optind
!= argc
- 1)
317 usage (EXIT_FAILURE
);
318 debug_file
= fopen (argv
[optind
], "w");
321 report_numbered_error (errno
);
324 setbuf (debug_file
, 0);
330 if (safe_read (STDIN_FILENO
, &command
, 1) != 1)
335 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
339 char device_string
[STRING_SIZE
];
340 char oflag_string
[STRING_SIZE
];
342 get_string (device_string
);
343 get_string (oflag_string
);
344 DEBUG2 ("rmtd: O %s %s\n", device_string
, oflag_string
);
349 tape
= open (device_string
, decode_oflag (oflag_string
), MODE_RW
);
357 char device_string
[STRING_SIZE
];
359 get_string (device_string
); /* discard */
362 if (close (tape
) < 0)
370 char count_string
[STRING_SIZE
];
371 char position_string
[STRING_SIZE
];
377 get_string (count_string
);
378 get_string (position_string
);
379 DEBUG2 ("rmtd: L %s %s\n", count_string
, position_string
);
381 /* Parse count_string, taking care to check for overflow.
382 We can't use standard functions,
383 since off_t might be longer than long. */
385 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
388 negative
= *p
== '-';
389 p
+= negative
|| *p
== '+';
393 int digit
= *p
++ - '0';
394 if (9 < (unsigned) digit
)
398 off_t c10
= 10 * count
;
399 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
400 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
402 report_error_message (N_("Seek offset out of range"));
409 switch (atoi (position_string
))
411 case 0: whence
= SEEK_SET
; break;
412 case 1: whence
= SEEK_CUR
; break;
413 case 2: whence
= SEEK_END
; break;
415 report_error_message (N_("Seek direction out of range"));
418 count
= lseek (tape
, count
, whence
);
422 /* Convert count back to string for reply.
423 We can't use sprintf, since off_t might be longer than long. */
424 p
= count_string
+ sizeof count_string
;
427 *--p
= '0' + (int) (count
% 10);
428 while ((count
/= 10) != 0);
430 DEBUG1 ("rmtd: A %s\n", p
);
432 sprintf (reply_buffer
, "A%s\n", p
);
433 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
439 char count_string
[STRING_SIZE
];
443 get_string (count_string
);
444 size
= atol (count_string
);
445 DEBUG1 ("rmtd: W %s\n", count_string
);
447 prepare_record_buffer (size
);
448 for (counter
= 0; counter
< size
; counter
+= status
)
450 status
= safe_read (STDIN_FILENO
, &record_buffer
[counter
],
454 DEBUG (_("rmtd: Premature eof\n"));
456 report_error_message (N_("Premature end of file"));
457 exit (EXIT_FAILURE
); /* exit status used to be 2 */
460 status
= full_write (tape
, record_buffer
, size
);
468 char count_string
[STRING_SIZE
];
471 get_string (count_string
);
472 DEBUG1 ("rmtd: R %s\n", count_string
);
474 size
= atol (count_string
);
475 prepare_record_buffer (size
);
476 status
= safe_read (tape
, record_buffer
, size
);
479 sprintf (reply_buffer
, "A%ld\n", (long) status
);
480 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
481 full_write (STDOUT_FILENO
, record_buffer
, status
);
487 char operation_string
[STRING_SIZE
];
488 char count_string
[STRING_SIZE
];
490 get_string (operation_string
);
491 get_string (count_string
);
492 DEBUG2 ("rmtd: I %s %s\n", operation_string
, count_string
);
501 /* Parse count_string, taking care to check for overflow.
502 We can't use standard functions,
503 since off_t might be longer than long. */
505 for (p
= count_string
; *p
== ' ' || *p
== '\t'; p
++)
508 negative
= *p
== '-';
509 p
+= negative
|| *p
== '+';
513 int digit
= *p
++ - '0';
514 if (9 < (unsigned) digit
)
518 off_t c10
= 10 * count
;
519 off_t nc
= negative
? c10
- digit
: c10
+ digit
;
520 if (c10
/ 10 != count
|| (negative
? c10
< nc
: nc
< c10
))
522 report_error_message (N_("Seek offset out of range"));
529 mtop
.mt_count
= count
;
530 if (mtop
.mt_count
!= count
)
532 report_error_message (N_("Seek offset out of range"));
535 mtop
.mt_op
= atoi (operation_string
);
537 if (ioctl (tape
, MTIOCTOP
, (char *) &mtop
) < 0)
544 case 'S': /* status */
550 struct mtget operation
;
552 if (ioctl (tape
, MTIOCGET
, (char *) &operation
) < 0)
554 status
= sizeof operation
;
555 sprintf (reply_buffer
, "A%ld\n", (long) status
);
556 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
557 full_write (STDOUT_FILENO
, (char *) &operation
, sizeof operation
);
564 DEBUG1 (_("rmtd: Garbage command %c\n"), command
);
566 report_error_message (N_("Garbage command"));
567 exit (EXIT_FAILURE
); /* exit status used to be 3 */
571 DEBUG1 ("rmtd: A %ld\n", (long) status
);
573 sprintf (reply_buffer
, "A%ld\n", (long) status
);
574 full_write (STDOUT_FILENO
, reply_buffer
, strlen (reply_buffer
));
578 report_numbered_error (errno
);
This page took 0.066334 seconds and 4 git commands to generate.