etc/protocols - sync with NetBSD-8
[minix.git] / usr.bin / ipcs / ipcs.c
blob8fbae90670d11765c480793464821b34ad31f9ab
1 /* $NetBSD: ipcs.c,v 1.43 2014/06/11 14:57:55 joerg Exp $ */
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Simon Burge.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
46 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
47 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
48 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
49 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
50 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
51 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
52 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
53 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
54 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 #include <sys/cdefs.h>
58 #include <sys/param.h>
59 #include <sys/sysctl.h>
60 #include <sys/inttypes.h>
61 #include <sys/ipc.h>
62 #include <sys/sem.h>
63 #include <sys/shm.h>
64 #include <sys/msg.h>
66 #include <err.h>
67 #include <fcntl.h>
68 #include <grp.h>
69 #include <limits.h>
70 #include <paths.h>
71 #include <pwd.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <time.h>
76 #include <unistd.h>
78 #define SHMINFO 1
79 #define SHMTOTAL 2
80 #define MSGINFO 4
81 #define MSGTOTAL 8
82 #define SEMINFO 16
83 #define SEMTOTAL 32
85 #define BIGGEST 1
86 #define CREATOR 2
87 #define OUTSTANDING 4
88 #define PID 8
89 #define TIME 16
91 static int display = 0;
92 static int option = 0;
94 static void cvt_time(time_t, char *, size_t);
95 static char *fmt_perm(u_short);
96 static void msg_sysctl(void);
97 static void sem_sysctl(void);
98 static void shm_sysctl(void);
99 static void show_msginfo(time_t, time_t, time_t, int, u_int64_t, mode_t,
100 uid_t, gid_t, uid_t, gid_t, u_int64_t, u_int64_t, u_int64_t, pid_t, pid_t);
101 static void show_msginfo_hdr(void);
102 static void show_msgtotal(struct msginfo *);
103 static void show_seminfo_hdr(void);
104 static void show_seminfo(time_t, time_t, int, u_int64_t, mode_t, uid_t,
105 gid_t, uid_t, gid_t, int16_t);
106 static void show_semtotal(struct seminfo *);
107 static void show_shminfo(time_t, time_t, time_t, int, u_int64_t, mode_t,
108 uid_t, gid_t, uid_t, gid_t, u_int32_t, u_int64_t, pid_t, pid_t);
109 static void show_shminfo_hdr(void);
110 static void show_shmtotal(struct shminfo *);
111 static void usage(void) __dead;
112 static void unconfsem(void);
113 static void unconfmsg(void);
114 static void unconfshm(void);
116 static void
117 unconfsem(void)
119 warnx("SVID semaphores facility not configured in the system");
122 static void
123 unconfmsg(void)
125 warnx("SVID messages facility not configured in the system");
128 static void
129 unconfshm(void)
131 warnx("SVID shared memory facility not configured in the system");
134 static char *
135 fmt_perm(u_short mode)
137 static char buffer[12];
139 buffer[0] = '-';
140 buffer[1] = '-';
141 buffer[2] = ((mode & 0400) ? 'r' : '-');
142 buffer[3] = ((mode & 0200) ? 'w' : '-');
143 buffer[4] = ((mode & 0100) ? 'a' : '-');
144 buffer[5] = ((mode & 0040) ? 'r' : '-');
145 buffer[6] = ((mode & 0020) ? 'w' : '-');
146 buffer[7] = ((mode & 0010) ? 'a' : '-');
147 buffer[8] = ((mode & 0004) ? 'r' : '-');
148 buffer[9] = ((mode & 0002) ? 'w' : '-');
149 buffer[10] = ((mode & 0001) ? 'a' : '-');
150 buffer[11] = '\0';
151 return (&buffer[0]);
154 static void
155 cvt_time(time_t t, char *buf, size_t buflen)
157 struct tm *tm;
159 if (t == 0)
160 (void)strlcpy(buf, "no-entry", buflen);
161 else {
162 tm = localtime(&t);
163 (void)snprintf(buf, buflen, "%2d:%02d:%02d",
164 tm->tm_hour, tm->tm_min, tm->tm_sec);
168 main(int argc, char *argv[])
170 int i;
171 time_t now;
173 while ((i = getopt(argc, argv, "MmQqSsabcoptT")) != -1)
174 switch (i) {
175 case 'M':
176 display |= SHMTOTAL;
177 break;
178 case 'm':
179 display |= SHMINFO;
180 break;
181 case 'Q':
182 display |= MSGTOTAL;
183 break;
184 case 'q':
185 display |= MSGINFO;
186 break;
187 case 'S':
188 display |= SEMTOTAL;
189 break;
190 case 's':
191 display |= SEMINFO;
192 break;
193 case 'T':
194 display |= SHMTOTAL | MSGTOTAL | SEMTOTAL;
195 break;
196 case 'a':
197 option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME;
198 break;
199 case 'b':
200 option |= BIGGEST;
201 break;
202 case 'c':
203 option |= CREATOR;
204 break;
205 case 'o':
206 option |= OUTSTANDING;
207 break;
208 case 'p':
209 option |= PID;
210 break;
211 case 't':
212 option |= TIME;
213 break;
214 default:
215 usage();
218 if (argc - optind > 0)
219 usage();
221 (void)time(&now);
222 (void)printf("IPC status from <running system> as of %s\n",
223 /* and extra \n from ctime(3) */
224 ctime(&now));
226 if (display == 0)
227 display = SHMINFO | MSGINFO | SEMINFO;
229 if (display & (MSGINFO | MSGTOTAL))
230 msg_sysctl();
231 if (display & (SHMINFO | SHMTOTAL))
232 shm_sysctl();
233 if (display & (SEMINFO | SEMTOTAL))
234 sem_sysctl();
235 return 0;
238 static void
239 show_msgtotal(struct msginfo *msginfo)
241 (void)printf("msginfo:\n");
242 (void)printf("\tmsgmax: %6d\t(max characters in a message)\n",
243 msginfo->msgmax);
244 (void)printf("\tmsgmni: %6d\t(# of message queues)\n",
245 msginfo->msgmni);
246 (void)printf("\tmsgmnb: %6d\t(max characters in a message queue)\n",
247 msginfo->msgmnb);
248 (void)printf("\tmsgtql: %6d\t(max # of messages in system)\n",
249 msginfo->msgtql);
250 (void)printf("\tmsgssz: %6d\t(size of a message segment)\n",
251 msginfo->msgssz);
252 (void)printf("\tmsgseg: %6d\t(# of message segments in system)\n\n",
253 msginfo->msgseg);
256 static void
257 show_shmtotal(struct shminfo *shminfo)
259 (void)printf("shminfo:\n");
260 (void)printf("\tshmmax: %" PRIu64 "\t(max shared memory segment size)\n",
261 shminfo->shmmax);
262 (void)printf("\tshmmin: %7d\t(min shared memory segment size)\n",
263 shminfo->shmmin);
264 (void)printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n",
265 shminfo->shmmni);
266 (void)printf("\tshmseg: %7d\t(max shared memory segments per process)\n",
267 shminfo->shmseg);
268 (void)printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n",
269 shminfo->shmall);
272 static void
273 show_semtotal(struct seminfo *seminfo)
275 (void)printf("seminfo:\n");
276 (void)printf("\tsemmap: %6d\t(# of entries in semaphore map)\n",
277 seminfo->semmap);
278 (void)printf("\tsemmni: %6d\t(# of semaphore identifiers)\n",
279 seminfo->semmni);
280 (void)printf("\tsemmns: %6d\t(# of semaphores in system)\n",
281 seminfo->semmns);
282 (void)printf("\tsemmnu: %6d\t(# of undo structures in system)\n",
283 seminfo->semmnu);
284 (void)printf("\tsemmsl: %6d\t(max # of semaphores per id)\n",
285 seminfo->semmsl);
286 (void)printf("\tsemopm: %6d\t(max # of operations per semop call)\n",
287 seminfo->semopm);
288 (void)printf("\tsemume: %6d\t(max # of undo entries per process)\n",
289 seminfo->semume);
290 (void)printf("\tsemusz: %6d\t(size in bytes of undo structure)\n",
291 seminfo->semusz);
292 (void)printf("\tsemvmx: %6d\t(semaphore maximum value)\n",
293 seminfo->semvmx);
294 (void)printf("\tsemaem: %6d\t(adjust on exit max value)\n\n",
295 seminfo->semaem);
298 static void
299 show_msginfo_hdr(void)
301 (void)printf("Message Queues:\n");
302 (void)printf("T ID KEY MODE OWNER GROUP");
303 if (option & CREATOR)
304 (void)printf(" CREATOR CGROUP");
305 if (option & OUTSTANDING)
306 (void)printf(" CBYTES QNUM");
307 if (option & BIGGEST)
308 (void)printf(" QBYTES");
309 if (option & PID)
310 (void)printf(" LSPID LRPID");
311 if (option & TIME)
312 (void)printf(" STIME RTIME CTIME");
313 (void)printf("\n");
316 static void
317 show_msginfo(time_t s_time, time_t r_time, time_t c_time, int ipcid,
318 u_int64_t key,
319 mode_t mode, uid_t uid, gid_t gid, uid_t cuid, gid_t cgid,
320 u_int64_t cbytes, u_int64_t qnum, u_int64_t qbytes, pid_t lspid,
321 pid_t lrpid)
323 char s_time_buf[100], r_time_buf[100], c_time_buf[100];
325 if (option & TIME) {
326 cvt_time(s_time, s_time_buf, sizeof(s_time_buf));
327 cvt_time(r_time, r_time_buf, sizeof(r_time_buf));
328 cvt_time(c_time, c_time_buf, sizeof(c_time_buf));
331 (void)printf("q %9d %10lld %s %8s %8s", ipcid, (long long)key, fmt_perm(mode),
332 user_from_uid(uid, 0), group_from_gid(gid, 0));
334 if (option & CREATOR)
335 (void)printf(" %8s %8s", user_from_uid(cuid, 0),
336 group_from_gid(cgid, 0));
338 if (option & OUTSTANDING)
339 (void)printf(" %6lld %5lld", (long long)cbytes, (long long)qnum);
341 if (option & BIGGEST)
342 (void)printf(" %6lld", (long long)qbytes);
344 if (option & PID)
345 (void)printf(" %5d %5d", lspid, lrpid);
347 if (option & TIME)
348 (void)printf(" %s %s %s", s_time_buf, r_time_buf, c_time_buf);
350 (void)printf("\n");
353 static void
354 show_shminfo_hdr(void)
356 (void)printf("Shared Memory:\n");
357 (void)printf("T ID KEY MODE OWNER GROUP");
358 if (option & CREATOR)
359 (void)printf(" CREATOR CGROUP");
360 if (option & OUTSTANDING)
361 (void)printf(" NATTCH");
362 if (option & BIGGEST)
363 (void)printf(" SEGSZ");
364 if (option & PID)
365 (void)printf(" CPID LPID");
366 if (option & TIME)
367 (void)printf(" ATIME DTIME CTIME");
368 (void)printf("\n");
371 static void
372 show_shminfo(time_t atime, time_t dtime, time_t c_time, int ipcid, u_int64_t key,
373 mode_t mode, uid_t uid, gid_t gid, uid_t cuid, gid_t cgid,
374 u_int32_t nattch, u_int64_t segsz, pid_t cpid, pid_t lpid)
376 char atime_buf[100], dtime_buf[100], c_time_buf[100];
378 if (option & TIME) {
379 cvt_time(atime, atime_buf, sizeof(atime_buf));
380 cvt_time(dtime, dtime_buf, sizeof(dtime_buf));
381 cvt_time(c_time, c_time_buf, sizeof(c_time_buf));
384 (void)printf("m %9d %10lld %s %8s %8s", ipcid, (long long)key, fmt_perm(mode),
385 user_from_uid(uid, 0), group_from_gid(gid, 0));
387 if (option & CREATOR)
388 (void)printf(" %8s %8s", user_from_uid(cuid, 0),
389 group_from_gid(cgid, 0));
391 if (option & OUTSTANDING)
392 (void)printf(" %6d", nattch);
394 if (option & BIGGEST)
395 (void)printf(" %7llu", (long long)segsz);
397 if (option & PID)
398 (void)printf(" %5d %5d", cpid, lpid);
400 if (option & TIME)
401 (void)printf(" %s %s %s",
402 atime_buf,
403 dtime_buf,
404 c_time_buf);
406 (void)printf("\n");
409 static void
410 show_seminfo_hdr(void)
412 (void)printf("Semaphores:\n");
413 (void)printf("T ID KEY MODE OWNER GROUP");
414 if (option & CREATOR)
415 (void)printf(" CREATOR CGROUP");
416 if (option & BIGGEST)
417 (void)printf(" NSEMS");
418 if (option & TIME)
419 (void)printf(" OTIME CTIME");
420 (void)printf("\n");
423 static void
424 show_seminfo(time_t otime, time_t c_time, int ipcid, u_int64_t key, mode_t mode,
425 uid_t uid, gid_t gid, uid_t cuid, gid_t cgid, int16_t nsems)
427 char c_time_buf[100], otime_buf[100];
429 if (option & TIME) {
430 cvt_time(otime, otime_buf, sizeof(otime_buf));
431 cvt_time(c_time, c_time_buf, sizeof(c_time_buf));
434 (void)printf("s %9d %10lld %s %8s %8s", ipcid, (long long)key, fmt_perm(mode),
435 user_from_uid(uid, 0), group_from_gid(gid, 0));
437 if (option & CREATOR)
438 (void)printf(" %8s %8s", user_from_uid(cuid, 0),
439 group_from_gid(cgid, 0));
441 if (option & BIGGEST)
442 (void)printf(" %5d", nsems);
444 if (option & TIME)
445 (void)printf(" %s %s", otime_buf, c_time_buf);
447 (void)printf("\n");
450 static void
451 msg_sysctl(void)
453 struct msg_sysctl_info *msgsi;
454 void *buf;
455 int mib[4];
456 size_t len;
457 int i, valid;
459 mib[0] = CTL_KERN;
460 mib[1] = KERN_SYSVIPC;
461 mib[2] = KERN_SYSVIPC_MSG;
462 len = sizeof(valid);
463 if (sysctl(mib, 3, &valid, &len, NULL, 0) < 0) {
464 warn("sysctl(KERN_SYSVIPC_MSG)");
465 return;
467 if (!valid) {
468 unconfmsg();
469 return;
472 mib[0] = CTL_KERN;
473 mib[1] = KERN_SYSVIPC;
474 mib[2] = KERN_SYSVIPC_INFO;
475 mib[3] = KERN_SYSVIPC_MSG_INFO;
477 if (!(display & MSGINFO)) {
478 /* totals only */
479 len = sizeof(struct msginfo);
480 } else {
481 if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) {
482 warn("sysctl(KERN_SYSVIPC_MSG_INFO)");
483 return;
487 if ((buf = malloc(len)) == NULL)
488 err(1, "malloc");
489 msgsi = (struct msg_sysctl_info *)buf;
490 if (sysctl(mib, 4, msgsi, &len, NULL, 0) < 0) {
491 warn("sysctl(KERN_SYSVIPC_MSG_INFO)");
492 goto done;
495 if (display & MSGTOTAL)
496 show_msgtotal(&msgsi->msginfo);
498 if (display & MSGINFO) {
499 show_msginfo_hdr();
500 for (i = 0; i < msgsi->msginfo.msgmni; i++) {
501 struct msgid_ds_sysctl *msqptr = &msgsi->msgids[i];
502 if (msqptr->msg_qbytes != 0)
503 show_msginfo(msqptr->msg_stime,
504 msqptr->msg_rtime,
505 msqptr->msg_ctime,
506 IXSEQ_TO_IPCID(i, msqptr->msg_perm),
507 msqptr->msg_perm._key,
508 msqptr->msg_perm.mode,
509 msqptr->msg_perm.uid,
510 msqptr->msg_perm.gid,
511 msqptr->msg_perm.cuid,
512 msqptr->msg_perm.cgid,
513 msqptr->_msg_cbytes,
514 msqptr->msg_qnum,
515 msqptr->msg_qbytes,
516 msqptr->msg_lspid,
517 msqptr->msg_lrpid);
519 (void)printf("\n");
521 done:
522 free(buf);
525 static void
526 shm_sysctl(void)
528 struct shm_sysctl_info *shmsi;
529 void *buf;
530 int mib[4];
531 size_t len;
532 uint32_t i;
533 long valid;
535 mib[0] = CTL_KERN;
536 mib[1] = KERN_SYSVIPC;
537 mib[2] = KERN_SYSVIPC_SHM;
538 len = sizeof(valid);
539 if (sysctl(mib, 3, &valid, &len, NULL, 0) < 0) {
540 warn("sysctl(KERN_SYSVIPC_SHM)");
541 return;
543 if (!valid) {
544 unconfshm();
545 return;
548 mib[0] = CTL_KERN;
549 mib[1] = KERN_SYSVIPC;
550 mib[2] = KERN_SYSVIPC_INFO;
551 mib[3] = KERN_SYSVIPC_SHM_INFO;
553 if (!(display & SHMINFO)) {
554 /* totals only */
555 len = sizeof(struct shminfo);
556 } else {
557 if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) {
558 warn("sysctl(KERN_SYSVIPC_SHM_INFO)");
559 return;
563 if ((buf = malloc(len)) == NULL)
564 err(1, "malloc");
565 shmsi = (struct shm_sysctl_info *)buf;
566 if (sysctl(mib, 4, shmsi, &len, NULL, 0) < 0) {
567 warn("sysctl(KERN_SYSVIPC_SHM_INFO)");
568 goto done;
571 if (display & SHMTOTAL)
572 show_shmtotal(&shmsi->shminfo);
574 if (display & SHMINFO) {
575 show_shminfo_hdr();
576 for (i = 0; i < shmsi->shminfo.shmmni; i++) {
577 struct shmid_ds_sysctl *shmptr = &shmsi->shmids[i];
578 if (shmptr->shm_perm.mode & 0x0800)
579 show_shminfo(shmptr->shm_atime,
580 shmptr->shm_dtime,
581 shmptr->shm_ctime,
582 IXSEQ_TO_IPCID(i, shmptr->shm_perm),
583 shmptr->shm_perm._key,
584 shmptr->shm_perm.mode,
585 shmptr->shm_perm.uid,
586 shmptr->shm_perm.gid,
587 shmptr->shm_perm.cuid,
588 shmptr->shm_perm.cgid,
589 shmptr->shm_nattch,
590 shmptr->shm_segsz,
591 shmptr->shm_cpid,
592 shmptr->shm_lpid);
594 (void)printf("\n");
596 done:
597 free(buf);
600 static void
601 sem_sysctl(void)
603 struct sem_sysctl_info *semsi;
604 void *buf;
605 int mib[4];
606 size_t len;
607 int i, valid;
609 mib[0] = CTL_KERN;
610 mib[1] = KERN_SYSVIPC;
611 mib[2] = KERN_SYSVIPC_SEM;
612 len = sizeof(valid);
613 if (sysctl(mib, 3, &valid, &len, NULL, 0) < 0) {
614 warn("sysctl(KERN_SYSVIPC_SEM)");
615 return;
617 if (!valid) {
618 unconfsem();
619 return;
622 mib[0] = CTL_KERN;
623 mib[1] = KERN_SYSVIPC;
624 mib[2] = KERN_SYSVIPC_INFO;
625 mib[3] = KERN_SYSVIPC_SEM_INFO;
627 if (!(display & SEMINFO)) {
628 /* totals only */
629 len = sizeof(struct seminfo);
630 } else {
631 if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) {
632 warn("sysctl(KERN_SYSVIPC_SEM_INFO)");
633 return;
637 if ((buf = malloc(len)) == NULL)
638 err(1, "malloc");
639 semsi = (struct sem_sysctl_info *)buf;
640 if (sysctl(mib, 4, semsi, &len, NULL, 0) < 0) {
641 warn("sysctl(KERN_SYSVIPC_SEM_INFO)");
642 goto done;
645 if (display & SEMTOTAL)
646 show_semtotal(&semsi->seminfo);
648 if (display & SEMINFO) {
649 show_seminfo_hdr();
650 for (i = 0; i < semsi->seminfo.semmni; i++) {
651 struct semid_ds_sysctl *semaptr = &semsi->semids[i];
652 if ((semaptr->sem_perm.mode & SEM_ALLOC) != 0)
653 show_seminfo(semaptr->sem_otime,
654 semaptr->sem_ctime,
655 IXSEQ_TO_IPCID(i, semaptr->sem_perm),
656 semaptr->sem_perm._key,
657 semaptr->sem_perm.mode,
658 semaptr->sem_perm.uid,
659 semaptr->sem_perm.gid,
660 semaptr->sem_perm.cuid,
661 semaptr->sem_perm.cgid,
662 semaptr->sem_nsems);
664 (void)printf("\n");
666 done:
667 free(buf);
670 static void
671 usage(void)
674 (void)fprintf(stderr,
675 "Usage: %s [-abcmopqstMQST]\n",
676 getprogname());
677 exit(1);