GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amq/amq.c Lines: 0 245 0.0 %
Date: 2017-11-13 Branches: 0 140 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 1990 Jan-Simon Pendry
3
 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4
 * Copyright (c) 1990, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Jan-Simon Pendry at Imperial College, London.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 *	from: @(#)amq.c	8.1 (Berkeley) 6/7/93
35
 *	$Id: amq.c,v 1.21 2017/01/21 08:33:51 krw Exp $
36
 */
37
38
/*
39
 * Automounter query tool
40
 */
41
42
#include "am.h"
43
#include "amq.h"
44
#include <stdio.h>
45
#include <fcntl.h>
46
#include <netdb.h>
47
#include <unistd.h>
48
49
static int privsock(int);
50
51
static int flush_flag;
52
static int minfo_flag;
53
static int unmount_flag;
54
static int stats_flag;
55
static int getvers_flag;
56
static char *debug_opts;
57
static char *logfile;
58
static char *xlog_optstr;
59
static char localhost[] = "localhost";
60
static char *def_server = localhost;
61
62
extern int optind;
63
extern char *optarg;
64
65
static struct timeval tmo = { 10, 0 };
66
#define	TIMEOUT tmo
67
68
enum show_opt { Full, Stats, Calc, Short, ShowDone };
69
70
/*
71
 * If (e) is Calc then just calculate the sizes
72
 * Otherwise display the mount node on stdout
73
 */
74
static void
75
show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid,
76
    int *twid)
77
{
78
	switch (e) {
79
	case Calc: {
80
		int mw = strlen(mt->mt_mountinfo);
81
		int dw = strlen(mt->mt_directory);
82
		int tw = strlen(mt->mt_type);
83
84
		if (mw > *mwid)
85
			*mwid = mw;
86
		if (dw > *dwid)
87
			*dwid = dw;
88
		if (tw > *twid)
89
			*twid = tw;
90
		break;
91
	    }
92
93
	case Full: {
94
		time_t t = mt->mt_mounttime;
95
96
		struct tm *tp = localtime(&t);
97
98
		printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d"
99
		    " %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
100
		    *dwid, *dwid, *mt->mt_directory ? mt->mt_directory : "/",
101
		    *twid, *twid, mt->mt_type, *mwid, *mwid,
102
		    mt->mt_mountinfo, mt->mt_mountpoint, mt->mt_mountuid,
103
		    mt->mt_getattr, mt->mt_lookup, mt->mt_readdir,
104
		    mt->mt_readlink, mt->mt_statfs,
105
		    tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
106
		    tp->tm_mon+1, tp->tm_mday,
107
		    tp->tm_hour, tp->tm_min, tp->tm_sec);
108
		break;
109
	    }
110
111
	case Stats: {
112
		time_t t = mt->mt_mounttime;
113
114
		struct tm *tp = localtime(&t);
115
116
		printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d"
117
		    " %02d/%02d/%02d %02d:%02d:%02d\n",
118
		    *dwid, *dwid, *mt->mt_directory ? mt->mt_directory : "/",
119
		    mt->mt_mountuid, mt->mt_getattr, mt->mt_lookup,
120
		    mt->mt_readdir, mt->mt_readlink, mt->mt_statfs,
121
		    tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
122
		    tp->tm_mon+1, tp->tm_mday,
123
		    tp->tm_hour, tp->tm_min, tp->tm_sec);
124
		break;
125
	    }
126
127
	case Short: {
128
		printf("%-*.*s %-*.*s %-*.*s %s\n",
129
		    *dwid, *dwid, *mt->mt_directory ? mt->mt_directory : "/",
130
		    *twid, *twid, mt->mt_type, *mwid, *mwid,
131
		    mt->mt_mountinfo, mt->mt_mountpoint);
132
		break;
133
	    }
134
135
	default:
136
		break;
137
	}
138
}
139
140
/*
141
 * Display a mount tree.
142
 */
143
static void
144
show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid,
145
    int *pwid)
146
{
147
	while (mt) {
148
		show_mti(mt, e, mwid, dwid, pwid);
149
		show_mt(mt->mt_next, e, mwid, dwid, pwid);
150
		mt = mt->mt_child;
151
	}
152
}
153
154
static void
155
show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid,
156
    int *dwid, int *twid)
