]> git.wh0rd.org - dump.git/blobdiff - common/dumprmt.c
Updated buggy example.
[dump.git] / common / dumprmt.c
index 6a79d0761be16c21956a4a1659ee6fd109793cd5..7f88f63a9fb95851eec469556015230170bde7ac 100644 (file)
@@ -2,8 +2,8 @@
  *     Ported to Linux's Second Extended File System as part of the
  *     dump and restore backup suit
  *     Remy Card <card@Linux.EU.Org>, 1994-1997
- *      Stelian Pop <pop@cybercable.fr>, 1999
- *
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
  */
 
 /*-
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  */
 
 #ifndef lint
-#if 0
-static char sccsid[] = "@(#)dumprmt.c  8.3 (Berkeley) 4/28/95";
-#endif
 static const char rcsid[] =
-       "$Id: dumprmt.c,v 1.4 1999/10/11 13:08:06 stelian Exp $";
+       "$Id: dumprmt.c,v 1.28 2003/10/26 16:05:45 stelian Exp $";
 #endif /* not lint */
 
-#ifdef __linux__
-#include <sys/types.h>
-#include <linux/types.h>
-#endif
+#include <config.h>
 #include <sys/param.h>
 #include <sys/mtio.h>
 #include <sys/socket.h>
 #include <sys/time.h>
+#include <fcntl.h>
 #ifdef __linux__
+#include <sys/types.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
 #include <linux/ext2_fs.h>
+#endif
 #include <bsdcompat.h>
 #include <signal.h>
-#else
-#ifdef sunos
+#elif defined sunos
 #include <sys/vnode.h>
 
 #include <ufs/inode.h>
 #else
 #include <ufs/ufs/dinode.h>
 #endif
-#endif
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
@@ -79,6 +73,7 @@ static const char rcsid[] =
 #include <ctype.h>
 #include <errno.h>
 #include <compaterr.h>
+#include <rmtflags.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <stdio.h>
@@ -92,23 +87,26 @@ static const char rcsid[] =
 #include <ext2fs/ext2fs.h>
 #endif
 
-#include "pathnames.h"
-#include "dump.h"
+#include <pathnames.h>
+#include "dump.h"      /* for X_STARTUP, X_ABORT etc */
 
 #define        TS_CLOSED       0
 #define        TS_OPEN         1
 
 static int rmtstate = TS_CLOSED;
-static int rmtape = -1;
+static int tormtape = -1;
+static int fromrmtape = -1;
+int rshpid = -1;
 static const char *rmtpeer = 0;
 
 static int okname __P((const char *));
-static int rmtcall __P((const char *, const char *));
+static OFF_T rmtcall __P((const char *, const char *));
 static void rmtconnaborted __P((int));
 static int rmtgetb __P((void));
-static void rmtgetconn __P((void));
+static int rmtgetconn __P((void));
 static void rmtgets __P((char *, size_t));
-static int rmtreply __P((const char *));
+static OFF_T rmtreply __P((const char *));
+static  int piped_child __P((const char **command));
 #ifdef KERBEROS
 int    krcmd __P((char **, int /*u_short*/, char *, char *, int *, char *));
 #endif
@@ -116,6 +114,8 @@ int krcmd __P((char **, int /*u_short*/, char *, char *, int *, char *));
 static int errfd = -1;
 extern int dokerberos;
 extern int ntrec;              /* blocking factor on tape */
+extern int abortifconnerr;     /* set to 1 if this lib should exit on connection errors
+                                otherwise just print a message using msg */
 #ifndef errno
 extern int errno;
 #endif
@@ -128,14 +128,11 @@ rmthost(const char *host)
        if ((rmtpeer = strdup(host)) == NULL)
                rmtpeer = host;
        signal(SIGPIPE, rmtconnaborted);
-       rmtgetconn();
-       if (rmtape < 0)
-               return (0);
-       return (1);
+       return rmtgetconn();
 }
 
 static void
