/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.99.2
src/print.c
2 137 строк
62 KB
Rui Chen
fix argument mismatch for gethostnm (#298)
13 ноя 2023, 04:11
Не верифицирован
13 ноя 2023, 04:11
eff3883
Код
Авторство
О чём код?
/* * print.c - common print support functions for lsof */ /* * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #include "common.h" #include "cli.h" #include "proto.h" /* * Local definitions, structures and function prototypes */ #define HCINC 64 /* host cache size increase chunk */ #define PORTHASHBUCKETS \ 128 /* port hash bucket count \ * !!MUST BE A POWER OF 2!! */ #define PORTTABTHRESH \ 10 /* threshold at which we will switch \ * from using getservbyport() to \ * getservent() -- see lkup_port() \ * and fill_porttab() */ struct hostcache { unsigned char a[MAX_AF_ADDR]; /* numeric address */ int af; /* address family -- e.g., AF_INET * or AF_INET6 */ char *name; /* name */ }; struct porttab { int port; MALLOC_S nl; /* name length (excluding '\0') */ int ss; /* service name status, 0 = lookup not * yet performed */ char *name; struct porttab *next; }; #if defined(HASNORPC_H) static struct porttab **Pth[2] = {NULL, NULL}; /* port hash buckets: * Pth[0] for TCP service names * Pth[1] for UDP service names */ #else /* !defined(HASNORPC_H) */ static struct porttab **Pth[4] = {NULL, NULL, NULL, NULL}; /* port hash buckets: * Pth[0] for TCP service names * Pth[1] for UDP service names * Pth[2] for TCP portmap info * Pth[3] for UDP portmap info */ #endif /* defined(HASNORPC_H) */ #define HASHPORT(p) (((((int)(p)) * 31415) >> 3) & (PORTHASHBUCKETS - 1)) #if !defined(HASNORPC_H) static void fill_portmap(struct lsof_context *ctx); static void update_portmap(struct lsof_context *ctx, struct porttab *pt, char *pn); #endif /* !defined(HASNORPC_H) */ static void fill_porttab(struct lsof_context *ctx); static char *lkup_port(struct lsof_context *ctx, int p, int pr, int src); static char *lkup_svcnam(struct lsof_context *ctx, int h, int p, int pr, int ss); static int printinaddr(struct lsof_context *ctx); static int human_readable_size(SZOFFTYPE sz, int print, int col); #if !defined(HASNORPC_H) /* * fill_portmap() -- fill the RPC portmap program name table via a conversation * with the portmapper * * The following copyright notice acknowledges that this function was adapted * from getrpcportnam() of the source code of the OpenBSD netstat program. */ /* * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static void fill_portmap(struct lsof_context *ctx) { static int already_run = 0; char buf[128], *cp, *nm; CLIENT *c; int h, port, pr; MALLOC_S nl; struct pmaplist *p = (struct pmaplist *)NULL; struct porttab *pt; struct rpcent *r; struct TIMEVAL_LSOF tm; # if !defined(CAN_USE_CLNT_CREATE) struct hostent *he; struct sockaddr_in ia; int s = RPC_ANYSOCK; # endif /* !defined(CAN_USE_CLNT_CREATE) */ /* * Make sure this is only run once. */ if (already_run) return; already_run = 1; /* * Construct structures for communicating with the portmapper. */ # if !defined(CAN_USE_CLNT_CREATE) zeromem(&ia, sizeof(ia)); ia.sin_family = AF_INET; if ((he = gethostbyname("localhost"))) MEMMOVE((caddr_t)&ia.sin_addr, he->h_addr, he->h_length); ia.sin_port = htons(PMAPPORT); # endif /* !defined(CAN_USE_CLNT_CREATE) */ tm.tv_sec = 60; tm.tv_usec = 0; /* * Get an RPC client handle. Then ask for a dump of the port map. */ # if defined(CAN_USE_CLNT_CREATE) if (!(c = clnt_create("localhost", PMAPPROG, PMAPVERS, "tcp"))) # else /* !defined(CAN_USE_CLNT_CREATE) */ if (!(c = clnttcp_create(&ia, PMAPPROG, PMAPVERS, &s, 0, 0))) # endif /* defined(CAN_USE_CLNT_CREATE) */ return; if (clnt_call(c, PMAPPROC_DUMP, XDR_VOID, NULL, XDR_PMAPLIST, (caddr_t)&p, tm) != RPC_SUCCESS) { clnt_destroy(c); return; } /* * Loop through the port map dump, creating portmap table entries from TCP * and UDP members. */ for (; p; p = p->pml_next) { /* * Determine the port map entry's protocol; ignore all but TCP and UDP. */ if (p->pml_map.pm_prot == IPPROTO_TCP) pr = 2; else if (p->pml_map.pm_prot == IPPROTO_UDP) pr = 3; else continue; /* * See if there's already a portmap entry for this port. If there is, * ignore this entry. */ h = HASHPORT((port = (int)p->pml_map.pm_port)); for (pt = Pth[pr][h]; pt; pt = pt->next) { if (pt->port == port) break; } if (pt) continue; /* * Save the registration name or number. */ cp = (char *)NULL; if ((r = (struct rpcent *)getrpcbynumber(p->pml_map.pm_prog))) { if (r->r_name && strlen(r->r_name)) cp = r->r_name; } if (!cp) { (void)snpf(buf, sizeof(buf), "%lu", (unsigned long)p->pml_map.pm_prog); cp = buf; } if (!strlen(cp)) continue; /* * Allocate space for the portmap name entry and copy it there. */ if (!(nm = mkstrcpy(cp, &nl))) { (void)fprintf(stderr, "%s: can't allocate space for portmap entry: ", Pn); safestrprt(cp, stderr, 1); Error(ctx); } if (!nl) { (void)free((FREE_P *)nm); continue; } /* * Allocate and fill a porttab struct entry for the portmap table. * Link it to the head of its hash bucket, and make it the new head. */ if (!(pt = (struct porttab *)malloc(sizeof(struct porttab)))) { (void)fprintf(stderr, "%s: can't allocate porttab entry for portmap: ", Pn); safestrprt(nm, stderr, 1); Error(ctx); } pt->name = nm; pt->nl = nl; pt->port = port; pt->next = Pth[pr][h]; pt->ss = 0; Pth[pr][h] = pt; } clnt_destroy(c); } #endif /* !defined(HASNORPC_H) */ /* * fill_porttab() -- fill the TCP and UDP service name port table with a * getservent() scan */ static void fill_porttab(struct lsof_context *ctx) { int h, p, pr; MALLOC_S nl; char *nm; struct porttab *pt; struct servent *se; (void)endservent(); /* * Scan the services data base for TCP and UDP entries that have a non-null * name associated with them. */ (void)setservent(1); while ((se = getservent())) { if (!se->s_name || !se->s_proto) continue; if (strcasecmp(se->s_proto, "TCP") == 0) pr = 0; else if (strcasecmp(se->s_proto, "UDP") == 0) pr = 1; else continue; if (!se->s_name || !strlen(se->s_name)) continue; p = ntohs(se->s_port); /* * See if a port->service entry is already cached for this port and * prototcol. If it is, leave it alone. */ h = HASHPORT(p); for (pt = Pth[pr][h]; pt; pt = pt->next) { if (pt->port == p) break; } if (pt) continue; /* * Add a new entry to the cache for this port and protocol. */ if (!(nm = mkstrcpy(se->s_name, &nl))) { (void)fprintf(stderr, "%s: can't allocate %d bytes for port %d name: %s\n", Pn, (int)(nl + 1), p, se->s_name); Error(ctx); } if (!nl) { (void)free((FREE_P *)nm); continue; } if (!(pt = (struct porttab *)malloc(sizeof(struct porttab)))) { (void)fprintf(stderr, "%s: can't allocate porttab entry for port %d: %s\n", Pn, p, se->s_name); Error(ctx); } pt->name = nm; pt->nl = nl - 1; pt->port = p; pt->next = Pth[pr][h]; pt->ss = 0; Pth[pr][h] = pt; } (void)endservent(); } /* * gethostnm() - get host name */ char *gethostnm(struct lsof_context *ctx, /* context */ unsigned char *ia, /* Internet address */ int af) /* address family -- e.g., AF_INET * or AF_INET6 */ { int al = MIN_AF_ADDR; char hbuf[256]; static struct hostcache *hc = (struct hostcache *)NULL; static int hcx = 0; char *hn, *np; struct hostent *he = (struct hostent *)NULL; int i, j; MALLOC_S len; static int nhc = 0; /* * Search cache. */ #if defined(HASIPv6) if (af == AF_INET6) al = MAX_AF_ADDR; #endif /* defined(HASIPv6) */ for (i = 0; i < hcx; i++) { if (af != hc[i].af) continue; for (j = 0; j < al; j++) { if (ia[j] != hc[i].a[j]) break; } if (j >= al) return (hc[i].name); } /* * If -n has been specified, construct a numeric address. Otherwise, look * up host name by address. If that fails, or if there is no name in the * returned hostent structure, construct a numeric version of the address. */ if (Fhost) he = gethostbyaddr((char *)ia, al, af); if (!he || !he->h_name) { #if defined(HASIPv6) if (af == AF_INET6) { /* * Since IPv6 numeric addresses use `:' as a separator, enclose * them in brackets. */ hbuf[0] = '['; if (!inet_ntop(af, ia, hbuf + 1, sizeof(hbuf) - 3)) { (void)snpf(&hbuf[1], (sizeof(hbuf) - 1), "can't format IPv6 address]"); } else { len = strlen(hbuf); (void)snpf(&hbuf[len], sizeof(hbuf) - len, "]"); } } else #endif /* defined(HASIPv6) */ if (af == AF_INET) (void)snpf(hbuf, sizeof(hbuf), "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]); else (void)snpf(hbuf, sizeof(hbuf), "(unknown AF value: %d)", af); hn = hbuf; } else hn = (char *)he->h_name; /* * Allocate space for name and copy name to it. */ if (!(np = mkstrcpy(hn, (MALLOC_S *)NULL))) { (void)fprintf(stderr, "%s: no space for host name: ", Pn); safestrprt(hn, stderr, 1); Error(ctx); } /* * Add address/name entry to cache. Allocate cache space in HCINC chunks. */ if (hcx >= nhc) { nhc += HCINC; len = (MALLOC_S)(nhc * sizeof(struct hostcache)); if (!hc) hc = (struct hostcache *)malloc(len); else hc = (struct hostcache *)realloc((MALLOC_P *)hc, len); if (!hc) { (void)fprintf(stderr, "%s: no space for host cache\n", Pn); Error(ctx); } } hc[hcx].af = af; for (i = 0; i < al; i++) { hc[hcx].a[i] = ia[i]; } hc[hcx++].name = np; return (np); } /* * lkup_port() - look up port for protocol */ static char *lkup_port(struct lsof_context *ctx, /* context */ int p, /* port number */ int pr, /* protocol index: 0 = tcp, 1 = udp */ int src) /* port source: 0 = local * 1 = foreign */ { int h, nh; MALLOC_S nl; char *nm, *pn; static char pb[128]; struct porttab *pt; /* * If the hash buckets haven't been allocated, do so. */ if (!Pth[0]) { #if defined(HASNORPC_H) nh = 2; #else /* !defined(HASNORPC_H) */ nh = FportMap ? 4 : 2; #endif /* defined(HASNORPC_H) */ for (h = 0; h < nh; h++) { if (!(Pth[h] = (struct porttab **)calloc( PORTHASHBUCKETS, sizeof(struct porttab *)))) { (void)fprintf( stderr, "%s: can't allocate %d bytes for %s %s hash buckets\n", Pn, (int)(2 * (PORTHASHBUCKETS * sizeof(struct porttab *))), (h & 1) ? "UDP" : "TCP", (h > 1) ? "portmap" : "port"); Error(ctx); } } } #if !defined(HASNORPC_H) /* * If we're looking up program names for portmapped ports, make sure the * portmap table has been loaded. */ if (FportMap) (void)fill_portmap(ctx); #endif /* !defined(HASNORPC_H) */ /* * Hash the port and see if its name has been cached. Look for a local * port first in the portmap, if portmap searching is enabled. */ h = HASHPORT(p); #if !defined(HASNORPC_H) if (!src && FportMap) { for (pt = Pth[pr + 2][h]; pt; pt = pt->next) { if (pt->port != p) continue; if (!pt->ss) { pn = Fport ? lkup_svcnam(ctx, h, p, pr, 0) : (char *)NULL; if (!pn) { (void)snpf(pb, sizeof(pb), "%d", p); pn = pb; } (void)update_portmap(ctx, pt, pn); } return (pt->name); } } #endif /* !defined(HASNORPC_H) */ for (pt = Pth[pr][h]; pt; pt = pt->next) { if (pt->port == p) return (pt->name); } /* * Search for a possible service name, unless the -P option has been * specified. * * If there is no service name, return a %d conversion. * * Don't cache %d conversions; a zero port number is a %d conversion that * is represented by "*". */ pn = Fport ? lkup_svcnam(ctx, h, p, pr, 1) : (char *)NULL; if (!pn || !strlen(pn)) { if (p) { (void)snpf(pb, sizeof(pb), "%d", p); return (pb); } else return ("*"); } /* * Allocate a new porttab entry for the TCP or UDP service name. */ if (!(pt = (struct porttab *)malloc(sizeof(struct porttab)))) { (void)fprintf(stderr, "%s: can't allocate porttab entry for port %d\n", Pn, p); Error(ctx); } /* * Allocate space for the name; copy it to the porttab entry; and link the * porttab entry to its hash bucket. * * Return a pointer to the name. */ if (!(nm = mkstrcpy(pn, &nl))) { (void)fprintf(stderr, "%s: can't allocate space for port name: ", Pn); safestrprt(pn, stderr, 1); Error(ctx); } pt->name = nm; pt->nl = nl; pt->port = p; pt->next = Pth[pr][h]; pt->ss = 0; Pth[pr][h] = pt; return (nm); } /* * lkup_svcnam() - look up service name for port */ static char *lkup_svcnam(struct lsof_context *ctx, /* context */ int h, /* porttab hash index */ int p, /* port number */ int pr, /* protocol: 0 = TCP, 1 = UDP */ int ss) /* search status: 1 = Pth[pr][h] * already searched */ { static int fl[PORTTABTHRESH]; static int fln = 0; static int gsbp = 0; int i; struct porttab *pt; static int ptf = 0; struct servent *se; /* * Do nothing if -P has been specified. */ if (!Fport) return ((char *)NULL); for (;;) { /* * Search service name cache, if it hasn't already been done. * Return the name of a match. */ if (!ss) { for (pt = Pth[pr][h]; pt; pt = pt->next) { if (pt->port == p) return (pt->name); } } /* * If fill_porttab() has been called, there is no service name. * * Do PORTTABTHRES getservbport() calls, remembering the failures, so * they won't be repeated. * * After PORTABTHRESH getservbyport() calls, call fill_porttab() once, */ if (ptf) break; if (gsbp < PORTTABTHRESH) { for (i = 0; i < fln; i++) { if (fl[i] == p) return ((char *)NULL); } gsbp++; if ((se = getservbyport(htons(p), pr ? "udp" : "tcp"))) return (se->s_name); if (fln < PORTTABTHRESH) fl[fln++] = p; return ((char *)NULL); } (void)fill_porttab(ctx); ptf++; ss = 0; } return ((char *)NULL); } /* * print_file() - print file */ void print_file(struct lsof_context *ctx) { char buf[128]; char *cp = (char *)NULL; dev_t dev; int devs, len; char access; char lock; char fd[FDLEN]; char type[TYPEL]; if (PrPass && !Hdr) { /* * Print the header line if this is the second pass and the * header hasn't already been printed. */ (void)printf("%-*.*s %*s", CmdColW, CmdColW, CMDTTL, PidColW, PIDTTL); #if defined(HASTASKS) if (TaskPrtTid) (void)printf(" %*s", TaskTidColW, TASKTIDTTL); if (TaskPrtCmd) (void)printf(" %-*.*s", TaskCmdColW, TaskCmdColW, TASKCMDTTL); #endif /* defined(HASTASKS) */ #if defined(HASZONES) if (Fzone) (void)printf(" %-*s", ZoneColW, ZONETTL); #endif /* defined(HASZONES) */ #if defined(HASSELINUX) if (Fcntx) (void)printf(" %-*s", CntxColW, CNTXTTL); #endif /* defined(HASSELINUX) */ #if defined(HASPPID) if (Fppid) (void)printf(" %*s", PpidColW, PPIDTTL); #endif /* defined(HASPPID) */ if (Fpgid) (void)printf(" %*s", PgidColW, PGIDTTL); (void)printf(" %*s %*s %*s", UserColW, USERTTL, FdColW - 2, FDTTL, TypeColW, TYPETTL); #if defined(HASFSTRUCT) if (Fsv) { # if !defined(HASNOFSADDR) if (Fsv & FSV_FA) (void)printf(" %*s", FsColW, FSTTL); # endif /* !defined(HASNOFSADDR) */ # if !defined(HASNOFSCOUNT) if (Fsv & FSV_CT) (void)printf(" %*s", FcColW, FCTTL); # endif /* !defined(HASNOFSCOUNT) */ # if !defined(HASNOFSFLAGS) if (Fsv & FSV_FG) (void)printf(" %*s", FgColW, FGTTL); # endif /* !defined(HASNOFSFLAGS) */ # if !defined(HASNOFSNADDR) if (Fsv & FSV_NI) (void)printf(" %*s", NiColW, NiTtl); # endif /* !defined(HASNOFSNADDR) */ } #endif /* defined(HASFSTRUCT) */ (void)printf(" %*s", DevColW, DEVTTL); if (Foffset) (void)printf(" %*s", SzOffColW, OFFTTL); else if (Fsize) (void)printf(" %*s", SzOffColW, SZTTL); else (void)printf(" %*s", SzOffColW, SZOFFTTL); if (Fnlink) (void)printf(" %*s", NlColW, NLTTL); (void)printf(" %*s %s\n", NodeColW, NODETTL, NMTTL); Hdr++; } /* * Size or print the command. * * CAUTION: command can be empty, see issue #246, * use NULL to represent failure instead of empty string */ cp = Lp->cmd ? Lp->cmd : "(unknown)"; if (!PrPass) { len = safestrlen(cp, 2); if (CmdLim && (len > CmdLim)) len = CmdLim; if (len > CmdColW) CmdColW = len; } else safestrprtn(cp, CmdColW, stdout, 2); /* * Size or print the process ID. */ if (!PrPass) { (void)snpf(buf, sizeof(buf), "%d", Lp->pid); if ((len = strlen(buf)) > PidColW) PidColW = len; } else (void)printf(" %*d", PidColW, Lp->pid); #if defined(HASTASKS) /* * Size or print task ID and command name. */ if (!PrPass) { if ((cp = Lp->tcmd)) { len = safestrlen(cp, 2); if (TaskCmdLim && (len > TaskCmdLim)) len = TaskCmdLim; if (len > TaskCmdColW) TaskCmdColW = len; TaskPrtCmd = 1; } if (Lp->tid) { (void)snpf(buf, sizeof(buf), "%d", Lp->tid); if ((len = strlen(buf)) > TaskTidColW) TaskTidColW = len; TaskPrtTid = 1; } } else { if (TaskPrtTid) { if (Lp->tid) (void)printf(" %*d", TaskTidColW, Lp->tid); else (void)printf(" %*s", TaskTidColW, ""); } if (TaskPrtCmd) { cp = Lp->tcmd ? Lp->tcmd : ""; printf(" "); safestrprtn(cp, TaskCmdColW, stdout, 2); } } #endif /* defined(HASTASKS) */ #if defined(HASZONES) /* * Size or print the zone. */ if (Fzone) { if (!PrPass) { if (Lp->zn) { if ((len = strlen(Lp->zn)) > ZoneColW) ZoneColW = len; } } else (void)printf(" %-*s", ZoneColW, Lp->zn ? Lp->zn : ""); } #endif /* defined(HASZONES) */ #if defined(HASSELINUX) /* * Size or print the context. */ if (Fcntx) { if (!PrPass) { if (Lp->cntx) { if ((len = strlen(Lp->cntx)) > CntxColW) CntxColW = len; } } else (void)printf(" %-*s", CntxColW, Lp->cntx ? Lp->cntx : ""); } #endif /* defined(HASSELINUX) */ #if defined(HASPPID) if (Fppid) { /* * Size or print the parent process ID. */ if (!PrPass) { (void)snpf(buf, sizeof(buf), "%d", Lp->ppid); if ((len = strlen(buf)) > PpidColW) PpidColW = len; } else (void)printf(" %*d", PpidColW, Lp->ppid); } #endif /* defined(HASPPID) */ if (Fpgid) { /* * Size or print the process group ID. */ if (!PrPass) { (void)snpf(buf, sizeof(buf), "%d", Lp->pgid); if ((len = strlen(buf)) > PgidColW) PgidColW = len; } else (void)printf(" %*d", PgidColW, Lp->pgid); } /* * Size or print the user ID or login name. */ if (!PrPass) { if ((len = strlen(printuid(ctx, (UID_ARG)Lp->uid, NULL))) > UserColW) UserColW = len; } else (void)printf(" %*.*s", UserColW, UserColW, printuid(ctx, (UID_ARG)Lp->uid, NULL)); /* * Size or print the file descriptor, access mode and lock status. */ fd_to_string(Lf->fd_type, Lf->fd_num, fd); access = access_to_char(Lf->access); lock = lock_to_char(Lf->lock); if (!PrPass) { (void)snpf(buf, sizeof(buf), "%s%c%c", fd, (lock == ' ') ? access : (access == ' ') ? '-' : access, lock); if ((len = strlen(buf)) > FdColW) FdColW = len; } else (void)printf(" %*.*s%c%c", FdColW - 2, FdColW - 2, fd, (lock == ' ') ? access : (access == ' ') ? '-' : access, lock); /* * Size or print the type. */ file_type_to_string(Lf->type, Lf->unknown_file_type_number, type, sizeof(type)); if (!PrPass) { if ((len = strlen(type)) > TypeColW) TypeColW = len; } else (void)printf(" %*.*s", TypeColW, TypeColW, type); #if defined(HASFSTRUCT) /* * Size or print the file structure address, file usage count, and node * ID (address). */ if (Fsv) { # if !defined(HASNOFSADDR) if (Fsv & FSV_FA) { cp = (Lf->fsv & FSV_FA) ? print_kptr(Lf->fsa, buf, sizeof(buf)) : ""; if (!PrPass) { if ((len = strlen(cp)) > FsColW) FsColW = len; } else (void)printf(" %*.*s", FsColW, FsColW, cp); } # endif /* !defined(HASNOFSADDR) */ # if !defined(HASNOFSCOUNT) if (Fsv & FSV_CT) { if (Lf->fsv & FSV_CT) { (void)snpf(buf, sizeof(buf), "%ld", Lf->fct); cp = buf; } else cp = ""; if (!PrPass) { if ((len = strlen(cp)) > FcColW) FcColW = len; } else (void)printf(" %*.*s", FcColW, FcColW, cp); } # endif /* !defined(HASNOFSCOUNT) */ # if !defined(HASNOFSFLAGS) if (Fsv & FSV_FG) { if ((Lf->fsv & FSV_FG) && (FsvFlagX || Lf->ffg || Lf->pof)) cp = print_fflags(ctx, Lf->ffg, Lf->pof); else cp = ""; if (!PrPass) { if ((len = strlen(cp)) > FgColW) FgColW = len; } else (void)printf(" %*.*s", FgColW, FgColW, cp); } # endif /* !defined(HASNOFSFLAGS) */ # if !defined(HASNOFSNADDR) if (Fsv & FSV_NI) { cp = (Lf->fsv & FSV_NI) ? print_kptr(Lf->fna, buf, sizeof(buf)) : ""; if (!PrPass) { if ((len = strlen(cp)) > NiColW) NiColW = len; } else (void)printf(" %*.*s", NiColW, NiColW, cp); } # endif /* !defined(HASNOFSNADDR) */ } #endif /* defined(HASFSTRUCT) */ /* * Size or print the device information. */ if (Lf->rdev_def) { dev = Lf->rdev; devs = 1; } else if (Lf->dev_def) { dev = Lf->dev; devs = 1; } else devs = 0; if (devs) { #if defined(HASPRINTDEV) cp = HASPRINTDEV(Lf, &dev); #else /* !defined(HASPRINTDEV) */ (void)snpf(buf, sizeof(buf), "%u,%u", GET_MAJ_DEV(dev), GET_MIN_DEV(dev)); cp = buf; #endif /* defined(HASPRINTDEV) */ } if (!PrPass) { if (devs) len = strlen(cp); else if (Lf->dev_ch) len = strlen(Lf->dev_ch); else len = 0; if (len > DevColW) DevColW = len; } else { if (devs) (void)printf(" %*.*s", DevColW, DevColW, cp); else { if (Lf->dev_ch) (void)printf(" %*.*s", DevColW, DevColW, Lf->dev_ch); else (void)printf(" %*.*s", DevColW, DevColW, ""); } } /* * Size or print the size or offset. */ if (!PrPass) { if (!Foffset && Lf->sz_def) { if (Fhuman) { len = human_readable_size(Lf->sz, 0, 0); } else { (void)snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); len = strlen(buf); } } else if (!Fsize && Lf->off_def) { (void)snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); cp = buf; len = strlen(cp); if (OffDecDig && len > (OffDecDig + 2)) { (void)snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); cp = buf; len = strlen(cp); } } else len = 0; if (len > SzOffColW) SzOffColW = len; } else { putchar(' '); if (!Foffset && Lf->sz_def) { if (Fhuman) { human_readable_size(Lf->sz, 1, SzOffColW); } else { (void)snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); len = strlen(buf); (void)printf(SzOffFmt_dv, SzOffColW, Lf->sz); } } else if (!Fsize && Lf->off_def) { (void)snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); cp = buf; if (OffDecDig && (int)strlen(cp) > (OffDecDig + 2)) { (void)snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); cp = buf; } (void)printf("%*.*s", SzOffColW, SzOffColW, cp); } else (void)printf("%*.*s", SzOffColW, SzOffColW, ""); } /* * Size or print the link count. */ if (Fnlink) { if (Lf->nlink_def) { (void)snpf(buf, sizeof(buf), " %ld", Lf->nlink); cp = buf; } else cp = ""; if (!PrPass) { if ((len = strlen(cp)) > NlColW) NlColW = len; } else (void)printf(" %*s", NlColW, cp); } /* * Size or print the inode information. */ switch (Lf->inp_ty) { case 1: #if defined(HASPRINTINO) cp = HASPRINTINO(Lf); #else /* !defined(HASPRINTINO) */ (void)snpf(buf, sizeof(buf), InodeFmt_d, Lf->inode); cp = buf; #endif /* defined(HASPRINTINO) */ break; case 2: if (Lf->iproto[0]) cp = Lf->iproto; else cp = ""; break; case 3: (void)snpf(buf, sizeof(buf), InodeFmt_x, Lf->inode); cp = buf; break; default: cp = ""; } if (!PrPass) { if ((len = strlen(cp)) > NodeColW) NodeColW = len; } else { (void)printf(" %*.*s", NodeColW, NodeColW, cp); } /* * If this is the second pass, print the name column. (It doesn't need * to be sized.) */ if (PrPass) { putchar(' '); #if defined(HASPRINTNM) HASPRINTNM(ctx, Lf); #else /* !defined(HASPRINTNM) */ printname(ctx, 1); #endif /* defined(HASPRINTNM) */ } } /* * printinaddr() - print Internet addresses */ static int printinaddr(struct lsof_context *ctx) { int i, len, src; char *host, *port; int nl = Namechl - 1; char *np = Namech; char pbuf[32]; /* * Process local network address first. If there's a foreign address, * separate it from the local address with "->". */ for (i = 0, *np = '\0'; i < 2; i++) { if (!Lf->li[i].af) continue; host = port = (char *)NULL; if (i) { /* * If this is the foreign address, insert the separator. */ if (nl < 2) addr_too_long : { (void)snpf(Namech, Namechl, "network addresses too long"); return (1); } (void)snpf(np, nl, "->"); np += 2; nl -= 2; } /* * Convert the address to a host name. */ #if defined(HASIPv6) if ((Lf->li[i].af == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&Lf->li[i].ia.a6)) || (Lf->li[i].af == AF_INET && Lf->li[i].ia.a4.s_addr == INADDR_ANY)) host = "*"; else host = gethostnm(ctx, (unsigned char *)&Lf->li[i].ia, Lf->li[i].af); #else /* !defined(HASIPv6) */ if (Lf->li[i].ia.a4.s_addr == INADDR_ANY) host = "*"; else host = gethostnm(ctx, (unsigned char *)&Lf->li[i].ia, Lf->li[i].af); #endif /* defined(HASIPv6) */ /* * Process the port number. */ if (Lf->li[i].p > 0) { if (Fport #if !defined(HASNORPC_H) || FportMap #endif /* defined(HASNORPC_H) */ ) { /* * If converting port numbers to service names, or looking * up portmap program names and numbers, do so by protocol. * * Identify the port source as local if: 1) it comes from the * local entry (0) of the file's Internet address array; or * 2) it comes from the foreign entry (1), and the foreign * Internet address matches the local one; or 3) it is the * loopback address 127.0.0.1. (Test 2 may not always work * -- e.g., on hosts with multiple interfaces.) */ #if !defined(HASNORPC_H) if ((src = i) && FportMap) { # if defined(HASIPv6) if (Lf->li[0].af == AF_INET6) { if (IN6_IS_ADDR_LOOPBACK(&Lf->li[i].ia.a6) || IN6_ARE_ADDR_EQUAL(&Lf->li[0].ia.a6, &Lf->li[1].ia.a6)) src = 0; } else # endif /* defined(HASIPv6) */ if (Lf->li[0].af == AF_INET) { if (Lf->li[i].ia.a4.s_addr == htonl(INADDR_LOOPBACK) || Lf->li[0].ia.a4.s_addr == Lf->li[1].ia.a4.s_addr) src = 0; } } #else /* * Just for suppressing warnings reported from compiler. * * src is referenced in lkup_port() only if * "!defined(HASNORPC_H)" is true. The condition here is * !defined(HASNORPC_H) is false. Therefore the value of src has * no impact. */ src = 1; #endif /* !defined(HASNORPC_H) */ if (strcasecmp(Lf->iproto, "TCP") == 0) port = lkup_port(ctx, Lf->li[i].p, 0, src); else if (strcasecmp(Lf->iproto, "UDP") == 0) port = lkup_port(ctx, Lf->li[i].p, 1, src); } if (!port) { (void)snpf(pbuf, sizeof(pbuf), "%d", Lf->li[i].p); port = pbuf; } } else if (Lf->li[i].p == 0) port = "*"; /* * Enter the host name. */ if (host) { if ((len = strlen(host)) > nl) goto addr_too_long; if (len) { (void)snpf(np, nl, "%s", host); np += len; nl -= len; } } /* * Enter the port number, preceded by a colon. */ if (port) { if (((len = strlen(port)) + 1) >= nl) goto addr_too_long; (void)snpf(np, nl, ":%s", port); np += len + 1; nl -= len - 1; } } if (Namech[0]) { safestrprt(Namech, stdout, 0); return (1); } return (0); } /* * print_init() - initialize for printing */ void print_init(struct lsof_context *ctx) { /* * Preset standard values. */ PrPass = (Ffield || Fterse) ? 1 : 0; LastPid = -1; TaskPrtCmd = TaskPrtTid = 0; /* * Size columns by their titles. */ CmdColW = strlen(CMDTTL); DevColW = strlen(DEVTTL); FdColW = strlen(FDTTL); if (Fnlink) NlColW = strlen(NLTTL); NmColW = strlen(NMTTL); NodeColW = strlen(NODETTL); PgidColW = strlen(PGIDTTL); PidColW = strlen(PIDTTL); PpidColW = strlen(PPIDTTL); if (Fsize) SzOffColW = strlen(SZTTL); else if (Foffset) SzOffColW = strlen(OFFTTL); else SzOffColW = strlen(SZOFFTTL); #if defined(HASTASKS) TaskCmdColW = strlen(TASKCMDTTL); TaskTidColW = strlen(TASKTIDTTL); #endif /* defined(HASTASKS) */ TypeColW = strlen(TYPETTL); UserColW = strlen(USERTTL); #if defined(HASFSTRUCT) # if !defined(HASNOFSADDR) FsColW = strlen(FSTTL); # endif /* !defined(HASNOFSADDR) */ # if !defined(HASNOFSCOUNT) FcColW = strlen(FCTTL); # endif /* !defined(HASNOFSCOUNT) */ # if !defined(HASNOFSFLAGS) FgColW = strlen(FGTTL); # endif /* !defined(HASNOFSFLAGS) */ # if !defined(HASNOFSNADDR) NiColW = strlen(NiTtl); # endif /* !defined(HASNOFSNADDR) */ #endif /* defined(HASFSTRUCT) */ #if defined(HASSELINUX) if (Fcntx) CntxColW = strlen(CNTXTTL); #endif /* defined(HASSELINUX) */ #if defined(HASZONES) if (Fzone) ZoneColW = strlen(ZONETTL); #endif /* defined(HASZONES) */ } /* * printname() - print output name field */ void printname(struct lsof_context *ctx, int nl) /* NL status */ { #if defined(HASNCACHE) char buf[MAXPATHLEN]; char *cp; int fp; #endif /* defined(HASNCACHE) */ int ps = 0; if (Lf->nm && Lf->nm[0]) { /* * Print the name characters, if there are some. */ safestrprt(Lf->nm, stdout, 0); ps++; if (!Lf->li[0].af && !Lf->li[1].af) goto print_nma; } if (Lf->li[0].af || Lf->li[1].af) { if (ps) putchar(' '); /* * If the file has Internet addresses, print them. */ if (printinaddr(ctx)) ps++; goto print_nma; } if (((Lf->ntype == N_BLK) || (Lf->ntype == N_CHR)) && Lf->dev_def && Lf->rdev_def && printdevname(ctx, &Lf->dev, &Lf->rdev, 0, Lf->ntype)) { /* * If this is a block or character device and it has a name, print it. */ ps++; goto print_nma; } if (Lf->is_com) { /* * If this is a common node, print that fact. */ (void)fputs("COMMON: ", stdout); ps++; goto print_nma; } #if defined(HASPRIVNMCACHE) if (HASPRIVNMCACHE(ctx, Lf)) { ps++; goto print_nma; } #endif /* defined(HASPRIVNMCACHE) */ if (Lf->lmi_srch) { struct mounts *mp; /* * Do a deferred local mount info table search for the file system * (mounted) directory name and inode number, and mounted device name. */ for (mp = readmnt(ctx); mp; mp = mp->next) { if (Lf->dev == mp->dev) { Lf->fsdir = mp->dir; Lf->fsdev = mp->fsname; #if defined(HASFSINO) Lf->fs_ino = mp->inode; #endif /* defined(HASFSINO) */ break; } } Lf->lmi_srch = 0; } if (Lf->fsdir || Lf->fsdev) { /* * Print the file system directory name, device name, and * possible path name components. */ #if !defined(HASNCACHE) || HASNCACHE < 2 if (Lf->fsdir) { safestrprt(Lf->fsdir, stdout, 0); ps++; } #endif /* !defined(HASNCACHE) || HASNCACHE<2 */ #if defined(HASNCACHE) # if HASNCACHE < 2 if (Lf->na) { if (NcacheReload) { # if defined(NCACHELDPFX) NCACHELDPFX # endif /* defined(NCACHELDPFX) */ (void) ncache_load(ctx); # if defined(NCACHELDSFX) NCACHELDSFX # endif /* defined(NCACHELDSFX) */ NcacheReload = 0; } if ((cp = ncache_lookup(ctx, buf, sizeof(buf), &fp))) { char *cp1; if (*cp == '\0') goto print_nma; if (fp && Lf->fsdir) { if (*cp != '/') { cp1 = strrchr(Lf->fsdir, '/'); if (cp1 == (char *)NULL || *(cp1 + 1) != '\0') putchar('/'); } } else (void)fputs(" -- ", stdout); safestrprt(cp, stdout, 0); ps++; goto print_nma; } } # else /* HASNCACHE>1 */ if (NcacheReload) { # if defined(NCACHELDPFX) NCACHELDPFX # endif /* defined(NCACHELDPFX) */ (void) ncache_load(); # if defined(NCACHELDSFX) NCACHELDSFX # endif /* defined(NCACHELDSFX) */ NcacheReload = 0; } if ((cp = ncache_lookup(buf, sizeof(buf), &fp))) { if (fp) { safestrprt(cp, stdout, 0); ps++; } else { if (Lf->fsdir) { safestrprt(Lf->fsdir, stdout, 0); ps++; } if (*cp) { (void)fputs(" -- ", stdout); safestrprt(cp, stdout, 0); ps++; } } goto print_nma; } if (Lf->fsdir) { safestrprt(Lf->fsdir, stdout, 0); ps++; } # endif /* HASNCACHE<2 */ #endif /* defined(HASNCACHE) */ if (Lf->fsdev) { if (Lf->fsdir) (void)fputs(" (", stdout); else (void)putchar('('); safestrprt(Lf->fsdev, stdout, 0); (void)putchar(')'); ps++; } } /* * Print the NAME column addition, if there is one. If there isn't * make sure a NL is printed, as requested. */ print_nma: if (Lf->nma) { if (ps) putchar(' '); safestrprt(Lf->nma, stdout, 0); ps++; } /* * If this file has TCP/IP state information, print it. */ if (!Ffield && Ftcptpi && (Lf->lts.type >= 0 #if defined(HASTCPTPIQ) || ((Ftcptpi & TCPTPI_QUEUES) && (Lf->lts.rqs || Lf->lts.sqs)) #endif /* defined(HASTCPTPIQ) */ #if defined(HASTCPTPIW) || ((Ftcptpi & TCPTPI_WINDOWS) && (Lf->lts.rws || Lf->lts.wws)) #endif /* defined(HASTCPTPIW) */ )) { if (ps) putchar(' '); (void)print_tcptpi(ctx, 0); } if (nl) putchar('\n'); } /* * printrawaddr() - print raw socket address */ void printrawaddr(struct lsof_context *ctx, struct sockaddr *sa) /* socket address */ { char *ep; size_t sz; ep = endnm(ctx, &sz); (void)snpf(ep, sz, "%u/%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", sa->sa_family, (unsigned char)sa->sa_data[0], (unsigned char)sa->sa_data[1], (unsigned char)sa->sa_data[2], (unsigned char)sa->sa_data[3], (unsigned char)sa->sa_data[4], (unsigned char)sa->sa_data[5], (unsigned char)sa->sa_data[6], (unsigned char)sa->sa_data[7], (unsigned char)sa->sa_data[8], (unsigned char)sa->sa_data[9], (unsigned char)sa->sa_data[10], (unsigned char)sa->sa_data[11], (unsigned char)sa->sa_data[12], (unsigned char)sa->sa_data[13]); } /* * printsockty() - print socket type */ char *printsockty(int ty) /* socket type -- e.g., from so_type */ { static char buf[64]; char *cp; switch (ty) { #if defined(SOCK_STREAM) case SOCK_STREAM: cp = "STREAM"; break; #endif /* defined(SOCK_STREAM) */ #if defined(SOCK_STREAM) case SOCK_DGRAM: cp = "DGRAM"; break; #endif /* defined(SOCK_DGRAM) */ #if defined(SOCK_RAW) case SOCK_RAW: cp = "RAW"; break; #endif /* defined(SOCK_RAW) */ #if defined(SOCK_RDM) case SOCK_RDM: cp = "RDM"; break; #endif /* defined(SOCK_RDM) */ #if defined(SOCK_SEQPACKET) case SOCK_SEQPACKET: cp = "SEQPACKET"; break; #endif /* defined(SOCK_SEQPACKET) */ default: (void)snpf(buf, sizeof(buf), "SOCK_%#x", ty); return (buf); } (void)snpf(buf, sizeof(buf), "SOCK_%s", cp); return (buf); } /* * printuid() - print User ID or login name */ char *printuid(struct lsof_context *ctx, /* context */ UID_ARG uid, /* User IDentification number */ int *ty) /* returned UID type pointer (NULL * (if none wanted). If non-NULL * then: *ty = 0 = login name * = 1 = UID number */ { int i; struct passwd *pw; struct stat sb; static struct stat sbs; static struct uidcache { uid_t uid; char nm[LOGINML + 1]; struct uidcache *next; } **uc = (struct uidcache **)NULL; struct uidcache *up, *upn; static char user[USERPRTL + 1]; if (Futol) { if (CkPasswd) { /* * Get the mtime and ctime of /etc/passwd, as required. */ if (stat("/etc/passwd", &sb) != 0) { (void)fprintf(stderr, "%s: can't stat(/etc/passwd): %s\n", Pn, strerror(errno)); Error(ctx); } } /* * Define the UID cache, if necessary. */ if (!uc) { if (!(uc = (struct uidcache **)calloc(UIDCACHEL, sizeof(struct uidcache *)))) { (void)fprintf( stderr, "%s: no space for %d byte UID cache hash buckets\n", Pn, (int)(UIDCACHEL * (sizeof(struct uidcache *)))); Error(ctx); } if (CkPasswd) { sbs = sb; CkPasswd = 0; } } /* * If it's time to check /etc/passwd and if its the mtime/ctime has * changed, destroy the existing UID cache. */ if (CkPasswd) { if (sbs.st_mtime != sb.st_mtime || sbs.st_ctime != sb.st_ctime) { for (i = 0; i < UIDCACHEL; i++) { if ((up = uc[i])) { do { upn = up->next; (void)free((FREE_P *)up); } while ((up = upn) != (struct uidcache *)NULL); uc[i] = (struct uidcache *)NULL; } } sbs = sb; } CkPasswd = 0; } /* * Search the UID cache. */ i = (int)((((unsigned long)uid * 31415L) >> 7) & (UIDCACHEL - 1)); for (up = uc[i]; up; up = up->next) { if (up->uid == (uid_t)uid) { if (ty) *ty = 0; return (up->nm); } } /* * The UID is not in the cache. * * Look up the login name from the UID for a new cache entry. */ if (!(pw = getpwuid((uid_t)uid))) { if (!Fwarn) { (void)fprintf(stderr, "%s: no pwd entry for UID %lu\n", Pn, (unsigned long)uid); } } else { /* * Allocate and fill a new cache entry. Link it to its hash bucket. */ if (!(upn = (struct uidcache *)malloc(sizeof(struct uidcache)))) { (void)fprintf( stderr, "%s: no space for UID cache entry for: %lu, %s)\n", Pn, (unsigned long)uid, pw->pw_name); Error(ctx); } (void)strncpy(upn->nm, pw->pw_name, LOGINML); upn->nm[LOGINML] = '\0'; upn->uid = (uid_t)uid; upn->next = uc[i]; uc[i] = upn; if (ty) *ty = 0; return (upn->nm); } } /* * Produce a numeric conversion of the UID. */ (void)snpf(user, sizeof(user), "%*lu", USERPRTL, (unsigned long)uid); if (ty) *ty = 1; return (user); } #if !defined(HASNORPC_H) /* * update_portmap() - update a portmap entry with its port number or service * name */ static void update_portmap(struct lsof_context *ctx, /* context */ struct porttab *pt, /* porttab entry */ char *pn) /* port name */ { MALLOC_S al, nl; char *cp; if (pt->ss) return; if (!(al = strlen(pn))) { pt->ss = 1; return; } nl = al + pt->nl + 2; if (!(cp = (char *)malloc(nl + 1))) { (void)fprintf(stderr, "%s: can't allocate %d bytes for portmap name: %s[%s]\n", Pn, (int)(nl + 1), pn, pt->name); Error(ctx); } (void)snpf(cp, nl + 1, "%s[%s]", pn, pt->name); (void)free((FREE_P *)pt->name); pt->name = cp; pt->nl = nl; pt->ss = 1; } #endif /* !defined(HASNORPC_H) */ /* * Convert sz to human readable format, print to stdout if print=1 * * Return the length of output */ int human_readable_size(SZOFFTYPE sz, int print, int col) { char buf[128]; SZOFFTYPE base = 1024; SZOFFTYPE unit = base; SZOFFTYPE upper = base * base; int suffix_count = 6; char *suffix[6] = {"K", "M", "G", "T", "P", "E"}; int i; int len; double val; if (sz < base) { /* <1KB */ (void)snpf(buf, sizeof(buf), "%" SZOFFPSPEC "uB", sz); } else { for (i = 0; i < suffix_count - 1; i++) { if (sz < upper) { break; } unit = upper; upper = upper * base; } /* Avoid floating point overflow */ val = (double)(sz / (unit / base)) / base; (void)snpf(buf, sizeof(buf), "%.1lf%s", val, suffix[i]); } if (print) { printf("%*s", col, buf); } return strlen(buf); } /* * print_proc() - print process */ int print_proc(struct lsof_context *ctx) { char buf[128], *cp; int lc, len, st, ty; int rv = 0; unsigned long ul; char fd[FDLEN]; char type[TYPEL]; /* * If nothing in the process has been selected, skip it. */ if (!Lp->pss) return (0); if (Fterse) { if (Lp->pid == LastPid) /* eliminate duplicates */ return (0); LastPid = Lp->pid; /* * The mode is terse and something in the process appears to have * been selected. Make sure of that by looking for a selected file, * so that the HASSECURITY and HASNOSOCKSECURITY option combination * won't produce a false positive result. */ for (Lf = Lp->file; Lf; Lf = Lf->next) { if (is_file_sel(ctx, Lp, Lf)) { (void)printf("%d\n", Lp->pid); return (1); } } return (0); } /* * If fields have been selected, output the process-only ones, provided * that some file has also been selected. */ if (Ffield) { for (Lf = Lp->file; Lf; Lf = Lf->next) { if (is_file_sel(ctx, Lp, Lf)) break; } if (!Lf) return (rv); rv = 1; (void)printf("%c%d%c", LSOF_FID_PID, Lp->pid, Terminator); #if defined(HASTASKS) if (FieldSel[LSOF_FIX_TID].st && Lp->tid) (void)printf("%c%d%c", LSOF_FID_TID, Lp->tid, Terminator); if (FieldSel[LSOF_FIX_TCMD].st && Lp->tcmd) (void)printf("%c%s%c", LSOF_FID_TCMD, Lp->tcmd, Terminator); #endif /* defined(HASTASKS) */ #if defined(HASZONES) if (FieldSel[LSOF_FIX_ZONE].st && Fzone && Lp->zn) (void)printf("%c%s%c", LSOF_FID_ZONE, Lp->zn, Terminator); #endif /* defined(HASZONES) */ #if defined(HASSELINUX) if (FieldSel[LSOF_FIX_CNTX].st && Fcntx && Lp->cntx && CntxStatus) (void)printf("%c%s%c", LSOF_FID_CNTX, Lp->cntx, Terminator); #endif /* defined(HASSELINUX) */ if (FieldSel[LSOF_FIX_PGID].st && Fpgid) (void)printf("%c%d%c", LSOF_FID_PGID, Lp->pgid, Terminator); #if defined(HASPPID) if (FieldSel[LSOF_FIX_PPID].st && Fppid) (void)printf("%c%d%c", LSOF_FID_PPID, Lp->ppid, Terminator); #endif /* defined(HASPPID) */ if (FieldSel[LSOF_FIX_CMD].st) { putchar(LSOF_FID_CMD); safestrprt(Lp->cmd ? Lp->cmd : "(unknown)", stdout, 0); putchar(Terminator); } if (FieldSel[LSOF_FIX_UID].st) (void)printf("%c%d%c", LSOF_FID_UID, (int)Lp->uid, Terminator); if (FieldSel[LSOF_FIX_LOGIN].st) { cp = printuid(ctx, (UID_ARG)Lp->uid, &ty); if (ty == 0) (void)printf("%c%s%c", LSOF_FID_LOGIN, cp, Terminator); } if (Terminator == '\0') putchar('\n'); } /* * Print files. */ for (Lf = Lp->file; Lf; Lf = Lf->next) { if (!is_file_sel(ctx, Lp, Lf)) continue; rv = 1; /* * If no field output selected, print dialect-specific formatted * output. */ if (!Ffield) { print_file(ctx); continue; } lc = st = 0; if (FieldSel[LSOF_FIX_FD].st) { fd_to_string(Lf->fd_type, Lf->fd_num, fd); (void)printf("%c%s%c", LSOF_FID_FD, fd, Terminator); lc++; } /* * Print selected fields. */ if (FieldSel[LSOF_FIX_ACCESS].st) { (void)printf("%c%c%c", LSOF_FID_ACCESS, access_to_char(Lf->access), Terminator); lc++; } if (FieldSel[LSOF_FIX_LOCK].st) { (void)printf("%c%c%c", LSOF_FID_LOCK, lock_to_char(Lf->lock), Terminator); lc++; } if (FieldSel[LSOF_FIX_TYPE].st) { if (Lf->type != LSOF_FILE_NONE) { file_type_to_string(Lf->type, Lf->unknown_file_type_number, type, TYPEL); (void)printf("%c%s%c", LSOF_FID_TYPE, type, Terminator); lc++; } } #if defined(HASFSTRUCT) if (FieldSel[LSOF_FIX_FA].st && (Fsv & FSV_FA) && (Lf->fsv & FSV_FA)) { (void)printf("%c%s%c", LSOF_FID_FA, print_kptr(Lf->fsa, (char *)NULL, 0), Terminator); lc++; } if (FieldSel[LSOF_FIX_CT].st && (Fsv & FSV_CT) && (Lf->fsv & FSV_CT)) { (void)printf("%c%ld%c", LSOF_FID_CT, Lf->fct, Terminator); lc++; } if (FieldSel[LSOF_FIX_FG].st && (Fsv & FSV_FG) && (Lf->fsv & FSV_FG) && (FsvFlagX || Lf->ffg || Lf->pof)) { (void)printf("%c%s%c", LSOF_FID_FG, print_fflags(ctx, Lf->ffg, Lf->pof), Terminator); lc++; } if (FieldSel[LSOF_FIX_NI].st && (Fsv & FSV_NI) && (Lf->fsv & FSV_NI)) { (void)printf("%c%s%c", LSOF_FID_NI, print_kptr(Lf->fna, (char *)NULL, 0), Terminator); lc++; } #endif /* defined(HASFSTRUCT) */ if (FieldSel[LSOF_FIX_DEVCH].st && Lf->dev_ch && Lf->dev_ch[0]) { for (cp = Lf->dev_ch; *cp == ' '; cp++) ; if (*cp) { (void)printf("%c%s%c", LSOF_FID_DEVCH, cp, Terminator); lc++; } } if (FieldSel[LSOF_FIX_DEVN].st && Lf->dev_def) { if (sizeof(unsigned long) > sizeof(dev_t)) ul = (unsigned long)((unsigned int)Lf->dev); else ul = (unsigned long)Lf->dev; (void)printf("%c0x%lx%c", LSOF_FID_DEVN, ul, Terminator); lc++; } if (FieldSel[LSOF_FIX_RDEV].st && Lf->rdev_def) { if (sizeof(unsigned long) > sizeof(dev_t)) ul = (unsigned long)((unsigned int)Lf->rdev); else ul = (unsigned long)Lf->rdev; (void)printf("%c0x%lx%c", LSOF_FID_RDEV, ul, Terminator); lc++; } if (FieldSel[LSOF_FIX_SIZE].st && Lf->sz_def) { putchar(LSOF_FID_SIZE); (void)snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); cp = buf; (void)printf("%s", cp); putchar(Terminator); lc++; } if (FieldSel[LSOF_FIX_OFFSET].st && Lf->off_def) { putchar(LSOF_FID_OFFSET); (void)snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); cp = buf; len = strlen(cp); if (OffDecDig && len > (OffDecDig + 2)) { (void)snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); cp = buf; } (void)printf("%s", cp); putchar(Terminator); lc++; } if (FieldSel[LSOF_FIX_INODE].st && Lf->inp_ty == 1) { putchar(LSOF_FID_INODE); (void)printf(InodeFmt_d, Lf->inode); putchar(Terminator); lc++; } if (FieldSel[LSOF_FIX_NLINK].st && Lf->nlink_def) { (void)printf("%c%ld%c", LSOF_FID_NLINK, Lf->nlink, Terminator); lc++; } if (FieldSel[LSOF_FIX_PROTO].st && Lf->inp_ty == 2) { for (cp = Lf->iproto; *cp == ' '; cp++) ; if (*cp) { (void)printf("%c%s%c", LSOF_FID_PROTO, cp, Terminator); lc++; } } if (FieldSel[LSOF_FIX_STREAM].st && Lf->nm && Lf->is_stream) { if (strncmp(Lf->nm, "STR:", 4) == 0 || strcmp(Lf->iproto, "STR") == 0) { putchar(LSOF_FID_STREAM); printname(ctx, 0); putchar(Terminator); lc++; st++; } } if (st == 0 && FieldSel[LSOF_FIX_NAME].st) { putchar(LSOF_FID_NAME); printname(ctx, 0); putchar(Terminator); lc++; } if (Lf->lts.type >= 0 && FieldSel[LSOF_FIX_TCPTPI].st) { print_tcptpi(ctx, 0); lc++; } if (Terminator == '\0' && lc) putchar('\n'); } return (rv); } #if defined(HASFSTRUCT) static char *alloc_fflbuf(struct lsof_context *ctx, char **bp, int *al, int lr); /* * alloc_fflbuf() - allocate file flags print buffer */ static char *alloc_fflbuf(struct lsof_context *ctx, char **bp, /* current buffer pointer */ int *al, /* current allocated length */ int lr) /* length required */ { int sz; sz = (int)(lr + 1); /* allocate '\0' space */ if (*bp && (sz <= *al)) return (*bp); if (*bp) *bp = (char *)realloc((MALLOC_P *)*bp, (MALLOC_S)sz); else *bp = (char *)malloc((MALLOC_S)sz); if (!*bp) { (void)fprintf(stderr, "%s: no space (%d) for print flags\n", Pn, sz); Error(ctx); } *al = sz; return (*bp); } #endif /* defined(HASFSTRUCT) */ #if defined(HASFSTRUCT) /* * print_fflags() - print interpreted f_flag[s] */ char *print_fflags(struct lsof_context *ctx, long ffg, /* file structure's flags value */ long pof) /* process open files flags value */ { int al, ct, fx; static int bl = 0; static char *bp = (char *)NULL; char *sep; int sepl; struct pff_tab *tp; long wf; char xbuf[64]; /* * Reduce the supplied flags according to the definitions in Pff_tab[] and * Pof_tab[]. */ for (ct = fx = 0; fx < 2; fx++) { if (fx == 0) { sep = ""; sepl = 0; tp = Pff_tab; wf = ffg; } else { sep = ";"; sepl = 1; tp = Pof_tab; wf = pof; } for (; wf && !FsvFlagX; ct += al) { while (tp->nm) { if (wf & tp->val) break; tp++; } if (!tp->nm) break; al = (int)strlen(tp->nm) + sepl; bp = alloc_fflbuf(ctx, &bp, &bl, al + ct); (void)snpf(bp + ct, al + 1, "%s%s", sep, tp->nm); sep = ","; sepl = 1; wf &= ~(tp->val); } /* * If flag bits remain, print them in hex. If hex output was * specified with +fG, print all flag values, including zero, * in hex. */ if (wf || FsvFlagX) { (void)snpf(xbuf, sizeof(xbuf), "0x%lx", wf); al = (int)strlen(xbuf) + sepl; bp = alloc_fflbuf(ctx, &bp, &bl, al + ct); (void)snpf(bp + ct, al + 1, "%s%s", sep, xbuf); ct += al; } } /* * Make sure there is at least a NUL terminated reply. */ if (!bp) { bp = alloc_fflbuf(ctx, &bp, &bl, 0); *bp = '\0'; } return (bp); } #endif /* defined(HASFSTRUCT) */