Annotation of src/usr.bin/rdist/rdist.c, Revision 1.5
1.5 ! millert 1: /* $OpenBSD$ */
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[] =
! 42: "$OpenBSD$";
! 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: */
61:
62: char *distfile = NULL; /* Name of distfile to use */
63: int maxchildren = MAXCHILDREN; /* Max no of concurrent PIDs */
64: int nflag = 0; /* Say without doing */
65: long min_freespace = 0; /* Min filesys free space */
66: long min_freefiles = 0; /* Min filesys free # files */
67: FILE *fin = NULL; /* Input file pointer */
68: struct group *gr = NULL; /* Static area for getgrent */
69: char localmsglist[] = "stdout=all:notify=all:syslog=nerror,ferror";
70: char *remotemsglist = NULL;
71: char optchars[] = "A:a:bcd:DFf:hil:L:M:m:NnOo:p:P:qRrst:Vvwxy";
72: FILE *opendist();
73: char *path_rdistd = _PATH_RDISTD;
1.4 millert 74: char *path_remsh = NULL;
1.1 dm 75:
76: /*
77: * Add a hostname to the host list
78: */
79: static void addhostlist(name, hostlist)
80: char *name;
81: struct namelist **hostlist;
82: {
83: register struct namelist *ptr, *new;
84:
85: if (!name || !hostlist)
86: return;
87:
88: new = (struct namelist *) xmalloc(sizeof(struct namelist));
89: new->n_name = strdup(name);
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.1 dm 101: main(argc, argv, envp)
102: int argc;
103: char *argv[];
104: char **envp;
105: {
106: struct namelist *hostlist = NULL;
107: register int x;
108: register char *cp;
109: int cmdargs = 0;
110: int c;
111:
112: /*
113: * We initialize progname here instead of init() because
114: * things in msgparseopts() need progname set.
115: */
116: setprogname(argv);
117:
1.5 ! millert 118: if ((cp = msgparseopts(localmsglist, TRUE))) {
1.1 dm 119: error("Bad builtin log option (%s): %s.",
120: localmsglist, cp);
121: usage();
122: }
123:
124: if (init(argc, argv, envp) < 0)
125: exit(1);
126:
127: /*
128: * Be backwards compatible.
129: */
130: for (x = 1; x <= argc && argv[x]; x++) {
131: if (strcmp(argv[x], "-Server") != 0)
132: continue;
133: #if defined(_PATH_OLDRDIST)
134: message(MT_SYSLOG,
135: "Old rdist (-Server) requested; running %s",
136: _PATH_OLDRDIST);
137: (void) execl(_PATH_OLDRDIST, xbasename(_PATH_OLDRDIST),
1.5 ! millert 138: "-Server", NULL);
1.1 dm 139: fatalerr("Exec old rdist failed: %s: %s.",
140: _PATH_OLDRDIST, SYSERR);
141: #else /* !_PATH_OLDRDIST */
142: fatalerr("Old rdist not available.");
143: #endif /* _PATH_OLDRDIST */
144: exit(1);
145: }
146:
147: #if defined(DIRECT_RCMD)
148: if (becomeuser() != 0)
149: exit(1);
150: #else /* !DIRECT_RCMD */
151: /*
152: * Perform check to make sure we are not incorrectly installed
153: * setuid to root or anybody else.
154: */
155: if (getuid() != geteuid())
156: fatalerr("This version of rdist should not be installed setuid.");
157: #endif /* DIRECT_RCMD */
158:
159: while ((c = getopt(argc, argv, optchars)) != -1)
160: switch (c) {
161: case 'l':
1.5 ! millert 162: if ((cp = msgparseopts(optarg, TRUE))) {
1.1 dm 163: error("Bad log option \"%s\": %s.", optarg,cp);
164: usage();
165: }
166: break;
167:
168: case 'L':
169: remotemsglist = strdup(optarg);
170: break;
171:
172: case 'A':
173: case 'a':
174: case 'M':
175: case 't':
176: if (!isdigit(*optarg)) {
177: error("\"%s\" is not a number.", optarg);
178: usage();
179: }
180: if (c == 'a')
181: min_freespace = atoi(optarg);
182: else if (c == 'A')
183: min_freefiles = atoi(optarg);
184: else if (c == 'M')
185: maxchildren = atoi(optarg);
186: else if (c == 't')
187: rtimeout = atoi(optarg);
188: break;
189:
190: case 'F':
191: do_fork = FALSE;
192: break;
193:
194: case 'f':
195: distfile = strdup(optarg);
196: if (distfile[0] == '-' && distfile[1] == CNULL)
197: fin = stdin;
198: break;
199:
200: case 'm':
201: addhostlist(optarg, &hostlist);
202: break;
203:
204: case 'd':
205: define(optarg);
206: break;
207:
208: case 'D':
209: debug = DM_ALL;
1.5 ! millert 210: if ((cp = msgparseopts("stdout=all,debug", TRUE))) {
1.1 dm 211: error("Enable debug messages failed: %s.", cp);
212: usage();
213: }
214: break;
215:
216: case 'c':
217: cmdargs++;
218: break;
219:
220: case 'n':
221: nflag++;
222: break;
223:
224: case 'V':
225: printf("%s\n", getversion());
226: exit(0);
227:
228: case 'o':
229: if (parsedistopts(optarg, &options, TRUE)) {
230: error("Bad dist option string \"%s\".",
231: optarg);
232: usage();
233: }
234: break;
235:
236: case 'p':
237: if (!optarg) {
238: error("No path specified to \"-p\".");
239: usage();
240: }
241: path_rdistd = strdup(optarg);
242: break;
243:
244: case 'P':
245: if (!optarg) {
246: error("No path specified to \"-P\".");
247: usage();
248: }
1.5 ! millert 249: if ((cp = searchpath(optarg)))
1.1 dm 250: path_remsh = strdup(cp);
251: else {
252: error("No component of path \"%s\" exists.",
253: optarg);
254: usage();
255: }
256: break;
257:
258: /*
259: * These options are obsoleted by -o. They are
260: * provided only for backwards compatibility
261: */
262: case 'v': FLAG_ON(options, DO_VERIFY); break;
263: case 'N': FLAG_ON(options, DO_CHKNFS); break;
264: case 'O': FLAG_ON(options, DO_CHKREADONLY); break;
265: case 'q': FLAG_ON(options, DO_QUIET); break;
266: case 'b': FLAG_ON(options, DO_COMPARE); break;
267: case 'r': FLAG_ON(options, DO_NODESCEND); break;
268: case 'R': FLAG_ON(options, DO_REMOVE); break;
269: case 's': FLAG_ON(options, DO_SAVETARGETS); break;
270: case 'w': FLAG_ON(options, DO_WHOLE); break;
271: case 'y': FLAG_ON(options, DO_YOUNGER); break;
272: case 'h': FLAG_ON(options, DO_FOLLOW); break;
273: case 'i': FLAG_ON(options, DO_IGNLNKS); break;
274: case 'x': FLAG_ON(options, DO_NOEXEC); break;
275:
276: case '?':
277: default:
278: usage();
279: }
280:
281: if (debug) {
282: printf("%s\n", getversion());
283: msgprconfig();
284: }
285:
286: if (nflag && IS_ON(options, DO_VERIFY))
287: fatalerr(
288: "The -n flag and \"verify\" mode may not both be used.");
1.4 millert 289:
290: if (path_remsh == NULL)
291: path_remsh = getenv("RSH");
1.1 dm 292:
293: /*
294: * Don't fork children for nflag
295: */
296: if (nflag)
297: do_fork = 0;
298:
299: if (cmdargs)
300: docmdargs(realargc - optind, &realargv[optind]);
301: else {
302: if (fin == NULL)
303: fin = opendist(distfile);
304: (void) yyparse();
305: /*
306: * Need to keep stdin open for child processing later
307: */
308: if (fin != stdin)
309: (void) fclose(fin);
310: if (nerrs == 0)
311: docmds(hostlist, realargc-optind, &realargv[optind]);
312: }
313:
314: exit(nerrs != 0);
315: }
316:
317: /*
318: * Open a distfile
319: */
320: FILE *opendist(distfile)
321: char *distfile;
322: {
323: char *file = NULL;
324: FILE *fp;
325:
326: if (distfile == NULL) {
327: if (access("distfile", R_OK) == 0)
328: file = "distfile";
329: else if (access("Distfile", R_OK) == 0)
330: file = "Distfile";
331: } else {
332: /*
333: * Try to test to see if file is readable before running m4.
334: */
335: if (access(distfile, R_OK) != 0)
336: fatalerr("%s: Cannot access file: %s.",
337: distfile, SYSERR);
338: file = distfile;
339: }
340:
341: if (file == NULL)
342: fatalerr("No distfile found.");
343:
344: fp = fopen(file, "r");
345:
346: if (fp == NULL)
347: fatalerr("%s: open failed: %s.", file, SYSERR);
348:
349: return(fp);
350: }
351:
352: /*
353: * Print usage message and exit.
354: */
1.5 ! millert 355: void
1.1 dm 356: usage()
357: {
358: char *sopts = "cDFnv";
359:
360: (void) fprintf(stderr,
361: "Usage: %s [-%s] [-A <num>] [-a <num>] [-d var=value]\n",
362: progname, sopts);
363: (void) fprintf(stderr,
364: "\t[-f distfile] [-l <msgopt>] [-L <msgopt>] [-M <maxproc>]\n");
365: (void) fprintf(stderr,
366: "\t[-m host] [-o <distopts>] [-p <rdistd-cmd>] [-P <rsh-path>]\n");
367: (void) fprintf(stderr,
368: "\t[-t <timeout>] [target ...]\n");
369:
370: (void) fprintf(stderr,
371: "OR: %s [-%s] -c source [...] machine[:dest]\n",
372: progname, sopts);
373:
374: (void) fprintf(stderr, "OR: %s -V\n", progname);
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.1 dm 388: docmdargs(nargs, args)
389: int nargs;
390: char *args[];
391: {
392: register struct namelist *nl, *prev;
393: register char *cp;
394: struct namelist *files, *hosts;
395: struct subcmd *cmds;
396: char *dest;
397: static struct namelist tnl = { NULL, NULL };
398: int i;
399:
400: if (nargs < 2)
401: usage();
402:
403: prev = NULL;
404: files = NULL;
405: for (i = 0; i < nargs - 1; i++) {
406: nl = makenl(args[i]);
407: if (prev == NULL)
408: files = prev = nl;
409: else {
410: prev->n_next = nl;
411: prev = nl;
412: }
413: }
414:
415: cp = args[i];
416: if ((dest = strchr(cp, ':')) != NULL)
417: *dest++ = '\0';
418: tnl.n_name = cp;
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);
! 435: docmds(0, NULL, 0, (char **)NULL);
1.1 dm 436: }
437:
438: /*
439: * Get a list of NAME blocks (mostly for debugging).
440: */
441: extern char *getnlstr(nl)
442: register struct namelist *nl;
443: {
444: static char buf[16384];
445: register int count = 0, len = 0;
446:
447: (void) sprintf(buf, "(");
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)) {
454: (void) strcpy(buf,
455: "getnlstr() Buffer not large enough");
456: return(buf);
457: }
458: ++count;
459: (void) strcat(buf, " ");
460: (void) strcat(buf, nl->n_name);
461: nl = nl->n_next;
462: }
463:
464: (void) strcat(buf, " )");
465:
466: return(buf);
467: }