-rmtconnaborted(int signo)
+rmtconnaborted(UNUSED(int signo))
 {
        msg("Lost connection to remote host.\n");
        if (errfd != -1) {
@@ -157,78 +154,129 @@ rmtconnaborted(int signo)
                        }
                }
        }
-
-       exit(X_ABORT);
+       if (abortifconnerr)
+               exit(X_ABORT);
 }
 
-static void
+static int
 rmtgetconn(void)
 {
-       register char *cp;
-       register const char *rmt;
+       char *cp;
+       const char *rmt;
        static struct servent *sp = NULL;
        static struct passwd *pwd = NULL;
        const char *tuser;
+       const char *rsh;
        int size;
        int throughput;
        int on;
+       char *rmtpeercopy;
+
+       rsh = getenv("RSH");
 
-       if (sp == NULL) {
+       if (!rsh && sp == NULL) {
                sp = getservbyname(dokerberos ? "kshell" : "shell", "tcp");
-               if (sp == NULL)
-                       errx(1, "%s/tcp: unknown service",
-                           dokerberos ? "kshell" : "shell");
+               if (sp == NULL) {
+                       if (abortifconnerr) {
+                               errx(1, "%s/tcp: unknown service", dokerberos ? "kshell" : "shell");
+                       } else {
+                               msg("%s/tcp: unknown service", dokerberos ? "kshell" : "shell");
+                               return 0;
+                       }
+               }
+       }
+       if (pwd == NULL) {
                pwd = getpwuid(getuid());
-               if (pwd == NULL)
-                       errx(1, "who are you?");
+               if (pwd == NULL) {
+                       if (abortifconnerr) {
+                               errx(1, "who are you?");
+                       } else {
+                               msg("who are you?");
+                               return 0;
+                       }
+               }
        }
        if ((cp = strchr(rmtpeer, '@')) != NULL) {
                tuser = rmtpeer;
                *cp = '\0';
-               if (!okname(tuser))
-                       exit(X_STARTUP);
+               if (!okname(tuser)) {
+                       if (abortifconnerr) {
+                               exit(X_STARTUP);
+                       } else {
+                               return 0;
+                       }
+               }
                rmtpeer = ++cp;
        } else
                tuser = pwd->pw_name;
        if ((rmt = getenv("RMT")) == NULL)
                rmt = _PATH_RMT;
        msg("");
+
+       if (rsh) {
+               const char *rshcmd[6];
+               rshcmd[0] = rsh;
+               rshcmd[1] = rmtpeer;
+               rshcmd[2] = "-l";
+               rshcmd[3] = tuser;
+               rshcmd[4] = rmt;
+               rshcmd[5] = NULL;
+
+               /* Restore the uid and gid. We really don't want
+                * to execute whatever is put into RSH variable with
+                * more priviledges than needed... */
+               setuid(getuid());
+               setgid(getgid());
+
+               if ((rshpid = piped_child(rshcmd)) < 0) {
+                       msg("cannot open connection\n");
+                       return 0;
+               }
+       }
+       else {
+               /* Copy rmtpeer to rmtpeercopy to ignore the
+                  return value from rcmd. I cannot figure if
+                  this is this a bug in rcmd or in my code... */
+               rmtpeercopy = (char *)rmtpeer;
 #ifdef KERBEROS
-       if (dokerberos)
-               rmtape = krcmd((char **)&rmtpeer, sp->s_port, tuser, rmt, &errfd,
-                              (char *)0);
-       else
+               if (dokerberos)
+                       tormtape = krcmd(&rmtpeercopy, sp->s_port, tuser, rmt, &errfd,
+                                      (char *)0);
+               else
 #endif
-               rmtape = rcmd((char **)&rmtpeer, (u_short)sp->s_port, pwd->pw_name,
-                             tuser, rmt, &errfd);
-       if (rmtape < 0) {
-               msg("login to %s as %s failed.\n", rmtpeer, tuser);
-               return;
+                       tormtape = rcmd(&rmtpeercopy, (u_short)sp->s_port, pwd->pw_name,
+                                     tuser, rmt, &errfd);
+               if (tormtape < 0) {
+                       msg("login to %s as %s failed.\n", rmtpeer, tuser);
+                       return 0;
+               }
+               size = ntrec * TP_BSIZE;
+               if (size > 60 * 1024)           /* XXX */
+                       size = 60 * 1024;
+               /* Leave some space for rmt request/response protocol */
+               size += 2 * 1024;
+               while (size > TP_BSIZE &&
+                   setsockopt(tormtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
+                           size -= TP_BSIZE;
+               (void)setsockopt(tormtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
+               throughput = IPTOS_THROUGHPUT;
+               if (setsockopt(tormtape, IPPROTO_IP, IP_TOS,
+                   &throughput, sizeof(throughput)) < 0)
+                       perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
+               on = 1;
+               if (setsockopt(tormtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
+                       perror("TCP_NODELAY setsockopt");
+               fromrmtape = tormtape;
        }
-       (void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
-       size = ntrec * TP_BSIZE;
-       if (size > 60 * 1024)           /* XXX */
-               size = 60 * 1024;
-       /* Leave some space for rmt request/response protocol */
-       size += 2 * 1024;
-       while (size > TP_BSIZE &&
-           setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
-                   size -= TP_BSIZE;
-       (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
-       throughput = IPTOS_THROUGHPUT;
-       if (setsockopt(rmtape, IPPROTO_IP, IP_TOS,
-           &throughput, sizeof(throughput)) < 0)
-               perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
-       on = 1;
-       if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
-               perror("TCP_NODELAY setsockopt");
+       (void)fprintf(stdout, "Connection to %s established.\n", rmtpeer);
+       return 1;
 }
 
 static int
 okname(const char *cp0)
 {
-       register const char *cp;
-       register int c;
+       const char *cp;
+       int c;
 
        for (cp = cp0; *cp; cp++) {
                c = *cp;
@@ -241,11 +289,17 @@ okname(const char *cp0)
 }
 
 int
-rmtopen(const char *tape, int mode)
+rmtopen(const char *tape, const int mode)
 {
        char buf[MAXPATHLEN];
-
-       (void)snprintf(buf, sizeof (buf), "O%s\n%d\n", tape, mode);
+       char *rmtflags;
+
+       rmtflags = rmtflags_tochar(mode);
+       (void)snprintf(buf, sizeof (buf), "O%s\n%d %s\n", 
+                      tape, 
+                      mode & O_ACCMODE, 
+                      rmtflags);
+       free(rmtflags);
        rmtstate = TS_OPEN;
        return (rmtcall(tape, buf));
 }
@@ -269,11 +323,13 @@ rmtread(char *buf, size_t count)
 
        (void)snprintf(line, sizeof (line), "R%u\n", (unsigned)count);
        n = rmtcall("read", line);
-       if (n < 0)
+       if (n < 0) {
                /* rmtcall() properly sets errno for us on errors. */
-               return (n);
+               errno = n;
+               return (-1);
+       }
        for (i = 0; i < n; i += cc) {
-               cc = read(rmtape, buf+i, n - i);
+               cc = read(fromrmtape, buf+i, n - i);
                if (cc <= 0)
                        rmtconnaborted(0);
        }
@@ -285,18 +341,18 @@ rmtwrite(const char *buf, size_t count)
 {
        char line[30];
 
-       (void)snprintf(line, sizeof (line), "W%d\n", count);
-       write(rmtape, line, strlen(line));
-       write(rmtape, buf, count);
+       (void)snprintf(line, sizeof (line), "W%ld\n", (long)count);
+       write(tormtape, line, strlen(line));
+       write(tormtape, buf, count);
        return (rmtreply("write"));
 }
 
-int
-rmtseek(int offset, int pos)
+OFF_T
+rmtseek(OFF_T offset, int pos)
 {
        char line[80];
 
-       (void)snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos);
+       (void)snprintf(line, sizeof (line), "L%lld\n%d\n", (long long)offset, pos);
        return (rmtcall("seek", line));
 }
 
@@ -305,13 +361,21 @@ struct    mtget mts;
 struct mtget *
 rmtstatus(void)
 {
-       register int i;
-       register char *cp;
+       int i;
+       char *cp;
 
        if (rmtstate != TS_OPEN)
                return (NULL);
-       rmtcall("status", "S\n");
-       for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
+       i = rmtcall("status", "S");
+       if (i < 0) return NULL;
+       if (i != (int)sizeof(mts)) {
+               msg("mtget sizes different between host (%d) "
+                   "and remote tape (%d)", sizeof(mts), i);
+               for ( /* empty */; i > 0; --i)
+                       rmtgetb();
+               return NULL;
+       }
+       for (i = 0, cp = (char *)&mts; i < (int)sizeof(mts); i++)
                *cp++ = rmtgetb();
        return (&mts);
 }
@@ -327,19 +391,19 @@ rmtioctl(int cmd, int count)
        return (rmtcall("ioctl", buf));
 }
 
-static int
+static OFF_T
 rmtcall(const char *cmd, const char *buf)
 {
 
-       if (write(rmtape, buf, strlen(buf)) != strlen(buf))
+       if (write(tormtape, buf, strlen(buf)) != (ssize_t)strlen(buf))
                rmtconnaborted(0);
        return (rmtreply(cmd));
 }
 
-static int
+static OFF_T
 rmtreply(const char *cmd)
 {
-       register char *cp;
+       char *cp;
        char code[30], emsg[BUFSIZ];
 
        rmtgets(code, sizeof (code));
@@ -361,7 +425,7 @@ rmtreply(const char *cmd)
                    code);
                rmtconnaborted(0);
        }
-       return (atoi(code + 1));
+       return (OFF_T)(atoll(code + 1));
 }
 
 static int
@@ -369,7 +433,7 @@ rmtgetb(void)
 {
        char c;
 
-       if (read(rmtape, &c, 1) != 1)
+       if (read(fromrmtape, &c, 1) != 1)
                rmtconnaborted(0);
        return (c);
 }
@@ -378,7 +442,7 @@ rmtgetb(void)
 static void
 rmtgets(char *line, size_t len)
 {
-       register char *cp = line;
+       char *cp = line;
 
        while (len > 1) {
                *cp = rmtgetb();
@@ -394,3 +458,56 @@ rmtgets(char *line, size_t len)
        msg("(rmtgets got \"%s\").\n", line);
        rmtconnaborted(0);
 }
+
+int piped_child(const char **command) {
+       int pid;
+       int to_child_pipe[2];
+       int from_child_pipe[2];
+
+       if (pipe (to_child_pipe) < 0) {
+               msg ("cannot create pipe: %s\n", strerror(errno));
+               return -1;
+       }
+       if (pipe (from_child_pipe) < 0) {
+               msg ("cannot create pipe: %s\n", strerror(errno)); 
+               return -1;
+       }
+       pid = fork ();
+       if (pid < 0) {
+               msg ("cannot fork: %s\n", strerror(errno));
+               return -1;
+       }
+       if (pid == 0) {
+               if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0) {
+                       msg ("cannot dup2 pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               if (close (to_child_pipe[1]) < 0) {
+                       msg ("cannot close pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               if (close (from_child_pipe[0]) < 0) {
+                       msg ("cannot close pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) {
+                       msg ("cannot dup2 pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               setpgid(0, getpid());
+               execvp (command[0], (char *const *) command);
+               msg("cannot exec %s: %s\n", command[0], strerror(errno));
+               exit(1);
+       }
+       if (close (to_child_pipe[0]) < 0) {
+               msg ("cannot close pipe: %s\n", strerror(errno));
+               return -1;
+       }
+       if (close (from_child_pipe[1]) < 0) {
+               msg ("cannot close pipe: %s\n", strerror(errno));
+               return -1;
+       }
+       tormtape = to_child_pipe[1];
+       fromrmtape = from_child_pipe[0];
+       return pid;
+}