xref: /original-bsd/usr.sbin/amd/amq/amq.c (revision cde495fc)
1 /*
2  * $Id: amq.c,v 5.2.1.3 91/03/17 17:33:42 jsp Alpha $
3  *
4  * Copyright (c) 1990 Jan-Simon Pendry
5  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Jan-Simon Pendry at Imperial College, London.
11  *
12  * %sccs.include.redist.c%
13  */
14 
15 /*
16  * Automounter query tool
17  */
18 
19 #ifndef lint
20 char copyright[] = "\
21 @(#)Copyright (c) 1990 Jan-Simon Pendry\n\
22 @(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
23 @(#)Copyright (c) 1990 The Regents of the University of California.\n\
24 @(#)All rights reserved.\n";
25 #endif /* not lint */
26 
27 #ifndef lint
28 static char rcsid[] = "$Id: amq.c,v 5.2.1.3 91/03/17 17:33:42 jsp Alpha $";
29 static char sccsid[] = "@(#)amq.c	5.2 (Berkeley) 03/17/91";
30 #endif /* not lint */
31 
32 #include "am.h"
33 #include "amq.h"
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <netdb.h>
37 
38 static int privsock();
39 
40 char *progname;
41 static int flush_flag;
42 static int minfo_flag;
43 static int unmount_flag;
44 static int stats_flag;
45 static int getvers_flag;
46 static char *debug_opts;
47 static char *logfile;
48 static char *mount_map;
49 static char *xlog_optstr;
50 static char localhost[] = "localhost";
51 static char *def_server = localhost;
52 
53 extern int optind;
54 extern char *optarg;
55 
56 static struct timeval tmo = { 10, 0 };
57 #define	TIMEOUT tmo
58 
59 enum show_opt { Full, Stats, Calc, Short, ShowDone };
60 
61 /*
62  * If (e) is Calc then just calculate the sizes
63  * Otherwise display the mount node on stdout
64  */
65 static void show_mti(mt, e, mwid, dwid, twid)
66 amq_mount_tree *mt;
67 enum show_opt e;
68 int *mwid;
69 int *dwid;
70 int *twid;
71 {
72 	switch (e) {
73 	case Calc: {
74 		int mw = strlen(mt->mt_mountinfo);
75 		int dw = strlen(mt->mt_directory);
76 		int tw = strlen(mt->mt_type);
77 		if (mw > *mwid) *mwid = mw;
78 		if (dw > *dwid) *dwid = dw;
79 		if (tw > *twid) *twid = tw;
80 	} break;
81 
82 	case Full: {
83 		struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
84 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
85 			*dwid, *dwid,
86 			*mt->mt_directory ? mt->mt_directory : "/",	/* XXX */
87 			*twid, *twid,
88 			mt->mt_type,
89 			*mwid, *mwid,
90 			mt->mt_mountinfo,
91 			mt->mt_mountpoint,
92 
93 			mt->mt_mountuid,
94 			mt->mt_getattr,
95 			mt->mt_lookup,
96 			mt->mt_readdir,
97 			mt->mt_readlink,
98 			mt->mt_statfs,
99 
100 			tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
101 			tp->tm_mon+1, tp->tm_mday,
102 			tp->tm_hour, tp->tm_min, tp->tm_sec);
103 	} break;
104 
105 	case Stats: {
106 		struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
107 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
108 			*dwid, *dwid,
109 			*mt->mt_directory ? mt->mt_directory : "/",	/* XXX */
110 
111 			mt->mt_mountuid,
112 			mt->mt_getattr,
113 			mt->mt_lookup,
114 			mt->mt_readdir,
115 			mt->mt_readlink,
116 			mt->mt_statfs,
117 
118 			tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
119 			tp->tm_mon+1, tp->tm_mday,
120 			tp->tm_hour, tp->tm_min, tp->tm_sec);
121 	} break;
122 
123 	case Short: {
124 		printf("%-*.*s %-*.*s %-*.*s %s\n",
125 			*dwid, *dwid,
126 			*mt->mt_directory ? mt->mt_directory : "/",
127 			*twid, *twid,
128 			mt->mt_type,
129 			*mwid, *mwid,
130 			mt->mt_mountinfo,
131 			mt->mt_mountpoint);
132 	} break;
133 	}
134 }
135 
136 /*
137  * Display a mount tree.
138  */
139 static void show_mt(mt, e, mwid, dwid, pwid)
140 amq_mount_tree *mt;
141 enum show_opt e;
142 int *mwid;
143 int *dwid;
144 int *pwid;
145 {
146 	while (mt) {
147 		show_mti(mt, e, mwid, dwid, pwid);
148 		show_mt(mt->mt_next, e, mwid, dwid, pwid);
149 		mt = mt->mt_child;
150 	}
151 }
152 
153 static void show_mi(ml, e, mwid, dwid, twid)
154 amq_mount_info_list *ml;
155 enum show_opt e;
156 int *mwid;
157 int *dwid;
158 int *twid;
159 {
160 	int i;
161 	switch (e) {
162 	case Calc: {
163 		for (i = 0; i < ml->amq_mount_info_list_len; i++) {
164 			amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
165 			int mw = strlen(mi->mi_mountinfo);
166 			int dw = strlen(mi->mi_mountpt);
167 			int tw = strlen(mi->mi_type);
168 			if (mw > *mwid) *mwid = mw;
169 			if (dw > *dwid) *dwid = dw;
170 			if (tw > *twid) *twid = tw;
171 		}
172 	} break;
173 
174 	case Full: {
175 		for (i = 0; i < ml->amq_mount_info_list_len; i++) {
176 			amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
177 			printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
178 						*mwid, *mwid, mi->mi_mountinfo,
179 						*dwid, *dwid, mi->mi_mountpt,
180 						*twid, *twid, mi->mi_type,
181 						mi->mi_refc, mi->mi_fserver,
182 						mi->mi_up > 0 ? "up" :
183 						mi->mi_up < 0 ? "starting" : "down");
184 			if (mi->mi_error > 0) {
185 				extern char *sys_errlist[];
186 				extern int sys_nerr;
187 				if (mi->mi_error < sys_nerr)
188 					printf(" (%s)", sys_errlist[mi->mi_error]);
189 				else
190 					printf(" (Error %d)", mi->mi_error);
191 			} else if (mi->mi_error < 0) {
192 				fputs(" (in progress)", stdout);
193 			}
194 			fputc('\n', stdout);
195 		}
196 	} break;
197 	}
198 }
199 
200 /*
201  * Display general mount statistics
202  */
203 static void show_ms(ms)
204 amq_mount_stats *ms;
205 {
206 	printf("\
207 requests  stale     mount     mount     unmount\n\
208 deferred  fhandles  ok        failed    failed\n\
209 %-9d %-9d %-9d %-9d %-9d\n",
210 	ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
211 }
212 
213 static bool_t
214 xdr_pri_free(xdr_args, args_ptr)
215 xdrproc_t xdr_args;
216 caddr_t args_ptr;
217 {
218 	XDR xdr;
219 	xdr.x_op = XDR_FREE;
220 	return ((*xdr_args)(&xdr, args_ptr));
221 }
222 
223 #ifdef hpux
224 #include <cluster.h>
225 static char *cluster_server()
226 {
227 	struct cct_entry *cp;
228 
229 	if (cnodeid() == 0) {
230 		/*
231 		 * Not clustered
232 		 */
233 		return def_server;
234 	}
235 
236 	while (cp = getccent())
237 		if (cp->cnode_type == 'r')
238 			return cp->cnode_name;
239 
240 
241 	return def_server;
242 }
243 #endif /* hpux */
244 
245 /*
246  * MAIN
247  */
248 main(argc, argv)
249 int argc;
250 char *argv[];
251 {
252 	int opt_ch;
253 	int errs = 0;
254 	char *server;
255 	struct sockaddr_in server_addr;
256 
257 	/* In order to pass the Amd security check, we must use a priv port. */
258 	int s;
259 
260 	CLIENT *clnt;
261 	struct hostent *hp;
262 	int nodefault = 0;
263 
264 	/*
265 	 * Compute program name
266 	 */
267 	if (argv[0]) {
268 		progname = strrchr(argv[0], '/');
269 		if (progname && progname[1])
270 			progname++;
271 		else
272 			progname = argv[0];
273 	}
274 	if (!progname)
275 		progname = "amq";
276 
277 	/*
278 	 * Parse arguments
279 	 */
280 	while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:")) != EOF)
281 	switch (opt_ch) {
282 	case 'f':
283 		flush_flag = 1;
284 		nodefault = 1;
285 		break;
286 
287 	case 'h':
288 		def_server = optarg;
289 		break;
290 
291 	case 'l':
292 		logfile = optarg;
293 		nodefault = 1;
294 		break;
295 
296 	case 'm':
297 		minfo_flag = 1;
298 		nodefault = 1;
299 		break;
300 
301 	case 's':
302 		stats_flag = 1;
303 		nodefault = 1;
304 		break;
305 
306 	case 'u':
307 		unmount_flag = 1;
308 		nodefault = 1;
309 		break;
310 
311 	case 'v':
312 		getvers_flag = 1;
313 		nodefault = 1;
314 		break;
315 
316 	case 'x':
317 		xlog_optstr = optarg;
318 		nodefault = 1;
319 		break;
320 
321 	case 'D':
322 		debug_opts = optarg;
323 		nodefault = 1;
324 		break;
325 
326 	case 'M':
327 		mount_map = optarg;
328 		nodefault = 1;
329 		break;
330 
331 	default:
332 		errs = 1;
333 		break;
334 	}
335 
336 	if (optind == argc) {
337 		if (unmount_flag)
338 			errs = 1;
339 	}
340 
341 	if (errs) {
342 show_usage:
343 		fprintf(stderr, "\
344 Usage: %s [-h host] [[-f] [-m] [-v] [-s]] | [[-u] directory ...]] |\n\
345 \t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n", progname);
346 		exit(1);
347 	}
348 
349 #ifdef hpux
350 	/*
351 	 * Figure out root server of cluster
352 	 */
353 	if (def_server == localhost)
354 		server = cluster_server();
355 	else
356 #endif /* hpux */
357 	server = def_server;
358 
359 	/*
360 	 * Get address of server
361 	 */
362 	if ((hp = gethostbyname(server)) == 0) {
363 		fprintf(stderr, "%s: Can't get address of %s\n", progname, server);
364 		exit(1);
365 	}
366 	bzero(&server_addr, sizeof server_addr);
367 	server_addr.sin_family = AF_INET;
368 	bcopy((voidp) hp->h_addr, (voidp) &server_addr.sin_addr, sizeof(server_addr.sin_addr));
369 
370 	/*
371 	 * Create RPC endpoint
372 	 */
373 	s = privsock();
374 	clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, TIMEOUT, &s);
375 	if (clnt == 0) {
376 		fprintf(stderr, "%s: ", progname);
377 		clnt_pcreateerror(server);
378 		exit(1);
379 	}
380 
381 	/*
382 	 * Control debugging
383 	 */
384 	if (debug_opts) {
385 		int *rc;
386 		amq_setopt opt;
387 		opt.as_opt = AMOPT_DEBUG;
388 		opt.as_str = debug_opts;
389 		rc = amqproc_setopt_1(&opt, clnt);
390 		if (rc && *rc < 0) {
391 			fprintf(stderr, "%s: daemon not compiled for debug", progname);
392 			errs = 1;
393 		} else if (!rc || *rc > 0) {
394 			fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts);
395 			errs = 1;
396 		}
397 	}
398 
399 	/*
400 	 * Control logging
401 	 */
402 	if (xlog_optstr) {
403 		int *rc;
404 		amq_setopt opt;
405 		opt.as_opt = AMOPT_XLOG;
406 		opt.as_str = xlog_optstr;
407 		rc = amqproc_setopt_1(&opt, clnt);
408 		if (!rc || *rc) {
409 			fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr);
410 			errs = 1;
411 		}
412 	}
413 
414 	/*
415 	 * Control log file
416 	 */
417 	if (logfile) {
418 		int *rc;
419 		amq_setopt opt;
420 		opt.as_opt = AMOPT_LOGFILE;
421 		opt.as_str = logfile;
422 		rc = amqproc_setopt_1(&opt, clnt);
423 		if (!rc || *rc) {
424 			fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, logfile);
425 			errs = 1;
426 		}
427 	}
428 
429 	/*
430 	 * Flush map cache
431 	 */
432 	if (flush_flag) {
433 		int *rc;
434 		amq_setopt opt;
435 		opt.as_opt = AMOPT_FLUSHMAPC;
436 		opt.as_str = "";
437 		rc = amqproc_setopt_1(&opt, clnt);
438 		if (!rc || *rc) {
439 			fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server);
440 			errs = 1;
441 		}
442 	}
443 
444 	/*
445 	 * Mount info
446 	 */
447 	if (minfo_flag) {
448 		int dummy;
449 		amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
450 		if (ml) {
451 			int mwid = 0, dwid = 0, twid = 0;
452 			show_mi(ml, Calc, &mwid, &dwid, &twid);
453 			mwid++; dwid++; twid++;
454 			show_mi(ml, Full, &mwid, &dwid, &twid);
455 
456 		} else {
457 			fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server);
458 		}
459 	}
460 
461 	/*
462 	 * Mount map
463 	 */
464 	if (mount_map) {
465 		int *rc;
466 		do {
467 			rc = amqproc_mount_1(&mount_map, clnt);
468 		} while (rc && *rc < 0);
469 		if (!rc || *rc > 0) {
470 			if (rc)
471 				errno = *rc;
472 			else
473 				errno = ETIMEDOUT;
474 			fprintf(stderr, "%s: could not start new ", progname);
475 			perror("autmount point");
476 		}
477 	}
478 
479 	/*
480 	 * Get Version
481 	 */
482 	if (getvers_flag) {
483 		amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
484 		if (spp && *spp) {
485 			printf("%s.\n", *spp);
486 			free(*spp);
487 		} else {
488 			fprintf(stderr, "%s: failed to get version infromation\n", progname);
489 			errs = 1;
490 		}
491 	}
492 
493 	/*
494 	 * Apply required operation to all remaining arguments
495 	 */
496 	if (optind < argc) {
497 		do {
498 			char *fs = argv[optind++];
499 			if (unmount_flag) {
500 				/*
501 				 * Unmount request
502 				 */
503 				amqproc_umnt_1(&fs, clnt);
504 			} else {
505 				/*
506 				 * Stats request
507 				 */
508 				amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
509 				if (mtp) {
510 					amq_mount_tree *mt = *mtp;
511 					if (mt) {
512 						int mwid = 0, dwid = 0, twid = 0;
513 						show_mt(mt, Calc, &mwid, &dwid, &twid);
514 						mwid++; dwid++, twid++;
515 		printf("%-*.*s Uid   Getattr Lookup RdDir   RdLnk   Statfs Mounted@\n",
516 			dwid, dwid, "What");
517 						show_mt(mt, Stats, &mwid, &dwid, &twid);
518 					} else {
519 						fprintf(stderr, "%s: %s not automounted\n", progname, fs);
520 					}
521 					xdr_pri_free(xdr_amq_mount_tree_p, (caddr_t) mtp);
522 				} else {
523 					fprintf(stderr, "%s: ", progname);
524 					clnt_perror(clnt, server);
525 					errs = 1;
526 				}
527 			}
528 		} while (optind < argc);
529 	} else if (unmount_flag) {
530 		goto show_usage;
531 	} else if (stats_flag) {
532 		amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
533 		if (ms) {
534 			show_ms(ms);
535 		} else {
536 			fprintf(stderr, "%s: ", progname);
537 			clnt_perror(clnt, server);
538 			errs = 1;
539 		}
540 	} else if (!nodefault) {
541 		amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
542 		if (mlp) {
543 			enum show_opt e = Calc;
544 			int mwid = 0, dwid = 0, pwid = 0;
545 			while (e != ShowDone) {
546 				int i;
547 				for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
548 					show_mt(mlp->amq_mount_tree_list_val[i],
549 						 e, &mwid, &dwid, &pwid);
550 				}
551 				mwid++; dwid++, pwid++;
552 				if (e == Calc) e = Short;
553 				else if (e == Short) e = ShowDone;
554 			}
555 		} else {
556 			fprintf(stderr, "%s: ", progname);
557 			clnt_perror(clnt, server);
558 			errs = 1;
559 		}
560 	}
561 
562 	exit(errs);
563 }
564 
565 /*
566  * udpresport creates a datagram socket and attempts to bind it to a
567  * secure port.
568  * returns: The bound socket, or -1 to indicate an error.
569  */
570 static int udpresport()
571 {
572 	int alport;
573 	struct sockaddr_in addr;
574 	int sock;
575 
576 	/* Use internet address family */
577 	addr.sin_family = AF_INET;
578 	addr.sin_addr.s_addr = INADDR_ANY;
579 	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
580 		return -1;
581 	for (alport = IPPORT_RESERVED-1; alport > IPPORT_RESERVED/2 + 1; alport--) {
582 		addr.sin_port = htons((u_short)alport);
583 		if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) >= 0)
584 			return sock;
585 		if (errno != EADDRINUSE) {
586 			close(sock);
587 			return -1;
588 		}
589 	}
590 	close(sock);
591 	errno = EAGAIN;
592 	return -1;
593 }
594 
595 /*
596  * Privsock() calls udpresport() to attempt to bind a socket to a secure
597  * port.  If udpresport() fails, privsock returns a magic socket number which
598  * indicates to RPC that it should make its own socket.
599  * returns: A privileged socket # or RPC_ANYSOCK.
600  */
601 static int privsock()
602 {
603 	int sock = udpresport();
604 
605 	if (sock < 0) {
606 		errno = 0;
607 		/* Couldn't get a secure port, let RPC make an insecure one */
608 		sock = RPC_ANYSOCK;
609 	}
610 	return sock;
611 }
612 
613 #ifdef DEBUG
614 xfree(f, l, p)
615 char *f, *l;
616 voidp p;
617 {
618 	free(p);
619 }
620 #endif /* DEBUG */
621