]> Dogcows Code - chaz/tar/blob - src/rtapelib.c
(namelist_match, excluded_name): Do not match subfiles of a directory
[chaz/tar] / src / rtapelib.c
1 /* Functions for communicating with a remote tape drive.
2 Copyright 1988, 92, 94, 96, 97, 99, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 /* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol
19 which rdump and rrestore use. Unfortunately, the man page is *WRONG*.
20 The author of the routines I'm including originally wrote his code just
21 based on the man page, and it didn't work, so he went to the rdump source
22 to figure out why. The only thing he had to change was to check for the
23 'F' return code in addition to the 'E', and to separate the various
24 arguments with \n instead of a space. I personally don't think that this
25 is much of a problem, but I wanted to point it out. -- Arnold Robbins
26
27 Originally written by Jeff Lee, modified some by Arnold Robbins. Redone
28 as a library that can replace open, read, write, etc., by Fred Fish, with
29 some additional work by Arnold Robbins. Modified to make all rmt* calls
30 into macros for speed by Jay Fenlason. Use -DWITH_REXEC for rexec
31 code, courtesy of Dan Kegel. */
32
33 #include "system.h"
34
35 #include <safe-read.h>
36
37 /* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h,
38 3B2/SVR3 has it in sys/inet.h. Otherwise, like on MSDOS, use EINVAL. */
39
40 #ifndef EOPNOTSUPP
41 # if HAVE_NET_ERRNO_H
42 # include <net/errno.h>
43 # endif
44 # if HAVE_SYS_INET_H
45 # include <sys/inet.h>
46 # endif
47 # ifndef EOPNOTSUPP
48 # define EOPNOTSUPP EINVAL
49 # endif
50 #endif
51
52 #include <signal.h>
53
54 #if HAVE_NETDB_H
55 # include <netdb.h>
56 #endif
57
58 #include "rmt.h"
59
60 char *base_name PARAMS ((char const *));
61
62 /* Exit status if exec errors. */
63 #define EXIT_ON_EXEC_ERROR 128
64
65 /* FIXME: Size of buffers for reading and writing commands to rmt. */
66 #define COMMAND_BUFFER_SIZE 64
67
68 #ifndef RETSIGTYPE
69 # define RETSIGTYPE void
70 #endif
71
72 /* FIXME: Maximum number of simultaneous remote tape connections. */
73 #define MAXUNIT 4
74
75 #define PREAD 0 /* read file descriptor from pipe() */
76 #define PWRITE 1 /* write file descriptor from pipe() */
77
78 /* Return the parent's read side of remote tape connection Fd. */
79 #define READ_SIDE(Fd) (from_remote[Fd][PREAD])
80
81 /* Return the parent's write side of remote tape connection Fd. */
82 #define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE])
83
84 /* The pipes for receiving data from remote tape drives. */
85 static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
86
87 /* The pipes for sending data to remote tape drives. */
88 static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
89
90 /* Temporary variable used by macros in rmt.h. */
91 char *rmt_path__;
92 \f
93
94 /* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. */
95 static void
96 _rmt_shutdown (int handle, int errno_value)
97 {
98 close (READ_SIDE (handle));
99 close (WRITE_SIDE (handle));
100 READ_SIDE (handle) = -1;
101 WRITE_SIDE (handle) = -1;
102 errno = errno_value;
103 }
104
105 /* Attempt to perform the remote tape command specified in BUFFER on
106 remote tape connection HANDLE. Return 0 if successful, -1 on
107 error. */
108 static int
109 do_command (int handle, const char *buffer)
110 {
111 /* Save the current pipe handler and try to make the request. */
112
113 size_t length = strlen (buffer);
114 RETSIGTYPE (*pipe_handler) () = signal (SIGPIPE, SIG_IGN);
115 ssize_t written = full_write (WRITE_SIDE (handle), buffer, length);
116 signal (SIGPIPE, pipe_handler);
117
118 if (written == length)
119 return 0;
120
121 /* Something went wrong. Close down and go home. */
122
123 _rmt_shutdown (handle, EIO);
124 return -1;
125 }
126
127 static char *
128 get_status_string (int handle, char *command_buffer)
129 {
130 char *cursor;
131 int counter;
132
133 /* Read the reply command line. */
134
135 for (counter = 0, cursor = command_buffer;
136 counter < COMMAND_BUFFER_SIZE;
137 counter++, cursor++)
138 {
139 if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
140 {
141 _rmt_shutdown (handle, EIO);
142 return 0;
143 }
144 if (*cursor == '\n')
145 {
146 *cursor = '\0';
147 break;
148 }
149 }
150
151 if (counter == COMMAND_BUFFER_SIZE)
152 {
153 _rmt_shutdown (handle, EIO);
154 return 0;
155 }
156
157 /* Check the return status. */
158
159 for (cursor = command_buffer; *cursor; cursor++)
160 if (*cursor != ' ')
161 break;
162
163 if (*cursor == 'E' || *cursor == 'F')
164 {
165 errno = atoi (cursor + 1);
166
167 /* Skip the error message line. */
168
169 /* FIXME: there is better to do than merely ignoring error messages
170 coming from the remote end. Translate them, too... */
171
172 {
173 char character;
174
175 while (safe_read (READ_SIDE (handle), &character, 1) == 1)
176 if (character == '\n')
177 break;
178 }
179
180 if (*cursor == 'F')
181 _rmt_shutdown (handle, errno);
182
183 return 0;
184 }
185
186 /* Check for mis-synced pipes. */
187
188 if (*cursor != 'A')
189 {
190 _rmt_shutdown (handle, EIO);
191 return 0;
192 }
193
194 /* Got an `A' (success) response. */
195
196 return cursor + 1;
197 }
198
199 /* Read and return the status from remote tape connection HANDLE. If
200 an error occurred, return -1 and set errno. */
201 static long
202 get_status (int handle)
203 {
204 char command_buffer[COMMAND_BUFFER_SIZE];
205 const char *status = get_status_string (handle, command_buffer);
206 return status ? atol (status) : -1L;
207 }
208
209 static off_t
210 get_status_off (int handle)
211 {
212 char command_buffer[COMMAND_BUFFER_SIZE];
213 const char *status = get_status_string (handle, command_buffer);
214
215 if (! status)
216 return -1;
217 else
218 {
219 /* Parse status, taking care to check for overflow.
220 We can't use standard functions,
221 since off_t might be longer than long. */
222
223 off_t count = 0;
224 int negative;
225
226 for (; *status == ' ' || *status == '\t'; status++)
227 continue;
228
229 negative = *status == '-';
230 status += negative || *status == '+';
231
232 for (;;)
233 {
234 int digit = *status++ - '0';
235 if (9 < (unsigned) digit)
236 break;
237 else
238 {
239 off_t c10 = 10 * count;
240 off_t nc = negative ? c10 - digit : c10 + digit;
241 if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
242 return -1;
243 count = nc;
244 }
245 }
246
247 return count;
248 }
249 }
250
251 #if WITH_REXEC
252
253 int rexec ();
254
255 /* Execute /etc/rmt as user USER on remote system HOST using rexec.
256 Return a file descriptor of a bidirectional socket for stdin and
257 stdout. If USER is zero, use the current username.
258
259 By default, this code is not used, since it requires that the user
260 have a .netrc file in his/her home directory, or that the
261 application designer be willing to have rexec prompt for login and
262 password info. This may be unacceptable, and .rhosts files for use
263 with rsh are much more common on BSD systems. */
264 static int
265 _rmt_rexec (char *host, char *user)
266 {
267 int saved_stdin = dup (STDIN_FILENO);
268 int saved_stdout = dup (STDOUT_FILENO);
269 struct servent *rexecserv;
270 int result;
271
272 /* When using cpio -o < filename, stdin is no longer the tty. But the
273 rexec subroutine reads the login and the passwd on stdin, to allow
274 remote execution of the command. So, reopen stdin and stdout on
275 /dev/tty before the rexec and give them back their original value
276 after. */
277
278 if (! freopen ("/dev/tty", "r", stdin))
279 freopen ("/dev/null", "r", stdin);
280 if (! freopen ("/dev/tty", "w", stdout))
281 freopen ("/dev/null", "w", stdout);
282
283 if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
284 error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
285
286 result = rexec (&host, rexecserv->s_port, user, 0, "/etc/rmt", 0);
287 if (fclose (stdin) == EOF)
288 error (0, errno, _("stdin"));
289 fdopen (saved_stdin, "r");
290 if (fclose (stdout) == EOF)
291 error (0, errno, _("stdout"));
292 fdopen (saved_stdout, "w");
293
294 return result;
295 }
296
297 #endif /* WITH_REXEC */
298
299 /* Place into BUF a string representing OFLAG, which must be suitable
300 as argument 2 of `open'. BUF must be large enough to hold the
301 result. This function should generate a string that decode_oflag
302 can parse. */
303 static void
304 encode_oflag (char *buf, int oflag)
305 {
306 sprintf (buf, "%d ", oflag);
307
308 switch (oflag & O_ACCMODE)
309 {
310 case O_RDONLY: strcat (buf, "O_RDONLY"); break;
311 case O_RDWR: strcat (buf, "O_RDWR"); break;
312 case O_WRONLY: strcat (buf, "O_WRONLY"); break;
313 default: abort ();
314 }
315
316 #ifdef O_APPEND
317 if (oflag & O_APPEND) strcat (buf, "|O_APPEND");
318 #endif
319 if (oflag & O_CREAT) strcat (buf, "|O_CREAT");
320 #ifdef O_DSYNC
321 if (oflag & O_DSYNC) strcat (buf, "|O_DSYNC");
322 #endif
323 if (oflag & O_EXCL) strcat (buf, "|O_EXCL");
324 #ifdef O_LARGEFILE
325 if (oflag & O_LARGEFILE) strcat (buf, "|O_LARGEFILE");
326 #endif
327 #ifdef O_NOCTTY
328 if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY");
329 #endif
330 #ifdef O_NONBLOCK
331 if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK");
332 #endif
333 #ifdef O_RSYNC
334 if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC");
335 #endif
336 #ifdef O_SYNC
337 if (oflag & O_SYNC) strcat (buf, "|O_SYNC");
338 #endif
339 if (oflag & O_TRUNC) strcat (buf, "|O_TRUNC");
340 }
341
342 /* Open a file (a magnetic tape device?) on the system specified in
343 PATH, as the given user. PATH has the form `[USER@]HOST:FILE'.
344 OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the
345 remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On
346 error, return -1. */
347 int
348 rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
349 {
350 int remote_pipe_number; /* pseudo, biased file descriptor */
351 char *path_copy ; /* copy of path string */
352 char *remote_host; /* remote host name */
353 char *remote_file; /* remote file name (often a device) */
354 char *remote_user; /* remote user name */
355
356 /* Find an unused pair of file descriptors. */
357
358 for (remote_pipe_number = 0;
359 remote_pipe_number < MAXUNIT;
360 remote_pipe_number++)
361 if (READ_SIDE (remote_pipe_number) == -1
362 && WRITE_SIDE (remote_pipe_number) == -1)
363 break;
364
365 if (remote_pipe_number == MAXUNIT)
366 {
367 errno = EMFILE;
368 return -1;
369 }
370
371 /* Pull apart the system and device, and optional user. */
372
373 {
374 char *cursor;
375
376 path_copy = xstrdup (path);
377 remote_host = path_copy;
378 remote_user = 0;
379 remote_file = 0;
380
381 for (cursor = path_copy; *cursor; cursor++)
382 switch (*cursor)
383 {
384 default:
385 break;
386
387 case '\n':
388 /* Do not allow newlines in the path, since the protocol
389 uses newline delimiters. */
390 free (path_copy);
391 errno = ENOENT;
392 return -1;
393
394 case '@':
395 if (!remote_user)
396 {
397 remote_user = remote_host;
398 *cursor = '\0';
399 remote_host = cursor + 1;
400 }
401 break;
402
403 case ':':
404 if (!remote_file)
405 {
406 *cursor = '\0';
407 remote_file = cursor + 1;
408 }
409 break;
410 }
411 }
412
413 /* FIXME: Should somewhat validate the decoding, here. */
414
415 if (remote_user && *remote_user == '\0')
416 remote_user = 0;
417
418 #if WITH_REXEC
419
420 /* Execute the remote command using rexec. */
421
422 READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
423 if (READ_SIDE (remote_pipe_number) < 0)
424 {
425 int e = errno;
426 free (path_copy);
427 errno = e;
428 return -1;
429 }
430
431 WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
432
433 #else /* not WITH_REXEC */
434 {
435 const char *remote_shell_basename;
436 pid_t status;
437
438 /* Identify the remote command to be executed. */
439
440 if (!remote_shell)
441 {
442 #ifdef REMOTE_SHELL
443 remote_shell = REMOTE_SHELL;
444 #else
445 free (path_copy);
446 errno = EIO;
447 return -1;
448 #endif
449 }
450 remote_shell_basename = base_name (remote_shell);
451
452 /* Set up the pipes for the `rsh' command, and fork. */
453
454 if (pipe (to_remote[remote_pipe_number]) == -1
455 || pipe (from_remote[remote_pipe_number]) == -1)
456 {
457 int e = errno;
458 free (path_copy);
459 errno = e;
460 return -1;
461 }
462
463 status = fork ();
464 if (status == -1)
465 {
466 int e = errno;
467 free (path_copy);
468 errno = e;
469 return -1;
470 }
471
472 if (status == 0)
473 {
474 /* Child. */
475
476 close (STDIN_FILENO);
477 dup (to_remote[remote_pipe_number][PREAD]);
478 close (to_remote[remote_pipe_number][PREAD]);
479 close (to_remote[remote_pipe_number][PWRITE]);
480
481 close (STDOUT_FILENO);
482 dup (from_remote[remote_pipe_number][PWRITE]);
483 close (from_remote[remote_pipe_number][PREAD]);
484 close (from_remote[remote_pipe_number][PWRITE]);
485
486 #if !MSDOS
487 setuid (getuid ());
488 setgid (getgid ());
489 #endif
490
491 if (remote_user)
492 execl (remote_shell, remote_shell_basename, remote_host,
493 "-l", remote_user, "/etc/rmt", (char *) 0);
494 else
495 execl (remote_shell, remote_shell_basename, remote_host,
496 "/etc/rmt", (char *) 0);
497
498 /* Bad problems if we get here. */
499
500 /* In a previous version, _exit was used here instead of exit. */
501 error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
502 }
503
504 /* Parent. */
505
506 close (from_remote[remote_pipe_number][PWRITE]);
507 close (to_remote[remote_pipe_number][PREAD]);
508 }
509 #endif /* not WITH_REXEC */
510
511 /* Attempt to open the tape device. */
512
513 {
514 size_t remote_file_len = strlen (remote_file);
515 char *command_buffer = xmalloc (remote_file_len + 1000);
516 sprintf (command_buffer, "O%s\n", remote_file);
517 encode_oflag (command_buffer + remote_file_len + 2, open_mode);
518 strcat (command_buffer, "\n");
519 if (do_command (remote_pipe_number, command_buffer) == -1
520 || get_status (remote_pipe_number) == -1)
521 {
522 int e = errno;
523 free (command_buffer);
524 free (path_copy);
525 _rmt_shutdown (remote_pipe_number, e);
526 return -1;
527 }
528 free (command_buffer);
529 }
530
531 free (path_copy);
532 return remote_pipe_number + bias;
533 }
534
535 /* Close remote tape connection HANDLE and shut down. Return 0 if
536 successful, -1 on error. */
537 int
538 rmt_close__ (int handle)
539 {
540 int status;
541
542 if (do_command (handle, "C\n") == -1)
543 return -1;
544
545 status = get_status (handle);
546 _rmt_shutdown (handle, errno);
547 return status;
548 }
549
550 /* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
551 Return the number of bytes read on success, -1 on error. */
552 ssize_t
553 rmt_read__ (int handle, char *buffer, size_t length)
554 {
555 char command_buffer[COMMAND_BUFFER_SIZE];
556 ssize_t status, rlen;
557 size_t counter;
558
559 sprintf (command_buffer, "R%lu\n", (unsigned long) length);
560 if (do_command (handle, command_buffer) == -1
561 || (status = get_status (handle)) == -1)
562 return -1;
563
564 for (counter = 0; counter < status; counter += rlen, buffer += rlen)
565 {
566 rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
567 if (rlen <= 0)
568 {
569 _rmt_shutdown (handle, EIO);
570 return -1;
571 }
572 }
573
574 return status;
575 }
576
577 /* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
578 Return the number of bytes written on success, -1 on error. */
579 ssize_t
580 rmt_write__ (int handle, char *buffer, size_t length)
581 {
582 char command_buffer[COMMAND_BUFFER_SIZE];
583 RETSIGTYPE (*pipe_handler) ();
584 size_t written;
585
586 sprintf (command_buffer, "W%lu\n", (unsigned long) length);
587 if (do_command (handle, command_buffer) == -1)
588 return -1;
589
590 pipe_handler = signal (SIGPIPE, SIG_IGN);
591 written = full_write (WRITE_SIDE (handle), buffer, length);
592 signal (SIGPIPE, pipe_handler);
593 if (written == length)
594 return get_status (handle);
595
596 /* Write error. */
597
598 _rmt_shutdown (handle, EIO);
599 return -1;
600 }
601
602 /* Perform an imitation lseek operation on remote tape connection
603 HANDLE. Return the new file offset if successful, -1 if on error. */
604 off_t
605 rmt_lseek__ (int handle, off_t offset, int whence)
606 {
607 char command_buffer[COMMAND_BUFFER_SIZE];
608 char operand_buffer[UINTMAX_STRSIZE_BOUND];
609 uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
610 char *p = operand_buffer + sizeof operand_buffer;
611
612 do
613 *--p = '0' + (int) (u % 10);
614 while ((u /= 10) != 0);
615 if (offset < 0)
616 *--p = '-';
617
618 switch (whence)
619 {
620 case SEEK_SET: whence = 0; break;
621 case SEEK_CUR: whence = 1; break;
622 case SEEK_END: whence = 2; break;
623 default: abort ();
624 }
625
626 sprintf (command_buffer, "L%s\n%d\n", p, whence);
627
628 if (do_command (handle, command_buffer) == -1)
629 return -1;
630
631 return get_status_off (handle);
632 }
633
634 /* Perform a raw tape operation on remote tape connection HANDLE.
635 Return the results of the ioctl, or -1 on error. */
636 int
637 rmt_ioctl__ (int handle, int operation, char *argument)
638 {
639 switch (operation)
640 {
641 default:
642 errno = EOPNOTSUPP;
643 return -1;
644
645 #ifdef MTIOCTOP
646 case MTIOCTOP:
647 {
648 char command_buffer[COMMAND_BUFFER_SIZE];
649 char operand_buffer[UINTMAX_STRSIZE_BOUND];
650 uintmax_t u = (((struct mtop *) argument)->mt_count < 0
651 ? - (uintmax_t) ((struct mtop *) argument)->mt_count
652 : (uintmax_t) ((struct mtop *) argument)->mt_count);
653 char *p = operand_buffer + sizeof operand_buffer;
654
655 do
656 *--p = '0' + (int) (u % 10);
657 while ((u /= 10) != 0);
658 if (((struct mtop *) argument)->mt_count < 0)
659 *--p = '-';
660
661 /* MTIOCTOP is the easy one. Nothing is transferred in binary. */
662
663 sprintf (command_buffer, "I%d\n%s\n",
664 ((struct mtop *) argument)->mt_op, p);
665 if (do_command (handle, command_buffer) == -1)
666 return -1;
667
668 return get_status (handle);
669 }
670 #endif /* MTIOCTOP */
671
672 #ifdef MTIOCGET
673 case MTIOCGET:
674 {
675 ssize_t status;
676 ssize_t counter;
677
678 /* Grab the status and read it directly into the structure. This
679 assumes that the status buffer is not padded and that 2 shorts
680 fit in a long without any word alignment problems; i.e., the
681 whole struct is contiguous. NOTE - this is probably NOT a good
682 assumption. */
683
684 if (do_command (handle, "S") == -1
685 || (status = get_status (handle), status == -1))
686 return -1;
687
688 for (; status > 0; status -= counter, argument += counter)
689 {
690 counter = safe_read (READ_SIDE (handle), argument, status);
691 if (counter <= 0)
692 {
693 _rmt_shutdown (handle, EIO);
694 return -1;
695 }
696 }
697
698 /* Check for byte position. mt_type (or mt_model) is a small integer
699 field (normally) so we will check its magnitude. If it is larger
700 than 256, we will assume that the bytes are swapped and go through
701 and reverse all the bytes. */
702
703 if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256)
704 return 0;
705
706 for (counter = 0; counter < status; counter += 2)
707 {
708 char copy = argument[counter];
709
710 argument[counter] = argument[counter + 1];
711 argument[counter + 1] = copy;
712 }
713
714 return 0;
715 }
716 #endif /* MTIOCGET */
717
718 }
719 }
This page took 0.067936 seconds and 4 git commands to generate.