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