xref: /titanic_50/usr/src/lib/libproc/common/Pfdinfo.c (revision d907f8b938aec9d8b57fdb15c241b98641b8b052)
134bdffbfSGarrett D'Amore /*
234bdffbfSGarrett D'Amore  * This file and its contents are supplied under the terms of the
334bdffbfSGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
434bdffbfSGarrett D'Amore  * You may only use this file in accordance with the terms of version
534bdffbfSGarrett D'Amore  * 1.0 of the CDDL.
634bdffbfSGarrett D'Amore  *
734bdffbfSGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
834bdffbfSGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
934bdffbfSGarrett D'Amore  * http://www.illumos.org/license/CDDL.
1034bdffbfSGarrett D'Amore  */
1134bdffbfSGarrett D'Amore 
1234bdffbfSGarrett D'Amore /*
1334bdffbfSGarrett D'Amore  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
1434bdffbfSGarrett D'Amore  */
15dfc0fed8SRobert Mustacchi /*
16dfc0fed8SRobert Mustacchi  * Copyright (c) 2013 Joyent, Inc.  All Rights reserved.
17dfc0fed8SRobert Mustacchi  */
1834bdffbfSGarrett D'Amore 
1934bdffbfSGarrett D'Amore #include <limits.h>
2034bdffbfSGarrett D'Amore #include <stdio.h>
2134bdffbfSGarrett D'Amore #include <errno.h>
2234bdffbfSGarrett D'Amore #include <unistd.h>
2334bdffbfSGarrett D'Amore #include <dirent.h>
2434bdffbfSGarrett D'Amore #include <ctype.h>
2534bdffbfSGarrett D'Amore #include <string.h>
2634bdffbfSGarrett D'Amore #include <sys/mkdev.h>
2734bdffbfSGarrett D'Amore 
2834bdffbfSGarrett D'Amore #include "libproc.h"
2934bdffbfSGarrett D'Amore #include "Pcontrol.h"
3034bdffbfSGarrett D'Amore 
3134bdffbfSGarrett D'Amore /*
3234bdffbfSGarrett D'Amore  * Pfdinfo.c - obtain open file information.
3334bdffbfSGarrett D'Amore  */
3434bdffbfSGarrett D'Amore 
3534bdffbfSGarrett D'Amore /*
3634bdffbfSGarrett D'Amore  * Allocate an fd_info structure and stick it on the list.
3734bdffbfSGarrett D'Amore  * (Unless one already exists.)  The list is sorted in
3834bdffbfSGarrett D'Amore  * reverse order.  We will traverse it in that order later.
3934bdffbfSGarrett D'Amore  * This makes the usual ordered insert *fast*.
4034bdffbfSGarrett D'Amore  */
4134bdffbfSGarrett D'Amore fd_info_t *
Pfd2info(struct ps_prochandle * P,int fd)4234bdffbfSGarrett D'Amore Pfd2info(struct ps_prochandle *P, int fd)
4334bdffbfSGarrett D'Amore {
4434bdffbfSGarrett D'Amore 	fd_info_t	*fip = list_next(&P->fd_head);
4534bdffbfSGarrett D'Amore 	fd_info_t	*next;
4634bdffbfSGarrett D'Amore 	int i;
4734bdffbfSGarrett D'Amore 
4834bdffbfSGarrett D'Amore 	if (fip == NULL) {
4934bdffbfSGarrett D'Amore 		list_link(&P->fd_head, NULL);
5034bdffbfSGarrett D'Amore 		fip = list_next(&P->fd_head);
5134bdffbfSGarrett D'Amore 	}
5234bdffbfSGarrett D'Amore 
5334bdffbfSGarrett D'Amore 	for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) {
5434bdffbfSGarrett D'Amore 		if (fip->fd_info.pr_fd == fd) {
5534bdffbfSGarrett D'Amore 			return (fip);
5634bdffbfSGarrett D'Amore 		}
5734bdffbfSGarrett D'Amore 		if (fip->fd_info.pr_fd < fd) {
5834bdffbfSGarrett D'Amore 			break;
5934bdffbfSGarrett D'Amore 		}
6034bdffbfSGarrett D'Amore 	}
6134bdffbfSGarrett D'Amore 
6234bdffbfSGarrett D'Amore 	next = fip;
6334bdffbfSGarrett D'Amore 	if ((fip = calloc(1, sizeof (*fip))) == NULL)
6434bdffbfSGarrett D'Amore 		return (NULL);
6534bdffbfSGarrett D'Amore 
6634bdffbfSGarrett D'Amore 	fip->fd_info.pr_fd = fd;
6734bdffbfSGarrett D'Amore 	list_link(fip, next ? next : (void *)&(P->fd_head));
6834bdffbfSGarrett D'Amore 	P->num_fd++;
6934bdffbfSGarrett D'Amore 	return (fip);
7034bdffbfSGarrett D'Amore }
7134bdffbfSGarrett D'Amore 
7234bdffbfSGarrett D'Amore /*
7334bdffbfSGarrett D'Amore  * Attempt to load the open file information from a live process.
7434bdffbfSGarrett D'Amore  */
7534bdffbfSGarrett D'Amore static void
load_fdinfo(struct ps_prochandle * P)7634bdffbfSGarrett D'Amore load_fdinfo(struct ps_prochandle *P)
7734bdffbfSGarrett D'Amore {
7834bdffbfSGarrett D'Amore 	/*
7934bdffbfSGarrett D'Amore 	 * In the unlikely case there are *no* file descriptors open,
8034bdffbfSGarrett D'Amore 	 * we will keep rescanning the proc directory, which will be empty.
8134bdffbfSGarrett D'Amore 	 * This is an edge case it isn't worth adding additional state to
8234bdffbfSGarrett D'Amore 	 * to eliminate.
8334bdffbfSGarrett D'Amore 	 */
8434bdffbfSGarrett D'Amore 	if (P->num_fd > 0) {
8534bdffbfSGarrett D'Amore 		return;
8634bdffbfSGarrett D'Amore 	}
8734bdffbfSGarrett D'Amore 
8834bdffbfSGarrett D'Amore 	if (P->state != PS_DEAD && P->state != PS_IDLE) {
8934bdffbfSGarrett D'Amore 		char dir_name[PATH_MAX];
9034bdffbfSGarrett D'Amore 		char path[PATH_MAX];
9134bdffbfSGarrett D'Amore 		struct dirent *ent;
9234bdffbfSGarrett D'Amore 		DIR	*dirp;
9334bdffbfSGarrett D'Amore 		int	fd;
9434bdffbfSGarrett D'Amore 
9534bdffbfSGarrett D'Amore 		/*
9634bdffbfSGarrett D'Amore 		 * Try to get the path information first.
9734bdffbfSGarrett D'Amore 		 */
9834bdffbfSGarrett D'Amore 		(void) snprintf(dir_name, sizeof (dir_name),
9934bdffbfSGarrett D'Amore 		    "%s/%d/path", procfs_path, (int)P->pid);
10034bdffbfSGarrett D'Amore 		dirp = opendir(dir_name);
10134bdffbfSGarrett D'Amore 		if (dirp == NULL) {
10234bdffbfSGarrett D'Amore 			return;
10334bdffbfSGarrett D'Amore 		}
10434bdffbfSGarrett D'Amore 		ent = NULL;
10534bdffbfSGarrett D'Amore 		while ((ent = readdir(dirp)) != NULL) {
10634bdffbfSGarrett D'Amore 			fd_info_t	*fip;
10734bdffbfSGarrett D'Amore 			prfdinfo_t	*info;
10834bdffbfSGarrett D'Amore 			int		len;
10934bdffbfSGarrett D'Amore 			struct stat64	stat;
11034bdffbfSGarrett D'Amore 
11134bdffbfSGarrett D'Amore 			if (!isdigit(ent->d_name[0]))
11234bdffbfSGarrett D'Amore 				continue;
11334bdffbfSGarrett D'Amore 
11434bdffbfSGarrett D'Amore 			fd = atoi(ent->d_name);
11534bdffbfSGarrett D'Amore 
11634bdffbfSGarrett D'Amore 			fip = Pfd2info(P, fd);
11734bdffbfSGarrett D'Amore 			info = &fip->fd_info;
11834bdffbfSGarrett D'Amore 			info->pr_fd = fd;
11934bdffbfSGarrett D'Amore 
12034bdffbfSGarrett D'Amore 			if (pr_fstat64(P, fd, &stat) == 0) {
12134bdffbfSGarrett D'Amore 				info->pr_mode = stat.st_mode;
12234bdffbfSGarrett D'Amore 				info->pr_uid = stat.st_uid;
12334bdffbfSGarrett D'Amore 				info->pr_gid = stat.st_gid;
12434bdffbfSGarrett D'Amore 				info->pr_major = major(stat.st_dev);
12534bdffbfSGarrett D'Amore 				info->pr_minor = minor(stat.st_dev);
12634bdffbfSGarrett D'Amore 				info->pr_rmajor = major(stat.st_rdev);
12734bdffbfSGarrett D'Amore 				info->pr_rminor = minor(stat.st_rdev);
12834bdffbfSGarrett D'Amore 				info->pr_size = stat.st_size;
12934bdffbfSGarrett D'Amore 				info->pr_ino = stat.st_ino;
13034bdffbfSGarrett D'Amore 			}
13134bdffbfSGarrett D'Amore 
13234bdffbfSGarrett D'Amore 			info->pr_fileflags = pr_fcntl(P, fd, F_GETXFL, 0);
13334bdffbfSGarrett D'Amore 			info->pr_fdflags = pr_fcntl(P, fd, F_GETFD, 0);
13434bdffbfSGarrett D'Amore 			info->pr_offset = pr_llseek(P, fd, 0, SEEK_CUR);
13534bdffbfSGarrett D'Amore 
13634bdffbfSGarrett D'Amore 			/* attempt to determine the path to it */
137*d907f8b9SDave Eddy 			switch (info->pr_mode & S_IFMT) {
138*d907f8b9SDave Eddy 			case S_IFDOOR:
139*d907f8b9SDave Eddy 			case S_IFSOCK:
140*d907f8b9SDave Eddy 				/* not applicable */
141*d907f8b9SDave Eddy 				len = -1;
142*d907f8b9SDave Eddy 				break;
143*d907f8b9SDave Eddy 			default:
14434bdffbfSGarrett D'Amore 				(void) snprintf(path, sizeof (path),
145*d907f8b9SDave Eddy 				    "%s/%d/path/%d", procfs_path, (int)P->pid,
146*d907f8b9SDave Eddy 				    fd);
14734bdffbfSGarrett D'Amore 				len = readlink(path, info->pr_path,
14834bdffbfSGarrett D'Amore 				    sizeof (info->pr_path) - 1);
149*d907f8b9SDave Eddy 				break;
150*d907f8b9SDave Eddy 			}
15134bdffbfSGarrett D'Amore 
15234bdffbfSGarrett D'Amore 			if (len < 0) {
15334bdffbfSGarrett D'Amore 				info->pr_path[0] = 0;
15434bdffbfSGarrett D'Amore 			} else {
15534bdffbfSGarrett D'Amore 				info->pr_path[len] = 0;
15634bdffbfSGarrett D'Amore 			}
15734bdffbfSGarrett D'Amore 		}
15834bdffbfSGarrett D'Amore 		(void) closedir(dirp);
15934bdffbfSGarrett D'Amore 
16034bdffbfSGarrett D'Amore 	}
16134bdffbfSGarrett D'Amore }
16234bdffbfSGarrett D'Amore 
16334bdffbfSGarrett D'Amore int
Pfdinfo_iter(struct ps_prochandle * P,proc_fdinfo_f * func,void * cd)16434bdffbfSGarrett D'Amore Pfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd)
16534bdffbfSGarrett D'Amore {
16634bdffbfSGarrett D'Amore 	fd_info_t *fip;
16734bdffbfSGarrett D'Amore 	int rv;
16834bdffbfSGarrett D'Amore 
16934bdffbfSGarrett D'Amore 	/* Make sure we have live data, if appropriate */
17034bdffbfSGarrett D'Amore 	load_fdinfo(P);
17134bdffbfSGarrett D'Amore 
17234bdffbfSGarrett D'Amore 	/* NB: We walk the list backwards. */
17334bdffbfSGarrett D'Amore 
17434bdffbfSGarrett D'Amore 	for (fip = list_prev(&P->fd_head);
175dfc0fed8SRobert Mustacchi 	    fip != (void *)&P->fd_head && fip != NULL;
17634bdffbfSGarrett D'Amore 	    fip = list_prev(fip)) {
17734bdffbfSGarrett D'Amore 		if ((rv = func(cd, &fip->fd_info)) != 0)
17834bdffbfSGarrett D'Amore 			return (rv);
17934bdffbfSGarrett D'Amore 	}
18034bdffbfSGarrett D'Amore 	return (0);
18134bdffbfSGarrett D'Amore }
182