]> git.gag.com Git - debian/tar/blob - src/rtapelib.c
Bugfix by Jürgen Weigert
[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, 2004 Free
4    Software 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 #include "common.h"
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       /* Skip the error message line.  */
167
168       /* FIXME: there is better to do than merely ignoring error messages
169          coming from the remote end.  Translate them, too...  */
170
171       {
172         char character;
173
174         while (safe_read (READ_SIDE (handle), &character, 1) == 1)
175           if (character == '\n')
176             break;
177       }
178
179       errno = atoi (cursor + 1);
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 int
203 get_status (int handle)
204 {
205   char command_buffer[COMMAND_BUFFER_SIZE];
206   const char *status = get_status_string (handle, command_buffer);
207   if (status)
208     {
209       long int result = atol (status);
210       if (0 <= result)
211         return result;
212       errno = EIO;
213     }
214   return -1;
215 }
216
217 static off_t
218 get_status_off (int handle)
219 {
220   char command_buffer[COMMAND_BUFFER_SIZE];
221   const char *status = get_status_string (handle, command_buffer);
222
223   if (! status)
224     return -1;
225   else
226     {
227       /* Parse status, taking care to check for overflow.
228          We can't use standard functions,
229          since off_t might be longer than long.  */
230
231       off_t count = 0;
232       int negative;
233
234       for (;  *status == ' ' || *status == '\t';  status++)
235         continue;
236
237       negative = *status == '-';
238       status += negative || *status == '+';
239
240       for (;;)
241         {
242           int digit = *status++ - '0';
243           if (9 < (unsigned) digit)
244             break;
245           else
246             {
247               off_t c10 = 10 * count;
248               off_t nc = negative ? c10 - digit : c10 + digit;
249               if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
250                 return -1;
251               count = nc;
252             }
253         }
254
255       return count;
256     }
257 }
258
259 #if WITH_REXEC
260
261 /* Execute /etc/rmt as user USER on remote system HOST using rexec.
262    Return a file descriptor of a bidirectional socket for stdin and
263    stdout.  If USER is zero, use the current username.
264
265    By default, this code is not used, since it requires that the user
266    have a .netrc file in his/her home directory, or that the
267    application designer be willing to have rexec prompt for login and
268    password info.  This may be unacceptable, and .rhosts files for use
269    with rsh are much more common on BSD systems.  */
270 static int
271 _rmt_rexec (char *host, char *user)
272 {
273   int saved_stdin = dup (STDIN_FILENO);
274   int saved_stdout = dup (STDOUT_FILENO);
275   struct servent *rexecserv;
276   int result;
277
278   /* When using cpio -o < filename, stdin is no longer the tty.  But the
279      rexec subroutine reads the login and the passwd on stdin, to allow
280      remote execution of the command.  So, reopen stdin and stdout on
281      /dev/tty before the rexec and give them back their original value
282      after.  */
283
284   if (! freopen ("/dev/tty", "r", stdin))
285     freopen ("/dev/null", "r", stdin);
286   if (! freopen ("/dev/tty", "w", stdout))
287     freopen ("/dev/null", "w", stdout);
288
289   if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
290     error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
291
292   result = rexec (&host, rexecserv->s_port, user, 0, "/etc/rmt", 0);
293   if (fclose (stdin) == EOF)
294     error (0, errno, _("stdin"));
295   fdopen (saved_stdin, "r");
296   if (fclose (stdout) == EOF)
297     error (0, errno, _("stdout"));
298   fdopen (saved_stdout, "w");
299
300   return result;
301 }
302
303 #endif /* WITH_REXEC */
304
305 /* Place into BUF a string representing OFLAG, which must be suitable
306    as argument 2 of `open'.  BUF must be large enough to hold the
307    result.  This function should generate a string that decode_oflag
308    can parse.  */
309 static void
310 encode_oflag (char *buf, int oflag)
311 {
312   sprintf (buf, "%d ", oflag);
313
314   switch (oflag & O_ACCMODE)
315     {
316     case O_RDONLY: strcat (buf, "O_RDONLY"); break;
317     case O_RDWR: strcat (buf, "O_RDWR"); break;
318     case O_WRONLY: strcat (buf, "O_WRONLY"); break;
319     default: abort ();
320     }
321
322 #ifdef O_APPEND
323   if (oflag & O_APPEND) strcat (buf, "|O_APPEND");
324 #endif
325   if (oflag & O_CREAT) strcat (buf, "|O_CREAT");
326 #ifdef O_DSYNC
327   if (oflag & O_DSYNC) strcat (buf, "|O_DSYNC");
328 #endif
329   if (oflag & O_EXCL) strcat (buf, "|O_EXCL");
330 #ifdef O_LARGEFILE
331   if (oflag & O_LARGEFILE) strcat (buf, "|O_LARGEFILE");
332 #endif
333 #ifdef O_NOCTTY
334   if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY");
335 #endif
336 #ifdef O_NONBLOCK
337   if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK");
338 #endif
339 #ifdef O_RSYNC
340   if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC");
341 #endif
342 #ifdef O_SYNC
343   if (oflag & O_SYNC) strcat (buf, "|O_SYNC");
344 #endif
345   if (oflag & O_TRUNC) strcat (buf, "|O_TRUNC");
346 }
347
348 /* Open a file (a magnetic tape device?) on the system specified in
349    PATH, as the given user.  PATH has the form `[USER@]HOST:FILE'.
350    OPEN_MODE is O_RDONLY, O_WRONLY, etc.  If successful, return the
351    remote pipe number plus BIAS.  REMOTE_SHELL may be overridden.  On
352    error, return -1.  */
353 int
354 rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
355 {
356   int remote_pipe_number;       /* pseudo, biased file descriptor */
357   char *path_copy ;             /* copy of path string */
358   char *remote_host;            /* remote host name */
359   char *remote_file;            /* remote file name (often a device) */
360   char *remote_user;            /* remote user name */
361
362   /* Find an unused pair of file descriptors.  */
363
364   for (remote_pipe_number = 0;
365        remote_pipe_number < MAXUNIT;
366        remote_pipe_number++)
367     if (READ_SIDE (remote_pipe_number) == -1
368         && WRITE_SIDE (remote_pipe_number) == -1)
369       break;
370
371   if (remote_pipe_number == MAXUNIT)
372     {
373       errno = EMFILE;
374       return -1;
375     }
376
377   /* Pull apart the system and device, and optional user.  */
378
379   {
380     char *cursor;
381
382     path_copy = xstrdup (path);
383     remote_host = path_copy;
384     remote_user = 0;
385     remote_file = 0;
386
387     for (cursor = path_copy; *cursor; cursor++)
388       switch (*cursor)
389         {
390         default:
391           break;
392
393         case '\n':
394           /* Do not allow newlines in the path, since the protocol
395              uses newline delimiters.  */
396           free (path_copy);
397           errno = ENOENT;
398           return -1;
399
400         case '@':
401           if (!remote_user)
402             {
403               remote_user = remote_host;
404               *cursor = '\0';
405               remote_host = cursor + 1;
406             }
407           break;
408
409         case ':':
410           if (!remote_file)
411             {
412               *cursor = '\0';
413               remote_file = cursor + 1;
414             }
415           break;
416         }
417   }
418
419   /* FIXME: Should somewhat validate the decoding, here.  */
420
421   if (remote_user && *remote_user == '\0')
422     remote_user = 0;
423
424 #if WITH_REXEC
425
426   /* Execute the remote command using rexec.  */
427
428   READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
429   if (READ_SIDE (remote_pipe_number) < 0)
430     {
431       int e = errno;
432       free (path_copy);
433       errno = e;
434       return -1;
435     }
436
437   WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
438
439 #else /* not WITH_REXEC */
440   {
441     const char *remote_shell_basename;
442     pid_t status;
443
444     /* Identify the remote command to be executed.  */
445
446     if (!remote_shell)
447       {
448 #ifdef REMOTE_SHELL
449         remote_shell = REMOTE_SHELL;
450 #else
451         free (path_copy);
452         errno = EIO;
453         return -1;
454 #endif
455       }
456     remote_shell_basename = base_name (remote_shell);
457
458     /* Set up the pipes for the `rsh' command, and fork.  */
459
460     if (pipe (to_remote[remote_pipe_number]) == -1
461         || pipe (from_remote[remote_pipe_number]) == -1)
462       {
463         int e = errno;
464         free (path_copy);
465         errno = e;
466         return -1;
467       }
468
469     status = fork ();
470     if (status == -1)
471       {
472         int e = errno;
473         free (path_copy);
474         errno = e;
475         return -1;
476       }
477
478     if (status == 0)
479       {
480         /* Child.  */
481
482         close (STDIN_FILENO);
483         dup (to_remote[remote_pipe_number][PREAD]);
484         close (to_remote[remote_pipe_number][PREAD]);
485         close (to_remote[remote_pipe_number][PWRITE]);
486
487         close (STDOUT_FILENO);
488         dup (from_remote[remote_pipe_number][PWRITE]);
489         close (from_remote[remote_pipe_number][PREAD]);
490         close (from_remote[remote_pipe_number][PWRITE]);
491
492         sys_reset_uid_gid ();
493
494         if (remote_user)
495           execl (remote_shell, remote_shell_basename, remote_host,
496                  "-l", remote_user, "/etc/rmt", (char *) 0);
497         else
498           execl (remote_shell, remote_shell_basename, remote_host,
499                  "/etc/rmt", (char *) 0);
500
501         /* Bad problems if we get here.  */
502
503         /* In a previous version, _exit was used here instead of exit.  */
504         error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
505       }
506
507     /* Parent.  */
508
509     close (from_remote[remote_pipe_number][PWRITE]);
510     close (to_remote[remote_pipe_number][PREAD]);
511   }
512 #endif /* not WITH_REXEC */
513
514   /* Attempt to open the tape device.  */
515
516   {
517     size_t remote_file_len = strlen (remote_file);
518     char *command_buffer = xmalloc (remote_file_len + 1000);
519     sprintf (command_buffer, "O%s\n", remote_file);
520     encode_oflag (command_buffer + remote_file_len + 2, open_mode);
521     strcat (command_buffer, "\n");
522     if (do_command (remote_pipe_number, command_buffer) == -1
523         || get_status (remote_pipe_number) == -1)
524       {
525         int e = errno;
526         free (command_buffer);
527         free (path_copy);
528         _rmt_shutdown (remote_pipe_number, e);
529         return -1;
530       }
531     free (command_buffer);
532   }
533
534   free (path_copy);
535   return remote_pipe_number + bias;
536 }
537
538 /* Close remote tape connection HANDLE and shut down.  Return 0 if
539    successful, -1 on error.  */
540 int
541 rmt_close__ (int handle)
542 {
543   long int status;
544
545   if (do_command (handle, "C\n") == -1)
546     return -1;
547
548   status = get_status (handle);
549   _rmt_shutdown (handle, errno);
550   return status;
551 }
552
553 /* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
554    Return the number of bytes read on success, SAFE_READ_ERROR on error.  */
555 size_t
556 rmt_read__ (int handle, char *buffer, size_t length)
557 {
558   char command_buffer[COMMAND_BUFFER_SIZE];
559   size_t status;
560   size_t rlen;
561   size_t counter;
562
563   sprintf (command_buffer, "R%lu\n", (unsigned long) length);
564   if (do_command (handle, command_buffer) == -1
565       || (status = get_status (handle)) == SAFE_READ_ERROR)
566     return SAFE_READ_ERROR;
567
568   for (counter = 0; counter < status; counter += rlen, buffer += rlen)
569     {
570       rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
571       if (rlen == SAFE_READ_ERROR || rlen == 0)
572         {
573           _rmt_shutdown (handle, EIO);
574           return SAFE_READ_ERROR;
575         }
576     }
577
578   return status;
579 }
580
581 /* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
582    Return the number of bytes written.  */
583 size_t
584 rmt_write__ (int handle, char *buffer, size_t length)
585 {
586   char command_buffer[COMMAND_BUFFER_SIZE];
587   RETSIGTYPE (*pipe_handler) ();
588   size_t written;
589
590   sprintf (command_buffer, "W%lu\n", (unsigned long) length);
591   if (do_command (handle, command_buffer) == -1)
592     return 0;
593
594   pipe_handler = signal (SIGPIPE, SIG_IGN);
595   written = full_write (WRITE_SIDE (handle), buffer, length);
596   signal (SIGPIPE, pipe_handler);
597   if (written == length)
598     {
599       long int r = get_status (handle);
600       if (r < 0)
601         return 0;
602       if (r == length)
603         return length;
604       written = r;
605     }
606
607   /* Write error.  */
608
609   _rmt_shutdown (handle, EIO);
610   return written;
611 }
612
613 /* Perform an imitation lseek operation on remote tape connection
614    HANDLE.  Return the new file offset if successful, -1 if on error.  */
615 off_t
616 rmt_lseek__ (int handle, off_t offset, int whence)
617 {
618   char command_buffer[COMMAND_BUFFER_SIZE];
619   char operand_buffer[UINTMAX_STRSIZE_BOUND];
620   uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
621   char *p = operand_buffer + sizeof operand_buffer;
622
623   *--p = 0;
624   do
625     *--p = '0' + (int) (u % 10);
626   while ((u /= 10) != 0);
627   if (offset < 0)
628     *--p = '-';
629
630   switch (whence)
631     {
632     case SEEK_SET: whence = 0; break;
633     case SEEK_CUR: whence = 1; break;
634     case SEEK_END: whence = 2; break;
635     default: abort ();
636     }
637
638   sprintf (command_buffer, "L%s\n%d\n", p, whence);
639
640   if (do_command (handle, command_buffer) == -1)
641     return -1;
642
643   return get_status_off (handle);
644 }
645
646 /* Perform a raw tape operation on remote tape connection HANDLE.
647    Return the results of the ioctl, or -1 on error.  */
648 int
649 rmt_ioctl__ (int handle, int operation, char *argument)
650 {
651   switch (operation)
652     {
653     default:
654       errno = EOPNOTSUPP;
655       return -1;
656
657 #ifdef MTIOCTOP
658     case MTIOCTOP:
659       {
660         char command_buffer[COMMAND_BUFFER_SIZE];
661         char operand_buffer[UINTMAX_STRSIZE_BOUND];
662         uintmax_t u = (((struct mtop *) argument)->mt_count < 0
663                        ? - (uintmax_t) ((struct mtop *) argument)->mt_count
664                        : (uintmax_t) ((struct mtop *) argument)->mt_count);
665         char *p = operand_buffer + sizeof operand_buffer;
666
667         *--p = 0;
668         do
669           *--p = '0' + (int) (u % 10);
670         while ((u /= 10) != 0);
671         if (((struct mtop *) argument)->mt_count < 0)
672           *--p = '-';
673
674         /* MTIOCTOP is the easy one.  Nothing is transferred in binary.  */
675
676         sprintf (command_buffer, "I%d\n%s\n",
677                  ((struct mtop *) argument)->mt_op, p);
678         if (do_command (handle, command_buffer) == -1)
679           return -1;
680
681         return get_status (handle);
682       }
683 #endif /* MTIOCTOP */
684
685 #ifdef MTIOCGET
686     case MTIOCGET:
687       {
688         ssize_t status;
689         size_t counter;
690
691         /* Grab the status and read it directly into the structure.  This
692            assumes that the status buffer is not padded and that 2 shorts
693            fit in a long without any word alignment problems; i.e., the
694            whole struct is contiguous.  NOTE - this is probably NOT a good
695            assumption.  */
696
697         if (do_command (handle, "S") == -1
698             || (status = get_status (handle), status == -1))
699           return -1;
700
701         for (; status > 0; status -= counter, argument += counter)
702           {
703             counter = safe_read (READ_SIDE (handle), argument, status);
704             if (counter == SAFE_READ_ERROR || counter == 0)
705               {
706                 _rmt_shutdown (handle, EIO);
707                 return -1;
708               }
709           }
710
711         /* Check for byte position.  mt_type (or mt_model) is a small integer
712            field (normally) so we will check its magnitude.  If it is larger
713            than 256, we will assume that the bytes are swapped and go through
714            and reverse all the bytes.  */
715
716         if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256)
717           return 0;
718
719         for (counter = 0; counter < status; counter += 2)
720           {
721             char copy = argument[counter];
722
723             argument[counter] = argument[counter + 1];
724             argument[counter + 1] = copy;
725           }
726
727         return 0;
728       }
729 #endif /* MTIOCGET */
730
731     }
732 }