Annotation of src/usr.bin/rdist/rdist.c, Revision 1.18
1.18 ! jmc 1: /* $OpenBSD: rdist.c,v 1.17 2003/06/03 02:56:15 millert Exp $ */
1.3 deraadt 2:
1.1 dm 3: /*
4: * Copyright (c) 1983 Regents of the University of California.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.17 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 dm 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
1.16 millert 32: #include "defs.h"
33: #include "y.tab.h"
34:
1.1 dm 35: #ifndef lint
1.5 millert 36: #if 0
1.16 millert 37: static char RCSid[] __attribute__((__unused__)) =
38: "$From: rdist.c,v 1.6 2001/03/12 18:16:36 kim Exp $";
1.5 millert 39: #else
1.16 millert 40: static char RCSid[] __attribute__((__unused__)) =
1.18 ! jmc 41: "$OpenBSD: rdist.c,v 1.17 2003/06/03 02:56:15 millert Exp $";
1.5 millert 42: #endif
1.1 dm 43:
1.16 millert 44: static char sccsid[] __attribute__((__unused__)) =
45: "@(#)main.c 5.1 (Berkeley) 6/6/85";
1.1 dm 46:
1.16 millert 47: static char copyright[] __attribute__((__unused__)) =
1.1 dm 48: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
49: All rights reserved.\n";
50: #endif /* not lint */
51:
52:
53: #include <netdb.h>
54: #include <sys/ioctl.h>
55:
56: /*
57: * Remote distribution program.
58: */
1.6 millert 59:
1.1 dm 60: char *distfile = NULL; /* Name of distfile to use */
61: int maxchildren = MAXCHILDREN; /* Max no of concurrent PIDs */
62: int nflag = 0; /* Say without doing */
63: long min_freespace = 0; /* Min filesys free space */
64: long min_freefiles = 0; /* Min filesys free # files */
65: FILE *fin = NULL; /* Input file pointer */
66: char localmsglist[] = "stdout=all:notify=all:syslog=nerror,ferror";
67: char *remotemsglist = NULL;
68: char optchars[] = "A:a:bcd:DFf:hil:L:M:m:NnOo:p:P:qRrst:Vvwxy";
69: char *path_rdistd = _PATH_RDISTD;
1.4 millert 70: char *path_remsh = NULL;
1.1 dm 71:
1.16 millert 72: static void addhostlist(char *, struct namelist **);
73: static void usage(void);
74: int main(int, char **, char **);
75:
1.1 dm 76: /*
77: * Add a hostname to the host list
78: */
1.16 millert 79: static void
80: addhostlist(char *name, struct namelist **hostlist)
1.1 dm 81: {
1.9 mpech 82: struct namelist *ptr, *new;
1.1 dm 83:
84: if (!name || !hostlist)
85: return;
86:
87: new = (struct namelist *) xmalloc(sizeof(struct namelist));
1.7 millert 88: new->n_name = xstrdup(name);
1.15 millert 89: new->n_regex = NULL;
1.1 dm 90: new->n_next = NULL;
91:
92: if (*hostlist) {
93: for (ptr = *hostlist; ptr && ptr->n_next; ptr = ptr->n_next)
94: ;
95: ptr->n_next = new;
96: } else
97: *hostlist = new;
98: }
99:
1.5 millert 100: int
1.16 millert 101: main(int argc, char **argv, char **envp)
1.1 dm 102: {
1.16 millert 103: extern char *__progname;
1.1 dm 104: struct namelist *hostlist = NULL;
1.9 mpech 105: int x;
106: char *cp;
1.1 dm 107: int cmdargs = 0;
108: int c;
109:
1.16 millert 110: progname = __progname;
1.1 dm 111:
1.16 millert 112: if ((cp = msgparseopts(localmsglist, TRUE)) != NULL) {
1.1 dm 113: error("Bad builtin log option (%s): %s.",
114: localmsglist, cp);
115: usage();
116: }
117:
1.16 millert 118: if ((cp = getenv("RDIST_OPTIONS")) != NULL)
119: if (parsedistopts(cp, &options, TRUE)) {
120: error("Bad dist option environment string \"%s\".",
121: cp);
122: exit(1);
123: }
124:
1.1 dm 125: if (init(argc, argv, envp) < 0)
126: exit(1);
127:
128: /*
129: * Be backwards compatible.
130: */
131: for (x = 1; x <= argc && argv[x]; x++) {
132: if (strcmp(argv[x], "-Server") != 0)
133: continue;
134: #if defined(_PATH_OLDRDIST)
135: message(MT_SYSLOG,
136: "Old rdist (-Server) requested; running %s",
137: _PATH_OLDRDIST);
138: (void) execl(_PATH_OLDRDIST, xbasename(_PATH_OLDRDIST),
1.8 deraadt 139: "-Server", (char *)NULL);
1.1 dm 140: fatalerr("Exec old rdist failed: %s: %s.",
141: _PATH_OLDRDIST, SYSERR);
142: #else /* !_PATH_OLDRDIST */
143: fatalerr("Old rdist not available.");
144: #endif /* _PATH_OLDRDIST */
145: exit(1);
146: }
147:
148: #if defined(DIRECT_RCMD)
149: if (becomeuser() != 0)
150: exit(1);
151: #else /* !DIRECT_RCMD */
152: /*
153: * Perform check to make sure we are not incorrectly installed
154: * setuid to root or anybody else.
155: */
156: if (getuid() != geteuid())
157: fatalerr("This version of rdist should not be installed setuid.");
158: #endif /* DIRECT_RCMD */
159:
160: while ((c = getopt(argc, argv, optchars)) != -1)
161: switch (c) {
162: case 'l':
1.16 millert 163: if ((cp = msgparseopts(optarg, TRUE)) != NULL) {
1.1 dm 164: error("Bad log option \"%s\": %s.", optarg,cp);
165: usage();
166: }
167: break;
168:
169: case 'L':
1.7 millert 170: remotemsglist = xstrdup(optarg);
1.1 dm 171: break;
172:
173: case 'A':
174: case 'a':
175: case 'M':
176: case 't':
1.16 millert 177: if (!isdigit((unsigned char)*optarg)) {
1.1 dm 178: error("\"%s\" is not a number.", optarg);
179: usage();
180: }
181: if (c == 'a')
182: min_freespace = atoi(optarg);
183: else if (c == 'A')
184: min_freefiles = atoi(optarg);
185: else if (c == 'M')
186: maxchildren = atoi(optarg);
187: else if (c == 't')
188: rtimeout = atoi(optarg);
189: break;
190:
191: case 'F':
192: do_fork = FALSE;
193: break;
194:
195: case 'f':
1.7 millert 196: distfile = xstrdup(optarg);
1.1 dm 197: if (distfile[0] == '-' && distfile[1] == CNULL)
198: fin = stdin;
199: break;
200:
201: case 'm':
202: addhostlist(optarg, &hostlist);
203: break;
204:
205: case 'd':
206: define(optarg);
207: break;
208:
209: case 'D':
210: debug = DM_ALL;
1.16 millert 211: if ((cp = msgparseopts("stdout=all,debug",
212: TRUE)) != NULL) {
1.1 dm 213: error("Enable debug messages failed: %s.", cp);
214: usage();
215: }
216: break;
217:
218: case 'c':
219: cmdargs++;
220: break;
221:
222: case 'n':
223: nflag++;
224: break;
225:
226: case 'V':
227: printf("%s\n", getversion());
228: exit(0);
229:
230: case 'o':
231: if (parsedistopts(optarg, &options, TRUE)) {
232: error("Bad dist option string \"%s\".",
233: optarg);
234: usage();
235: }
236: break;
237:
238: case 'p':
239: if (!optarg) {
240: error("No path specified to \"-p\".");
241: usage();
242: }
1.7 millert 243: path_rdistd = xstrdup(optarg);
1.1 dm 244: break;
245:
246: case 'P':
247: if (!optarg) {
248: error("No path specified to \"-P\".");
249: usage();
250: }
1.16 millert 251: if ((cp = searchpath(optarg)) != NULL)
1.7 millert 252: path_remsh = xstrdup(cp);
1.1 dm 253: else {
254: error("No component of path \"%s\" exists.",
255: optarg);
256: usage();
257: }
258: break;
259:
260: /*
261: * These options are obsoleted by -o. They are
262: * provided only for backwards compatibility
263: */
264: case 'v': FLAG_ON(options, DO_VERIFY); break;
265: case 'N': FLAG_ON(options, DO_CHKNFS); break;
266: case 'O': FLAG_ON(options, DO_CHKREADONLY); break;
267: case 'q': FLAG_ON(options, DO_QUIET); break;
268: case 'b': FLAG_ON(options, DO_COMPARE); break;
269: case 'r': FLAG_ON(options, DO_NODESCEND); break;
270: case 'R': FLAG_ON(options, DO_REMOVE); break;
271: case 's': FLAG_ON(options, DO_SAVETARGETS); break;
272: case 'w': FLAG_ON(options, DO_WHOLE); break;
273: case 'y': FLAG_ON(options, DO_YOUNGER); break;
274: case 'h': FLAG_ON(options, DO_FOLLOW); break;
275: case 'i': FLAG_ON(options, DO_IGNLNKS); break;
276: case 'x': FLAG_ON(options, DO_NOEXEC); break;
277:
278: case '?':
279: default:
280: usage();
281: }
282:
283: if (debug) {
284: printf("%s\n", getversion());
285: msgprconfig();
286: }
287:
288: if (nflag && IS_ON(options, DO_VERIFY))
289: fatalerr(
290: "The -n flag and \"verify\" mode may not both be used.");
1.4 millert 291:
1.13 millert 292: if (path_remsh == NULL) {
293: if ((cp = getenv("RSH")) != NULL && *cp != '\0')
294: path_remsh = cp;
295: else
1.16 millert 296: path_remsh = _PATH_REMSH;
1.13 millert 297: }
1.1 dm 298:
299: /*
300: * Don't fork children for nflag
301: */
302: if (nflag)
303: do_fork = 0;
304:
305: if (cmdargs)
306: docmdargs(realargc - optind, &realargv[optind]);
307: else {
308: if (fin == NULL)
309: fin = opendist(distfile);
310: (void) yyparse();
311: /*
312: * Need to keep stdin open for child processing later
313: */
314: if (fin != stdin)
315: (void) fclose(fin);
316: if (nerrs == 0)
317: docmds(hostlist, realargc-optind, &realargv[optind]);
318: }
319:
320: exit(nerrs != 0);
321: }
322:
323: /*
324: * Open a distfile
325: */
1.16 millert 326: FILE *
327: opendist(char *distfile)
1.1 dm 328: {
329: char *file = NULL;
330: FILE *fp;
331:
332: if (distfile == NULL) {
333: if (access("distfile", R_OK) == 0)
334: file = "distfile";
335: else if (access("Distfile", R_OK) == 0)
336: file = "Distfile";
337: } else {
338: /*
339: * Try to test to see if file is readable before running m4.
340: */
341: if (access(distfile, R_OK) != 0)
342: fatalerr("%s: Cannot access file: %s.",
343: distfile, SYSERR);
344: file = distfile;
345: }
346:
347: if (file == NULL)
348: fatalerr("No distfile found.");
349:
350: fp = fopen(file, "r");
351:
352: if (fp == NULL)
353: fatalerr("%s: open failed: %s.", file, SYSERR);
354:
355: return(fp);
356: }
357:
358: /*
359: * Print usage message and exit.
360: */
1.16 millert 361: static void
362: usage(void)
1.1 dm 363: {
1.18 ! jmc 364: extern char *__progname;
1.1 dm 365:
366: (void) fprintf(stderr,
1.18 ! jmc 367: "usage: %s [-DFnV] [-Server] [-A num] [-a num] "
! 368: "[-c mini_distfile]\n"
! 369: "\t[-d var=value] [-f distfile] [-L remote_logopts] "
! 370: "[-l local_logopts]\n"
! 371: "\t[-M maxproc] [-m host] [-o distopts] [-P rsh-path] "
! 372: "[-p rdistd-path]\n"
! 373: "\t[-t timeout] [name ...]\n", __progname);
1.1 dm 374:
375:
376: (void) fprintf(stderr, "\nThe values for <distopts> are:\n\t%s\n",
377: getdistoptlist());
378:
379: msgprusage();
380:
381: exit(1);
382: }
383:
384: /*
385: * rcp like interface for distributing files.
386: */
1.5 millert 387: void
1.16 millert 388: docmdargs(int nargs, char **args)
1.1 dm 389: {
1.9 mpech 390: struct namelist *nl, *prev;
391: char *cp;
1.1 dm 392: struct namelist *files, *hosts;
393: struct subcmd *cmds;
394: char *dest;
1.15 millert 395: static struct namelist tnl;
1.1 dm 396: int i;
397:
398: if (nargs < 2)
399: usage();
400:
401: prev = NULL;
402: files = NULL;
403: for (i = 0; i < nargs - 1; i++) {
404: nl = makenl(args[i]);
405: if (prev == NULL)
406: files = prev = nl;
407: else {
408: prev->n_next = nl;
409: prev = nl;
410: }
411: }
412:
413: cp = args[i];
414: if ((dest = strchr(cp, ':')) != NULL)
415: *dest++ = '\0';
416: tnl.n_name = cp;
1.15 millert 417: tnl.n_regex = NULL;
418: tnl.n_next = NULL;
1.1 dm 419: hosts = expand(&tnl, E_ALL);
420: if (nerrs)
421: exit(1);
422:
423: if (dest == NULL || *dest == '\0')
424: cmds = NULL;
425: else {
426: cmds = makesubcmd(INSTALL);
427: cmds->sc_options = options;
428: cmds->sc_name = dest;
429: }
430:
431: debugmsg(DM_MISC, "docmdargs()\nfiles = %s", getnlstr(files));
432: debugmsg(DM_MISC, "host = %s", getnlstr(hosts));
433:
1.5 millert 434: insert(NULL, files, hosts, cmds);
1.16 millert 435: docmds(NULL, 0, NULL);
1.1 dm 436: }
437:
438: /*
439: * Get a list of NAME blocks (mostly for debugging).
440: */
1.16 millert 441: char *
442: getnlstr(struct namelist *nl)
1.1 dm 443: {
444: static char buf[16384];
1.16 millert 445: size_t len = 0;
1.1 dm 446:
1.16 millert 447: (void) snprintf(buf, sizeof(buf), "(");
1.1 dm 448:
449: while (nl != NULL) {
450: if (nl->n_name == NULL)
451: continue;
452: len += strlen(nl->n_name) + 2;
453: if (len >= sizeof(buf)) {
1.14 deraadt 454: (void) strlcpy(buf,
1.16 millert 455: "getnlstr() Buffer not large enough",
456: sizeof(buf));
1.1 dm 457: return(buf);
458: }
1.16 millert 459: (void) strlcat(buf, " ", sizeof(buf));
460: (void) strlcat(buf, nl->n_name, sizeof(buf));
1.1 dm 461: nl = nl->n_next;
462: }
463:
1.16 millert 464: (void) strlcat(buf, " )", sizeof(buf));
1.1 dm 465:
466: return(buf);
467: }