No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / am-utils / dist / amq / amq.c
blob505b9c8ac1975b2abd1523ea0e958aa5942f8ab5
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
42 * File: am-utils/amq/amq.c
47 * Automounter query tool
50 #ifdef HAVE_CONFIG_H
51 # include <config.h>
52 #endif /* HAVE_CONFIG_H */
53 #include <am_defs.h>
54 #include <amq.h>
56 /* locals */
57 static int flush_flag;
58 static int getpid_flag;
59 static int getpwd_flag;
60 static int getvers_flag;
61 static int minfo_flag;
62 static int quiet_flag;
63 static int stats_flag;
64 static int unmount_flag;
65 static int use_tcp_flag;
66 static int use_udp_flag;
67 static u_long amd_program_number = AMQ_PROGRAM;
68 static char *debug_opts;
69 static char *amq_logfile;
70 static char *xlog_optstr;
71 static char localhost[] = "localhost";
72 static char *def_server = localhost;
74 /* externals */
75 extern int optind;
76 extern char *optarg;
78 /* structures */
79 enum show_opt {
80 Full, Stats, Calc, Short, ShowDone
85 * If (e) is Calc then just calculate the sizes
86 * Otherwise display the mount node on stdout
88 static void
89 show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
91 switch (e) {
92 case Calc:
94 int mw = strlen(mt->mt_mountinfo);
95 int dw = strlen(mt->mt_directory);
96 int tw = strlen(mt->mt_type);
97 if (mw > *mwid)
98 *mwid = mw;
99 if (dw > *dwid)
100 *dwid = dw;
101 if (tw > *twid)
102 *twid = tw;
104 break;
106 case Full:
108 struct tm *tp = localtime((time_t *) ((voidp) &mt->mt_mounttime));
109 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%04d %02d:%02d:%02d\n",
110 *dwid, *dwid,
111 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
112 *twid, *twid,
113 mt->mt_type,
114 *mwid, *mwid,
115 mt->mt_mountinfo,
116 mt->mt_mountpoint,
118 mt->mt_mountuid,
119 mt->mt_getattr,
120 mt->mt_lookup,
121 mt->mt_readdir,
122 mt->mt_readlink,
123 mt->mt_statfs,
125 tp->tm_mon + 1, tp->tm_mday,
126 tp->tm_year < 1900 ? tp->tm_year + 1900 : tp->tm_year,
127 tp->tm_hour, tp->tm_min, tp->tm_sec);
129 break;
131 case Stats:
133 struct tm *tp = localtime((time_t *) ((voidp) &mt->mt_mounttime));
134 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%04d\n",
135 *dwid, *dwid,
136 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
138 mt->mt_mountuid,
139 mt->mt_getattr,
140 mt->mt_lookup,
141 mt->mt_readdir,
142 mt->mt_readlink,
143 mt->mt_statfs,
145 tp->tm_mon + 1, tp->tm_mday,
146 tp->tm_year < 1900 ? tp->tm_year + 1900 : tp->tm_year,
147 tp->tm_hour, tp->tm_min, tp->tm_sec);
149 break;
151 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);
162 break;
164 default:
165 break;
171 * Display a pwd data
173 static void
174 show_pwd(amq_mount_tree *mt, char *path, size_t l, int *flag)
176 int len;
178 while (mt) {
179 len = strlen(mt->mt_mountpoint);
180 if (NSTREQ(path, mt->mt_mountpoint, len) &&
181 !STREQ(mt->mt_directory, mt->mt_mountpoint)) {
182 char buf[MAXPATHLEN+1]; /* must be same size as 'path' */
183 xstrlcpy(buf, mt->mt_directory, sizeof(buf));
184 xstrlcat(buf, &path[len], sizeof(buf));
185 xstrlcpy(path, buf, l);
186 *flag = 1;
188 show_pwd(mt->mt_next, path, l, flag);
189 mt = mt->mt_child;
195 * Display a mount tree.
197 static void
198 show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
200 while (mt) {
201 show_mti(mt, e, mwid, dwid, pwid);
202 show_mt(mt->mt_next, e, mwid, dwid, pwid);
203 mt = mt->mt_child;
208 static void
209 show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
211 u_int i;
213 switch (e) {
215 case Calc:
217 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
218 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
219 int mw = strlen(mi->mi_mountinfo);
220 int dw = strlen(mi->mi_mountpt);
221 int tw = strlen(mi->mi_type);
222 if (mw > *mwid)
223 *mwid = mw;
224 if (dw > *dwid)
225 *dwid = dw;
226 if (tw > *twid)
227 *twid = tw;
230 break;
232 case Full:
234 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
235 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
236 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
237 *mwid, *mwid, mi->mi_mountinfo,
238 *dwid, *dwid, mi->mi_mountpt,
239 *twid, *twid, mi->mi_type,
240 mi->mi_refc, mi->mi_fserver,
241 mi->mi_up > 0 ? "up" :
242 mi->mi_up < 0 ? "starting" : "down");
243 if (mi->mi_error > 0) {
244 printf(" (%s)", strerror(mi->mi_error));
245 } else if (mi->mi_error < 0) {
246 fputs(" (in progress)", stdout);
248 fputc('\n', stdout);
251 break;
253 default:
254 break;
260 * Display general mount statistics
262 static void
263 show_ms(amq_mount_stats *ms)
265 printf("\
266 requests stale mount mount unmount\n\
267 deferred fhandles ok failed failed\n\
268 %-9d %-9d %-9d %-9d %-9d\n",
269 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
273 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
274 static char *
275 cluster_server(void)
277 struct cct_entry *cp;
279 if (cnodeid() == 0) {
281 * Not clustered
283 return def_server;
285 while (cp = getccent())
286 if (cp->cnode_type == 'r')
287 return cp->cnode_name;
289 return def_server;
291 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
294 static void
295 print_umnt_error(amq_sync_umnt *rv, const char *fs)
298 switch (rv->au_etype) {
299 case AMQ_UMNT_OK:
300 break;
301 case AMQ_UMNT_FAILED:
302 printf("unmount failed: %s\n", strerror(rv->au_errno));
303 break;
304 case AMQ_UMNT_FORK:
305 if (rv->au_errno == 0)
306 printf("%s is not mounted\n", fs);
307 else
308 printf("falling back to asynchronous unmount: %s\n",
309 strerror(rv->au_errno));
310 break;
311 case AMQ_UMNT_READ:
312 printf("pipe read error: %s\n", strerror(rv->au_errno));
313 break;
314 case AMQ_UMNT_SERVER:
315 printf("amd server down\n");
316 break;
317 case AMQ_UMNT_SIGNAL:
318 printf("got signal: %d\n", rv->au_signal);
319 break;
321 * Omit default so the compiler can check for missing cases.
323 default:
324 break;
330 static int
331 amu_sync_umnt_to_retval(amq_sync_umnt *rv)
333 switch (rv->au_etype) {
334 case AMQ_UMNT_FORK:
335 if (rv->au_errno == 0) {
337 * We allow this error so that things like:
338 * amq -uu /l/cd0d && eject cd0
339 * will work when /l/cd0d is not mounted.
340 * XXX - We still print an error message.
342 return 0;
344 default:
345 return rv->au_etype;
350 static int
351 clnt_failed(CLIENT *clnt, char *server)
353 fprintf(stderr, "%s: ", am_get_progname());
354 clnt_perror(clnt, server);
355 return 1;
360 * MAIN
363 main(int argc, char *argv[])
365 int opt_ch;
366 int errs = 0;
367 char *server;
368 struct sockaddr_in server_addr;
369 CLIENT *clnt = NULL;
370 struct hostent *hp;
371 int nodefault = 0;
372 struct timeval tv;
373 char *progname = NULL;
376 * Compute program name
378 if (argv[0]) {
379 progname = strrchr(argv[0], '/');
380 if (progname && progname[1])
381 progname++;
382 else
383 progname = argv[0];
385 if (!progname)
386 progname = "amq";
387 am_set_progname(progname);
390 * Parse arguments
392 while ((opt_ch = getopt(argc, argv, "Hfh:l:mqsuvx:D:pP:TUw")) != -1)
393 switch (opt_ch) {
394 case 'H':
395 goto show_usage;
396 break;
398 case 'f':
399 flush_flag = 1;
400 nodefault = 1;
401 break;
403 case 'h':
404 def_server = optarg;
405 break;
407 case 'l':
408 amq_logfile = optarg;
409 nodefault = 1;
410 break;
412 case 'm':
413 minfo_flag = 1;
414 nodefault = 1;
415 break;
417 case 'p':
418 getpid_flag = 1;
419 nodefault = 1;
420 break;
422 case 'q':
423 quiet_flag = 1;
424 nodefault = 1;
425 break;
427 case 's':
428 stats_flag = 1;
429 nodefault = 1;
430 break;
432 case 'u':
433 unmount_flag++;
434 nodefault = 1;
435 break;
437 case 'v':
438 getvers_flag = 1;
439 nodefault = 1;
440 break;
442 case 'x':
443 xlog_optstr = optarg;
444 nodefault = 1;
445 break;
447 case 'D':
448 debug_opts = optarg;
449 nodefault = 1;
450 break;
452 case 'P':
453 amd_program_number = atoi(optarg);
454 break;
456 case 'T':
457 use_tcp_flag = 1;
458 break;
460 case 'U':
461 use_udp_flag = 1;
462 break;
464 case 'w':
465 getpwd_flag = 1;
466 break;
468 default:
469 errs = 1;
470 break;
473 if (optind == argc) {
474 if (unmount_flag)
475 errs = 1;
477 if (errs) {
478 show_usage:
479 fprintf(stderr, "\
480 Usage: %s [-fmpqsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\
481 \t[-x log_options] [-D debug_options]\n\
482 \t[-P program_number] [[-u[u]] directory ...]\n",
483 am_get_progname()
485 exit(1);
489 /* set use_udp and use_tcp flags both to on if none are defined */
490 if (!use_tcp_flag && !use_udp_flag)
491 use_tcp_flag = use_udp_flag = 1;
493 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
495 * Figure out root server of cluster
497 if (def_server == localhost)
498 server = cluster_server();
499 else
500 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
501 server = def_server;
504 * Get address of server
506 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) {
507 fprintf(stderr, "%s: Can't get address of %s\n",
508 am_get_progname(), server);
509 exit(1);
511 memset(&server_addr, 0, sizeof(server_addr));
512 /* as per POSIX, sin_len need not be set (used internally by kernel) */
513 server_addr.sin_family = AF_INET;
514 if (hp) {
515 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr,
516 sizeof(server_addr.sin_addr));
517 } else {
518 /* fake "localhost" */
519 server_addr.sin_addr.s_addr = htonl(0x7f000001);
523 * Create RPC endpoint
525 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */
526 tv.tv_usec = 0;
528 if (use_tcp_flag) /* try tcp first */
529 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp");
530 if (!clnt && use_udp_flag) { /* try udp next */
531 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp");
532 /* if ok, set timeout (valid for connectionless transports only) */
533 if (clnt)
534 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv);
536 if (!clnt) {
537 fprintf(stderr, "%s: ", am_get_progname());
538 clnt_pcreateerror(server);
539 exit(1);
543 * Control debugging
545 if (debug_opts) {
546 int *rc;
547 amq_setopt opt;
548 opt.as_opt = AMOPT_DEBUG;
549 opt.as_str = debug_opts;
550 rc = amqproc_setopt_1(&opt, clnt);
551 if (rc && *rc < 0) {
552 fprintf(stderr, "%s: daemon not compiled for debug\n",
553 am_get_progname());
554 errs = 1;
555 } else if (!rc || *rc > 0) {
556 fprintf(stderr, "%s: debug setting for \"%s\" failed\n",
557 am_get_progname(), debug_opts);
558 errs = 1;
563 * Control logging
565 if (xlog_optstr) {
566 int *rc;
567 amq_setopt opt;
568 opt.as_opt = AMOPT_XLOG;
569 opt.as_str = xlog_optstr;
570 rc = amqproc_setopt_1(&opt, clnt);
571 if (!rc || *rc) {
572 fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
573 am_get_progname(), xlog_optstr);
574 errs = 1;
579 * Control log file
581 if (amq_logfile) {
582 int *rc;
583 amq_setopt opt;
584 opt.as_opt = AMOPT_LOGFILE;
585 opt.as_str = amq_logfile;
586 rc = amqproc_setopt_1(&opt, clnt);
587 if (!rc || *rc) {
588 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
589 am_get_progname(), amq_logfile);
590 errs = 1;
595 * Flush map cache
597 if (flush_flag) {
598 int *rc;
599 amq_setopt opt;
600 opt.as_opt = AMOPT_FLUSHMAPC;
601 opt.as_str = "";
602 rc = amqproc_setopt_1(&opt, clnt);
603 if (!rc || *rc) {
604 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n",
605 am_get_progname(), server);
606 errs = 1;
611 * getpwd info
613 if (getpwd_flag) {
614 char path[MAXPATHLEN+1];
615 char *wd = getcwd(path, MAXPATHLEN+1);
616 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
617 amq_mount_tree_p mt;
618 u_int i;
619 int flag;
621 if (!wd) {
622 perror("getcwd");
623 exit(1);
625 for (i = 0; mlp && i < mlp->amq_mount_tree_list_len; i++) {
626 mt = mlp->amq_mount_tree_list_val[i];
627 while (1) {
628 flag = 0;
629 show_pwd(mt, path, sizeof(path), &flag);
630 if (!flag) {
631 printf("%s\n", path);
632 break;
636 exit(0);
640 * Mount info
642 if (minfo_flag) {
643 int dummy;
644 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
645 if (ml) {
646 int mwid = 0, dwid = 0, twid = 0;
647 show_mi(ml, Calc, &mwid, &dwid, &twid);
648 mwid++;
649 dwid++;
650 twid++;
651 show_mi(ml, Full, &mwid, &dwid, &twid);
653 } else {
654 fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
655 am_get_progname(), server);
660 * Get Version
662 if (getvers_flag) {
663 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
664 if (spp && *spp) {
665 fputs(*spp, stdout);
666 XFREE(*spp);
667 } else {
668 fprintf(stderr, "%s: failed to get version information\n",
669 am_get_progname());
670 errs = 1;
675 * Get PID of amd
677 if (getpid_flag) {
678 int *ip = amqproc_getpid_1((voidp) 0, clnt);
679 if (ip && *ip) {
680 printf("%d\n", *ip);
681 } else {
682 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname());
683 errs = 1;
688 * Apply required operation to all remaining arguments
690 if (optind < argc) {
691 do {
692 char *fs = argv[optind++];
693 if (unmount_flag > 1) {
694 amq_sync_umnt *sup;
696 * Synchronous unmount request
698 sup = amqproc_sync_umnt_1(&fs, clnt);
699 if (sup) {
700 if (quiet_flag == 0)
701 print_umnt_error(sup, fs);
702 errs = amu_sync_umnt_to_retval(sup);
703 } else {
704 errs = clnt_failed(clnt, server);
706 } else if (unmount_flag) {
708 * Unmount request
710 amqproc_umnt_1(&fs, clnt);
711 } else {
713 * Stats request
715 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
716 if (mtp) {
717 amq_mount_tree *mt = *mtp;
718 if (mt) {
719 int mwid = 0, dwid = 0, twid = 0;
720 show_mt(mt, Calc, &mwid, &dwid, &twid);
721 mwid++;
722 dwid++, twid++;
723 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
724 dwid, dwid, "What");
725 show_mt(mt, Stats, &mwid, &dwid, &twid);
726 } else {
727 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs);
729 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
730 } else {
731 errs = clnt_failed(clnt, server);
734 } while (optind < argc);
736 } else if (unmount_flag) {
737 goto show_usage;
739 } else if (stats_flag) {
740 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
741 if (ms) {
742 show_ms(ms);
743 } else {
744 errs = clnt_failed(clnt, server);
747 } else if (!nodefault) {
748 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
749 if (mlp) {
750 enum show_opt e = Calc;
751 int mwid = 0, dwid = 0, pwid = 0;
753 while (e != ShowDone) {
754 u_int i;
755 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
756 show_mt(mlp->amq_mount_tree_list_val[i],
757 e, &mwid, &dwid, &pwid);
759 mwid++;
760 dwid++, pwid++;
761 if (e == Calc)
762 e = Short;
763 else if (e == Short)
764 e = ShowDone;
767 } else {
768 errs = clnt_failed(clnt, server);
771 exit(errs);
772 return errs; /* should never reach here */