GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amq/amq.c Lines: 0 216 0.0 %
Date: 2016-12-06 Branches: 0 150 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.19 2015/12/11 04:26:01 mmcc 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
}
136
137
/*
138
 * Display a mount tree.
139
 */
140
static void
141
show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid,
142
    int *pwid)
143
{
144
	while (mt) {
145
		show_mti(mt, e, mwid, dwid, pwid);
146
		show_mt(mt->mt_next, e, mwid, dwid, pwid);
147
		mt = mt->mt_child;
148
	}
149
}
150
151
static void
152
show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid,
153
    int *dwid, int *twid)
154
{
155
	int i;
156
157
	switch (e) {
158
	case Calc: {
159
		for (i = 0; i < ml->amq_mount_info_list_len; i++) {
160
			amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
161
			int mw = strlen(mi->mi_mountinfo);
162
			int dw = strlen(mi->mi_mountpt);
163
			int tw = strlen(mi->mi_type);
164
165
			if (mw > *mwid)
166
				*mwid = mw;
167
			if (dw > *dwid)
168
				*dwid = dw;
169
			if (tw > *twid)
170
				*twid = tw;
171
		}
172
		break;
173
	    }
174
175
	case Full: {
176
		for (i = 0; i < ml->amq_mount_info_list_len; i++) {
177
			amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
178
			printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
179
			    *mwid, *mwid, mi->mi_mountinfo,
180
			    *dwid, *dwid, mi->mi_mountpt,
181
			    *twid, *twid, mi->mi_type,
182
			    mi->mi_refc, mi->mi_fserver,
183
			    mi->mi_up > 0 ? "up" :
184
			    mi->mi_up < 0 ? "starting" : "down");
185
			if (mi->mi_error > 0) {
186
				printf(" (%s)", strerror(mi->mi_error));
187
			} else if (mi->mi_error < 0) {
188
				fputs(" (in progress)", stdout);
189
			}
190
			fputc('\n', stdout);
191
		}
192
		break;
193
	    }
194
	}
195
}
196
197
/*
198
 * Display general mount statistics
199
 */