157
{
158
	int i;
159
160
	switch (e) {
161
	case Calc: {
162
		for (i = 0; i < ml->amq_mount_info_list_len; i++) {
163
			amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
164
			int mw = strlen(mi->mi_mountinfo);
165
			int dw = strlen(mi->mi_mountpt);
166
			int tw = strlen(mi->mi_type);
167
168
			if (mw > *mwid)
169
				*mwid = mw;
170
			if (dw > *dwid)
171
				*dwid = dw;
172
			if (tw > *twid)
173
				*twid = tw;
174
		}
175
		break;
176
	    }
177
178
	case Full: {
179
		for (i = 0; i < ml->amq_mount_info_list_len; i++) {
180
			amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
181
			printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
182
			    *mwid, *mwid, mi->mi_mountinfo,
183
			    *dwid, *dwid, mi->mi_mountpt,
184
			    *twid, *twid, mi->mi_type,
185
			    mi->mi_refc, mi->mi_fserver,
186
			    mi->mi_up > 0 ? "up" :
187
			    mi->mi_up < 0 ? "starting" : "down");
188
			if (mi->mi_error > 0) {
189
				printf(" (%s)", strerror(mi->mi_error));
190
			} else if (mi->mi_error < 0) {
191
				fputs(" (in progress)", stdout);
192
			}
193
			fputc('\n', stdout);
194
		}
195
		break;
196
	    }
197
	default:
198
		break;
199
	}
200
}
201
202
/*
203
 * Display general mount statistics
204
 */
205
static void
206
show_ms(amq_mount_stats *ms)
207
{
208
	printf("requests  stale     mount     mount     unmount\n"
209
	    "deferred  fhandles  ok        failed    failed\n"
210
	    "%-9d %-9d %-9d %-9d %-9d\n",
211
	    ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
212
}
213
214
static bool_t
215
xdr_pri_free(xdrproc_t xdr_args, void *args_ptr)
216
{
217
	XDR xdr;
218
219
	xdr.x_op = XDR_FREE;
220
	return ((*xdr_args)(&xdr, args_ptr));
221
}
222
223
/*
224
 * MAIN
225
 */
226
int
227
main(int argc, char *argv[])
228
{
229
	int nodefault = 0, opt_ch, errs = 0, s;
230
	struct sockaddr_in server_addr;
231
	struct hostent *hp;
232
	CLIENT *clnt;
233
	char *server;
234
235
	/*
236
	 * Parse arguments
237
	 */
238
	while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:")) != -1)
239
		switch (opt_ch) {
240
		case 'f':
241
			flush_flag = 1;
242
			nodefault = 1;
243
			break;
244
245
		case 'h':
246
			def_server = optarg;
247
			break;
248
249
		case 'l':
250
			logfile = optarg;
251
			nodefault = 1;
252
			break;
253
254
		case 'm':
255
			minfo_flag = 1;
256
			nodefault = 1;
257
			break;
258
259
		case 's':
260
			stats_flag = 1;
261
			nodefault = 1;
262
			break;
263
264
		case 'u':
265
			unmount_flag = 1;
266
			nodefault = 1;
267
			break;
268
269
		case 'v':
270
			getvers_flag = 1;
271
			nodefault = 1;
272
			break;
273
274
		case 'x':
275
			xlog_optstr = optarg;
276
			nodefault = 1;
277
			break;
278
279
		case 'D':
280
			debug_opts = optarg;
281
			nodefault = 1;
282
			break;
283
284
		default:
285
			errs = 1;
286
			break;
287
		}
288
289
	if (optind == argc) {
290
		if (unmount_flag)
291
			errs = 1;
292
	}
293
294
	if (errs) {
295
show_usage:
296
		fprintf(stderr, "usage: %s [-fmsuv] [-h hostname] "
297
	    "[directory ...]\n", __progname);
298
		exit(1);
299
	}
300
301
	server = def_server;
302
303
	/*
304
	 * Get address of server
305
	 */
306
	if ((hp = gethostbyname(server)) == 0 && strcmp(server, localhost) != 0) {
307
		fprintf(stderr, "%s: Can't get address of %s\n", __progname, server);
308
		exit(1);
309
	}
310
	bzero(&server_addr, sizeof server_addr);
311
	server_addr.sin_family = AF_INET;
312
	if (hp) {
313
		bcopy(hp->h_addr, &server_addr.sin_addr,
314
			sizeof(server_addr.sin_addr));
315
	} else {
316
		/* fake "localhost" */
317
		server_addr.sin_addr.s_addr = htonl(0x7f000001);
318
	}
319
320
	/*
321
	 * Create RPC endpoint
322
	 */
323
	s = privsock(SOCK_STREAM);
324
	clnt = clnttcp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, &s, 0, 0);
325
	if (clnt == 0) {
326
		close(s);
327
		s = privsock(SOCK_DGRAM);
328
		clnt = clntudp_create(&server_addr, AMQ_PROGRAM,
329
		    AMQ_VERSION, TIMEOUT, &s);
330
	}
331
	if (clnt == 0) {
332
		fprintf(stderr, "%s: ", __progname);
333
		clnt_pcreateerror(server);
334
		exit(1);
335
	}
336
337
	/*
338
	 * Control debugging
339
	 */
340
	if (debug_opts) {
341
		int *rc;
342
		amq_setopt opt;
343
		opt.as_opt = AMOPT_DEBUG;
344
		opt.as_str = debug_opts;
345
		rc = amqproc_setopt_57(&opt, clnt);
346
		if (rc && *rc < 0) {
347
			fprintf(stderr,
348
			    "%s: daemon not compiled for debug", __progname);
349
			errs = 1;
350
		} else if (!rc || *rc > 0) {
351
			fprintf(stderr,
352
			    "%s: debug setting for \"%s\" failed\n",
353
			    __progname, debug_opts);
354
			errs = 1;
355
		}
356
	}
357
358
	/*
359
	 * Control logging
360
	 */
361
	if (xlog_optstr) {
362
		int *rc;
363
		amq_setopt opt;
364
		opt.as_opt = AMOPT_XLOG;
365
		opt.as_str = xlog_optstr;
366
		rc = amqproc_setopt_57(&opt, clnt);
367
		if (!rc || *rc) {
368
			fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
369
			    __progname, xlog_optstr);
370
			errs = 1;
371
		}
372
	}
