1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
25 */
26 /*
27 * Copyright (c) 2017 Joyent, Inc. All Rights reserved.
28 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
29 * Copyright 2024 Oxide Computer Company
30 */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <signal.h>
39 #include <dirent.h>
40 #include <limits.h>
41 #include <door.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/stat.h>
45 #include <sys/mkdev.h>
46 #include <sys/stropts.h>
47 #include <sys/timod.h>
48 #include <sys/un.h>
49 #include <libproc.h>
50 #include <netinet/in.h>
51 #include <netinet/udp.h>
52 #include <arpa/inet.h>
53 #include <ucred.h>
54 #include <zone.h>
55
56 static char *command;
57 static volatile int interrupt;
58 static int Fflag;
59 static boolean_t nflag = B_FALSE;
60
61 static void intr(int);
62 static void dofcntl(struct ps_prochandle *, const prfdinfo_t *, int, int);
63 static void dosocket(struct ps_prochandle *, const prfdinfo_t *);
64 static void dosocknames(struct ps_prochandle *, const prfdinfo_t *);
65 static void dofifo(struct ps_prochandle *, const prfdinfo_t *);
66 static void show_files(struct ps_prochandle *);
67 static void show_fileflags(int);
68 static void show_door(struct ps_prochandle *, const prfdinfo_t *);
69
70 int
main(int argc,char ** argv)71 main(int argc, char **argv)
72 {
73 int retc = 0;
74 int opt;
75 int errflg = 0;
76 struct ps_prochandle *Pr;
77
78 if ((command = strrchr(argv[0], '/')) != NULL)
79 command++;
80 else
81 command = argv[0];
82
83 /* options */
84 while ((opt = getopt(argc, argv, "Fn")) != EOF) {
85 switch (opt) {
86 case 'F': /* force grabbing (no O_EXCL) */
87 Fflag = PGRAB_FORCE;
88 break;
89 case 'n':
90 nflag = B_TRUE;
91 break;
92 default:
93 errflg = 1;
94 break;
95 }
96 }
97
98 argc -= optind;
99 argv += optind;
100
101 if (errflg || argc <= 0) {
102 (void) fprintf(stderr, "usage:\t%s [-F] { pid | core } ...\n",
103 command);
104 (void) fprintf(stderr,
105 " (report open files of each process)\n");
106 (void) fprintf(stderr,
107 " -F: force grabbing of the target process\n");
108 exit(2);
109 }
110
111 /* catch signals from terminal */
112 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
113 (void) sigset(SIGHUP, intr);
114 if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
115 (void) sigset(SIGINT, intr);
116 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
117 (void) sigset(SIGQUIT, intr);
118 (void) sigset(SIGPIPE, intr);
119 (void) sigset(SIGTERM, intr);
120
121 (void) proc_initstdio();
122
123
124 while (--argc >= 0 && !interrupt) {
125 char *arg;
126 psinfo_t psinfo;
127 pid_t pid;
128 int gret;
129
130 (void) proc_flushstdio();
131
132 arg = *argv++;
133
134 /* get the specified pid and the psinfo struct */
135 if ((pid = proc_arg_psinfo(arg, PR_ARG_PIDS,
136 &psinfo, &gret)) == -1) {
137
138 if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_CORES,
139 Fflag, &gret, NULL)) == NULL) {
140 (void) fprintf(stderr,
141 "%s: cannot examine %s: %s\n",
142 command, arg, Pgrab_error(gret));
143 retc++;
144 continue;
145 }
146 if (proc_arg_psinfo(arg, PR_ARG_ANY, &psinfo,
147 &gret) < 0) {
148 (void) fprintf(stderr,
149 "%s: cannot examine %s: %s\n",
150 command, arg, Pgrab_error(gret));
151 retc++;
152 Prelease(Pr, 0);
153 continue;
154 }
155 (void) printf("core '%s' of %d:\t%.70s\n",
156 arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
157
158 show_files(Pr);
159 Prelease(Pr, 0);
160
161 } else if ((Pr = Pgrab(pid, Fflag, &gret)) != NULL) {
162 if (Pcreate_agent(Pr) == 0) {
163 proc_unctrl_psinfo(&psinfo);
164 (void) printf("%d:\t%.70s\n",
165 (int)pid, psinfo.pr_psargs);
166 show_files(Pr);
167 Pdestroy_agent(Pr);
168 } else {
169 (void) fprintf(stderr,
170 "%s: cannot control process %d\n",
171 command, (int)pid);
172 retc++;
173 }
174 Prelease(Pr, 0);
175 Pr = NULL;
176 } else {
177 switch (gret) {
178 case G_SYS:
179 proc_unctrl_psinfo(&psinfo);
180 (void) printf("%d:\t%.70s\n", (int)pid,
181 psinfo.pr_psargs);
182 (void) printf(" [system process]\n");
183 break;
184 default:
185 (void) fprintf(stderr, "%s: %s: %d\n",
186 command, Pgrab_error(gret), (int)pid);
187 retc++;
188 break;
189 }
190 }
191 }
192
193 (void) proc_finistdio();
194
195 if (interrupt && retc == 0)
196 retc++;
197 return (retc);
198 }
199
200 /* ARGSUSED */
201 static void
intr(int sig)202 intr(int sig)
203 {
204 interrupt = 1;
205 }
206
207 /* ------ begin specific code ------ */
208
209 static int
show_paths(uint_t type,const void * data,size_t len,void * arg __unused)210 show_paths(uint_t type, const void *data, size_t len, void *arg __unused)
211 {
212 if (type == PR_PATHNAME)
213 (void) printf(" %.*s\n", len, data);
214 return (0);
215 }
216
217 static int
show_file(void * data,const prfdinfo_t * info)218 show_file(void *data, const prfdinfo_t *info)
219 {
220 struct ps_prochandle *Pr = data;
221 char unknown[12];
222 char *s;
223 mode_t mode;
224
225 if (interrupt)
226 return (1);
227
228 mode = info->pr_mode;
229
230 switch (mode & S_IFMT) {
231 case S_IFCHR: s = "S_IFCHR"; break;
232 case S_IFBLK: s = "S_IFBLK"; break;
233 case S_IFIFO: s = "S_IFIFO"; break;
234 case S_IFDIR: s = "S_IFDIR"; break;
235 case S_IFREG: s = "S_IFREG"; break;
236 case S_IFLNK: s = "S_IFLNK"; break;
237 case S_IFSOCK: s = "S_IFSOCK"; break;
238 case S_IFDOOR: s = "S_IFDOOR"; break;
239 case S_IFPORT: s = "S_IFPORT"; break;
240 default:
241 s = unknown;
242 (void) sprintf(s, "0x%.4x ", (int)mode & S_IFMT);
243 break;
244 }
245
246 (void) printf("%4d: %s mode:0%.3o", info->pr_fd, s,
247 (int)mode & ~S_IFMT);
248
249 (void) printf(" dev:%u,%u",
250 (unsigned)info->pr_major, (unsigned)info->pr_minor);
251
252 if ((mode & S_IFMT) == S_IFPORT) {
253 (void) printf(" uid:%d gid:%d",
254 (int)info->pr_uid, (int)info->pr_gid);
255 (void) printf(" size:%lld\n", (longlong_t)info->pr_size);
256 return (0);
257 }
258
259 (void) printf(" ino:%llu uid:%d gid:%d",
260 (u_longlong_t)info->pr_ino, (int)info->pr_uid, (int)info->pr_gid);
261
262 if ((info->pr_rmajor == (major_t)NODEV) &&
263 (info->pr_rminor == (minor_t)NODEV))
264 (void) printf(" size:%lld\n", (longlong_t)info->pr_size);
265 else
266 (void) printf(" rdev:%u,%u\n",
267 (unsigned)info->pr_rmajor, (unsigned)info->pr_rminor);
268
269 if (!nflag) {
270 dofcntl(Pr, info,
271 (mode & (S_IFMT|S_ENFMT|S_IXGRP)) == (S_IFREG|S_ENFMT),
272 (mode & S_IFMT) == S_IFDOOR);
273
274 if (Pstate(Pr) != PS_DEAD) {
275 switch (mode & S_IFMT) {
276 case S_IFSOCK:
277 dosocket(Pr, info);
278 break;
279 case S_IFIFO:
280 dofifo(Pr, info);
281 break;
282 case S_IFCHR:
283 /*
284 * This may be a TLI endpoint. If so, it will
285 * have socket names in the fdinfo and this
286 * will print them.
287 */
288 dosocknames(Pr, info);
289 break;
290 }
291 }
292
293 (void) proc_fdinfowalk(info, show_paths, NULL);
294
295 if (info->pr_offset != -1) {
296 (void) printf(" offset:%lld\n",
297 (long long)info->pr_offset);
298 }
299 }
300
301 return (0);
302 }
303
304 static void
show_files(struct ps_prochandle * Pr)305 show_files(struct ps_prochandle *Pr)
306 {
307 struct rlimit rlim;
308
309 if (pr_getrlimit(Pr, RLIMIT_NOFILE, &rlim) == 0) {
310 ulong_t nfd = rlim.rlim_cur;
311 if (nfd == RLIM_INFINITY)
312 (void) printf(
313 " Current rlimit: unlimited file descriptors\n");
314 else
315 (void) printf(
316 " Current rlimit: %lu file descriptors\n", nfd);
317 }
318
319 (void) Pfdinfo_iter(Pr, show_file, Pr);
320 }
321
322 static void
show_fdflags(int fdflags)323 show_fdflags(int fdflags)
324 {
325 if (fdflags <= 0)
326 return;
327
328 /*
329 * show_fileflags() already has printed content here. We translate these
330 * back to the O_ versions for consistency with the flags that were
331 * already printed.
332 */
333 if ((fdflags & FD_CLOEXEC) != 0) {
334 (void) printf("|O_CLOEXEC");
335 }
336
337 if ((fdflags & FD_CLOFORK) != 0) {
338 (void) printf("|O_CLOFORK");
339 }
340 }
341
342 /* examine open file with fcntl() */
343 static void
dofcntl(struct ps_prochandle * Pr,const prfdinfo_t * info,int mandatory,int isdoor)344 dofcntl(struct ps_prochandle *Pr, const prfdinfo_t *info, int mandatory,
345 int isdoor)
346 {
347 int fileflags;
348 int fdflags;
349
350 fileflags = info->pr_fileflags;
351 fdflags = info->pr_fdflags;
352
353 if (fileflags != -1 || fdflags != -1) {
354 (void) printf(" ");
355 if (fileflags != -1)
356 show_fileflags(fileflags);
357 if (fdflags != -1)
358 show_fdflags(fdflags);
359 if (isdoor && (Pstate(Pr) != PS_DEAD))
360 show_door(Pr, info);
361 (void) fputc('\n', stdout);
362 } else if (isdoor && (Pstate(Pr) != PS_DEAD)) {
363 (void) printf(" ");
364 show_door(Pr, info);
365 (void) fputc('\n', stdout);
366 }
367
368 if (Pstate(Pr) != PS_DEAD) {
369 if (info->pr_locktype != F_UNLCK &&
370 (info->pr_locksysid != -1 || info->pr_lockpid != -1)) {
371 unsigned long sysid = info->pr_locksysid;
372
373 (void) printf(" %s %s lock set",
374 mandatory ? "mandatory" : "advisory",
375 info->pr_locktype == F_RDLCK? "read" : "write");
376 if (sysid)
377 (void) printf(" by system 0x%lX", sysid);
378 if (info->pr_lockpid != -1)
379 (void) printf(" by process %d",
380 (int)info->pr_lockpid);
381 (void) fputc('\n', stdout);
382 }
383 }
384 }
385
386 #define ALL_O_FLAGS O_ACCMODE | O_NDELAY | O_NONBLOCK | O_APPEND | \
387 O_SYNC | O_DSYNC | O_RSYNC | O_XATTR | \
388 O_CREAT | O_TRUNC | O_EXCL | O_NOCTTY | O_LARGEFILE
389
390 static void
show_fileflags(int flags)391 show_fileflags(int flags)
392 {
393 char buffer[136];
394 char *str = buffer;
395
396 switch (flags & O_ACCMODE) {
397 case O_RDONLY:
398 (void) strcpy(str, "O_RDONLY");
399 break;
400 case O_WRONLY:
401 (void) strcpy(str, "O_WRONLY");
402 break;
403 case O_RDWR:
404 (void) strcpy(str, "O_RDWR");
405 break;
406 case O_SEARCH:
407 (void) strcpy(str, "O_SEARCH");
408 break;
409 case O_EXEC:
410 (void) strcpy(str, "O_EXEC");
411 break;
412 default:
413 (void) sprintf(str, "0x%x", flags & O_ACCMODE);
414 break;
415 }
416
417 if (flags & O_NDELAY)
418 (void) strcat(str, "|O_NDELAY");
419 if (flags & O_NONBLOCK)
420 (void) strcat(str, "|O_NONBLOCK");
421 if (flags & O_APPEND)
422 (void) strcat(str, "|O_APPEND");
423 if (flags & O_SYNC)
424 (void) strcat(str, "|O_SYNC");
425 if (flags & O_DSYNC)
426 (void) strcat(str, "|O_DSYNC");
427 if (flags & O_RSYNC)
428 (void) strcat(str, "|O_RSYNC");
429 if (flags & O_CREAT)
430 (void) strcat(str, "|O_CREAT");
431 if (flags & O_TRUNC)
432 (void) strcat(str, "|O_TRUNC");
433 if (flags & O_EXCL)
434 (void) strcat(str, "|O_EXCL");
435 if (flags & O_NOCTTY)
436 (void) strcat(str, "|O_NOCTTY");
437 if (flags & O_LARGEFILE)
438 (void) strcat(str, "|O_LARGEFILE");
439 if (flags & O_XATTR)
440 (void) strcat(str, "|O_XATTR");
441 if (flags & ~(ALL_O_FLAGS))
442 (void) sprintf(str + strlen(str), "|0x%x",
443 flags & ~(ALL_O_FLAGS));
444
445 (void) printf("%s", str);
446 }
447
448 /* show process on the other end of a door, socket or fifo */
449 static void
show_peer_process(pid_t ppid)450 show_peer_process(pid_t ppid)
451 {
452 psinfo_t psinfo;
453
454 if (proc_get_psinfo(ppid, &psinfo) == 0)
455 (void) printf(" %s[%d]", psinfo.pr_fname, (int)ppid);
456 else
457 (void) printf(" pid %d", (int)ppid);
458 }
459
460 /* show door info */
461 static void
show_door(struct ps_prochandle * Pr,const prfdinfo_t * info)462 show_door(struct ps_prochandle *Pr, const prfdinfo_t *info)
463 {
464 door_info_t door_info;
465
466 if (pr_door_info(Pr, info->pr_fd, &door_info) != 0)
467 return;
468
469 (void) printf(" door to");
470 show_peer_process(door_info.di_target);
471 }
472
473 /*
474 * Print out the socket address pointed to by `sa'. `len' is only
475 * needed for AF_UNIX sockets.
476 */
477 static void
show_sockaddr(const char * str,const struct sockaddr * sa,socklen_t len)478 show_sockaddr(const char *str, const struct sockaddr *sa, socklen_t len)
479 {
480 struct sockaddr_in *so_in = (struct sockaddr_in *)(void *)sa;
481 struct sockaddr_in6 *so_in6 = (struct sockaddr_in6 *)(void *)sa;
482 struct sockaddr_un *so_un = (struct sockaddr_un *)sa;
483 char abuf[INET6_ADDRSTRLEN];
484 const char *p;
485
486 if (len == 0)
487 return;
488
489 switch (sa->sa_family) {
490 default:
491 return;
492 case AF_INET:
493 (void) printf("\t%s: AF_INET %s port: %u\n", str,
494 inet_ntop(AF_INET, &so_in->sin_addr, abuf, sizeof (abuf)),
495 ntohs(so_in->sin_port));
496 return;
497 case AF_INET6:
498 (void) printf("\t%s: AF_INET6 %s port: %u\n", str,
499 inet_ntop(AF_INET6, &so_in6->sin6_addr,
500 abuf, sizeof (abuf)),
501 ntohs(so_in->sin_port));
502 return;
503 case AF_UNIX:
504 if (len >= sizeof (so_un->sun_family)) {
505 (void) printf("\t%s: AF_UNIX %.*s\n",
506 str, len - sizeof (so_un->sun_family),
507 so_un->sun_path);
508 }
509 return;
510 case AF_IMPLINK: p = "AF_IMPLINK"; break;
511 case AF_PUP: p = "AF_PUP"; break;
512 case AF_CHAOS: p = "AF_CHAOS"; break;
513 case AF_NS: p = "AF_NS"; break;
514 case AF_NBS: p = "AF_NBS"; break;
515 case AF_ECMA: p = "AF_ECMA"; break;
516 case AF_DATAKIT: p = "AF_DATAKIT"; break;
517 case AF_CCITT: p = "AF_CCITT"; break;
518 case AF_SNA: p = "AF_SNA"; break;
519 case AF_DECnet: p = "AF_DECnet"; break;
520 case AF_DLI: p = "AF_DLI"; break;
521 case AF_LAT: p = "AF_LAT"; break;
522 case AF_HYLINK: p = "AF_HYLINK"; break;
523 case AF_APPLETALK: p = "AF_APPLETALK"; break;
524 case AF_NIT: p = "AF_NIT"; break;
525 case AF_802: p = "AF_802"; break;
526 case AF_OSI: p = "AF_OSI"; break;
527 case AF_X25: p = "AF_X25"; break;
528 case AF_OSINET: p = "AF_OSINET"; break;
529 case AF_GOSIP: p = "AF_GOSIP"; break;
530 case AF_IPX: p = "AF_IPX"; break;
531 case AF_ROUTE: p = "AF_ROUTE"; break;
532 case AF_KEY: p = "AF_KEY"; break;
533 case AF_POLICY: p = "AF_POLICY"; break;
534 case AF_LINK: p = "AF_LINK"; break;
535 }
536
537 (void) printf("\t%s: %s\n", str, p);
538 }
539
540 /*
541 * Print out the process information for the other end of local sockets
542 * and fifos
543 */
544 static void
show_ucred(const char * str,ucred_t * cred)545 show_ucred(const char *str, ucred_t *cred)
546 {
547 pid_t upid = ucred_getpid(cred);
548 zoneid_t uzid = ucred_getzoneid(cred);
549 char zonename[ZONENAME_MAX];
550
551 if ((upid != -1) || (uzid != -1)) {
552 (void) printf("\t%s:", str);
553 if (upid != -1) {
554 show_peer_process(upid);
555 }
556 if (uzid != -1) {
557 if (getzonenamebyid(uzid, zonename, sizeof (zonename))
558 != -1) {
559 (void) printf(" zone: %s[%d]", zonename,
560 (int)uzid);
561 } else {
562 (void) printf(" zoneid: %d", (int)uzid);
563 }
564 }
565 (void) printf("\n");
566 }
567 }
568
569 static void
show_socktype(uint_t type)570 show_socktype(uint_t type)
571 {
572 static const char *types[] = {
573 NULL, "DGRAM", "STREAM", NULL, "RAW", "RDM", "SEQPACKET"
574 };
575
576 if (type < sizeof (types) / sizeof (*types) && types[type] != NULL)
577 (void) printf("\tSOCK_%s\n", types[type]);
578 else
579 (void) printf("\tunknown socket type %u\n", type);
580 }
581
582 #define BUFSIZE 200
583 static void
show_sockopts(struct ps_prochandle * Pr,const prfdinfo_t * info)584 show_sockopts(struct ps_prochandle *Pr, const prfdinfo_t *info)
585 {
586 const int *val;
587 size_t vlen;
588 char buf[BUFSIZE];
589 char buf1[32];
590 char ipaddr[INET_ADDRSTRLEN];
591 int i;
592 const in_addr_t *nexthop_val;
593 const prsockopts_bool_opts_t *opts;
594 struct boolopt {
595 int opt;
596 const char *name;
597 };
598 static struct boolopt boolopts[] = {
599 { PR_SO_DEBUG, "SO_DEBUG," },
600 { PR_SO_REUSEADDR, "SO_REUSEADDR," },
601 { PR_SO_KEEPALIVE, "SO_KEEPALIVE," },
602 { PR_SO_DONTROUTE, "SO_DONTROUTE," },
603 { PR_SO_BROADCAST, "SO_BROADCAST," },
604 { PR_SO_OOBINLINE, "SO_OOBINLINE," },
605 { PR_SO_DGRAM_ERRIND, "SO_DGRAM_ERRIND,"},
606 { PR_SO_ALLZONES, "SO_ALLZONES," },
607 { PR_SO_MAC_EXEMPT, "SO_MAC_EXEMPT," },
608 { PR_SO_MAC_IMPLICIT, "SO_MAC_IMPLICIT," },
609 { PR_SO_EXCLBIND, "SO_EXCLBIND," },
610 { PR_SO_VRRP, "SO_VRRP," },
611 { PR_UDP_NAT_T_ENDPOINT, "UDP_NAT_T_ENDPOINT," },
612 };
613 const struct linger *l;
614
615 opts = proc_fdinfo_misc(info, PR_SOCKOPTS_BOOL_OPTS, NULL);
616
617 buf[0] = '!'; /* sentinel value, never printed */
618 buf[1] = '\0';
619
620 for (i = 0; i < sizeof (boolopts) / sizeof (boolopts[0]); i++) {
621 if (opts != NULL && opts->prsock_bool_opts & boolopts[i].opt)
622 (void) strlcat(buf, boolopts[i].name, sizeof (buf));
623 }
624
625 l = proc_fdinfo_misc(info, PR_SOCKOPT_LINGER, NULL);
626 if (l != NULL && l->l_onoff != 0) {
627 (void) snprintf(buf1, sizeof (buf1), "SO_LINGER(%d),",
628 l->l_linger);
629 (void) strlcat(buf, buf1, sizeof (buf));
630 }
631
632 val = proc_fdinfo_misc(info, PR_SOCKOPT_SNDBUF, NULL);
633 if (val != NULL) {
634 (void) snprintf(buf1, sizeof (buf1), "SO_SNDBUF(%d),", *val);
635 (void) strlcat(buf, buf1, sizeof (buf));
636 }
637
638 val = proc_fdinfo_misc(info, PR_SOCKOPT_RCVBUF, NULL);
639 if (val != NULL) {
640 (void) snprintf(buf1, sizeof (buf1), "SO_RCVBUF(%d),", *val);
641 (void) strlcat(buf, buf1, sizeof (buf));
642 }
643
644
645 nexthop_val = proc_fdinfo_misc(info, PR_SOCKOPT_IP_NEXTHOP, &vlen);
646 if (nexthop_val != NULL && vlen > 0) {
647 (void) inet_ntop(AF_INET, (void *) nexthop_val,
648 ipaddr, sizeof (ipaddr));
649 (void) snprintf(buf1, sizeof (buf1), "IP_NEXTHOP(%s),",
650 ipaddr);
651 (void) strlcat(buf, buf1, sizeof (buf));
652 }
653
654 buf[strlen(buf) - 1] = '\0'; /* overwrites sentinel if no options */
655 if (buf[1] != '\0')
656 (void) printf("\t%s\n", buf+1);
657 }
658
659 #define MAXNALLOC 32
660 static void
show_sockfilters(struct ps_prochandle * Pr,const prfdinfo_t * info)661 show_sockfilters(struct ps_prochandle *Pr, const prfdinfo_t *info)
662 {
663 struct fil_info *fi;
664 int i = 0, nalloc = 2, len = nalloc * sizeof (*fi);
665 boolean_t printhdr = B_TRUE;
666 int fd = info->pr_fd;
667
668 fi = calloc(nalloc, sizeof (*fi));
669 if (fi == NULL) {
670 perror("calloc");
671 return;
672 }
673 /* CONSTCOND */
674 while (1) {
675 if (pr_getsockopt(Pr, fd, SOL_FILTER, FIL_LIST, fi, &len) != 0)
676 break;
677 /* No filters */
678 if (len == 0)
679 break;
680 /* Make sure buffer was large enough */
681 if (fi->fi_pos >= nalloc) {
682 struct fil_info *new;
683
684 nalloc = fi->fi_pos + 1;
685 if (nalloc > MAXNALLOC)
686 break;
687 len = nalloc * sizeof (*fi);
688 new = realloc(fi, nalloc * sizeof (*fi));
689 if (new == NULL) {
690 perror("realloc");
691 break;
692 }
693 fi = new;
694 continue;
695 }
696
697 for (i = 0; (i + 1) * sizeof (*fi) <= len; i++) {
698 if (fi[i].fi_flags & FILF_BYPASS)
699 continue;
700 if (printhdr) {
701 (void) printf("\tfilters: ");
702 printhdr = B_FALSE;
703 }
704 (void) printf("%s", fi[i].fi_name);
705 if (fi[i].fi_flags != 0) {
706 (void) printf("(");
707 if (fi[i].fi_flags & FILF_AUTO)
708 (void) printf("auto,");
709 if (fi[i].fi_flags & FILF_PROG)
710 (void) printf("prog,");
711 (void) printf("\b)");
712 }
713 if (fi[i].fi_pos == 0) /* last one */
714 break;
715 (void) printf(",");
716 }
717 if (!printhdr)
718 (void) printf("\n");
719 break;
720 }
721 free(fi);
722 }
723
724 /* print peer credentials for sockets and named pipes */
725 static void
dopeerucred(struct ps_prochandle * Pr,const prfdinfo_t * info)726 dopeerucred(struct ps_prochandle *Pr, const prfdinfo_t *info)
727 {
728 ucred_t *peercred = NULL; /* allocated by getpeerucred */
729
730 if (pr_getpeerucred(Pr, info->pr_fd, &peercred) == 0) {
731 show_ucred("peer", peercred);
732 ucred_free(peercred);
733 }
734 }
735
736 static void
dosocknames(struct ps_prochandle * Pr,const prfdinfo_t * info)737 dosocknames(struct ps_prochandle *Pr, const prfdinfo_t *info)
738 {
739 const struct sockaddr *sa;
740 size_t vlen;
741
742 sa = proc_fdinfo_misc(info, PR_SOCKETNAME, &vlen);
743 if (sa != NULL)
744 show_sockaddr("sockname", sa, vlen);
745
746 sa = proc_fdinfo_misc(info, PR_PEERSOCKNAME, &vlen);
747 if (sa != NULL)
748 show_sockaddr("peername", sa, vlen);
749 }
750
751 /* the file is a socket */
752 static void
dosocket(struct ps_prochandle * Pr,const prfdinfo_t * info)753 dosocket(struct ps_prochandle *Pr, const prfdinfo_t *info)
754 {
755 const int *type;
756
757 type = proc_fdinfo_misc(info, PR_SOCKOPT_TYPE, NULL);
758 if (type != NULL)
759 show_socktype((uint_t)*type);
760
761 show_sockopts(Pr, info);
762 show_sockfilters(Pr, info);
763 dosocknames(Pr, info);
764 dopeerucred(Pr, info);
765 }
766
767 /* the file is a fifo (aka "named pipe") */
768 static void
dofifo(struct ps_prochandle * Pr,const prfdinfo_t * info)769 dofifo(struct ps_prochandle *Pr, const prfdinfo_t *info)
770 {
771 dopeerucred(Pr, info);
772 }
773