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