373
374
	/*
375
	 * Control log file
376
	 */
377
	if (logfile) {
378
		int *rc;
379
		amq_setopt opt;
380
		opt.as_opt = AMOPT_LOGFILE;
381
		opt.as_str = logfile;
382
		rc = amqproc_setopt_57(&opt, clnt);
383
		if (!rc || *rc) {
384
			fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
385
			    __progname, logfile);
386
			errs = 1;
387
		}
388
	}
389
390
	/*
391
	 * Flush map cache
392
	 */
393
	if (flush_flag) {
394
		int *rc;
395
		amq_setopt opt;
396
		opt.as_opt = AMOPT_FLUSHMAPC;
397
		opt.as_str = "";
398
		rc = amqproc_setopt_57(&opt, clnt);
399
		if (!rc || *rc) {
400
			fprintf(stderr,
401
			    "%s: amd on %s cannot flush the map cache\n",
402
			    __progname, server);
403
			errs = 1;
404
		}
405
	}
406
407
	/*
408
	 * Mount info
409
	 */
410
	if (minfo_flag) {
411
		int dummy;
412
		amq_mount_info_list *ml = amqproc_getmntfs_57(&dummy, clnt);
413
		if (ml) {
414
			int mwid = 0, dwid = 0, twid = 0;
415
			show_mi(ml, Calc, &mwid, &dwid, &twid);
416
			mwid++; dwid++; twid++;
417
			show_mi(ml, Full, &mwid, &dwid, &twid);
418
		} else {
419
			fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
420
			    __progname, server);
421
		}
422
	}
423
424
	/*
425
	 * Get Version
426
	 */
427
	if (getvers_flag) {
428
		amq_string *spp = amqproc_getvers_57(NULL, clnt);
429
		if (spp && *spp) {
430
			printf("%s.\n", *spp);
431
			free(*spp);
432
		} else {
433
			fprintf(stderr, "%s: failed to get version information\n",
434
			    __progname);
435
			errs = 1;
436
		}
437
	}
438
439
	/*
440
	 * Apply required operation to all remaining arguments
441
	 */