200
static void
201
show_ms(amq_mount_stats *ms)
202
{
203
	printf("requests  stale     mount     mount     unmount\n"
204
	    "deferred  fhandles  ok        failed    failed\n"
205
	    "%-9d %-9d %-9d %-9d %-9d\n",
206
	    ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
207
}
208
209
static bool_t
210
xdr_pri_free(xdrproc_t xdr_args, void *args_ptr)
211
{
212
	XDR xdr;
213
214
	xdr.x_op = XDR_FREE;
215
	return ((*xdr_args)(&xdr, args_ptr));
216
}
217
218
/*
219
 * MAIN
220
 */
221
int
222
main(int argc, char *argv[])
223
{
224
	int nodefault = 0, opt_ch, errs = 0, s;
225
	struct sockaddr_in server_addr;
226
	struct hostent *hp;
227
	CLIENT *clnt;
228
	char *server;
229
230
	/*
231
	 * Parse arguments
232
	 */
233
	while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:")) != -1)
234
		switch (opt_ch) {
235
		case 'f':
236
			flush_flag = 1;
237
			nodefault = 1;
238
			break;
239
240
		case 'h':
241
			def_server = optarg;
242
			break;
243
244
		case 'l':
245
			logfile = optarg;
246
			nodefault = 1;
247
			break;
248
249
		case 'm':
250
			minfo_flag = 1;
251
			nodefault = 1;
252
			break;
253
254
		case 's':
255
			stats_flag = 1;
256
			nodefault = 1;
257
			break;
258
259
		case 'u':
260
			unmount_flag = 1;
261
			nodefault = 1;
262
			break;
263
264
		case 'v':
265
			getvers_flag = 1;
266
			nodefault = 1;
267
			break;
268
269
		case 'x':
270
			xlog_optstr = optarg;
271
			nodefault = 1;
272
			break;
273
274
		case 'D':
275
			debug_opts = optarg;
276
			nodefault = 1;
277
			break;
278
279
		default:
280
			errs = 1;
281
			break;
282
		}
283
284
	if (optind == argc) {
285
		if (unmount_flag)
286
			errs = 1;
287
	}
288
289
	if (errs) {
290
show_usage:
291
		fprintf(stderr, "usage: %s [-fmsuv] [-h hostname] "
292
		    "[directory ...]\n", __progname);
293
		exit(1);
294
	}
295
296
	server = def_server;
297
298
	/*
299
	 * Get address of server
300
	 */
301
	if ((hp = gethostbyname(server)) == 0 && strcmp(server, localhost) != 0) {
302
		fprintf(stderr, "%s: Can't get address of %s\n", __progname, server);
303
		exit(1);
304
	}
305
	bzero(&server_addr, sizeof server_addr);
306
	server_addr.sin_family = AF_INET;
307
	if (hp) {
308
		bcopy(hp->h_addr, &server_addr.sin_addr,
309
			sizeof(server_addr.sin_addr));
310
	} else {
311
		/* fake "localhost" */
312
		server_addr.sin_addr.s_addr = htonl(0x7f000001);
313
	}
314
315
	/*
316
	 * Create RPC endpoint
317
	 */
318
	s = privsock(SOCK_STREAM);
319
	clnt = clnttcp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, &s, 0, 0);
320
	if (clnt == 0) {
321
		close(s);
322
		s = privsock(SOCK_DGRAM);
323
		clnt = clntudp_create(&server_addr, AMQ_PROGRAM,
324
		    AMQ_VERSION, TIMEOUT, &s);
325
	}
326
	if (clnt == 0) {
327
		fprintf(stderr, "%s: ", __progname);
328
		clnt_pcreateerror(server);
329
		exit(1);
330
	}
331
332
	/*
333
	 * Control debugging
334
	 */
335
	if (debug_opts) {
336
		int *rc;
337
		amq_setopt opt;
338
		opt.as_opt = AMOPT_DEBUG;
339
		opt.as_str = debug_opts;
340
		rc = amqproc_setopt_57(&opt, clnt);
341
		if (rc && *rc < 0) {
342
			fprintf(stderr,
343
			    "%s: daemon not compiled for debug", __progname);
344
			errs = 1;
345
		} else if (!rc || *rc > 0) {
346
			fprintf(stderr,
347
			    "%s: debug setting for \"%s\" failed\n",
348
			    __progname, debug_opts);
349
			errs = 1;
350
		}
351
	}
352
353
	/*
354
	 * Control logging
355
	 */
356
	if (xlog_optstr) {
357
		int *rc;
358
		amq_setopt opt;
359
		opt.as_opt = AMOPT_XLOG;
360
		opt.as_str = xlog_optstr;
361
		rc = amqproc_setopt_57(&opt, clnt);
362
		if (!rc || *rc) {
363
			fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
364
			    __progname, xlog_optstr);
365
			errs = 1;
366
		}
367
	}
368
369
	/*
370
	 * Control log file
371
	 */
372
	if (logfile) {
373
		int *rc;
374
		amq_setopt opt;
375
		opt.as_opt = AMOPT_LOGFILE;
376
		opt.as_str = logfile;
377
		rc = amqproc_setopt_57(&opt, clnt);
378
		if (!rc || *rc) {
379
			fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
380
			    __progname, logfile);
381
			errs = 1;
382
		}
383
	}
384
385
	/*
386
	 * Flush map cache
387
	 */
388
	if (flush_flag) {
389
		int *rc;
390
		amq_setopt opt;
391
		opt.as_opt = AMOPT_FLUSHMAPC;
392
		opt.as_str = "";
393
		rc = amqproc_setopt_57(&opt, clnt);
394
		if (!rc || *rc) {
395
			fprintf(stderr,
396
			    "%s: amd on %s cannot flush the map cache\n",
397
			    __progname, server);
398
			errs = 1;
399
		}
400
	}
401
402
	/*
403
	 * Mount info
404
	 */
405
	if (minfo_flag) {
406
		int dummy;
407
		amq_mount_info_list *ml = amqproc_getmntfs_57(&dummy, clnt);
408
		if (ml) {
409
			int mwid = 0, dwid = 0, twid = 0;
410
			show_mi(ml, Calc, &mwid, &dwid, &twid);
411
			mwid++; dwid++; twid++;
412
			show_mi(ml, Full, &mwid, &dwid, &twid);
413
		} else {
414
			fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
415
			    __progname, server);
416
		}
417
	}
418
419
	/*
420
	 * Get Version
421
	 */
422
	if (getvers_flag) {
423
		amq_string *spp = amqproc_getvers_57(NULL, clnt);
424
		if (spp && *spp) {
425
			printf("%s.\n", *spp);
426
			free(*spp);
427
		} else {
428
			fprintf(stderr, "%s: failed to get version information\n",
429
			    __progname);
430
			errs = 1;
431
		}
432
	}
