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