GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rdist/rdist.c Lines: 0 177 0.0 %
Date: 2016-12-06 Branches: 0 132 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: rdist.c,v 1.30 2015/02/08 23:40:34 deraadt Exp $	*/
2
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. Neither the name of the University nor the names of its contributors
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
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"
41
#include "y.tab.h"
42
43
44
/*
45
 * Remote distribution program.
46
 */
47
48
int     	maxchildren = MAXCHILDREN;	/* Max no of concurrent PIDs */
49
int		nflag = 0;			/* Say without doing */
50
int64_t		min_freespace = 0;		/* Min filesys free space */
51
int64_t		min_freefiles = 0;		/* Min filesys free # files */
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;
57
char	       *path_remsh = NULL;
58
59
static void addhostlist(char *, struct namelist **);
60
static void usage(void);
61
int main(int, char **, char **);
62
63
/*
64
 * Add a hostname to the host list
65
 */
66
static void
67
addhostlist(char *name, struct namelist **hostlist)
68
{
69
	struct namelist *ptr, *new;
70
71
	if (!name || !hostlist)
72
		return;
73
74
	new = xmalloc(sizeof *new);
75
	new->n_name = xstrdup(name);
76
	new->n_regex = NULL;
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
87
int
88
main(int argc, char **argv, char **envp)
89
{
90
	extern char *__progname;
91
	struct namelist *hostlist = NULL;
92
	char *distfile = NULL;
93
	char *cp;
94
	int cmdargs = 0;
95
	int c;
96
	const char *errstr;
97
98
	progname = __progname;
99
100
	if ((cp = msgparseopts(localmsglist, TRUE)) != NULL) {
101
		error("Bad builtin log option (%s): %s.",
102
		      localmsglist, cp);
103
		usage();
104
	}
105
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
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':
126
			if ((cp = msgparseopts(optarg, TRUE)) != NULL) {
127
				error("Bad log option \"%s\": %s.", optarg,cp);
128
				usage();
129
			}
130
			break;
131
132
		case 'L':
133
			remotemsglist = xstrdup(optarg);
134
			break;
135
136
		case 'A':
137
		case 'a':
138
		case 'M':
139
		case 't':
140
			if (!isdigit((unsigned char)*optarg)) {
141
				error("\"%s\" is not a number.", optarg);
142
				usage();
143
			}
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') {
152
				min_freefiles = (int64_t)strtonum(optarg,
153
					0, LLONG_MAX, &errstr);
154
				if (errstr)
155
					fatalerr("Minimum free files is %s: "
156
						 "'%s'", errstr, optarg);
157
			}
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':
169
			distfile = xstrdup(optarg);
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;
184
			if ((cp = msgparseopts("stdout=all,debug",
185
			    TRUE)) != NULL) {
186
				error("Enable debug messages failed: %s.", cp);
187
				usage();
188
			}
189
			break;
190
191
		case 'c':
192
			cmdargs = 1;
193
			break;
194
195
		case 'n':
196
			nflag = 1;
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
			}
216
			path_rdistd = xstrdup(optarg);
217
			break;
218
219
		case 'P':
220
			if (!optarg) {
221
				error("No path specified to \"-P\".");
222
				usage();
223
			}
224
			if ((cp = searchpath(optarg)) != NULL)
225
				path_remsh = xstrdup(cp);
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.");
264
265
	if (path_remsh == NULL) {
266
		if ((cp = getenv("RSH")) != NULL && *cp != '\0')
267
			path_remsh = cp;
268
		else
269
			path_remsh = _PATH_RSH;
270
	}
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
 */
299
FILE *
300
opendist(char *distfile)
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
 */
334
static void
335
usage(void)
336
{
337
	extern char *__progname;
338
339
	(void) fprintf(stderr,
340
		"usage: %s [-DFnV] [-A num] [-a num] "
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);
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
 */
360
void
361
docmdargs(int nargs, char **args)
362
{
363
	struct namelist *nl, *prev;
364
	char *cp;
365
	struct namelist *files, *hosts;
366
	struct subcmd *scmds;
367
	char *dest;
368
	static struct namelist tnl;
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;
390
	tnl.n_regex = NULL;
391
	tnl.n_next = NULL;
392
	hosts = expand(&tnl, E_ALL);
393
	if (nerrs)
394
		exit(1);
395
396
	if (dest == NULL || *dest == '\0')
397
		scmds = NULL;
398
	else {
399
		scmds = makesubcmd(INSTALL);
400
		scmds->sc_options = options;
401
		scmds->sc_name = dest;
402
	}
403
404
	debugmsg(DM_MISC, "docmdargs()\nfiles = %s", getnlstr(files));
405
	debugmsg(DM_MISC, "host = %s", getnlstr(hosts));
406
407
	insert(NULL, files, hosts, scmds);
408
	docmds(NULL, 0, NULL);
409
}
410
411
/*
412
 * Get a list of NAME blocks (mostly for debugging).
413
 */
414
char *
415
getnlstr(struct namelist *nl)
416
{
417
	static char buf[16384];
418
	size_t len = 0;
419
420
	(void) snprintf(buf, sizeof(buf), "(");
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)) {
427
			(void) strlcpy(buf,
428
				       "getnlstr() Buffer not large enough",
429
				       sizeof(buf));
430
			return(buf);
431
		}
432
		(void) strlcat(buf, " ", sizeof(buf));
433
		(void) strlcat(buf, nl->n_name, sizeof(buf));
434
		nl = nl->n_next;
435
	}
436
437
	(void) strlcat(buf, " )", sizeof(buf));
438
439
	return(buf);
440
}