19b50d902SRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
40daf62d9SStanislav Sedov * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
59b50d902SRodney W. Grimes * Copyright (c) 1988, 1993
69b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved.
79b50d902SRodney W. Grimes *
89b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
99b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions
109b50d902SRodney W. Grimes * are met:
119b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
129b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
139b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
149b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
159b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution.
16fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
179b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software
189b50d902SRodney W. Grimes * without specific prior written permission.
199b50d902SRodney W. Grimes *
209b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
219b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
249b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309b50d902SRodney W. Grimes * SUCH DAMAGE.
319b50d902SRodney W. Grimes */
329b50d902SRodney W. Grimes
339b50d902SRodney W. Grimes #include <sys/param.h>
349b50d902SRodney W. Grimes #include <sys/user.h>
359b50d902SRodney W. Grimes #include <sys/stat.h>
369b50d902SRodney W. Grimes #include <sys/socket.h>
379b50d902SRodney W. Grimes #include <sys/socketvar.h>
389b50d902SRodney W. Grimes #include <sys/sysctl.h>
39d2bccb9fSDavid Greenman #include <sys/queue.h>
4091ad311bSJeremie Le Hen #include <sys/un.h>
419b50d902SRodney W. Grimes
429b50d902SRodney W. Grimes #include <netinet/in.h>
439b50d902SRodney W. Grimes
4491ad311bSJeremie Le Hen #include <arpa/inet.h>
4591ad311bSJeremie Le Hen
460daf62d9SStanislav Sedov #include <assert.h>
479b50d902SRodney W. Grimes #include <ctype.h>
48c1e65942SPhilippe Charnier #include <err.h>
490daf62d9SStanislav Sedov #include <libprocstat.h>
50df3f5d9dSPeter Wemm #include <limits.h>
519b50d902SRodney W. Grimes #include <pwd.h>
5276db9ccfSWarner Losh #include <stdint.h>
539b50d902SRodney W. Grimes #include <stdio.h>
549b50d902SRodney W. Grimes #include <stdlib.h>
5505427aafSKonstantin Belousov #include <stddef.h>
569b50d902SRodney W. Grimes #include <string.h>
57df3f5d9dSPeter Wemm #include <unistd.h>
580b7a57ddSRuslan Ermilov #include <netdb.h>
599b50d902SRodney W. Grimes
600daf62d9SStanislav Sedov #include "functions.h"
619b50d902SRodney W. Grimes
62357050fcSEd Schouten static int fsflg, /* show files on same filesystem as file(s) argument */
639b50d902SRodney W. Grimes pflg, /* show files open by a particular pid */
6491ad311bSJeremie Le Hen sflg, /* show socket details */
659b50d902SRodney W. Grimes uflg; /* show files open by a particular (effective) user */
66357050fcSEd Schouten static int checkfile; /* restrict to particular files or filesystems */
67357050fcSEd Schouten static int nflg; /* (numerical) display f.s. and rdev as dev_t */
68357050fcSEd Schouten static int mflg; /* include memory-mapped files */
69357050fcSEd Schouten static int vflg; /* be verbose */
709b50d902SRodney W. Grimes
710daf62d9SStanislav Sedov typedef struct devs {
720daf62d9SStanislav Sedov struct devs *next;
7340ea8d27SAndriy Gapon uint64_t fsid;
740daf62d9SStanislav Sedov uint64_t ino;
750daf62d9SStanislav Sedov const char *name;
760daf62d9SStanislav Sedov } DEVS;
779b50d902SRodney W. Grimes
78357050fcSEd Schouten static DEVS *devs;
79357050fcSEd Schouten static char *memf, *nlistf;
809b50d902SRodney W. Grimes
810daf62d9SStanislav Sedov static int getfname(const char *filename);
820daf62d9SStanislav Sedov static void dofiles(struct procstat *procstat, struct kinfo_proc *p);
830daf62d9SStanislav Sedov static void print_access_flags(int flags);
840daf62d9SStanislav Sedov static void print_file_info(struct procstat *procstat,
850daf62d9SStanislav Sedov struct filestat *fst, const char *uname, const char *cmd, int pid);
860daf62d9SStanislav Sedov static void print_pipe_info(struct procstat *procstat,
870daf62d9SStanislav Sedov struct filestat *fst);
880daf62d9SStanislav Sedov static void print_pts_info(struct procstat *procstat,
890daf62d9SStanislav Sedov struct filestat *fst);
90958aa575SJohn Baldwin static void print_sem_info(struct procstat *procstat,
91958aa575SJohn Baldwin struct filestat *fst);
92e506e182SJohn Baldwin static void print_shm_info(struct procstat *procstat,
93e506e182SJohn Baldwin struct filestat *fst);
940daf62d9SStanislav Sedov static void print_socket_info(struct procstat *procstat,
950daf62d9SStanislav Sedov struct filestat *fst);
960daf62d9SStanislav Sedov static void print_vnode_info(struct procstat *procstat,
970daf62d9SStanislav Sedov struct filestat *fst);
980daf62d9SStanislav Sedov static void usage(void) __dead2;
991c17fc99SPeter Wemm
1001c17fc99SPeter Wemm int
do_fstat(int argc,char ** argv)1010daf62d9SStanislav Sedov do_fstat(int argc, char **argv)
1029b50d902SRodney W. Grimes {
1030daf62d9SStanislav Sedov struct kinfo_proc *p;
10427d57ea9SDavid Malone struct passwd *passwd;
1050daf62d9SStanislav Sedov struct procstat *procstat;
1069b50d902SRodney W. Grimes int arg, ch, what;
1070daf62d9SStanislav Sedov int cnt, i;
1089b50d902SRodney W. Grimes
1099b50d902SRodney W. Grimes arg = 0;
110f9feee17SEd Maste what = KERN_PROC_PROC;
1119b50d902SRodney W. Grimes nlistf = memf = NULL;
11291ad311bSJeremie Le Hen while ((ch = getopt(argc, argv, "fmnp:su:vN:M:")) != -1)
1139b50d902SRodney W. Grimes switch((char)ch) {
1149b50d902SRodney W. Grimes case 'f':
1159b50d902SRodney W. Grimes fsflg = 1;
1169b50d902SRodney W. Grimes break;
1179b50d902SRodney W. Grimes case 'M':
1189b50d902SRodney W. Grimes memf = optarg;
1199b50d902SRodney W. Grimes break;
1209b50d902SRodney W. Grimes case 'N':
1219b50d902SRodney W. Grimes nlistf = optarg;
1229b50d902SRodney W. Grimes break;
123d0482be8SBrian Feldman case 'm':
124d0482be8SBrian Feldman mflg = 1;
125d0482be8SBrian Feldman break;
1269b50d902SRodney W. Grimes case 'n':
1279b50d902SRodney W. Grimes nflg = 1;
1289b50d902SRodney W. Grimes break;
1299b50d902SRodney W. Grimes case 'p':
1309b50d902SRodney W. Grimes if (pflg++)
1319b50d902SRodney W. Grimes usage();
1329b50d902SRodney W. Grimes if (!isdigit(*optarg)) {
133c1e65942SPhilippe Charnier warnx("-p requires a process id");
1349b50d902SRodney W. Grimes usage();
1359b50d902SRodney W. Grimes }
1369b50d902SRodney W. Grimes what = KERN_PROC_PID;
1379b50d902SRodney W. Grimes arg = atoi(optarg);
1389b50d902SRodney W. Grimes break;
13991ad311bSJeremie Le Hen case 's':
14091ad311bSJeremie Le Hen sflg = 1;
14191ad311bSJeremie Le Hen break;
1429b50d902SRodney W. Grimes case 'u':
1439b50d902SRodney W. Grimes if (uflg++)
1449b50d902SRodney W. Grimes usage();
145c1e65942SPhilippe Charnier if (!(passwd = getpwnam(optarg)))
146c1e65942SPhilippe Charnier errx(1, "%s: unknown uid", optarg);
1479b50d902SRodney W. Grimes what = KERN_PROC_UID;
1489b50d902SRodney W. Grimes arg = passwd->pw_uid;
1499b50d902SRodney W. Grimes break;
1509b50d902SRodney W. Grimes case 'v':
1519b50d902SRodney W. Grimes vflg = 1;
1529b50d902SRodney W. Grimes break;
1539b50d902SRodney W. Grimes case '?':
1549b50d902SRodney W. Grimes default:
1559b50d902SRodney W. Grimes usage();
1569b50d902SRodney W. Grimes }
1579b50d902SRodney W. Grimes
1589b50d902SRodney W. Grimes if (*(argv += optind)) {
1599b50d902SRodney W. Grimes for (; *argv; ++argv) {
1609b50d902SRodney W. Grimes if (getfname(*argv))
1619b50d902SRodney W. Grimes checkfile = 1;
1629b50d902SRodney W. Grimes }
163487ac9acSUlrich Spörlein if (!checkfile) /* file(s) specified, but none accessible */
1649b50d902SRodney W. Grimes exit(1);
1659b50d902SRodney W. Grimes }
1669b50d902SRodney W. Grimes
1679b50d902SRodney W. Grimes if (fsflg && !checkfile) {
1689b50d902SRodney W. Grimes /* -f with no files means use wd */
1699b50d902SRodney W. Grimes if (getfname(".") == 0)
1709b50d902SRodney W. Grimes exit(1);
1719b50d902SRodney W. Grimes checkfile = 1;
1729b50d902SRodney W. Grimes }
1739b50d902SRodney W. Grimes
1741f910d6cSDag-Erling Smørgrav if (memf != NULL)
1750daf62d9SStanislav Sedov procstat = procstat_open_kvm(nlistf, memf);
1761f910d6cSDag-Erling Smørgrav else
1770daf62d9SStanislav Sedov procstat = procstat_open_sysctl();
1780daf62d9SStanislav Sedov if (procstat == NULL)
1790daf62d9SStanislav Sedov errx(1, "procstat_open()");
1800daf62d9SStanislav Sedov p = procstat_getprocs(procstat, what, arg, &cnt);
1810daf62d9SStanislav Sedov if (p == NULL)
1820daf62d9SStanislav Sedov errx(1, "procstat_getprocs()");
1831f910d6cSDag-Erling Smørgrav
1840daf62d9SStanislav Sedov /*
1850daf62d9SStanislav Sedov * Print header.
1860daf62d9SStanislav Sedov */
1871f910d6cSDag-Erling Smørgrav if (nflg)
1881f910d6cSDag-Erling Smørgrav printf("%s",
1891f910d6cSDag-Erling Smørgrav "USER CMD PID FD DEV INUM MODE SZ|DV R/W");
1901f910d6cSDag-Erling Smørgrav else
1911f910d6cSDag-Erling Smørgrav printf("%s",
1921f910d6cSDag-Erling Smørgrav "USER CMD PID FD MOUNT INUM MODE SZ|DV R/W");
1931f910d6cSDag-Erling Smørgrav if (checkfile && fsflg == 0)
1941f910d6cSDag-Erling Smørgrav printf(" NAME\n");
1951f910d6cSDag-Erling Smørgrav else
1961f910d6cSDag-Erling Smørgrav putchar('\n');
1970daf62d9SStanislav Sedov
1980daf62d9SStanislav Sedov /*
1990daf62d9SStanislav Sedov * Go through the process list.
2000daf62d9SStanislav Sedov */
2010daf62d9SStanislav Sedov for (i = 0; i < cnt; i++) {
2020daf62d9SStanislav Sedov if (p[i].ki_stat == SZOMB)
2030daf62d9SStanislav Sedov continue;
2040daf62d9SStanislav Sedov dofiles(procstat, &p[i]);
2050daf62d9SStanislav Sedov }
2060daf62d9SStanislav Sedov procstat_freeprocs(procstat, p);
2070daf62d9SStanislav Sedov procstat_close(procstat);
2080daf62d9SStanislav Sedov return (0);
2091f910d6cSDag-Erling Smørgrav }
2101f910d6cSDag-Erling Smørgrav
2111f910d6cSDag-Erling Smørgrav static void
dofiles(struct procstat * procstat,struct kinfo_proc * kp)2120daf62d9SStanislav Sedov dofiles(struct procstat *procstat, struct kinfo_proc *kp)
2131f910d6cSDag-Erling Smørgrav {
2140daf62d9SStanislav Sedov const char *cmd;
2150daf62d9SStanislav Sedov const char *uname;
2160daf62d9SStanislav Sedov struct filestat *fst;
2170daf62d9SStanislav Sedov struct filestat_list *head;
2180daf62d9SStanislav Sedov int pid;
2191f910d6cSDag-Erling Smørgrav
2200daf62d9SStanislav Sedov uname = user_from_uid(kp->ki_uid, 0);
2210daf62d9SStanislav Sedov pid = kp->ki_pid;
2220daf62d9SStanislav Sedov cmd = kp->ki_comm;
2231f910d6cSDag-Erling Smørgrav
2240daf62d9SStanislav Sedov head = procstat_getfiles(procstat, kp, mflg);
2250daf62d9SStanislav Sedov if (head == NULL)
2260daf62d9SStanislav Sedov return;
2270daf62d9SStanislav Sedov STAILQ_FOREACH(fst, head, next)
2280daf62d9SStanislav Sedov print_file_info(procstat, fst, uname, cmd, pid);
2290daf62d9SStanislav Sedov procstat_freefiles(procstat, head);
2309b50d902SRodney W. Grimes }
2310daf62d9SStanislav Sedov
2321f910d6cSDag-Erling Smørgrav
2331f910d6cSDag-Erling Smørgrav static void
print_file_info(struct procstat * procstat,struct filestat * fst,const char * uname,const char * cmd,int pid)2340daf62d9SStanislav Sedov print_file_info(struct procstat *procstat, struct filestat *fst,
2350daf62d9SStanislav Sedov const char *uname, const char *cmd, int pid)
2361f910d6cSDag-Erling Smørgrav {
2370daf62d9SStanislav Sedov struct vnstat vn;
23827d57ea9SDavid Malone DEVS *d;
2390daf62d9SStanislav Sedov const char *filename;
2400daf62d9SStanislav Sedov int error, fsmatch = 0;
2410daf62d9SStanislav Sedov char errbuf[_POSIX2_LINE_MAX];
2429b50d902SRodney W. Grimes
2430daf62d9SStanislav Sedov filename = NULL;
2440daf62d9SStanislav Sedov if (checkfile != 0) {
245b4fe201cSSergey Kandaurov if (fst->fs_type != PS_FST_TYPE_VNODE &&
246b4fe201cSSergey Kandaurov fst->fs_type != PS_FST_TYPE_FIFO)
247e22c40faSSergey Kandaurov return;
248b4fe201cSSergey Kandaurov error = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
2490daf62d9SStanislav Sedov if (error != 0)
2500daf62d9SStanislav Sedov return;
2510daf62d9SStanislav Sedov
2529b50d902SRodney W. Grimes for (d = devs; d != NULL; d = d->next)
2530daf62d9SStanislav Sedov if (d->fsid == vn.vn_fsid) {
2549b50d902SRodney W. Grimes fsmatch = 1;
255e458cb77SGleb Kurtsou if (d->ino == vn.vn_fileid) {
2569b50d902SRodney W. Grimes filename = d->name;
2579b50d902SRodney W. Grimes break;
2589b50d902SRodney W. Grimes }
2599b50d902SRodney W. Grimes }
2609b50d902SRodney W. Grimes if (fsmatch == 0 || (filename == NULL && fsflg == 0))
2619b50d902SRodney W. Grimes return;
2629b50d902SRodney W. Grimes }
2639b50d902SRodney W. Grimes
2640daf62d9SStanislav Sedov /*
2650daf62d9SStanislav Sedov * Print entry prefix.
2660daf62d9SStanislav Sedov */
2670daf62d9SStanislav Sedov printf("%-8.8s %-10s %5d", uname, cmd, pid);
2680daf62d9SStanislav Sedov if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
2690daf62d9SStanislav Sedov printf(" text");
2700daf62d9SStanislav Sedov else if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
2710daf62d9SStanislav Sedov printf(" wd");
2720daf62d9SStanislav Sedov else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
2730daf62d9SStanislav Sedov printf(" root");
2740daf62d9SStanislav Sedov else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
2750daf62d9SStanislav Sedov printf(" tr");
2760daf62d9SStanislav Sedov else if (fst->fs_uflags & PS_FST_UFLAG_MMAP)
2770daf62d9SStanislav Sedov printf(" mmap");
2780daf62d9SStanislav Sedov else if (fst->fs_uflags & PS_FST_UFLAG_JAIL)
2790daf62d9SStanislav Sedov printf(" jail");
2800daf62d9SStanislav Sedov else if (fst->fs_uflags & PS_FST_UFLAG_CTTY)
2810daf62d9SStanislav Sedov printf(" ctty");
2820daf62d9SStanislav Sedov else
2830daf62d9SStanislav Sedov printf(" %4d", fst->fs_fd);
2840daf62d9SStanislav Sedov
2850daf62d9SStanislav Sedov /*
2860daf62d9SStanislav Sedov * Print type-specific data.
2870daf62d9SStanislav Sedov */
2880daf62d9SStanislav Sedov switch (fst->fs_type) {
2890daf62d9SStanislav Sedov case PS_FST_TYPE_FIFO:
2900daf62d9SStanislav Sedov case PS_FST_TYPE_VNODE:
2910daf62d9SStanislav Sedov print_vnode_info(procstat, fst);
2929b50d902SRodney W. Grimes break;
2930daf62d9SStanislav Sedov case PS_FST_TYPE_SOCKET:
2940daf62d9SStanislav Sedov print_socket_info(procstat, fst);
2950daf62d9SStanislav Sedov break;
2960daf62d9SStanislav Sedov case PS_FST_TYPE_PIPE:
2970daf62d9SStanislav Sedov print_pipe_info(procstat, fst);
2980daf62d9SStanislav Sedov break;
2990daf62d9SStanislav Sedov case PS_FST_TYPE_PTS:
3000daf62d9SStanislav Sedov print_pts_info(procstat, fst);
3010daf62d9SStanislav Sedov break;
302e506e182SJohn Baldwin case PS_FST_TYPE_SHM:
303e506e182SJohn Baldwin print_shm_info(procstat, fst);
304e506e182SJohn Baldwin break;
305958aa575SJohn Baldwin case PS_FST_TYPE_SEM:
306958aa575SJohn Baldwin print_sem_info(procstat, fst);
307958aa575SJohn Baldwin break;
308a66732deSKonstantin Belousov case PS_FST_TYPE_DEV:
309a66732deSKonstantin Belousov break;
3109b50d902SRodney W. Grimes default:
3110daf62d9SStanislav Sedov if (vflg)
3120daf62d9SStanislav Sedov fprintf(stderr,
3130daf62d9SStanislav Sedov "unknown file type %d for file %d of pid %d\n",
3140daf62d9SStanislav Sedov fst->fs_type, fst->fs_fd, pid);
3159b50d902SRodney W. Grimes }
3169b50d902SRodney W. Grimes if (filename && !fsflg)
3179b50d902SRodney W. Grimes printf(" %s", filename);
3189b50d902SRodney W. Grimes putchar('\n');
3199b50d902SRodney W. Grimes }
3209b50d902SRodney W. Grimes
32191ad311bSJeremie Le Hen static char *
addr_to_string(struct sockaddr_storage * ss,char * buffer,int buflen)32291ad311bSJeremie Le Hen addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
32391ad311bSJeremie Le Hen {
32491ad311bSJeremie Le Hen char buffer2[INET6_ADDRSTRLEN];
32591ad311bSJeremie Le Hen struct sockaddr_in6 *sin6;
32691ad311bSJeremie Le Hen struct sockaddr_in *sin;
32791ad311bSJeremie Le Hen struct sockaddr_un *sun;
32891ad311bSJeremie Le Hen
32991ad311bSJeremie Le Hen switch (ss->ss_family) {
33091ad311bSJeremie Le Hen case AF_LOCAL:
33191ad311bSJeremie Le Hen sun = (struct sockaddr_un *)ss;
33291ad311bSJeremie Le Hen if (strlen(sun->sun_path) == 0)
33391ad311bSJeremie Le Hen strlcpy(buffer, "-", buflen);
33491ad311bSJeremie Le Hen else
33591ad311bSJeremie Le Hen strlcpy(buffer, sun->sun_path, buflen);
33691ad311bSJeremie Le Hen break;
33791ad311bSJeremie Le Hen
33891ad311bSJeremie Le Hen case AF_INET:
33991ad311bSJeremie Le Hen sin = (struct sockaddr_in *)ss;
34091ad311bSJeremie Le Hen if (sin->sin_addr.s_addr == INADDR_ANY)
34191ad311bSJeremie Le Hen snprintf(buffer, buflen, "%s:%d", "*",
34291ad311bSJeremie Le Hen ntohs(sin->sin_port));
34391ad311bSJeremie Le Hen else if (inet_ntop(AF_INET, &sin->sin_addr, buffer2,
34491ad311bSJeremie Le Hen sizeof(buffer2)) != NULL)
34591ad311bSJeremie Le Hen snprintf(buffer, buflen, "%s:%d", buffer2,
34691ad311bSJeremie Le Hen ntohs(sin->sin_port));
34791ad311bSJeremie Le Hen break;
34891ad311bSJeremie Le Hen
34991ad311bSJeremie Le Hen case AF_INET6:
35091ad311bSJeremie Le Hen sin6 = (struct sockaddr_in6 *)ss;
35191ad311bSJeremie Le Hen if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
35291ad311bSJeremie Le Hen snprintf(buffer, buflen, "%s.%d", "*",
35391ad311bSJeremie Le Hen ntohs(sin6->sin6_port));
35491ad311bSJeremie Le Hen else if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
35591ad311bSJeremie Le Hen sizeof(buffer2)) != NULL)
35691ad311bSJeremie Le Hen snprintf(buffer, buflen, "%s.%d", buffer2,
35791ad311bSJeremie Le Hen ntohs(sin6->sin6_port));
35891ad311bSJeremie Le Hen else
35991ad311bSJeremie Le Hen strlcpy(buffer, "-", buflen);
36091ad311bSJeremie Le Hen break;
36191ad311bSJeremie Le Hen
36291ad311bSJeremie Le Hen default:
36391ad311bSJeremie Le Hen strlcpy(buffer, "", buflen);
36491ad311bSJeremie Le Hen break;
36591ad311bSJeremie Le Hen }
36691ad311bSJeremie Le Hen return buffer;
36791ad311bSJeremie Le Hen }
36891ad311bSJeremie Le Hen
36991ad311bSJeremie Le Hen
3700daf62d9SStanislav Sedov static void
print_socket_info(struct procstat * procstat,struct filestat * fst)3710daf62d9SStanislav Sedov print_socket_info(struct procstat *procstat, struct filestat *fst)
3729b50d902SRodney W. Grimes {
37327d57ea9SDavid Malone static const char *stypename[] = {
3749b50d902SRodney W. Grimes "unused", /* 0 */
3759b50d902SRodney W. Grimes "stream", /* 1 */
3769b50d902SRodney W. Grimes "dgram", /* 2 */
3779b50d902SRodney W. Grimes "raw", /* 3 */
3789b50d902SRodney W. Grimes "rdm", /* 4 */
3799b50d902SRodney W. Grimes "seqpak" /* 5 */
3809b50d902SRodney W. Grimes };
3819b50d902SRodney W. Grimes #define STYPEMAX 5
3820daf62d9SStanislav Sedov struct sockstat sock;
3830daf62d9SStanislav Sedov struct protoent *pe;
3840daf62d9SStanislav Sedov char errbuf[_POSIX2_LINE_MAX];
38591ad311bSJeremie Le Hen char src_addr[PATH_MAX], dst_addr[PATH_MAX];
38691ad311bSJeremie Le Hen struct sockaddr_un *sun;
3870daf62d9SStanislav Sedov int error;
3880daf62d9SStanislav Sedov static int isopen;
3899b50d902SRodney W. Grimes
3900daf62d9SStanislav Sedov error = procstat_get_socket_info(procstat, fst, &sock, errbuf);
3910daf62d9SStanislav Sedov if (error != 0) {
3920daf62d9SStanislav Sedov printf("* error");
3930daf62d9SStanislav Sedov return;
3949b50d902SRodney W. Grimes }
3950daf62d9SStanislav Sedov if (sock.type > STYPEMAX)
3960daf62d9SStanislav Sedov printf("* %s ?%d", sock.dname, sock.type);
3979b50d902SRodney W. Grimes else
3980daf62d9SStanislav Sedov printf("* %s %s", sock.dname, stypename[sock.type]);
3999b50d902SRodney W. Grimes
4009b50d902SRodney W. Grimes /*
4019b50d902SRodney W. Grimes * protocol specific formatting
4029b50d902SRodney W. Grimes *
403*1a8d1764SGleb Smirnoff * Try to find interesting things to print. For internet and unix
404*1a8d1764SGleb Smirnoff * sockets, its the address of the socket pcb. For unix it is also the
405*1a8d1764SGleb Smirnoff * address of the connected pcb (if connected). Otherwise just print
406*1a8d1764SGleb Smirnoff * the protocol number and address of the socket itself.
4079b50d902SRodney W. Grimes * The idea is not to duplicate netstat, but to make available enough
4089b50d902SRodney W. Grimes * information for further analysis.
4099b50d902SRodney W. Grimes */
4100daf62d9SStanislav Sedov switch (sock.dom_family) {
4119b50d902SRodney W. Grimes case AF_INET:
412677e00c0SYoshinobu Inoue case AF_INET6:
4130daf62d9SStanislav Sedov if (!isopen)
4140daf62d9SStanislav Sedov setprotoent(++isopen);
4150daf62d9SStanislav Sedov if ((pe = getprotobynumber(sock.proto)) != NULL)
4160daf62d9SStanislav Sedov printf(" %s", pe->p_name);
4170daf62d9SStanislav Sedov else
4180daf62d9SStanislav Sedov printf(" %d", sock.proto);
419*1a8d1764SGleb Smirnoff if (sock.so_pcb != 0)
4200daf62d9SStanislav Sedov printf(" %lx", (u_long)sock.so_pcb);
42191ad311bSJeremie Le Hen if (!sflg)
42291ad311bSJeremie Le Hen break;
42391ad311bSJeremie Le Hen printf(" %s <-> %s",
42491ad311bSJeremie Le Hen addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)),
42591ad311bSJeremie Le Hen addr_to_string(&sock.sa_peer, dst_addr, sizeof(dst_addr)));
4269b50d902SRodney W. Grimes break;
4279b50d902SRodney W. Grimes case AF_UNIX:
4289b50d902SRodney W. Grimes /* print address of pcb and connected pcb */
4290daf62d9SStanislav Sedov if (sock.so_pcb != 0) {
4300daf62d9SStanislav Sedov printf(" %lx", (u_long)sock.so_pcb);
4310daf62d9SStanislav Sedov if (sock.unp_conn) {
4329b50d902SRodney W. Grimes char shoconn[4], *cp;
4339b50d902SRodney W. Grimes
4349b50d902SRodney W. Grimes cp = shoconn;
4350daf62d9SStanislav Sedov if (!(sock.so_rcv_sb_state & SBS_CANTRCVMORE))
4369b50d902SRodney W. Grimes *cp++ = '<';
4379b50d902SRodney W. Grimes *cp++ = '-';
4380daf62d9SStanislav Sedov if (!(sock.so_snd_sb_state & SBS_CANTSENDMORE))
4399b50d902SRodney W. Grimes *cp++ = '>';
4409b50d902SRodney W. Grimes *cp = '\0';
441df94d4d2SMatt Jacob printf(" %s %lx", shoconn,
4420daf62d9SStanislav Sedov (u_long)sock.unp_conn);
4439b50d902SRodney W. Grimes }
4449b50d902SRodney W. Grimes }
44591ad311bSJeremie Le Hen if (!sflg)
44691ad311bSJeremie Le Hen break;
44791ad311bSJeremie Le Hen sun = (struct sockaddr_un *)&sock.sa_local;
44891ad311bSJeremie Le Hen /*
44991ad311bSJeremie Le Hen * While generally we like to print two addresses,
45091ad311bSJeremie Le Hen * local and peer, for sockets, it turns out to be
45191ad311bSJeremie Le Hen * more useful to print the first non-null address for
45291ad311bSJeremie Le Hen * local sockets, as typically they aren't bound and
45391ad311bSJeremie Le Hen * connected, and the path strings can get long.
45491ad311bSJeremie Le Hen */
45591ad311bSJeremie Le Hen if (sun->sun_path[0] != 0)
45691ad311bSJeremie Le Hen addr_to_string(&sock.sa_local,
45791ad311bSJeremie Le Hen src_addr, sizeof(src_addr));
45891ad311bSJeremie Le Hen else
45991ad311bSJeremie Le Hen addr_to_string(&sock.sa_peer,
46091ad311bSJeremie Le Hen src_addr, sizeof(src_addr));
46191ad311bSJeremie Le Hen printf(" %s", src_addr);
4629b50d902SRodney W. Grimes break;
4639b50d902SRodney W. Grimes default:
4649b50d902SRodney W. Grimes /* print protocol number and socket address */
4650daf62d9SStanislav Sedov printf(" %d %lx", sock.proto, (u_long)sock.so_addr);
4669b50d902SRodney W. Grimes }
4679b50d902SRodney W. Grimes }
4689b50d902SRodney W. Grimes
4690daf62d9SStanislav Sedov static void
print_pipe_info(struct procstat * procstat,struct filestat * fst)4700daf62d9SStanislav Sedov print_pipe_info(struct procstat *procstat, struct filestat *fst)
471bc093719SEd Schouten {
4720daf62d9SStanislav Sedov struct pipestat ps;
4730daf62d9SStanislav Sedov char errbuf[_POSIX2_LINE_MAX];
4740daf62d9SStanislav Sedov int error;
4750daf62d9SStanislav Sedov
4760daf62d9SStanislav Sedov error = procstat_get_pipe_info(procstat, fst, &ps, errbuf);
4770daf62d9SStanislav Sedov if (error != 0) {
4780daf62d9SStanislav Sedov printf("* error");
4790daf62d9SStanislav Sedov return;
4800daf62d9SStanislav Sedov }
4810daf62d9SStanislav Sedov printf("* pipe %8lx <-> %8lx", (u_long)ps.addr, (u_long)ps.peer);
4820daf62d9SStanislav Sedov printf(" %6zd", ps.buffer_cnt);
4830daf62d9SStanislav Sedov print_access_flags(fst->fs_fflags);
4840daf62d9SStanislav Sedov }
4850daf62d9SStanislav Sedov
4860daf62d9SStanislav Sedov static void
print_pts_info(struct procstat * procstat,struct filestat * fst)4870daf62d9SStanislav Sedov print_pts_info(struct procstat *procstat, struct filestat *fst)
4880daf62d9SStanislav Sedov {
4890daf62d9SStanislav Sedov struct ptsstat pts;
4900daf62d9SStanislav Sedov char errbuf[_POSIX2_LINE_MAX];
4910daf62d9SStanislav Sedov int error;
4920daf62d9SStanislav Sedov
4930daf62d9SStanislav Sedov error = procstat_get_pts_info(procstat, fst, &pts, errbuf);
4940daf62d9SStanislav Sedov if (error != 0) {
4950daf62d9SStanislav Sedov printf("* error");
4960daf62d9SStanislav Sedov return;
4970daf62d9SStanislav Sedov }
4980daf62d9SStanislav Sedov printf("* pseudo-terminal master ");
4990daf62d9SStanislav Sedov if (nflg || !*pts.devname) {
5009f365aa1SEd Schouten printf("%#10jx", (uintmax_t)pts.dev);
5010daf62d9SStanislav Sedov } else {
5020daf62d9SStanislav Sedov printf("%10s", pts.devname);
5030daf62d9SStanislav Sedov }
5040daf62d9SStanislav Sedov print_access_flags(fst->fs_fflags);
5050daf62d9SStanislav Sedov }
5060daf62d9SStanislav Sedov
5070daf62d9SStanislav Sedov static void
print_sem_info(struct procstat * procstat,struct filestat * fst)508958aa575SJohn Baldwin print_sem_info(struct procstat *procstat, struct filestat *fst)
509958aa575SJohn Baldwin {
510958aa575SJohn Baldwin struct semstat sem;
511958aa575SJohn Baldwin char errbuf[_POSIX2_LINE_MAX];
512958aa575SJohn Baldwin char mode[15];
513958aa575SJohn Baldwin int error;
514958aa575SJohn Baldwin
515958aa575SJohn Baldwin error = procstat_get_sem_info(procstat, fst, &sem, errbuf);
516958aa575SJohn Baldwin if (error != 0) {
517958aa575SJohn Baldwin printf("* error");
518958aa575SJohn Baldwin return;
519958aa575SJohn Baldwin }
520958aa575SJohn Baldwin if (nflg) {
521958aa575SJohn Baldwin printf(" ");
522958aa575SJohn Baldwin (void)snprintf(mode, sizeof(mode), "%o", sem.mode);
523958aa575SJohn Baldwin } else {
524958aa575SJohn Baldwin printf(" %-15s", fst->fs_path != NULL ? fst->fs_path : "-");
525958aa575SJohn Baldwin strmode(sem.mode, mode);
526958aa575SJohn Baldwin }
527958aa575SJohn Baldwin printf(" %10s %6u", mode, sem.value);
528958aa575SJohn Baldwin print_access_flags(fst->fs_fflags);
529958aa575SJohn Baldwin }
530958aa575SJohn Baldwin
531958aa575SJohn Baldwin static void
print_shm_info(struct procstat * procstat,struct filestat * fst)532e506e182SJohn Baldwin print_shm_info(struct procstat *procstat, struct filestat *fst)
533e506e182SJohn Baldwin {
534e506e182SJohn Baldwin struct shmstat shm;
535e506e182SJohn Baldwin char errbuf[_POSIX2_LINE_MAX];
536e506e182SJohn Baldwin char mode[15];
537e506e182SJohn Baldwin int error;
538e506e182SJohn Baldwin
539e506e182SJohn Baldwin error = procstat_get_shm_info(procstat, fst, &shm, errbuf);
540e506e182SJohn Baldwin if (error != 0) {
541e506e182SJohn Baldwin printf("* error");
542e506e182SJohn Baldwin return;
543e506e182SJohn Baldwin }
544e506e182SJohn Baldwin if (nflg) {
545e506e182SJohn Baldwin printf(" ");
546e506e182SJohn Baldwin (void)snprintf(mode, sizeof(mode), "%o", shm.mode);
547e506e182SJohn Baldwin } else {
548e506e182SJohn Baldwin printf(" %-15s", fst->fs_path != NULL ? fst->fs_path : "-");
549e506e182SJohn Baldwin strmode(shm.mode, mode);
550e506e182SJohn Baldwin }
551e506e182SJohn Baldwin printf(" %10s %6ju", mode, shm.size);
552e506e182SJohn Baldwin print_access_flags(fst->fs_fflags);
553e506e182SJohn Baldwin }
554e506e182SJohn Baldwin
555e506e182SJohn Baldwin static void
print_vnode_info(struct procstat * procstat,struct filestat * fst)5560daf62d9SStanislav Sedov print_vnode_info(struct procstat *procstat, struct filestat *fst)
5570daf62d9SStanislav Sedov {
5580daf62d9SStanislav Sedov struct vnstat vn;
5590daf62d9SStanislav Sedov char errbuf[_POSIX2_LINE_MAX];
5600daf62d9SStanislav Sedov char mode[15];
5610daf62d9SStanislav Sedov const char *badtype;
5620daf62d9SStanislav Sedov int error;
5630daf62d9SStanislav Sedov
5640daf62d9SStanislav Sedov badtype = NULL;
5650daf62d9SStanislav Sedov error = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
5660daf62d9SStanislav Sedov if (error != 0)
5670daf62d9SStanislav Sedov badtype = errbuf;
5680daf62d9SStanislav Sedov else if (vn.vn_type == PS_FST_VTYPE_VBAD)
5690daf62d9SStanislav Sedov badtype = "bad";
5700daf62d9SStanislav Sedov else if (vn.vn_type == PS_FST_VTYPE_VNON)
5710daf62d9SStanislav Sedov badtype = "none";
5720daf62d9SStanislav Sedov if (badtype != NULL) {
5730daf62d9SStanislav Sedov printf(" - - %10s -", badtype);
5740daf62d9SStanislav Sedov return;
5750daf62d9SStanislav Sedov }
5760daf62d9SStanislav Sedov
5770daf62d9SStanislav Sedov if (nflg)
57805806a06SEd Schouten printf(" %#5jx", (uintmax_t)vn.vn_fsid);
5790daf62d9SStanislav Sedov else if (vn.vn_mntdir != NULL)
5800daf62d9SStanislav Sedov (void)printf(" %-8s", vn.vn_mntdir);
5810daf62d9SStanislav Sedov
5820daf62d9SStanislav Sedov /*
5830daf62d9SStanislav Sedov * Print access mode.
5840daf62d9SStanislav Sedov */
5850daf62d9SStanislav Sedov if (nflg)
5860daf62d9SStanislav Sedov (void)snprintf(mode, sizeof(mode), "%o", vn.vn_mode);
5870daf62d9SStanislav Sedov else {
5880daf62d9SStanislav Sedov strmode(vn.vn_mode, mode);
5890daf62d9SStanislav Sedov }
59076db9ccfSWarner Losh (void)printf(" %6jd %10s", (intmax_t)vn.vn_fileid, mode);
5910daf62d9SStanislav Sedov
5920daf62d9SStanislav Sedov if (vn.vn_type == PS_FST_VTYPE_VBLK || vn.vn_type == PS_FST_VTYPE_VCHR) {
5930daf62d9SStanislav Sedov if (nflg || !*vn.vn_devname)
5949f365aa1SEd Schouten printf(" %#6jx", (uintmax_t)vn.vn_dev);
5950daf62d9SStanislav Sedov else {
5960daf62d9SStanislav Sedov printf(" %6s", vn.vn_devname);
5970daf62d9SStanislav Sedov }
5980daf62d9SStanislav Sedov } else
5998d917b4bSWarner Losh printf(" %6ju", (uintmax_t)vn.vn_size);
6000daf62d9SStanislav Sedov print_access_flags(fst->fs_fflags);
6010daf62d9SStanislav Sedov }
6020daf62d9SStanislav Sedov
6030daf62d9SStanislav Sedov static void
print_access_flags(int flags)6040daf62d9SStanislav Sedov print_access_flags(int flags)
6050daf62d9SStanislav Sedov {
606bc093719SEd Schouten char rw[3];
607bc093719SEd Schouten
608bc093719SEd Schouten rw[0] = '\0';
6090daf62d9SStanislav Sedov if (flags & PS_FST_FFLAG_READ)
610bc093719SEd Schouten strcat(rw, "r");
6110daf62d9SStanislav Sedov if (flags & PS_FST_FFLAG_WRITE)
612bc093719SEd Schouten strcat(rw, "w");
6130daf62d9SStanislav Sedov printf(" %2s", rw);
6149b50d902SRodney W. Grimes }
6159b50d902SRodney W. Grimes
6161c17fc99SPeter Wemm int
getfname(const char * filename)6171e925017SDavid Malone getfname(const char *filename)
6189b50d902SRodney W. Grimes {
6199b50d902SRodney W. Grimes struct stat statbuf;
6209b50d902SRodney W. Grimes DEVS *cur;
6219b50d902SRodney W. Grimes
6229b50d902SRodney W. Grimes if (stat(filename, &statbuf)) {
623c1e65942SPhilippe Charnier warn("%s", filename);
6249b50d902SRodney W. Grimes return (0);
6259b50d902SRodney W. Grimes }
626c1e65942SPhilippe Charnier if ((cur = malloc(sizeof(DEVS))) == NULL)
627c1e65942SPhilippe Charnier err(1, NULL);
6289b50d902SRodney W. Grimes cur->next = devs;
6299b50d902SRodney W. Grimes devs = cur;
6309b50d902SRodney W. Grimes
6319b50d902SRodney W. Grimes cur->ino = statbuf.st_ino;
632b628b0dcSDavid Malone cur->fsid = statbuf.st_dev;
6339b50d902SRodney W. Grimes cur->name = filename;
6349b50d902SRodney W. Grimes return (1);
6359b50d902SRodney W. Grimes }
6369b50d902SRodney W. Grimes
6370daf62d9SStanislav Sedov static void
usage(void)6381e925017SDavid Malone usage(void)
6399b50d902SRodney W. Grimes {
6409b50d902SRodney W. Grimes (void)fprintf(stderr,
641f682f10cSRuslan Ermilov "usage: fstat [-fmnv] [-M core] [-N system] [-p pid] [-u user] [file ...]\n");
6429b50d902SRodney W. Grimes exit(1);
6439b50d902SRodney W. Grimes }
644