433
434
	/*
435
	 * Apply required operation to all remaining arguments
436
	 */
437
	if (optind < argc) {
438
		do {
439
			char *fs = argv[optind++];
440
			if (unmount_flag) {
441
				/*
442
				 * Unmount request
443
				 */
444
				amqproc_umnt_57(&fs, clnt);
445
			} else {
446
				/*
447
				 * Stats request
448
				 */
449
				amq_mount_tree_p *mtp = amqproc_mnttree_57(&fs, clnt);
450
				if (mtp) {
451
					amq_mount_tree *mt = *mtp;
452
					if (mt) {
453
						int mwid = 0, dwid = 0, twid = 0;
454
455
						show_mt(mt, Calc, &mwid, &dwid, &twid);
456
						mwid++;
457
						dwid++;
458
						twid++;
459
460
						printf("%-*.*s Uid   Getattr "
461
						    "Lookup RdDir   RdLnk   "
462
						    "Statfs Mounted@\n",
463
						    dwid, dwid, "What");
464
						show_mt(mt, Stats, &mwid, &dwid, &twid);
465
					} else {
466
						fprintf(stderr,
467
						    "%s: %s not automounted\n",
468
						    __progname, fs);
469
					}
470
					xdr_pri_free(xdr_amq_mount_tree_p, mtp);
471
				} else {
472
					fprintf(stderr, "%s: ", __progname);
473
					clnt_perror(clnt, server);
474
					errs = 1;
475
				}
476
			}
477
		} while (optind < argc);
478
	} else if (unmount_flag) {
479
		goto show_usage;
480
	} else if (stats_flag) {
481
		amq_mount_stats *ms = amqproc_stats_57(NULL, clnt);
482
		if (ms) {
483
			show_ms(ms);
484
		} else {
485
			fprintf(stderr, "%s: ", __progname);
486
			clnt_perror(clnt, server);
487
			errs = 1;
488
		}
489
	} else if (!nodefault) {
490
		amq_mount_tree_list *mlp = amqproc_export_57(NULL, clnt);
491
		if (mlp) {
492
			enum show_opt e = Calc;
493
			int mwid = 0, dwid = 0, pwid = 0;
494
495
			while (e != ShowDone) {
496
				int i;
497
498
				for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
499
					show_mt(mlp->amq_mount_tree_list_val[i],
500
					    e, &mwid, &dwid, &pwid);
501
				}
502
				mwid++;
503
				dwid++;
504
				pwid++;
505
				if (e == Calc)
506
					e = Short;
507
				else if (e == Short)
508
					e = ShowDone;
509
			}
510
		} else {
511
			fprintf(stderr, "%s: ", __progname);
512
			clnt_perror(clnt, server);
513
			errs = 1;
514
		}
515
	}
516
517
	exit(errs);
518
}
519
520
/*
521
 * udpresport creates a datagram socket and attempts to bind it to a
522
 * secure port.
523
 * returns: The bound socket, or -1 to indicate an error.
524
 */
525
static int
526
inetresport(int ty)
527
{
528
	struct sockaddr_in addr;
529
	int alport, sock;
530
531
	/* Use internet address family */
532
	addr.sin_family = AF_INET;
533
	addr.sin_addr.s_addr = INADDR_ANY;
534
	if ((sock = socket(AF_INET, ty, 0)) < 0)
535
		return -1;
536
	for (alport = IPPORT_RESERVED-1; alport > IPPORT_RESERVED/2 + 1; alport--) {
537
		addr.sin_port = htons((u_short)alport);
538
		if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) >= 0)
539
			return sock;
540
		if (errno != EADDRINUSE) {
541
			close(sock);
542
			return -1;
543
		}
544
	}
545
	close(sock);
546
	errno = EAGAIN;
547
	return -1;
548
}
549
550
/*
551
 * Privsock() calls inetresport() to attempt to bind a socket to a secure
552
 * port.  If inetresport() fails, privsock returns a magic socket number which
553
 * indicates to RPC that it should make its own socket.
554
 * returns: A privileged socket # or RPC_ANYSOCK.
555
 */
556
static int
557
privsock(int ty)
558
{
559
	int sock = inetresport(ty);
560
561
	if (sock < 0) {
562
		errno = 0;
563
		/* Couldn't get a secure port, let RPC make an insecure one */
564
		sock = RPC_ANYSOCK;
565
	}
566
	return sock;
567
}