]> git.wh0rd.org Git - dump.git/blob - common/dumprmt.c
Make configure understand CPPFLAGS=, CFLAGS=, LDFLAGS=...
[dump.git] / common / dumprmt.c
1 /*
2  *      Ported to Linux's Second Extended File System as part of the
3  *      dump and restore backup suit
4  *      Remy Card <card@Linux.EU.Org>, 1994-1997
5  *      Stelian Pop <stelian@popies.net>, 1999-2000
6  *      Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
7  */
8
9 /*-
10  * Copyright (c) 1980, 1993
11  *      The Regents of the University of California.  All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37
38 #ifndef lint
39 static const char rcsid[] =
40         "$Id: dumprmt.c,v 1.27 2003/03/30 15:40:33 stelian Exp $";
41 #endif /* not lint */
42
43 #include <config.h>
44 #include <sys/param.h>
45 #include <sys/mtio.h>
46 #include <sys/socket.h>
47 #include <sys/time.h>
48 #include <fcntl.h>
49 #ifdef __linux__
50 #include <sys/types.h>
51 #ifdef HAVE_EXT2FS_EXT2_FS_H
52 #include <ext2fs/ext2_fs.h>
53 #else
54 #include <linux/ext2_fs.h>
55 #endif
56 #include <bsdcompat.h>
57 #include <signal.h>
58 #elif defined sunos
59 #include <sys/vnode.h>
60
61 #include <ufs/inode.h>
62 #else
63 #include <ufs/ufs/dinode.h>
64 #endif
65
66 #include <netinet/in.h>
67 #include <netinet/in_systm.h>
68 #include <netinet/ip.h>
69 #include <netinet/tcp.h>
70
71 #include <protocols/dumprestore.h>
72
73 #include <ctype.h>
74 #include <errno.h>
75 #include <compaterr.h>
76 #include <rmtflags.h>
77 #include <netdb.h>
78 #include <pwd.h>
79 #include <stdio.h>
80 #ifdef __STDC__
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 #endif
85
86 #ifdef  __linux__
87 #include <ext2fs/ext2fs.h>
88 #endif
89
90 #include <pathnames.h>
91 #include "dump.h"       /* for X_STARTUP, X_ABORT etc */
92
93 #define TS_CLOSED       0
94 #define TS_OPEN         1
95
96 static  int rmtstate = TS_CLOSED;
97 static  int tormtape = -1;
98 static  int fromrmtape = -1;
99 int rshpid = -1;
100 static  const char *rmtpeer = 0;
101
102 static  int okname __P((const char *));
103 static  OFF_T rmtcall __P((const char *, const char *));
104 static  void rmtconnaborted __P((int));
105 static  int rmtgetb __P((void));
106 static  int rmtgetconn __P((void));
107 static  void rmtgets __P((char *, size_t));
108 static  OFF_T rmtreply __P((const char *));
109 static  int piped_child __P((const char **command));
110 #ifdef KERBEROS
111 int     krcmd __P((char **, int /*u_short*/, char *, char *, int *, char *));
112 #endif
113
114 static  int errfd = -1;
115 extern  int dokerberos;
116 extern  int ntrec;              /* blocking factor on tape */
117 #ifndef errno
118 extern  int errno;
119 #endif
120
121 int
122 rmthost(const char *host)
123 {
124         if (rmtpeer)
125                 free((void *)rmtpeer);
126         if ((rmtpeer = strdup(host)) == NULL)
127                 rmtpeer = host;
128         signal(SIGPIPE, rmtconnaborted);
129         return rmtgetconn();
130 }
131
132 static void
133 rmtconnaborted(UNUSED(int signo))
134 {
135         msg("Lost connection to remote host.\n");
136         if (errfd != -1) {
137                 fd_set r;
138                 struct timeval t;
139
140                 FD_ZERO(&r);
141                 FD_SET(errfd, &r);
142                 t.tv_sec = 0;
143                 t.tv_usec = 0;
144                 if (select(errfd + 1, &r, NULL, NULL, &t)) {
145                         int i;
146                         char buf[2048];
147
148                         if ((i = read(errfd, buf, sizeof(buf) - 1)) > 0) {
149                                 buf[i] = '\0';
150                                 msg("on %s: %s%s", rmtpeer, buf,
151                                         buf[i - 1] == '\n' ? "" : "\n");
152                         }
153                 }
154         }
155
156         exit(X_ABORT);
157 }
158
159 static int
160 rmtgetconn(void)
161 {
162         char *cp;
163         const char *rmt;
164         static struct servent *sp = NULL;
165         static struct passwd *pwd = NULL;
166         const char *tuser;
167         const char *rsh;
168         int size;
169         int throughput;
170         int on;
171         char *rmtpeercopy;
172
173         rsh = getenv("RSH");
174
175         if (!rsh && sp == NULL) {
176                 sp = getservbyname(dokerberos ? "kshell" : "shell", "tcp");
177                 if (sp == NULL)
178                         errx(1, "%s/tcp: unknown service",
179                             dokerberos ? "kshell" : "shell");
180         }
181         if (pwd == NULL) {
182                 pwd = getpwuid(getuid());
183                 if (pwd == NULL)
184                         errx(1, "who are you?");
185         }
186         if ((cp = strchr(rmtpeer, '@')) != NULL) {
187                 tuser = rmtpeer;
188                 *cp = '\0';
189                 if (!okname(tuser))
190                         exit(X_STARTUP);
191                 rmtpeer = ++cp;
192         } else
193                 tuser = pwd->pw_name;
194         if ((rmt = getenv("RMT")) == NULL)
195                 rmt = _PATH_RMT;
196         msg("");
197
198         if (rsh) {
199                 const char *rshcmd[6];
200                 rshcmd[0] = rsh;
201                 rshcmd[1] = rmtpeer;
202                 rshcmd[2] = "-l";
203                 rshcmd[3] = tuser;
204                 rshcmd[4] = rmt;
205                 rshcmd[5] = NULL;
206
207                 /* Restore the uid and gid. We really don't want
208                  * to execute whatever is put into RSH variable with
209                  * more priviledges than needed... */
210                 setuid(getuid());
211                 setgid(getgid());
212
213                 if ((rshpid = piped_child(rshcmd)) < 0) {
214                         msg("cannot open connection\n");
215                         return 0;
216                 }
217         }
218         else {
219                 /* Copy rmtpeer to rmtpeercopy to ignore the
220                    return value from rcmd. I cannot figure if
221                    this is this a bug in rcmd or in my code... */
222                 rmtpeercopy = (char *)rmtpeer;
223 #ifdef KERBEROS
224                 if (dokerberos)
225                         tormtape = krcmd(&rmtpeercopy, sp->s_port, tuser, rmt, &errfd,
226                                        (char *)0);
227                 else
228 #endif
229                         tormtape = rcmd(&rmtpeercopy, (u_short)sp->s_port, pwd->pw_name,
230                                       tuser, rmt, &errfd);
231                 if (tormtape < 0) {
232                         msg("login to %s as %s failed.\n", rmtpeer, tuser);
233                         return 0;
234                 }
235                 size = ntrec * TP_BSIZE;
236                 if (size > 60 * 1024)           /* XXX */
237                         size = 60 * 1024;
238                 /* Leave some space for rmt request/response protocol */
239                 size += 2 * 1024;
240                 while (size > TP_BSIZE &&
241                     setsockopt(tormtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
242                             size -= TP_BSIZE;
243                 (void)setsockopt(tormtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
244                 throughput = IPTOS_THROUGHPUT;
245                 if (setsockopt(tormtape, IPPROTO_IP, IP_TOS,
246                     &throughput, sizeof(throughput)) < 0)
247                         perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
248                 on = 1;
249                 if (setsockopt(tormtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
250                         perror("TCP_NODELAY setsockopt");
251                 fromrmtape = tormtape;
252         }
253         (void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
254         return 1;
255 }
256
257 static int
258 okname(const char *cp0)
259 {
260         const char *cp;
261         int c;
262
263         for (cp = cp0; *cp; cp++) {
264                 c = *cp;
265                 if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
266                         warnx("invalid user name %s\n", cp0);
267                         return (0);
268                 }
269         }
270         return (1);
271 }
272
273 int
274 rmtopen(const char *tape, const int mode)
275 {
276         char buf[MAXPATHLEN];
277         char *rmtflags;
278
279         rmtflags = rmtflags_tochar(mode);
280         (void)snprintf(buf, sizeof (buf), "O%s\n%d %s\n", 
281                        tape, 
282                        mode & O_ACCMODE, 
283                        rmtflags);
284         free(rmtflags);
285         rmtstate = TS_OPEN;
286         return (rmtcall(tape, buf));
287 }
288
289 void
290 rmtclose(void)
291 {
292
293         if (rmtstate != TS_OPEN)
294                 return;
295         rmtcall("close", "C\n");
296         rmtstate = TS_CLOSED;
297 }
298
299 int
300 rmtread(char *buf, size_t count)
301 {
302         char line[30];
303         int n, i;
304         ssize_t cc;
305
306         (void)snprintf(line, sizeof (line), "R%u\n", (unsigned)count);
307         n = rmtcall("read", line);
308         if (n < 0)
309                 /* rmtcall() properly sets errno for us on errors. */
310                 return (n);
311         for (i = 0; i < n; i += cc) {
312                 cc = read(fromrmtape, buf+i, n - i);
313                 if (cc <= 0)
314                         rmtconnaborted(0);
315         }
316         return (n);
317 }
318
319 int
320 rmtwrite(const char *buf, size_t count)
321 {
322         char line[30];
323
324         (void)snprintf(line, sizeof (line), "W%ld\n", (long)count);
325         write(tormtape, line, strlen(line));
326         write(tormtape, buf, count);
327         return (rmtreply("write"));
328 }
329
330 OFF_T
331 rmtseek(OFF_T offset, int pos)
332 {
333         char line[80];
334
335         (void)snprintf(line, sizeof (line), "L%lld\n%d\n", (long long)offset, pos);
336         return (rmtcall("seek", line));
337 }
338
339 struct  mtget mts;
340
341 struct mtget *
342 rmtstatus(void)
343 {
344         int i;
345         char *cp;
346
347         if (rmtstate != TS_OPEN)
348                 return (NULL);
349         i = rmtcall("status", "S");
350         if (i < 0) return NULL;
351         if (i != (int)sizeof(mts)) {
352                 msg("mtget sizes different between host (%d) "
353                     "and remote tape (%d)", sizeof(mts), i);
354                 for ( /* empty */; i > 0; --i)
355                         rmtgetb();
356                 return NULL;
357         }
358         for (i = 0, cp = (char *)&mts; i < (int)sizeof(mts); i++)
359                 *cp++ = rmtgetb();
360         return (&mts);
361 }
362
363 int
364 rmtioctl(int cmd, int count)
365 {
366         char buf[256];
367
368         if (count < 0)
369                 return (-1);
370         (void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count);
371         return (rmtcall("ioctl", buf));
372 }
373
374 static OFF_T
375 rmtcall(const char *cmd, const char *buf)
376 {
377
378         if (write(tormtape, buf, strlen(buf)) != (ssize_t)strlen(buf))
379                 rmtconnaborted(0);
380         return (rmtreply(cmd));
381 }
382
383 static OFF_T
384 rmtreply(const char *cmd)
385 {
386         char *cp;
387         char code[30], emsg[BUFSIZ];
388
389         rmtgets(code, sizeof (code));
390         if (*code == 'E' || *code == 'F') {
391                 rmtgets(emsg, sizeof (emsg));
392                 msg("%s: %s", cmd, emsg);
393                 errno = atoi(code + 1);
394                 if (*code == 'F')
395                         rmtstate = TS_CLOSED;
396                 return (-1);
397         }
398         if (*code != 'A') {
399                 /* Kill trailing newline */
400                 cp = code + strlen(code);
401                 if (cp > code && *--cp == '\n')
402                         *cp = '\0';
403
404                 msg("Protocol to remote tape server botched (code \"%s\").\n",
405                     code);
406                 rmtconnaborted(0);
407         }
408         return (OFF_T)(atoll(code + 1));
409 }
410
411 static int
412 rmtgetb(void)
413 {
414         char c;
415
416         if (read(fromrmtape, &c, 1) != 1)
417                 rmtconnaborted(0);
418         return (c);
419 }
420
421 /* Get a line (guaranteed to have a trailing newline). */
422 static void
423 rmtgets(char *line, size_t len)
424 {
425         char *cp = line;
426
427         while (len > 1) {
428                 *cp = rmtgetb();
429                 if (*cp == '\n') {
430                         cp[1] = '\0';
431                         return;
432                 }
433                 cp++;
434                 len--;
435         }
436         *cp = '\0';
437         msg("Protocol to remote tape server botched.\n");
438         msg("(rmtgets got \"%s\").\n", line);
439         rmtconnaborted(0);
440 }
441
442 int piped_child(const char **command) {
443         int pid;
444         int to_child_pipe[2];
445         int from_child_pipe[2];
446
447         if (pipe (to_child_pipe) < 0) {
448                 msg ("cannot create pipe: %s\n", strerror(errno));
449                 return -1;
450         }
451         if (pipe (from_child_pipe) < 0) {
452                 msg ("cannot create pipe: %s\n", strerror(errno)); 
453                 return -1;
454         }
455         pid = fork ();
456         if (pid < 0) {
457                 msg ("cannot fork: %s\n", strerror(errno));
458                 return -1;
459         }
460         if (pid == 0) {
461                 if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0) {
462                         msg ("cannot dup2 pipe: %s\n", strerror(errno));
463                         exit(1);
464                 }
465                 if (close (to_child_pipe[1]) < 0) {
466                         msg ("cannot close pipe: %s\n", strerror(errno));
467                         exit(1);
468                 }
469                 if (close (from_child_pipe[0]) < 0) {
470                         msg ("cannot close pipe: %s\n", strerror(errno));
471                         exit(1);
472                 }
473                 if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) {
474                         msg ("cannot dup2 pipe: %s\n", strerror(errno));
475                         exit(1);
476                 }
477                 setpgid(0, getpid());
478                 execvp (command[0], (char *const *) command);
479                 msg("cannot exec %s: %s\n", command[0], strerror(errno));
480                 exit(1);
481         }
482         if (close (to_child_pipe[0]) < 0) {
483                 msg ("cannot close pipe: %s\n", strerror(errno));
484                 return -1;
485         }
486         if (close (from_child_pipe[1]) < 0) {
487                 msg ("cannot close pipe: %s\n", strerror(errno));
488                 return -1;
489         }
490         tormtape = to_child_pipe[1];
491         fromrmtape = from_child_pipe[0];
492         return pid;
493 }