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