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