2 * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
32 #include <sys/types.h>
33 #include <sys/event.h>
35 #include <sys/proc_info.h>
36 #include <sys/param.h>
37 #include <pthread/pthread.h>
38 #include <mach/message.h>
40 #include <os/assumes.h>
41 #include <os/overflow.h>
45 #define ARRAYLEN(x) (sizeof((x))/sizeof((x[0])))
47 /* command line options */
50 static int ignore_empty
;
53 static char *self
= "lskq";
55 static inline const char *
56 filt_name(int16_t filt
)
58 static char unkn_filt
[32];
60 if (idx
>= 0 && idx
< ARRAYLEN(filt_strs
)) {
61 return filt_strs
[idx
];
63 snprintf(unkn_filt
, sizeof(unkn_filt
), "%i (?)", idx
);
68 static inline const char *
69 fdtype_str(uint32_t type
)
71 static char unkn_fdtype
[32];
72 if (type
< ARRAYLEN(fdtype_strs
)) {
73 return fdtype_strs
[type
];
75 snprintf(unkn_fdtype
, sizeof(unkn_fdtype
), "%i (?)", type
);
81 fflags_build(struct kevent_extinfo
*info
, char *str
, int len
)
83 unsigned ff
= info
->kqext_sfflags
;
85 switch (info
->kqext_kev
.filter
) {
88 snprintf(str
, len
, "%c ",
89 (ff
& NOTE_LOWAT
) ? 'l' : '-'
94 case EVFILT_MACHPORT
: {
95 snprintf(str
, len
, "%c ",
96 (ff
& MACH_RCV_MSG
) ? 'r' : '-'
102 snprintf(str
, len
, "%c%c%c%c%c%c%c%c",
103 (ff
& NOTE_DELETE
) ? 'd' : '-',
104 (ff
& NOTE_WRITE
) ? 'w' : '-',
105 (ff
& NOTE_EXTEND
) ? 'e' : '-',
106 (ff
& NOTE_ATTRIB
) ? 'a' : '-',
107 (ff
& NOTE_LINK
) ? 'l' : '-',
108 (ff
& NOTE_RENAME
) ? 'r' : '-',
109 (ff
& NOTE_REVOKE
) ? 'v' : '-',
110 (ff
& NOTE_FUNLOCK
) ? 'u' : '-'
116 /* NOTE_REAP is deprecated, but we still want to show if it's used */
117 #pragma clang diagnostic push
118 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
119 snprintf(str
, len
, "%c%c%c%c%c%c%c",
120 (ff
& NOTE_EXIT
) ? 'x' : '-',
121 (ff
& NOTE_EXITSTATUS
) ? 't' : '-',
122 (ff
& NOTE_EXIT_DETAIL
)? 'd' : '-',
123 (ff
& NOTE_FORK
) ? 'f' : '-',
124 (ff
& NOTE_EXEC
) ? 'e' : '-',
125 (ff
& NOTE_SIGNAL
) ? 's' : '-',
126 (ff
& NOTE_REAP
) ? 'r' : '-'
129 #pragma clang diagnostic pop
133 snprintf(str
, len
, "%c%c%c%c%c ",
134 (ff
& NOTE_SECONDS
) ? 's' :
135 (ff
& NOTE_USECONDS
) ? 'u' :
136 (ff
& NOTE_NSECONDS
) ? 'n' :
137 (ff
& NOTE_MACHTIME
) ? 'm' : '?',
138 (ff
& NOTE_ABSOLUTE
) ? 'a' :
139 (ff
& NOTE_MACH_CONTINUOUS_TIME
) ? 'A' : '-',
140 (ff
& NOTE_CRITICAL
) ? 'c' : '-',
141 (ff
& NOTE_BACKGROUND
) ? 'b' : '-',
142 (ff
& NOTE_LEEWAY
) ? 'l' : '-'
148 snprintf(str
, len
, "%c%c%c ",
149 (ff
& NOTE_TRIGGER
) ? 't' : '-',
150 (ff
& NOTE_FFAND
) ? 'a' : '-',
151 (ff
& NOTE_FFOR
) ? 'o' : '-'
155 case EVFILT_WORKLOOP
:
156 #ifdef NOTE_WL_SYNC_IPC
157 snprintf(str
, len
, "%c%c%c%c%c ",
159 snprintf(str
, len
, "%c%c%c%c ",
161 (ff
& NOTE_WL_THREAD_REQUEST
) ? 't' :
162 (ff
& NOTE_WL_SYNC_WAIT
) ? 'w' :
163 #ifdef NOTE_WL_SYNC_IPC
164 (ff
& NOTE_WL_SYNC_IPC
) ? 'i' : '-',
166 (ff
& NOTE_WL_SYNC_WAKE
) ? 'W' : '-',
167 (ff
& NOTE_WL_UPDATE_QOS
) ? 'q' : '-',
168 (ff
& NOTE_WL_DISCOVER_OWNER
) ? 'o' : '-',
169 (ff
& NOTE_WL_IGNORE_ESTALE
) ? 'e' : '-'
174 snprintf(str
, len
, "");
183 filter_is_fd_type(int filter
)
186 case EVFILT_VNODE
... EVFILT_READ
:
195 thread_qos_name(uint8_t th_qos
)
206 default: return "??";
211 * find index of fd in a list of fdinfo of length nfds
214 fd_list_getfd(struct proc_fdinfo
*fds
, int nfds
, int fd
)
217 for (i
= 0; i
< nfds
; i
++) {
218 if (fds
[i
].proc_fd
== fd
) {
227 * left truncate URL-form process names
230 shorten_procname(const char *proc
, int width
)
232 if (strcasestr(proc
, "com.") == proc
) {
233 long len
= strlen(proc
);
235 return &proc
[len
- width
];
245 * stringify knote ident where possible (signals, processes)
248 print_ident(uint64_t ident
, int16_t filter
, int width
)
251 printf("%#*llx ", width
, ident
);
262 int numlen
= sprintf(num
, "%llu", ident
);
263 int strwidth
= width
- numlen
- 1; // add room for a space
265 if (filter
== EVFILT_SIGNAL
) {
266 if (ident
< ARRAYLEN(sig_strs
)) {
267 snprintf(str
, strwidth
+ 1, "%s", sig_strs
[ident
]);
270 /* FIXME: this should be cached */
271 struct proc_bsdinfo bsdinfo
;
272 int ret
= proc_pidinfo((int)ident
, PROC_PIDTBSDINFO
, 0, &bsdinfo
, sizeof(bsdinfo
));
273 if (ret
== sizeof(bsdinfo
)) {
274 char *procname
= bsdinfo
.pbi_name
;
275 if (strlen(procname
) == 0) {
276 procname
= bsdinfo
.pbi_comm
;
278 snprintf(str
, strwidth
+ 1, "%s", shorten_procname(procname
, strwidth
));
282 if (str
[0] != '\0') {
283 snprintf(out
, width
+ 1, "%-*s %s", strwidth
, str
, num
);
285 snprintf(out
, width
+ 1, "%s", num
);
288 printf("%*s ", width
, out
);
292 case EVFILT_MACHPORT
:
294 /* hex, to match lsmp */
295 printf("%#*llx ", width
, ident
);
298 case EVFILT_WORKLOOP
:
299 printf("%#*llx ", width
, ident
);
303 printf("%*llu ", width
, ident
);
310 print_kqid(int state
, uint64_t kqid
)
312 if (state
& KQ_WORKQ
) {
313 printf("%18s ", "wq");
314 } else if (state
& KQ_WORKLOOP
) {
315 printf("%#18" PRIx64
" ", kqid
);
317 printf("fd %15" PRIi64
" ", kqid
);
321 #define PROCNAME_WIDTH 20
324 print_kq_info(int pid
, const char *procname
, uint64_t kqid
, int state
)
328 print_kqid(state
, kqid
);
329 printf("%#10x ", state
);
331 char tmpstr
[PROCNAME_WIDTH
+1];
332 strlcpy(tmpstr
, shorten_procname(procname
, PROCNAME_WIDTH
), PROCNAME_WIDTH
+1);
333 printf("%-*s ", PROCNAME_WIDTH
, tmpstr
);
335 print_kqid(state
, kqid
);
337 (state
& KQ_SLEEP
) ? 'k' : '-',
338 (state
& KQ_SEL
) ? 's' : '-',
339 (state
& KQ_WORKQ
) ? 'q' :
340 (state
& KQ_WORKLOOP
) ? 'l' : '-'
350 #define POLICY_TIMESHARE 1
352 #define POLICY_FIFO 4
355 process_kqueue(int pid
, const char *procname
, enum kqtype type
, uint64_t kqid
,
356 struct proc_fdinfo
*fdlist
, int nfds
)
360 int maxknotes
= 256; /* arbitrary starting point */
362 bool is_kev_64
, is_kev_qos
;
364 bool overflow
= false;
366 bool dynkq_printed
= false;
369 * get the basic kqueue info
371 struct kqueue_fdinfo kqfdinfo
= {};
372 struct kqueue_dyninfo kqinfo
= {};
375 ret
= proc_pidfdinfo(pid
, (int)kqid
, PROC_PIDFDKQUEUEINFO
, &kqfdinfo
, sizeof(kqfdinfo
));
379 ret
= proc_piddynkqueueinfo(pid
, PROC_PIDDYNKQUEUE_INFO
, kqid
, &kqinfo
, sizeof(kqinfo
));
382 os_crash("invalid kqueue type");
385 if (type
== KQTYPE_FD
&& (int)kqid
!= -1) {
386 if (ret
!= sizeof(kqfdinfo
)) {
387 /* every proc has an implicit workq kqueue, dont warn if its unused */
388 fprintf(stderr
, "WARN: FD table changed (pid %i, kq %i)\n", pid
,
391 } else if (type
== KQTYPE_DYNAMIC
) {
392 if (ret
< sizeof(struct kqueue_info
)) {
393 fprintf(stderr
, "WARN: kqueue missing (pid %i, kq %#" PRIx64
")\n",
396 kqfdinfo
.kqueueinfo
= kqinfo
.kqdi_info
;
398 if (verbose
&& ret
>= sizeof(struct kqueue_dyninfo
)) {
399 print_kq_info(pid
, procname
, kqid
, kqinfo
.kqdi_info
.kq_state
);
401 if (kqinfo
.kqdi_owner
) {
402 printf("%#18llx ", kqinfo
.kqdi_owner
); // ident
403 printf("%-9s ", "WL owned"); // filter
404 } else if (kqinfo
.kqdi_servicer
) {
405 printf("%#18llx ", kqinfo
.kqdi_servicer
); // ident
406 printf("%-9s ", "WL"); // filter
408 printf("%18s ", "-"); // ident
409 printf("%-9s ", "WL"); // filter
411 dynkq_printed
= true;
414 printf("%-10s ", " "); // fflags
415 printf("%-10s ", " "); // flags
416 printf("%-10s ", " "); // evst
418 const char *reqstate
= "???";
420 switch (kqinfo
.kqdi_request_state
) {
421 case WORKQ_TR_STATE_IDLE
:
424 case WORKQ_TR_STATE_NEW
:
427 case WORKQ_TR_STATE_QUEUED
:
430 case WORKQ_TR_STATE_CANCELED
:
431 reqstate
= "canceled";
433 case WORKQ_TR_STATE_BINDING
:
434 reqstate
= "binding";
436 case WORKQ_TR_STATE_BOUND
:
441 printf("%-8s ", reqstate
); // fdtype
443 switch (kqinfo
.kqdi_pol
) {
449 case POLICY_TIMESHARE
:
455 snprintf(tmpstr
, 4, "%c%c%c", (kqinfo
.kqdi_pri
== 0)?'-':'P', policy_type
, (kqinfo
.kqdi_cpupercent
== 0)?'-':'%');
456 printf("%-7s ", tmpstr
); // fflags
457 printf("%-15s ", " "); // flags
458 printf("%-15s ", " "); // evst
461 if (!raw
&& kqinfo
.kqdi_pri
!= 0) {
462 printf("%3d ", kqinfo
.kqdi_pri
); //qos
464 int qos
= MAX(MAX(kqinfo
.kqdi_events_qos
, kqinfo
.kqdi_async_qos
),
465 kqinfo
.kqdi_sync_waiter_qos
);
466 printf("%3s ", thread_qos_name(qos
)); //qos
473 * get extended kqueue info
475 struct kevent_extinfo
*kqextinfo
= NULL
;
478 kqextinfo
= malloc(sizeof(struct kevent_extinfo
) * maxknotes
);
482 perror("failed allocating memory");
489 nknotes
= proc_pidfdinfo(pid
, fd
, PROC_PIDFDKQUEUE_EXTINFO
,
490 kqextinfo
, sizeof(struct kevent_extinfo
) * maxknotes
);
493 nknotes
= proc_piddynkqueueinfo(pid
, PROC_PIDDYNKQUEUE_EXTINFO
, kqid
,
494 kqextinfo
, sizeof(struct kevent_extinfo
) * maxknotes
);
497 os_crash("invalid kqueue type");
502 /* proc_*() can't distinguish between error and empty list */
503 } else if (errno
== EAGAIN
) {
505 } else if (errno
== EBADF
) {
506 fprintf(stderr
, "WARN: FD table changed (pid %i, kq %#" PRIx64
")\n", pid
, kqid
);
510 perror("failed to get extended kqueue info");
515 if (nknotes
> maxknotes
) {
516 maxknotes
= nknotes
+ 16; /* arbitrary safety margin */
522 if (nknotes
>= PROC_PIDFDKQUEUE_KNOTES_MAX
) {
526 kq_state
= kqfdinfo
.kqueueinfo
.kq_state
;
527 is_kev_64
= (kq_state
& PROC_KQUEUE_64
);
528 is_kev_qos
= (kq_state
& PROC_KQUEUE_QOS
);
531 if (!ignore_empty
&& !dynkq_printed
) {
532 /* for empty kqueues, print a single empty entry */
533 print_kq_info(pid
, procname
, kqid
, kq_state
);
534 printf("%18s \n", "-");
539 for (i
= 0; i
< nknotes
; i
++) {
540 struct kevent_extinfo
*info
= &kqextinfo
[i
];
542 print_kq_info(pid
, procname
, kqid
, kqfdinfo
.kqueueinfo
.kq_state
);
543 print_ident(info
->kqext_kev
.ident
, info
->kqext_kev
.filter
, 18);
544 printf("%-9s ", filt_name(info
->kqext_kev
.filter
));
547 printf("%#10x ", info
->kqext_sfflags
);
548 printf("%#10x ", info
->kqext_kev
.flags
);
549 printf("%#10x ", info
->kqext_status
);
551 /* for kevents attached to file descriptors, print the type of FD (file, socket, etc) */
552 const char *fdstr
= "";
553 if (filter_is_fd_type(info
->kqext_kev
.filter
)) {
555 int knfd
= fd_list_getfd(fdlist
, nfds
, (int)info
->kqext_kev
.ident
);
557 fdstr
= fdtype_str(fdlist
[knfd
].proc_fdtype
);
560 printf("%-8s ", fdstr
);
562 /* print filter flags */
563 printf("%7s ", fflags_build(info
, tmpstr
, sizeof(tmpstr
)));
565 /* print generic flags */
566 unsigned flg
= info
->kqext_kev
.flags
;
567 printf("%c%c%c%c %c%c%c%c %c%c%c%c%c ",
568 (flg
& EV_ADD
) ? 'a' : '-',
569 (flg
& EV_ENABLE
) ? 'n' : '-',
570 (flg
& EV_DISABLE
) ? 'd' : '-',
571 (flg
& EV_DELETE
) ? 'x' : '-',
573 (flg
& EV_RECEIPT
) ? 'r' : '-',
574 (flg
& EV_ONESHOT
) ? '1' : '-',
575 (flg
& EV_CLEAR
) ? 'c' : '-',
576 (flg
& EV_DISPATCH
) ? 's' : '-',
578 (flg
& EV_UDATA_SPECIFIC
) ? 'u' : '-',
579 (flg
& EV_FLAG0
) ? 'p' : '-',
580 (flg
& EV_FLAG1
) ? 'b' : '-',
581 (flg
& EV_EOF
) ? 'o' : '-',
582 (flg
& EV_ERROR
) ? 'e' : '-'
585 unsigned st
= info
->kqext_status
;
586 printf("%c%c%c%c%c %c%c%c%c %c%c%c ",
587 (st
& KN_ACTIVE
) ? 'a' : '-',
588 (st
& KN_QUEUED
) ? 'q' : '-',
589 (st
& KN_DISABLED
) ? 'd' : '-',
590 (st
& KN_SUPPRESSED
) ? 'p' : '-',
591 (st
& KN_STAYACTIVE
) ? 's' : '-',
593 (st
& KN_DROPPING
) ? 'd' : '-',
594 (st
& KN_LOCKED
) ? 'l' : '-',
595 (st
& KN_POSTING
) ? 'P' : '-',
596 (st
& KN_MERGE_QOS
) ? 'm' : '-',
598 (st
& KN_DEFERDELETE
) ? 'D' : '-',
599 (st
& KN_REQVANISH
) ? 'v' : '-',
600 (st
& KN_VANISHED
) ? 'n' : '-'
604 printf("%3s ", thread_qos_name(info
->kqext_kev
.qos
));
606 printf("%#18llx ", (unsigned long long)info
->kqext_kev
.data
);
609 printf("%#18llx ", (unsigned long long)info
->kqext_kev
.udata
);
610 if (is_kev_qos
|| is_kev_64
) {
611 printf("%#18llx ", (unsigned long long)info
->kqext_kev
.ext
[0]);
612 printf("%#18llx ", (unsigned long long)info
->kqext_kev
.ext
[1]);
615 printf("%#18llx ", (unsigned long long)info
->kqext_kev
.ext
[2]);
616 printf("%#18llx ", (unsigned long long)info
->kqext_kev
.ext
[3]);
617 printf("%#10lx ", (unsigned long)info
->kqext_kev
.xflags
);
626 printf(" ***** output truncated (>=%i knotes on kq %" PRIu64
", proc %i) *****\n",
640 pid_kqids(pid_t pid
, kqueue_id_t
**kqids_out
)
642 static int kqids_len
= 256;
643 static kqueue_id_t
*kqids
= NULL
;
644 static uint32_t kqids_size
;
649 if (os_mul_overflow(sizeof(kqueue_id_t
), kqids_len
, &kqids_size
)) {
650 assert(kqids_len
> PROC_PIDDYNKQUEUES_MAX
);
651 kqids_len
= PROC_PIDDYNKQUEUES_MAX
;
655 kqids
= malloc(kqids_size
);
656 os_assert(kqids
!= NULL
);
659 nkqids
= proc_list_dynkqueueids(pid
, kqids
, kqids_size
);
660 if (nkqids
> kqids_len
&& kqids_len
< PROC_PIDDYNKQUEUES_MAX
) {
662 if (kqids_len
> PROC_PIDDYNKQUEUES_MAX
) {
663 kqids_len
= PROC_PIDDYNKQUEUES_MAX
;
671 return MIN(nkqids
, kqids_len
);
675 process_pid(pid_t pid
)
680 int maxfds
= 256; /* arbitrary starting point */
681 struct proc_fdinfo
*fdlist
= NULL
;
683 /* enumerate file descriptors */
686 fdlist
= malloc(sizeof(struct proc_fdinfo
) * maxfds
);
690 perror("failed to allocate");
694 nfds
= proc_pidinfo(pid
, PROC_PIDLISTFDS
, 0, fdlist
,
695 sizeof(struct proc_fdinfo
) * maxfds
);
698 fprintf(stderr
, "%s: failed enumerating file descriptors of process %i: %s",
699 self
, pid
, strerror(ret
));
700 if (ret
== EPERM
&& geteuid() != 0) {
701 fprintf(stderr
, " (are you root?)");
703 fprintf(stderr
, "\n");
707 nfds
/= sizeof(struct proc_fdinfo
);
708 if (nfds
>= maxfds
) {
715 /* get bsdinfo for the process name */
716 struct proc_bsdinfo bsdinfo
;
717 ret
= proc_pidinfo(pid
, PROC_PIDTBSDINFO
, 0, &bsdinfo
, sizeof(bsdinfo
));
718 if (ret
!= sizeof(bsdinfo
)) {
719 perror("failed retrieving process info");
724 char *procname
= bsdinfo
.pbi_name
;
725 if (strlen(procname
) == 0) {
726 procname
= bsdinfo
.pbi_comm
;
729 /* handle the special workq kq */
730 ret
= process_kqueue(pid
, procname
, KQTYPE_FD
, -1, fdlist
, nfds
);
735 for (i
= 0; i
< nfds
; i
++) {
736 if (fdlist
[i
].proc_fdtype
== PROX_FDTYPE_KQUEUE
) {
737 ret
= process_kqueue(pid
, procname
, KQTYPE_FD
,
738 (uint64_t)fdlist
[i
].proc_fd
, fdlist
, nfds
);
745 nkqids
= pid_kqids(pid
, &kqids
);
747 for (i
= 0; i
< nkqids
; i
++) {
748 ret
= process_kqueue(pid
, procname
, KQTYPE_DYNAMIC
, kqids
[i
], fdlist
, nfds
);
754 if (nkqids
>= PROC_PIDDYNKQUEUES_MAX
) {
755 printf(" ***** output truncated (>=%i dynamic kqueues in proc %i) *****\n",
769 process_all_pids(void)
778 pids
= malloc(sizeof(int) * maxpids
);
781 perror("failed allocating pids[]");
786 npids
= proc_listpids(PROC_ALL_PIDS
, 0, pids
, sizeof(int) * maxpids
);
790 } else if (errno
== EAGAIN
) {
794 perror("failed enumerating pids");
799 npids
/= sizeof(int);
800 if (npids
>= maxpids
) {
801 maxpids
= npids
+ 16;
807 for (i
= 0; i
< npids
; i
++) {
808 /* listpids gives us pid 0 for some reason */
810 ret
= process_pid(pids
[i
]);
811 /* ignore races with processes exiting */
812 if (ret
&& ret
!= ESRCH
) {
830 const char *bold
= "\033[1m";
831 const char *reset
= "\033[0m";
832 if (!isatty(STDERR_FILENO
)) {
836 fprintf(stderr
, "\nFilter-independent flags:\n\n\
838 command pid kq kqst knid filter fdtype fflags flags evst qos%s\n%s\
839 -------------------- ----- ------------------ ---- ------------------ --------- -------- ------- --------------- -------------- ---%s\n\
840 ┌ EV_UDATA_SPECIFIC\n\
841 EV_DISPATCH ┐ │┌ EV_FLAG0 (EV_POLL)\n\
842 EV_CLEAR ┐│ ││┌ EV_FLAG1 (EV_OOBAND)\n\
843 EV_ONESHOT ┐││ │││┌ EV_EOF\n\
844 EV_RECEIPT ┐│││ ││││┌ EV_ERROR\n\
846 launchd 1 4 ks- netbiosd 250 PROC ------- andx r1cs upboe aqdps dlPm Dvn IN%s\n\
847 │ │││ ││││ │││││ ││││ │││\n\
848 kqueue file descriptor/dynamic ID ┘ │││ EV_ADD ┘│││ KN_ACTIVE ┘││││ ││││ ││└ KN_VANISHED\n\
849 KQ_SLEEP ┘││ EV_ENABLE ┘││ KN_QUEUED ┘│││ ││││ │└ KN_REQVANISH\n\
850 KQ_SEL ┘│ EV_DISABLE ┘│ KN_DISABLED ┘││ ││││ └ KN_DEFERDELETE\n\
851 KQ_WORKQ (q) ┤ EV_DELETE ┘ KN_SUPPRESSED ┘│ ││││\n\
852 KQ_WORKLOOP (l) ┘ KN_STAYACTIVE ┘ ││││\n\
854 KN_DROPPING ┘││└ KN_MERGE_QOS\n\
855 KN_LOCKED ┘└ KN_POSTING\n\
856 \n", bold
, reset
, bold
, reset
, bold
, reset
);
862 fprintf(stderr
, "usage: %s [-vher] [-a | -p <pid>]\n", self
);
869 printf(" pid kq kqst knid filter fflags flags evst qos data");
871 printf("command pid kq kqst knid filter fdtype fflags flags evst qos data");
875 printf(" udata ext0 ext1 ext2 ext3 xflags");
881 printf("----- ------------------ ---------- ------------------ --------- ---------- ---------- ---------- --- ------------------");
883 printf("-------------------- ----- ------------------ ---- ------------------ --------- -------- ------- --------------- -------------- --- ------------------");
887 printf(" ------------------ ------------------ ------------------ ------------------ ------------------ ----------");
893 main(int argc
, char *argv
[])
904 while ((opt
= getopt(argc
, argv
, "eahvrp:")) != -1) {
936 /* also allow lskq <pid> */
937 if (pid
|| all_pids
) {
943 } else if (argc
> 1) {
948 /* exactly one of -p or -a is required */
949 if (!pid
&& !all_pids
) {
952 } else if (pid
&& all_pids
) {
960 return process_all_pids();
962 return process_pid(pid
);