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