diff options
author | Garrett D'Amore <garrett@damore.org> | 2012-11-02 09:48:42 -0700 |
---|---|---|
committer | Garrett D'Amore <garrett@damore.org> | 2012-11-02 09:48:42 -0700 |
commit | 34bdffbf3e3c188027e767e631f717b10159316d (patch) | |
tree | 4d4e8a7b31cd6528275774fd378cdc6ef52661b4 /usr/src/lib/libproc/common/Pfdinfo.c | |
parent | 70087ad34e224a679eb83e405bf394606ba94c1c (diff) | |
download | illumos-joyent-34bdffbf3e3c188027e767e631f717b10159316d.tar.gz |
3294 pfiles postmortem support
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Eric Schrock <eric.schrock@delphix.com>
Diffstat (limited to 'usr/src/lib/libproc/common/Pfdinfo.c')
-rw-r--r-- | usr/src/lib/libproc/common/Pfdinfo.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/usr/src/lib/libproc/common/Pfdinfo.c b/usr/src/lib/libproc/common/Pfdinfo.c new file mode 100644 index 0000000000..0d41b5606d --- /dev/null +++ b/usr/src/lib/libproc/common/Pfdinfo.c @@ -0,0 +1,168 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. + */ + +#include <limits.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <dirent.h> +#include <ctype.h> +#include <string.h> +#include <sys/mkdev.h> + +#include "libproc.h" +#include "Pcontrol.h" + +/* + * Pfdinfo.c - obtain open file information. + */ + +/* + * Allocate an fd_info structure and stick it on the list. + * (Unless one already exists.) The list is sorted in + * reverse order. We will traverse it in that order later. + * This makes the usual ordered insert *fast*. + */ +fd_info_t * +Pfd2info(struct ps_prochandle *P, int fd) +{ + fd_info_t *fip = list_next(&P->fd_head); + fd_info_t *next; + int i; + + if (fip == NULL) { + list_link(&P->fd_head, NULL); + fip = list_next(&P->fd_head); + } + + for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) { + if (fip->fd_info.pr_fd == fd) { + return (fip); + } + if (fip->fd_info.pr_fd < fd) { + break; + } + } + + next = fip; + if ((fip = calloc(1, sizeof (*fip))) == NULL) + return (NULL); + + fip->fd_info.pr_fd = fd; + list_link(fip, next ? next : (void *)&(P->fd_head)); + P->num_fd++; + return (fip); +} + +/* + * Attempt to load the open file information from a live process. + */ +static void +load_fdinfo(struct ps_prochandle *P) +{ + /* + * In the unlikely case there are *no* file descriptors open, + * we will keep rescanning the proc directory, which will be empty. + * This is an edge case it isn't worth adding additional state to + * to eliminate. + */ + if (P->num_fd > 0) { + return; + } + + if (P->state != PS_DEAD && P->state != PS_IDLE) { + char dir_name[PATH_MAX]; + char path[PATH_MAX]; + struct dirent *ent; + DIR *dirp; + int fd; + + /* + * Try to get the path information first. + */ + (void) snprintf(dir_name, sizeof (dir_name), + "%s/%d/path", procfs_path, (int)P->pid); + dirp = opendir(dir_name); + if (dirp == NULL) { + return; + } + ent = NULL; + while ((ent = readdir(dirp)) != NULL) { + fd_info_t *fip; + prfdinfo_t *info; + int len; + struct stat64 stat; + + if (!isdigit(ent->d_name[0])) + continue; + + fd = atoi(ent->d_name); + + fip = Pfd2info(P, fd); + info = &fip->fd_info; + info->pr_fd = fd; + + if (pr_fstat64(P, fd, &stat) == 0) { + info->pr_mode = stat.st_mode; + info->pr_uid = stat.st_uid; + info->pr_gid = stat.st_gid; + info->pr_major = major(stat.st_dev); + info->pr_minor = minor(stat.st_dev); + info->pr_rmajor = major(stat.st_rdev); + info->pr_rminor = minor(stat.st_rdev); + info->pr_size = stat.st_size; + info->pr_ino = stat.st_ino; + } + + info->pr_fileflags = pr_fcntl(P, fd, F_GETXFL, 0); + info->pr_fdflags = pr_fcntl(P, fd, F_GETFD, 0); + info->pr_offset = pr_llseek(P, fd, 0, SEEK_CUR); + + /* attempt to determine the path to it */ + (void) snprintf(path, sizeof (path), + "%s/%d/path/%d", procfs_path, (int)P->pid, fd); + len = readlink(path, info->pr_path, + sizeof (info->pr_path) - 1); + + if (len < 0) { + info->pr_path[0] = 0; + } else { + info->pr_path[len] = 0; + } + } + (void) closedir(dirp); + + } +} + +int +Pfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd) +{ + fd_info_t *fip; + int rv; + + /* Make sure we have live data, if appropriate */ + load_fdinfo(P); + + /* NB: We walk the list backwards. */ + + for (fip = list_prev(&P->fd_head); + fip != (void *)&P->fd_head; + fip = list_prev(fip)) { + if ((rv = func(cd, &fip->fd_info)) != 0) + return (rv); + } + return (0); +} |