442
	if (optind < argc) {
443
		do {
444
			char *fs = argv[optind++];
445
			if (unmount_flag) {
446
				/*
447
				 * Unmount request
448
				 */
449
				amqproc_umnt_57(&fs, clnt);
450
			} else {
451
				/*
452
				 * Stats request
453
				 */
454
				amq_mount_tree_p *mtp = amqproc_mnttree_57(&fs, clnt);
455
				if (mtp) {
456
					amq_mount_tree *mt = *mtp;
457
					if (mt) {
458
						int mwid = 0, dwid = 0, twid = 0;
459
460
						show_mt(mt, Calc, &mwid, &dwid, &twid);
461
						mwid++;
462
						dwid++;
463
						twid++;
464
465
						printf("%-*.*s Uid   Getattr "
466
						    "Lookup RdDir   RdLnk   "
467
						    "Statfs Mounted@\n",
468
						    dwid, dwid, "What");
469
						show_mt(mt, Stats, &mwid, &dwid, &twid);
470
					} else {
471
						fprintf(stderr,
472
						    "%s: %s not automounted\n",
473
						    __progname, fs);
474
					}
475
					xdr_pri_free(xdr_amq_mount_tree_p, mtp);
476
				} else {
477
					fprintf(stderr, "%s: ", __progname);
478
					clnt_perror(clnt, server);
479
					errs = 1;
480
				}
481
			}
482
		} while (optind < argc);
483
	} else if (unmount_flag) {
484
		goto show_usage;
485
	} else if (stats_flag) {
486
		amq_mount_stats *ms = amqproc_stats_57(NULL, clnt);
487
		if (ms) {
488
			show_ms(ms);
489
		} else {
490
			fprintf(stderr, "%s: ", __progname);
491
			clnt_perror(clnt, server);
492
			errs = 1;
493
		}
494
	} else if (!nodefault) {
495
		amq_mount_tree_list *mlp = amqproc_export_57(NULL, clnt);
496
		if (mlp) {
497
			enum show_opt e = Calc;
498
			int mwid = 0, dwid = 0, pwid = 0;
499
500
			while (e != ShowDone) {
501
				int i;
502
503
				for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
504
					show_mt(mlp->amq_mount_tree_list_val[i],
505
					    e, &mwid, &dwid, &pwid);
506
				}
507
				mwid++;
508
				dwid++;
509
				pwid++;
510
				if (e == Calc)
511
					e = Short;
512
				else if (e == Short)
513
					e = ShowDone;
514
			}
515
		} else {
516
			fprintf(stderr, "%s: ", __progname);
517
			clnt_perror(clnt, server);
518
			errs = 1;
519
		}
520
	}
521
522
	exit(errs);
523
}
524
525
/*
526
 * udpresport creates a datagram socket and attempts to bind it to a
527
 * secure port.
528
 * returns: The bound socket, or -1 to indicate an error.
529
 */
530
static int
531
inetresport(int ty)
532
{
533
	struct sockaddr_in addr;
534
	int alport, sock;
535
536
	/* Use internet address family */
537
	addr.sin_family = AF_INET;
538
	addr.sin_addr.s_addr = INADDR_ANY;
539
	if ((sock = socket(AF_INET, ty, 0)) < 0)
540
		return -1;
541
	for (alport = IPPORT_RESERVED-1; alport > IPPORT_RESERVED/2 + 1; alport--) {
542
		addr.sin_port = htons((u_short)alport);
543
		if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) >= 0)
544
			return sock;
545
		if (errno != EADDRINUSE) {
546
			close(sock);
547
			return -1;
548
		}
549
	}
550
	close(sock);
551
	errno = EAGAIN;
552
	return -1;
553
}
554
555
/*
556
 * Privsock() calls inetresport() to attempt to bind a socket to a secure
557
 * port.  If inetresport() fails, privsock returns a magic socket number which
558
 * indicates to RPC that it should make its own socket.
559
 * returns: A privileged socket # or RPC_ANYSOCK.
560
 */
561
static int
562
privsock(int ty)
563
{
564
	int sock = inetresport(ty);
565
566
	if (sock < 0) {
567
		errno = 0;
568
		/* Couldn't get a secure port, let RPC make an insecure one */
569
		sock = RPC_ANYSOCK;
570
	}
571
	return sock;
572
}