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