Annotation of src/usr.bin/rdist/rdist.c, Revision 1.33
1.33 ! cheloha 1: /* $OpenBSD: rdist.c,v 1.32 2021/06/22 20:19:28 jmc 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: default:
252: usage();
253: }
254:
255: if (debug) {
256: printf("%s\n", getversion());
257: msgprconfig();
258: }
259:
260: if (nflag && IS_ON(options, DO_VERIFY))
261: fatalerr(
262: "The -n flag and \"verify\" mode may not both be used.");
1.4 millert 263:
1.13 millert 264: if (path_remsh == NULL) {
265: if ((cp = getenv("RSH")) != NULL && *cp != '\0')
266: path_remsh = cp;
267: else
1.28 guenther 268: path_remsh = _PATH_RSH;
1.13 millert 269: }
1.1 dm 270:
271: /*
272: * Don't fork children for nflag
273: */
274: if (nflag)
275: do_fork = 0;
276:
277: if (cmdargs)
278: docmdargs(realargc - optind, &realargv[optind]);
279: else {
280: if (fin == NULL)
281: fin = opendist(distfile);
282: (void) yyparse();
283: /*
284: * Need to keep stdin open for child processing later
285: */
286: if (fin != stdin)
287: (void) fclose(fin);
288: if (nerrs == 0)
289: docmds(hostlist, realargc-optind, &realargv[optind]);
290: }
291:
292: exit(nerrs != 0);
293: }
294:
295: /*
296: * Open a distfile
297: */
1.16 millert 298: FILE *
299: opendist(char *distfile)
1.1 dm 300: {
301: char *file = NULL;
302: FILE *fp;
303:
304: if (distfile == NULL) {
305: if (access("distfile", R_OK) == 0)
306: file = "distfile";
307: else if (access("Distfile", R_OK) == 0)
308: file = "Distfile";
309: } else {
310: /*
311: * Try to test to see if file is readable before running m4.
312: */
313: if (access(distfile, R_OK) != 0)
314: fatalerr("%s: Cannot access file: %s.",
315: distfile, SYSERR);
316: file = distfile;
317: }
318:
319: if (file == NULL)
320: fatalerr("No distfile found.");
321:
322: fp = fopen(file, "r");
323:
324: if (fp == NULL)
325: fatalerr("%s: open failed: %s.", file, SYSERR);
326:
327: return(fp);
328: }
329:
330: /*
331: * Print usage message and exit.
332: */
1.16 millert 333: static void
334: usage(void)
1.1 dm 335: {
1.18 jmc 336: extern char *__progname;
1.1 dm 337:
338: (void) fprintf(stderr,
1.32 jmc 339: "usage: %s [-DFnV] [-A num] [-a num] [-c mini_distfile]"
340: " [-d var=value]\n"
341: "\t[-f distfile] [-L remote_logopts] [-l local_logopts]"
342: " [-M maxproc]\n"
343: "\t[-m host] [-o distopts] [-P rsh-path] [-p rdistd-path]"
344: " [-t timeout]\n"
345: "\t[name ...]\n", __progname);
1.1 dm 346:
347: exit(1);
348: }
349:
350: /*
351: * rcp like interface for distributing files.
352: */
1.5 millert 353: void
1.16 millert 354: docmdargs(int nargs, char **args)
1.1 dm 355: {
1.9 mpech 356: struct namelist *nl, *prev;
357: char *cp;
1.1 dm 358: struct namelist *files, *hosts;
1.29 guenther 359: struct subcmd *scmds;
1.1 dm 360: char *dest;
1.15 millert 361: static struct namelist tnl;
1.1 dm 362: int i;
363:
364: if (nargs < 2)
365: usage();
366:
367: prev = NULL;
368: files = NULL;
369: for (i = 0; i < nargs - 1; i++) {
370: nl = makenl(args[i]);
371: if (prev == NULL)
372: files = prev = nl;
373: else {
374: prev->n_next = nl;
375: prev = nl;
376: }
377: }
378:
379: cp = args[i];
380: if ((dest = strchr(cp, ':')) != NULL)
381: *dest++ = '\0';
382: tnl.n_name = cp;
1.15 millert 383: tnl.n_regex = NULL;
384: tnl.n_next = NULL;
1.1 dm 385: hosts = expand(&tnl, E_ALL);
386: if (nerrs)
387: exit(1);
388:
389: if (dest == NULL || *dest == '\0')
1.29 guenther 390: scmds = NULL;
1.1 dm 391: else {
1.29 guenther 392: scmds = makesubcmd(INSTALL);
393: scmds->sc_options = options;
394: scmds->sc_name = dest;
1.1 dm 395: }
396:
397: debugmsg(DM_MISC, "docmdargs()\nfiles = %s", getnlstr(files));
398: debugmsg(DM_MISC, "host = %s", getnlstr(hosts));
399:
1.29 guenther 400: insert(NULL, files, hosts, scmds);
1.16 millert 401: docmds(NULL, 0, NULL);
1.1 dm 402: }
403:
404: /*
405: * Get a list of NAME blocks (mostly for debugging).
406: */
1.16 millert 407: char *
408: getnlstr(struct namelist *nl)
1.1 dm 409: {
410: static char buf[16384];
1.16 millert 411: size_t len = 0;
1.1 dm 412:
1.16 millert 413: (void) snprintf(buf, sizeof(buf), "(");
1.1 dm 414:
415: while (nl != NULL) {
416: if (nl->n_name == NULL)
417: continue;
418: len += strlen(nl->n_name) + 2;
419: if (len >= sizeof(buf)) {
1.14 deraadt 420: (void) strlcpy(buf,
1.16 millert 421: "getnlstr() Buffer not large enough",
422: sizeof(buf));
1.1 dm 423: return(buf);
424: }
1.16 millert 425: (void) strlcat(buf, " ", sizeof(buf));
426: (void) strlcat(buf, nl->n_name, sizeof(buf));
1.1 dm 427: nl = nl->n_next;
428: }
429:
1.16 millert 430: (void) strlcat(buf, " )", sizeof(buf));
1.1 dm 431:
432: return(buf);
433: }