1 /*
2 * Copyright (c) 1997-2006 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *
40 * File: am-utils/amq/amq.c
41 *
42 */
43
44 /*
45 * Automounter query tool
46 */
47
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif /* HAVE_CONFIG_H */
51 #include <am_defs.h>
52 #include <amq.h>
53
54 /* locals */
55 static int flush_flag;
56 static int minfo_flag;
57 static int getpid_flag;
58 static int unmount_flag;
59 static int stats_flag;
60 static int getvers_flag;
61 static int amd_program_number = AMQ_PROGRAM;
62 static int use_tcp_flag, use_udp_flag;
63 static int getpwd_flag;
64 static char *debug_opts;
65 static char *amq_logfile;
66 static char *xlog_optstr;
67 static char localhost[] = "localhost";
68 static char *def_server = localhost;
69
70 /* externals */
71 extern int optind;
72 extern char *optarg;
73
74 /* structures */
75 enum show_opt {
76 Full, Stats, Calc, Short, ShowDone
77 };
78
79
80 /*
81 * If (e) is Calc then just calculate the sizes
82 * Otherwise display the mount node on stdout
83 */
84 static void
show_mti(amq_mount_tree * mt,enum show_opt e,int * mwid,int * dwid,int * twid)85 show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
86 {
87 switch (e) {
88 case Calc:
89 {
90 int mw = strlen(mt->mt_mountinfo);
91 int dw = strlen(mt->mt_directory);
92 int tw = strlen(mt->mt_type);
93 if (mw > *mwid)
94 *mwid = mw;
95 if (dw > *dwid)
96 *dwid = dw;
97 if (tw > *twid)
98 *twid = tw;
99 }
100 break;
101
102 case Full:
103 {
104 struct tm *tp = localtime((time_t *) ((voidp) &mt->mt_mounttime));
105 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%04d %02d:%02d:%02d\n",
106 *dwid, *dwid,
107 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
108 *twid, *twid,
109 mt->mt_type,
110 *mwid, *mwid,
111 mt->mt_mountinfo,
112 mt->mt_mountpoint,
113
114 mt->mt_mountuid,
115 mt->mt_getattr,
116 mt->mt_lookup,
117 mt->mt_readdir,
118 mt->mt_readlink,
119 mt->mt_statfs,
120
121 tp->tm_mon + 1, tp->tm_mday,
122 tp->tm_year < 1900 ? tp->tm_year + 1900 : tp->tm_year,
123 tp->tm_hour, tp->tm_min, tp->tm_sec);
124 }
125 break;
126
127 case Stats:
128 {
129 struct tm *tp = localtime((time_t *) ((voidp) &mt->mt_mounttime));
130 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%04d\n",
131 *dwid, *dwid,
132 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
133
134 mt->mt_mountuid,
135 mt->mt_getattr,
136 mt->mt_lookup,
137 mt->mt_readdir,
138 mt->mt_readlink,
139 mt->mt_statfs,
140
141 tp->tm_mon + 1, tp->tm_mday,
142 tp->tm_year < 1900 ? tp->tm_year + 1900 : tp->tm_year,
143 tp->tm_hour, tp->tm_min, tp->tm_sec);
144 }
145 break;
146
147 case Short:
148 {
149 printf("%-*.*s %-*.*s %-*.*s %s\n",
150 *dwid, *dwid,
151 *mt->mt_directory ? mt->mt_directory : "/",
152 *twid, *twid,
153 mt->mt_type,
154 *mwid, *mwid,
155 mt->mt_mountinfo,
156 mt->mt_mountpoint);
157 }
158 break;
159
160 default:
161 break;
162 }
163 }
164
165
166 /*
167 * Display a pwd data
168 */
169 static void
show_pwd(amq_mount_tree * mt,char * path,size_t l,int * flag)170 show_pwd(amq_mount_tree *mt, char *path, size_t l, int *flag)
171 {
172 int len;
173
174 while (mt) {
175 len = strlen(mt->mt_mountpoint);
176 if (NSTREQ(path, mt->mt_mountpoint, len) &&
177 !STREQ(mt->mt_directory, mt->mt_mountpoint)) {
178 char buf[MAXPATHLEN+1]; /* must be same size as 'path' */
179 xstrlcpy(buf, mt->mt_directory, sizeof(buf));
180 xstrlcat(buf, &path[len], sizeof(buf));
181 xstrlcpy(path, buf, l);
182 *flag = 1;
183 }
184 show_pwd(mt->mt_next, path, l, flag);
185 mt = mt->mt_child;
186 }
187 }
188
189
190 /*
191 * Display a mount tree.
192 */
193 static void
show_mt(amq_mount_tree * mt,enum show_opt e,int * mwid,int * dwid,int * pwid)194 show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
195 {
196 while (mt) {
197 show_mti(mt, e, mwid, dwid, pwid);
198 show_mt(mt->mt_next, e, mwid, dwid, pwid);
199 mt = mt->mt_child;
200 }
201 }
202
203
204 static void
show_mi(amq_mount_info_list * ml,enum show_opt e,int * mwid,int * dwid,int * twid)205 show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
206 {
207 u_int i;
208
209 switch (e) {
210
211 case Calc:
212 {
213 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
214 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
215 int mw = strlen(mi->mi_mountinfo);
216 int dw = strlen(mi->mi_mountpt);
217 int tw = strlen(mi->mi_type);
218 if (mw > *mwid)
219 *mwid = mw;
220 if (dw > *dwid)
221 *dwid = dw;
222 if (tw > *twid)
223 *twid = tw;
224 }
225 }
226 break;
227
228 case Full:
229 {
230 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
231 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
232 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
233 *mwid, *mwid, mi->mi_mountinfo,
234 *dwid, *dwid, mi->mi_mountpt,
235 *twid, *twid, mi->mi_type,
236 mi->mi_refc, mi->mi_fserver,
237 mi->mi_up > 0 ? "up" :
238 mi->mi_up < 0 ? "starting" : "down");
239 if (mi->mi_error > 0) {
240 printf(" (%s)", strerror(mi->mi_error));
241 } else if (mi->mi_error < 0) {
242 fputs(" (in progress)", stdout);
243 }
244 fputc('\n', stdout);
245 }
246 }
247 break;
248
249 default:
250 break;
251 }
252 }
253
254
255 /*
256 * Display general mount statistics
257 */
258 static void
show_ms(amq_mount_stats * ms)259 show_ms(amq_mount_stats *ms)
260 {
261 printf("\
262 requests stale mount mount unmount\n\
263 deferred fhandles ok failed failed\n\
264 %-9d %-9d %-9d %-9d %-9d\n",
265 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
266 }
267
268
269 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
270 static char *
cluster_server(void)271 cluster_server(void)
272 {
273 struct cct_entry *cp;
274
275 if (cnodeid() == 0) {
276 /*
277 * Not clustered
278 */
279 return def_server;
280 }
281 while (cp = getccent())
282 if (cp->cnode_type == 'r')
283 return cp->cnode_name;
284
285 return def_server;
286 }
287 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
288
289
290 /*
291 * MAIN
292 */
293 int
main(int argc,char * argv[])294 main(int argc, char *argv[])
295 {
296 int opt_ch;
297 int errs = 0;
298 char *server;
299 struct sockaddr_in server_addr;
300 CLIENT *clnt = NULL;
301 struct hostent *hp;
302 int nodefault = 0;
303 struct timeval tv;
304 char *progname = NULL;
305
306 /*
307 * Compute program name
308 */
309 if (argv[0]) {
310 progname = strrchr(argv[0], '/');
311 if (progname && progname[1])
312 progname++;
313 else
314 progname = argv[0];
315 }
316 if (!progname)
317 progname = "amq";
318 am_set_progname(progname);
319
320 /*
321 * Parse arguments
322 */
323 while ((opt_ch = getopt(argc, argv, "Hfh:l:msuvx:D:pP:TUw")) != -1)
324 switch (opt_ch) {
325 case 'H':
326 goto show_usage;
327 break;
328
329 case 'f':
330 flush_flag = 1;
331 nodefault = 1;
332 break;
333
334 case 'h':
335 def_server = optarg;
336 break;
337
338 case 'l':
339 amq_logfile = optarg;
340 nodefault = 1;
341 break;
342
343 case 'm':
344 minfo_flag = 1;
345 nodefault = 1;
346 break;
347
348 case 'p':
349 getpid_flag = 1;
350 nodefault = 1;
351 break;
352
353 case 's':
354 stats_flag = 1;
355 nodefault = 1;
356 break;
357
358 case 'u':
359 unmount_flag = 1;
360 nodefault = 1;
361 break;
362
363 case 'v':
364 getvers_flag = 1;
365 nodefault = 1;
366 break;
367
368 case 'x':
369 xlog_optstr = optarg;
370 nodefault = 1;
371 break;
372
373 case 'D':
374 debug_opts = optarg;
375 nodefault = 1;
376 break;
377
378 case 'P':
379 amd_program_number = atoi(optarg);
380 break;
381
382 case 'T':
383 use_tcp_flag = 1;
384 break;
385
386 case 'U':
387 use_udp_flag = 1;
388 break;
389
390 case 'w':
391 getpwd_flag = 1;
392 break;
393
394 default:
395 errs = 1;
396 break;
397 }
398
399 if (optind == argc) {
400 if (unmount_flag)
401 errs = 1;
402 }
403 if (errs) {
404 show_usage:
405 fprintf(stderr, "\
406 Usage: %s [-fmpsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\
407 \t[-x log_options] [-D debug_options]\n\
408 \t[-P program_number] [[-u] directory ...]\n",
409 am_get_progname()
410 );
411 exit(1);
412 }
413
414
415 /* set use_udp and use_tcp flags both to on if none are defined */
416 if (!use_tcp_flag && !use_udp_flag)
417 use_tcp_flag = use_udp_flag = 1;
418
419 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
420 /*
421 * Figure out root server of cluster
422 */
423 if (def_server == localhost)
424 server = cluster_server();
425 else
426 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
427 server = def_server;
428
429 /*
430 * Get address of server
431 */
432 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) {
433 fprintf(stderr, "%s: Can't get address of %s\n",
434 am_get_progname(), server);
435 exit(1);
436 }
437 memset(&server_addr, 0, sizeof(server_addr));
438 /* as per POSIX, sin_len need not be set (used internally by kernel) */
439 server_addr.sin_family = AF_INET;
440 if (hp) {
441 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr,
442 sizeof(server_addr.sin_addr));
443 } else {
444 /* fake "localhost" */
445 server_addr.sin_addr.s_addr = htonl(0x7f000001);
446 }
447
448 /*
449 * Create RPC endpoint
450 */
451 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */
452 tv.tv_usec = 0;
453
454 if (use_tcp_flag) /* try tcp first */
455 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp");
456 if (!clnt && use_udp_flag) { /* try udp next */
457 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp");
458 /* if ok, set timeout (valid for connectionless transports only) */
459 if (clnt)
460 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv);
461 }
462 if (!clnt) {
463 fprintf(stderr, "%s: ", am_get_progname());
464 clnt_pcreateerror(server);
465 exit(1);
466 }
467
468 /*
469 * Control debugging
470 */
471 if (debug_opts) {
472 int *rc;
473 amq_setopt opt;
474 opt.as_opt = AMOPT_DEBUG;
475 opt.as_str = debug_opts;
476 rc = amqproc_setopt_1(&opt, clnt);
477 if (rc && *rc < 0) {
478 fprintf(stderr, "%s: daemon not compiled for debug\n",
479 am_get_progname());
480 errs = 1;
481 } else if (!rc || *rc > 0) {
482 fprintf(stderr, "%s: debug setting for \"%s\" failed\n",
483 am_get_progname(), debug_opts);
484 errs = 1;
485 }
486 }
487
488 /*
489 * Control logging
490 */
491 if (xlog_optstr) {
492 int *rc;
493 amq_setopt opt;
494 opt.as_opt = AMOPT_XLOG;
495 opt.as_str = xlog_optstr;
496 rc = amqproc_setopt_1(&opt, clnt);
497 if (!rc || *rc) {
498 fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
499 am_get_progname(), xlog_optstr);
500 errs = 1;
501 }
502 }
503
504 /*
505 * Control log file
506 */
507 if (amq_logfile) {
508 int *rc;
509 amq_setopt opt;
510 opt.as_opt = AMOPT_LOGFILE;
511 opt.as_str = amq_logfile;
512 rc = amqproc_setopt_1(&opt, clnt);
513 if (!rc || *rc) {
514 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
515 am_get_progname(), amq_logfile);
516 errs = 1;
517 }
518 }
519
520 /*
521 * Flush map cache
522 */
523 if (flush_flag) {
524 int *rc;
525 amq_setopt opt;
526 opt.as_opt = AMOPT_FLUSHMAPC;
527 opt.as_str = "";
528 rc = amqproc_setopt_1(&opt, clnt);
529 if (!rc || *rc) {
530 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n",
531 am_get_progname(), server);
532 errs = 1;
533 }
534 }
535
536 /*
537 * getpwd info
538 */
539 if (getpwd_flag) {
540 char path[MAXPATHLEN+1];
541 char *wd = getcwd(path, MAXPATHLEN+1);
542 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
543 amq_mount_tree_p mt;
544 u_int i;
545 int flag;
546
547 if (!wd) {
548 perror("getcwd");
549 exit(1);
550 }
551 for (i = 0; mlp && i < mlp->amq_mount_tree_list_len; i++) {
552 mt = mlp->amq_mount_tree_list_val[i];
553 while (1) {
554 flag = 0;
555 show_pwd(mt, path, sizeof(path), &flag);
556 if (!flag) {
557 printf("%s\n", path);
558 break;
559 }
560 }
561 }
562 exit(0);
563 }
564
565 /*
566 * Mount info
567 */
568 if (minfo_flag) {
569 int dummy;
570 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
571 if (ml) {
572 int mwid = 0, dwid = 0, twid = 0;
573 show_mi(ml, Calc, &mwid, &dwid, &twid);
574 mwid++;
575 dwid++;
576 twid++;
577 show_mi(ml, Full, &mwid, &dwid, &twid);
578
579 } else {
580 fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
581 am_get_progname(), server);
582 }
583 }
584
585 /*
586 * Get Version
587 */
588 if (getvers_flag) {
589 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
590 if (spp && *spp) {
591 fputs(*spp, stdout);
592 XFREE(*spp);
593 } else {
594 fprintf(stderr, "%s: failed to get version information\n",
595 am_get_progname());
596 errs = 1;
597 }
598 }
599
600 /*
601 * Get PID of amd
602 */
603 if (getpid_flag) {
604 int *ip = amqproc_getpid_1((voidp) 0, clnt);
605 if (ip && *ip) {
606 printf("%d\n", *ip);
607 } else {
608 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname());
609 errs = 1;
610 }
611 }
612
613 /*
614 * Apply required operation to all remaining arguments
615 */
616 if (optind < argc) {
617 do {
618 char *fs = argv[optind++];
619 if (unmount_flag) {
620 /*
621 * Unmount request
622 */
623 amqproc_umnt_1(&fs, clnt);
624 } else {
625 /*
626 * Stats request
627 */
628 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
629 if (mtp) {
630 amq_mount_tree *mt = *mtp;
631 if (mt) {
632 int mwid = 0, dwid = 0, twid = 0;
633 show_mt(mt, Calc, &mwid, &dwid, &twid);
634 mwid++;
635 dwid++, twid++;
636 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
637 dwid, dwid, "What");
638 show_mt(mt, Stats, &mwid, &dwid, &twid);
639 } else {
640 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs);
641 }
642 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
643 } else {
644 fprintf(stderr, "%s: ", am_get_progname());
645 clnt_perror(clnt, server);
646 errs = 1;
647 }
648 }
649 } while (optind < argc);
650
651 } else if (unmount_flag) {
652 goto show_usage;
653
654 } else if (stats_flag) {
655 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
656 if (ms) {
657 show_ms(ms);
658 } else {
659 fprintf(stderr, "%s: ", am_get_progname());
660 clnt_perror(clnt, server);
661 errs = 1;
662 }
663
664 } else if (!nodefault) {
665 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
666 if (mlp) {
667 enum show_opt e = Calc;
668 int mwid = 0, dwid = 0, pwid = 0;
669
670 while (e != ShowDone) {
671 u_int i;
672 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
673 show_mt(mlp->amq_mount_tree_list_val[i],
674 e, &mwid, &dwid, &pwid);
675 }
676 mwid++;
677 dwid++, pwid++;
678 if (e == Calc)
679 e = Short;
680 else if (e == Short)
681 e = ShowDone;
682 }
683
684 } else {
685 fprintf(stderr, "%s: ", am_get_progname());
686 clnt_perror(clnt, server);
687 errs = 1;
688 }
689 }
690 exit(errs);
691 return errs; /* should never reach here */
692 }
693