34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore/*
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * This file and its contents are supplied under the terms of the
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * You may only use this file in accordance with the terms of version
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * 1.0 of the CDDL.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore *
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * http://www.illumos.org/license/CDDL.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore/*
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore */
dfc0fed81813380fb526f1a003d3be17ab26ce3bRobert Mustacchi/*
dfc0fed81813380fb526f1a003d3be17ab26ce3bRobert Mustacchi * Copyright (c) 2013 Joyent, Inc. All Rights reserved.
dfc0fed81813380fb526f1a003d3be17ab26ce3bRobert Mustacchi */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <limits.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <stdio.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <errno.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <unistd.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <dirent.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <ctype.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <string.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include <sys/mkdev.h>
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include "libproc.h"
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore#include "Pcontrol.h"
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore/*
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * Pfdinfo.c - obtain open file information.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore/*
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * Allocate an fd_info structure and stick it on the list.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * (Unless one already exists.) The list is sorted in
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * reverse order. We will traverse it in that order later.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * This makes the usual ordered insert *fast*.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amorefd_info_t *
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'AmorePfd2info(struct ps_prochandle *P, int fd)
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore{
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fd_info_t *fip = list_next(&P->fd_head);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fd_info_t *next;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore int i;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (fip == NULL) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore list_link(&P->fd_head, NULL);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fip = list_next(&P->fd_head);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (fip->fd_info.pr_fd == fd) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore return (fip);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (fip->fd_info.pr_fd < fd) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore break;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore next = fip;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if ((fip = calloc(1, sizeof (*fip))) == NULL)
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore return (NULL);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fip->fd_info.pr_fd = fd;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore list_link(fip, next ? next : (void *)&(P->fd_head));
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore P->num_fd++;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore return (fip);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore}
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore/*
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * Attempt to load the open file information from a live process.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amorestatic void
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amoreload_fdinfo(struct ps_prochandle *P)
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore{
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore /*
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * In the unlikely case there are *no* file descriptors open,
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * we will keep rescanning the proc directory, which will be empty.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * This is an edge case it isn't worth adding additional state to
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * to eliminate.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (P->num_fd > 0) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore return;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (P->state != PS_DEAD && P->state != PS_IDLE) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore char dir_name[PATH_MAX];
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore char path[PATH_MAX];
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore struct dirent *ent;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore DIR *dirp;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore int fd;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore /*
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore * Try to get the path information first.
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore (void) snprintf(dir_name, sizeof (dir_name),
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore "%s/%d/path", procfs_path, (int)P->pid);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore dirp = opendir(dir_name);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (dirp == NULL) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore return;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore ent = NULL;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore while ((ent = readdir(dirp)) != NULL) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fd_info_t *fip;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore prfdinfo_t *info;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore int len;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore struct stat64 stat;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (!isdigit(ent->d_name[0]))
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore continue;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fd = atoi(ent->d_name);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fip = Pfd2info(P, fd);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info = &fip->fd_info;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_fd = fd;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (pr_fstat64(P, fd, &stat) == 0) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_mode = stat.st_mode;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_uid = stat.st_uid;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_gid = stat.st_gid;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_major = major(stat.st_dev);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_minor = minor(stat.st_dev);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_rmajor = major(stat.st_rdev);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_rminor = minor(stat.st_rdev);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_size = stat.st_size;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_ino = stat.st_ino;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_fileflags = pr_fcntl(P, fd, F_GETXFL, 0);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_fdflags = pr_fcntl(P, fd, F_GETFD, 0);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_offset = pr_llseek(P, fd, 0, SEEK_CUR);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore /* attempt to determine the path to it */
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy switch (info->pr_mode & S_IFMT) {
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy case S_IFDOOR:
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy case S_IFSOCK:
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy /* not applicable */
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy len = -1;
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy break;
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy default:
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy (void) snprintf(path, sizeof (path),
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy "%s/%d/path/%d", procfs_path, (int)P->pid,
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy fd);
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy len = readlink(path, info->pr_path,
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy sizeof (info->pr_path) - 1);
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy break;
d907f8b938aec9d8b57fdb15c241b98641b8b052Dave Eddy }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if (len < 0) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_path[0] = 0;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore } else {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore info->pr_path[len] = 0;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore (void) closedir(dirp);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore}
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amoreint
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'AmorePfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd)
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore{
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fd_info_t *fip;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore int rv;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore /* Make sure we have live data, if appropriate */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore load_fdinfo(P);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore /* NB: We walk the list backwards. */
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore for (fip = list_prev(&P->fd_head);
dfc0fed81813380fb526f1a003d3be17ab26ce3bRobert Mustacchi fip != (void *)&P->fd_head && fip != NULL;
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore fip = list_prev(fip)) {
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore if ((rv = func(cd, &fip->fd_info)) != 0)
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore return (rv);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore }
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore return (0);
34bdffbf3e3c188027e767e631f717b10159316dGarrett D'Amore}