1/*
2 * dfile.c -- Darwin file processing functions for libproc-based lsof
3 */
4
5
6/*
7 * Portions Copyright 2005-2007 Apple Inc.  All rights reserved.
8 *
9 * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
10 * 47907.  All rights reserved.
11 *
12 * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue
13 * University.
14 *
15 * This software is not subject to any license of the American Telephone
16 * and Telegraph Company or the Regents of the University of California.
17 *
18 * Permission is granted to anyone to use this software for any purpose on
19 * any computer system, and to alter it and redistribute it freely, subject
20 * to the following restrictions:
21 *
22 * 1. Neither the authors, nor Apple Inc. nor Purdue University are
23 *    responsible for any consequences of the use of this software.
24 *
25 * 2. The origin of this software must not be misrepresented, either
26 *    by explicit claim or by omission.  Credit to the authors, Apple
27 *    Inc. and Purdue University must appear in documentation and sources.
28 *
29 * 3. Altered versions must be plainly marked as such, and must not be
30 *    misrepresented as being the original software.
31 *
32 * 4. This notice may not be removed or altered.
33 */
34
35
36#ifndef lint
37static char copyright[] =
38"@(#) Copyright 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
39static char *rcsid = "$Id: dfile.c,v 1.8 2012/04/10 16:41:04 abe Exp $";
40#endif
41
42
43#include "lsof.h"
44
45
46/*
47 * enter_file_info() -- enter file information
48 */
49
50void
51enter_file_info(pfi)
52	struct proc_fileinfo *pfi;	/* pointer to process file info */
53{
54	int f;
55/*
56 * Construct access code
57 */
58	f = pfi->fi_openflags & (FREAD | FWRITE);
59	if (f == FREAD)
60	    Lf->access = 'r';
61	else if (f == FWRITE)
62	    Lf->access = 'w';
63	else if (f == (FREAD | FWRITE))
64	    Lf->access = 'u';
65/*
66 * Save the offset / size
67 */
68	Lf->off = (SZOFFTYPE)pfi->fi_offset;
69	if (Foffset)
70	    Lf->off_def = 1;
71/*
72 * Save file structure information as requested.
73 */
74	if (Fsv & FSV_FG) {
75	    Lf->ffg = (long)pfi->fi_openflags;
76	    Lf->fsv |= FSV_FG;
77
78#ifdef		PROC_FP_GUARDED
79	    if (pfi->fi_status & PROC_FP_GUARDED) {
80		Lf->guardflags = pfi->fi_guardflags;
81	    }
82#endif		/* PROC_FP_GUARDED */
83	}
84	Lf->pof = (long)pfi->fi_status;
85}
86
87
88/*
89 * enter_vnode_info() -- enter vnode information
90 */
91
92void
93enter_vnode_info(vip)
94	struct vnode_info_path *vip;	/* pointer to vnode info with path */
95{
96	char buf[32], *cp;
97	dev_t dev = 0;
98	int devs = 0;
99	struct mounts *mp;
100/*
101 * Derive file type.
102 */
103	switch ((int)(vip->vip_vi.vi_stat.vst_mode & S_IFMT)) {
104	case S_IFIFO:
105	    cp = "FIFO";
106	    Ntype = N_FIFO;
107	    break;
108	case S_IFCHR:
109	    cp = "CHR";
110	    Ntype = N_CHR;
111	    break;
112	case S_IFDIR:
113	    cp = "DIR";
114	    Ntype = N_REGLR;
115	    break;
116	case S_IFBLK:
117	    cp = "BLK";
118	    Ntype = N_BLK;
119	    break;
120	case S_IFREG:
121	    cp = "REG";
122	    Ntype = N_REGLR;
123	    break;
124	case S_IFLNK:
125	    cp = "LINK";
126	    Ntype = N_REGLR;
127	    break;
128	default:
129	    (void) snpf(buf, sizeof(buf), "%04o",
130		(((vip->vip_vi.vi_stat.vst_mode & S_IFMT) >> 12) & 0xfff));
131	    cp = buf;
132	    Ntype = N_REGLR;
133	}
134	if (!Lf->type[0])
135	    (void) snpf(Lf->type, sizeof(Lf->type), "%s", cp);
136	Lf->ntype = Ntype;
137/*
138 * Save device number and path
139 */
140	switch (Ntype) {
141	case N_FIFO:
142	    break;
143	case N_CHR:
144	case N_BLK:
145	    Lf->rdev = vip->vip_vi.vi_stat.vst_rdev;
146	    Lf->rdev_def = 1;
147	    /* fall through */
148	default:
149	    Lf->dev = dev = vip->vip_vi.vi_stat.vst_dev;
150	    Lf->dev_def = devs = 1;
151	}
152/*
153 * Save path name.
154 */
155	vip->vip_path[sizeof(vip->vip_path) - 1] = '\0';
156	if (vip->vip_path[0] != '\0') {
157	    Lf->V_path = mkstrcpy(vip->vip_path, (MALLOC_S *)NULL);
158	}
159/*
160 * Save node number.
161 */
162	Lf->inode = (INODETYPE)vip->vip_vi.vi_stat.vst_ino;
163	Lf->inp_ty = 1;
164/*
165 * Save link count, as requested.
166 */
167	if (Fnlink) {
168	    Lf->nlink = vip->vip_vi.vi_stat.vst_nlink;
169	    Lf->nlink_def = 1;
170	    if (Nlink && (Lf->nlink < Nlink))
171		Lf->sf |= SELNLINK;
172	}
173/*
174 * If a device number is defined, locate file system and save its identity.
175 */
176	if (devs) {
177	    for (mp = readmnt(); mp; mp = mp->next) {
178		if (dev == mp->dev) {
179		    Lf->fsdir = mp->dir;
180		    Lf->fsdev = mp->fsname;
181		    if (mp->is_nfs && Fnfs)
182			Lf->sf |= SELNFS;
183		    break;
184		}
185	    }
186	}
187/*
188 * Save the file size.
189 */
190	switch (Ntype) {
191	case N_CHR:
192	case N_FIFO:
193	    Lf->off_def = 1;
194	    break;
195	default:
196	    Lf->sz = (SZOFFTYPE)vip->vip_vi.vi_stat.vst_size;
197	    Lf->sz_def = 1;
198	}
199/*
200 * Test for specified file.
201 */
202	if (Sfile && is_file_named(NULL,
203				   ((Ntype == N_CHR) || (Ntype == N_BLK) ? 1
204									 : 0)))
205	{
206	    Lf->sf |= SELNM;
207	}
208/*
209 * Enter name characters.
210 */
211	if (!Lf->nm && Namech[0])
212	    enter_nm(Namech);
213}
214
215
216/*
217 * err2nm() -- convert errno to a message in Namech
218 */
219
220void
221err2nm(pfx)
222	char *pfx;			/* Namech message prefix */
223{
224	char *sfx;
225
226	switch (errno) {
227	case EBADF:
228
229	/*
230	 * The file descriptor is no longer available.
231	 */
232	    sfx = "FD unavailable";
233	    break;
234	case ESRCH:
235
236	/*
237	 * The process is no longer available.
238	 */
239	    sfx = "process unavailable";
240	    break;
241	default:
242
243	/*
244	 * All other errors are reported with strerror() information.
245	 */
246	    sfx = strerror(errno);
247	}
248	(void) snpf(Namech, Namechl, "%s: %s", pfx, sfx);
249	enter_nm(Namech);
250}
251
252
253/*
254 * print_nm() -- print Name column
255 */
256void
257print_nm(lf)
258	struct lfile *lf;
259{
260	unsigned char extra = 0;
261
262	printname(0);
263
264#ifdef		PROC_PIDLISTFILEPORTS
265	if (lf->fileport) extra++;
266#endif		/* PROC_PIDLISTFILEPORTS */
267#ifdef		PROC_FP_GUARDED
268	if (lf->guardflags) extra++;
269#endif		/* PROC_FP_GUARDED */
270
271	if (extra)
272	    (void) printf(" (");
273
274#ifdef		PROC_PIDLISTFILEPORTS
275	if (lf->fileport)
276	    (void) printf("fileport=0x%04x", lf->fileport);
277#endif		/* PROC_PIDLISTFILEPORTS */
278
279	if (extra > 1)
280	    (void) printf(",");
281
282#ifdef		PROC_FP_GUARDED
283	if (lf->guardflags) {
284	    struct pff_tab *tp;
285	    long gf;
286
287	    (void) printf("guard=");
288	    tp = Pgf_tab;
289	    gf = lf->guardflags;
290	    while (gf && !FsvFlagX) {
291		while (tp->nm) {
292		    if (gf & tp->val)
293			break;
294		    tp++;
295		}
296		if (!tp->nm)
297		    break;
298		gf &= ~(tp->val);
299		(void) printf("%s%s", tp->nm, gf ? "," : "");
300	    }
301	/*
302	 * If flag bits remain, print them in hex.  If hex output was
303	 * specified with +fG, print all flag values, including zero,
304	 * in hex.
305	 */
306	    if (gf || FsvFlagX)
307		(void) printf("0x%lx", gf);
308	}
309#endif		/* PROC_FP_GUARDED */
310
311	if (extra)
312	    (void) printf(")");
313
314	putchar('\n');
315}
316
317
318/*
319 * print_v_path() -- print vnode's path
320 */
321
322int
323print_v_path(lf)
324	struct lfile *lf;
325{
326	if (lf->V_path) {
327	    safestrprt(lf->V_path, stdout, 0);
328	    return(1);
329	}
330	return(0);
331}
332
333
334/*
335 * process_atalk() -- process an Apple Talk file
336 */
337
338void
339process_atalk(pid, fd)
340	int pid;			/* PID */
341	int32_t fd;			/* FD */
342{
343	(void) snpf(Lf->type, sizeof(Lf->type), "ATALK");
344	return;
345}
346
347
348/*
349 * process_fsevents() -- process a file system events file
350 */
351
352void
353process_fsevents(pid, fd)
354	int pid;			/* PID */
355	int32_t fd;			/* FD */
356{
357	(void) snpf(Lf->type, sizeof(Lf->type), "FSEVENTS");
358}
359
360
361/*
362 * process_kqueue() -- process a kernel queue file
363 */
364
365void
366process_kqueue(pid, fd)
367	int pid;			/* PID */
368	int32_t fd;			/* FD */
369{
370	struct kqueue_fdinfo kq;
371	int nb;
372/*
373 * Get the kernel queue file information.
374 */
375	(void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE");
376	nb = proc_pidfdinfo(pid, fd, PROC_PIDFDKQUEUEINFO, &kq, sizeof(kq));
377	if (nb <= 0) {
378	    (void) err2nm("kqueue");
379	    return;
380	} else if (nb < sizeof(kq)) {
381	    (void) fprintf(stderr,
382		"%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDKQUEUEINFO);\n",
383		Pn, pid, fd);
384	    (void) fprintf(stderr,
385		"      too few bytes; expected %ld, got %d\n",
386		sizeof(kq), nb);
387	    Exit(1);
388	}
389/*
390 * Enter the kernel queue file information.
391 */
392	enter_file_info(&kq.pfi);
393/*
394 * Enter queue counts as NAME column information.
395 */
396	(void) snpf(Namech, Namechl,
397	    "count=%" SZOFFPSPEC "u, state=%#x",
398	    (SZOFFTYPE)kq.kqueueinfo.kq_stat.vst_size,
399	    kq.kqueueinfo.kq_state);
400	enter_nm(Namech);
401}
402
403
404/*
405 * process_pipe() -- process pipe file
406 */
407
408static void
409process_pipe_common(pi)
410	struct pipe_fdinfo *pi;
411{
412	char dev_ch[32], *ep;
413        size_t sz;
414
415	(void) snpf(Lf->type, sizeof(Lf->type), "PIPE");
416/*
417 * Enter the pipe handle as the device.
418 */
419	(void) snpf(dev_ch, sizeof(dev_ch), "%s",
420	    print_kptr((KA_T)pi->pipeinfo.pipe_handle, (char *)NULL, 0));
421	enter_dev_ch(dev_ch);
422/*
423 * Enable offset or size reporting.
424 */
425	if (Foffset)
426	    Lf->off_def = 1;
427	else {
428	    Lf->sz = (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_blksize;
429	    Lf->sz_def = 1;
430	}
431/*
432 * If there is a peer handle, enter it in as NAME column information.
433 */
434	if (pi->pipeinfo.pipe_peerhandle) {
435	    (void) snpf(Namech, Namechl, "->%s",
436		print_kptr((KA_T)pi->pipeinfo.pipe_peerhandle, (char *)NULL, 0));
437	    enter_nm(Namech);
438	} else
439	    Namech[0] = '\0';
440/*
441 * If the pipe has a count, add it to the NAME column.
442 */
443	if (pi->pipeinfo.pipe_stat.vst_size) {
444	    ep = endnm(&sz);
445	    (void) snpf(ep, sz, ", cnt=%" SZOFFPSPEC "u",
446		(SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_size);
447	}
448}
449
450
451void
452process_pipe(pid, fd)
453	int pid;			/* PID */
454	int32_t fd;			/* FD */
455{
456	int nb;
457	struct pipe_fdinfo pi;
458/*
459 * Get pipe file information.
460 */
461	nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPIPEINFO, &pi, sizeof(pi));
462	if (nb <= 0) {
463	    (void) err2nm("pipe");
464	    return;
465	} else if (nb < sizeof(pi)) {
466	    (void) fprintf(stderr,
467		"%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPIPEINFO);\n",
468		Pn, pid, fd);
469	    (void) fprintf(stderr,
470		"      too few bytes; expected %ld, got %d\n",
471	       sizeof(pi), nb);
472	    Exit(1);
473	}
474
475	process_pipe_common(&pi);
476}
477
478
479#ifdef	PROC_PIDLISTFILEPORTS
480void
481process_fileport_pipe(pid, fp)
482	int pid;			/* PID */
483	uint32_t fp;			/* FILEPORT */
484{
485	int nb;
486	struct pipe_fdinfo pi;
487/*
488 * Get pipe file information.
489 */
490	nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPIPEINFO, &pi, sizeof(pi));
491	if (nb <= 0) {
492	    (void) err2nm("pipe");
493	    return;
494	} else if (nb < sizeof(pi)) {
495	    (void) fprintf(stderr,
496		"%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPIPEINFO);\n",
497		Pn, pid, fp);
498	    (void) fprintf(stderr,
499		"      too few bytes; expected %ld, got %d\n",
500	       sizeof(pi), nb);
501	    Exit(1);
502	}
503
504	process_pipe_common(&pi);
505}
506#endif	/* PROC_PIDLISTFILEPORTS */
507
508
509/*
510 * process_psem() -- process a POSIX semaphore file
511 */
512
513void
514process_psem(pid, fd)
515	int pid;			/* PID */
516	int32_t fd;			/* FD */
517{
518	int nb;
519	struct psem_fdinfo ps;
520/*
521 * Get the sempaphore file information.
522 */
523	(void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM");
524	nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSEMINFO, &ps, sizeof(ps));
525	if (nb <= 0) {
526	    (void) err2nm("semaphore");
527	    return;
528	} else if (nb < sizeof(ps)) {
529	    (void) fprintf(stderr,
530		"%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSEMINFO);\n",
531		Pn, pid, fd);
532	    (void) fprintf(stderr,
533		"      too few bytes; expected %ld, got %d\n",
534		sizeof(ps), nb);
535	    Exit(1);
536	}
537/*
538 * Enter the semaphore file information.
539 */
540	enter_file_info(&ps.pfi);
541/*
542 * If there is a semaphore file name, enter it.
543 */
544	if (ps.pseminfo.psem_name[0]) {
545	    ps.pseminfo.psem_name[sizeof(ps.pseminfo.psem_name) - 1] = '\0';
546	    (void) snpf(Namech, Namechl, "%s", ps.pseminfo.psem_name);
547	    enter_nm(Namech);
548	}
549/*
550 * Unless file size has been specifically requested, enable the printing of
551 * file offset.
552 */
553	if (!Fsize)
554	    Lf->off_def = 1;
555}
556
557
558/*
559 * process_pshm() -- process POSIX shared memory file
560 */
561
562static void
563process_pshm_common(ps)
564	struct pshm_fdinfo *ps;
565{
566	(void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM");
567/*
568 * Enter the POSIX shared memory file information.
569 */
570	enter_file_info(&ps->pfi);
571/*
572 * If the POSIX shared memory file has a path name, enter it; otherwise, if it
573 * has a mapping address, enter that.
574 */
575	if (ps->pshminfo.pshm_name[0]) {
576	    ps->pshminfo.pshm_name[sizeof(ps->pshminfo.pshm_name) - 1] = '\0';
577	    (void) snpf(Namech, Namechl, "%s", ps->pshminfo.pshm_name);
578	    enter_nm(Namech);
579	} else if (ps->pshminfo.pshm_mappaddr) {
580	    (void) snpf(Namech, Namechl, "obj=%s",
581		print_kptr((KA_T)ps->pshminfo.pshm_mappaddr, (char *)NULL, 0));
582	    enter_nm(Namech);
583	}
584/*
585 * Enable offset or size reporting.
586 */
587	if (Foffset)
588	    Lf->off_def = 1;
589	else {
590	    Lf->sz = (SZOFFTYPE)ps->pshminfo.pshm_stat.vst_size;
591	    Lf->sz_def = 1;
592	}
593}
594
595
596void
597process_pshm(pid, fd)
598	int pid;			/* PID */
599	int32_t fd;			/* FD */
600{
601	int nb;
602	struct pshm_fdinfo ps;
603/*
604 * Get the POSIX shared memory file information.
605 */
606	nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSHMINFO, &ps, sizeof(ps));
607	if (nb <= 0) {
608	    (void) err2nm("POSIX shared memory");
609	    return;
610	} else if (nb < sizeof(ps)) {
611	    (void) fprintf(stderr,
612		"%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSHMINFO);\n",
613		Pn, pid, fd);
614	    (void) fprintf(stderr,
615		"      too few bytes; expected %ld, got %d\n",
616		sizeof(ps), nb);
617	    Exit(1);
618	}
619
620	process_pshm_common(&ps);
621}
622
623
624#ifdef	PROC_PIDLISTFILEPORTS
625void
626process_fileport_pshm(pid, fp)
627	int pid;			/* PID */
628	uint32_t fp;			/* FILEPORT */
629{
630	int nb;
631	struct pshm_fdinfo ps;
632/*
633 * Get the POSIX shared memory file information.
634 */
635	nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPSHMINFO, &ps, sizeof(ps));
636	if (nb <= 0) {
637	    (void) err2nm("POSIX shared memory");
638	    return;
639	} else if (nb < sizeof(ps)) {
640	    (void) fprintf(stderr,
641		"%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPSHMINFO);\n",
642		Pn, pid, fp);
643	    (void) fprintf(stderr,
644		"      too few bytes; expected %ld, got %d\n",
645		sizeof(ps), nb);
646	    Exit(1);
647	}
648
649	process_pshm_common(&ps);
650}
651#endif	/* PROC_PIDLISTFILEPORTS */
652
653
654/*
655 * process_vnode() -- process a vnode file
656 */
657
658static void
659process_vnode_common(vi)
660	struct vnode_fdinfowithpath *vi;
661{
662/*
663 * Enter the file and vnode information.
664 */
665	enter_file_info(&vi->pfi);
666	enter_vnode_info(&vi->pvip);
667}
668
669
670void
671process_vnode(pid, fd)
672	int pid;			/* PID */
673	int32_t fd;			/* FD */
674{
675	int nb;
676	struct vnode_fdinfowithpath vi;
677
678	nb = proc_pidfdinfo(pid, fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi));
679	if (nb <= 0) {
680	    if (errno == ENOENT) {
681
682	    /*
683	     * The file descriptor's vnode may have been revoked.  This is a
684	     * bit of a hack, since an ENOENT error might not always mean the
685	     * descriptor's vnode has been revoked.  As the libproc API
686	     * matures, this code may need to be revisited.
687	     */
688		enter_nm("(revoked)");
689	    } else
690		(void) err2nm("vnode");
691	    return;
692	} else if (nb < sizeof(vi)) {
693	    (void) fprintf(stderr,
694		"%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n",
695		Pn, pid, fd);
696	    (void) fprintf(stderr,
697		"      too few bytes; expected %ld, got %d\n",
698		sizeof(vi), nb);
699	    Exit(1);
700	}
701
702	process_vnode_common(&vi);
703}
704
705
706#ifdef	PROC_PIDLISTFILEPORTS
707void
708process_fileport_vnode(pid, fp)
709	int pid;			/* PID */
710	uint32_t fp;			/* FILEPORT */
711{
712	int nb;
713	struct vnode_fdinfowithpath vi;
714
715	nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTVNODEPATHINFO, &vi, sizeof(vi));
716	if (nb <= 0) {
717	    if (errno == ENOENT) {
718
719	    /*
720	     * The file descriptor's vnode may have been revoked.  This is a
721	     * bit of a hack, since an ENOENT error might not always mean the
722	     * descriptor's vnode has been revoked.  As the libproc API
723	     * matures, this code may need to be revisited.
724	     */
725		enter_nm("(revoked)");
726	    } else
727		(void) err2nm("vnode");
728	    return;
729	} else if (nb < sizeof(vi)) {
730	    (void) fprintf(stderr,
731		"%s: PID %d, FILEPORT %u: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n",
732		Pn, pid, fp);
733	    (void) fprintf(stderr,
734		"      too few bytes; expected %ld, got %d\n",
735		sizeof(vi), nb);
736	    Exit(1);
737	}
738
739	process_vnode_common(&vi);
740}
741#endif	/* PROC_PIDLISTFILEPORTS */
742