 |
|
|
| |
1 /*
2 * Copyright (c) 1997-2005 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
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 *) &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 *) &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
170 show_pwd(amq_mount_tree *mt, char *path, 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];
179 strcpy(buf, mt->mt_directory);
180 strcat(buf, &path[len]);
181 strcpy(path, buf);
182 *flag = 1;
183 }
184 show_pwd(mt->mt_next, path, flag);
185 mt = mt->mt_child;
186 }
187 }
188
189
190 /*
191 * Display a mount tree.
192 */
193 static void
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
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
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 *
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
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 server_addr.sin_family = AF_INET;
439 if (hp) {
440 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr,
441 sizeof(server_addr.sin_addr));
442 } else {
443 /* fake "localhost" */
444 server_addr.sin_addr.s_addr = htonl(0x7f000001);
445 }
446
447 /*
448 * Create RPC endpoint
449 */
450 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */
451 tv.tv_usec = 0;
452
453 if (use_tcp_flag) /* try tcp first */
454 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp");
455 if (!clnt && use_udp_flag) { /* try udp next */
456 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp");
457 /* if ok, set timeout (valid for connectionless transports only) */
458 if (clnt)
459 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv);
460 }
461 if (!clnt) {
462 fprintf(stderr, "%s: ", am_get_progname());
463 clnt_pcreateerror(server);
464 exit(1);
465 }
466
467 /*
468 * Control debugging
469 */
470 if (debug_opts) {
471 int *rc;
472 amq_setopt opt;
473 opt.as_opt = AMOPT_DEBUG;
474 opt.as_str = debug_opts;
475 rc = amqproc_setopt_1(&opt, clnt);
476 if (rc && *rc < 0) {
477 fprintf(stderr, "%s: daemon not compiled for debug\n",
478 am_get_progname());
479 errs = 1;
480 } else if (!rc || *rc > 0) {
481 fprintf(stderr, "%s: debug setting for \"%s\" failed\n",
482 am_get_progname(), debug_opts);
483 errs = 1;
484 }
485 }
486
487 /*
488 * Control logging
489 */
490 if (xlog_optstr) {
491 int *rc;
492 amq_setopt opt;
493 opt.as_opt = AMOPT_XLOG;
494 opt.as_str = xlog_optstr;
495 rc = amqproc_setopt_1(&opt, clnt);
496 if (!rc || *rc) {
497 fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
498 am_get_progname(), xlog_optstr);
499 errs = 1;
500 }
501 }
502
503 /*
504 * Control log file
505 */
506 if (amq_logfile) {
507 int *rc;
508 amq_setopt opt;
509 opt.as_opt = AMOPT_LOGFILE;
510 opt.as_str = amq_logfile;
511 rc = amqproc_setopt_1(&opt, clnt);
512 if (!rc || *rc) {
513 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
514 am_get_progname(), amq_logfile);
515 errs = 1;
516 }
517 }
518
519 /*
520 * Flush map cache
521 */
522 if (flush_flag) {
523 int *rc;
524 amq_setopt opt;
525 opt.as_opt = AMOPT_FLUSHMAPC;
526 opt.as_str = "";
527 rc = amqproc_setopt_1(&opt, clnt);
528 if (!rc || *rc) {
529 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n",
530 am_get_progname(), server);
531 errs = 1;
532 }
533 }
534
535 /*
536 * getpwd info
537 */
538 if (getpwd_flag) {
539 char path[MAXPATHLEN+1];
540 char *wd = getcwd(path, MAXPATHLEN+1);
541 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
542 amq_mount_tree_p mt;
543 u_int i;
544 int flag;
545
546 if (!wd) {
547 perror("getcwd");
548 exit(1);
549 }
550 for (i = 0; mlp && i < mlp->amq_mount_tree_list_len; i++) {
551 mt = mlp->amq_mount_tree_list_val[i];
552 while (1) {
553 flag = 0;
554 show_pwd(mt, path, &flag);
555 if (!flag) {
556 printf("%s\n", path);
557 break;
558 }
559 }
560 }
561 exit(0);
562 }
563
564 /*
565 * Mount info
566 */
567 if (minfo_flag) {
568 int dummy;
569 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
570 if (ml) {
571 int mwid = 0, dwid = 0, twid = 0;
572 show_mi(ml, Calc, &mwid, &dwid, &twid);
573 mwid++;
574 dwid++;
575 twid++;
576 show_mi(ml, Full, &mwid, &dwid, &twid);
577
578 } else {
579 fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
580 am_get_progname(), server);
581 }
582 }
583
584 /*
585 * Get Version
586 */
587 if (getvers_flag) {
588 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
589 if (spp && *spp) {
590 fputs(*spp, stdout);
591 XFREE(*spp);
592 } else {
593 fprintf(stderr, "%s: failed to get version information\n",
594 am_get_progname());
595 errs = 1;
596 }
597 }
598
599 /*
600 * Get PID of amd
601 */
602 if (getpid_flag) {
603 int *ip = amqproc_getpid_1((voidp) 0, clnt);
604 if (ip && *ip) {
605 printf("%d\n", *ip);
606 } else {
607 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname());
608 errs = 1;
609 }
610 }
611
612 /*
613 * Apply required operation to all remaining arguments
614 */
615 if (optind < argc) {
616 do {
617 char *fs = argv[optind++];
618 if (unmount_flag) {
619 /*
620 * Unmount request
621 */
622 amqproc_umnt_1(&fs, clnt);
623 } else {
624 /*
625 * Stats request
626 */
627 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
628 if (mtp) {
629 amq_mount_tree *mt = *mtp;
630 if (mt) {
631 int mwid = 0, dwid = 0, twid = 0;
632 show_mt(mt, Calc, &mwid, &dwid, &twid);
633 mwid++;
634 dwid++, twid++;
635 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
636 dwid, dwid, "What");
637 show_mt(mt, Stats, &mwid, &dwid, &twid);
638 } else {
639 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs);
640 }
641 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
642 } else {
643 fprintf(stderr, "%s: ", am_get_progname());
644 clnt_perror(clnt, server);
645 errs = 1;
646 }
647 }
648 } while (optind < argc);
649
650 } else if (unmount_flag) {
651 goto show_usage;
652
653 } else if (stats_flag) {
654 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
655 if (ms) {
656 show_ms(ms);
657 } else {
658 fprintf(stderr, "%s: ", am_get_progname());
659 clnt_perror(clnt, server);
660 errs = 1;
661 }
662
663 } else if (!nodefault) {
664 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
665 if (mlp) {
666 enum show_opt e = Calc;
667 int mwid = 0, dwid = 0, pwid = 0;
668
669 while (e != ShowDone) {
670 u_int i;
671 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
672 show_mt(mlp->amq_mount_tree_list_val[i],
673 e, &mwid, &dwid, &pwid);
674 }
675 mwid++;
676 dwid++, pwid++;
677 if (e == Calc)
678 e = Short;
679 else if (e == Short)
680 e = ShowDone;
681 }
682
683 } else {
684 fprintf(stderr, "%s: ", am_get_progname());
685 clnt_perror(clnt, server);
686 errs = 1;
687 }
688 }
689 exit(errs);
690 return errs; /* should never reach here */
691 }
692