1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. 14 */ 15 16 #include <limits.h> 17 #include <stdio.h> 18 #include <errno.h> 19 #include <unistd.h> 20 #include <dirent.h> 21 #include <ctype.h> 22 #include <string.h> 23 #include <sys/mkdev.h> 24 25 #include "libproc.h" 26 #include "Pcontrol.h" 27 28 /* 29 * Pfdinfo.c - obtain open file information. 30 */ 31 32 /* 33 * Allocate an fd_info structure and stick it on the list. 34 * (Unless one already exists.) The list is sorted in 35 * reverse order. We will traverse it in that order later. 36 * This makes the usual ordered insert *fast*. 37 */ 38 fd_info_t * 39 Pfd2info(struct ps_prochandle *P, int fd) 40 { 41 fd_info_t *fip = list_next(&P->fd_head); 42 fd_info_t *next; 43 int i; 44 45 if (fip == NULL) { 46 list_link(&P->fd_head, NULL); 47 fip = list_next(&P->fd_head); 48 } 49 50 for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) { 51 if (fip->fd_info.pr_fd == fd) { 52 return (fip); 53 } 54 if (fip->fd_info.pr_fd < fd) { 55 break; 56 } 57 } 58 59 next = fip; 60 if ((fip = calloc(1, sizeof (*fip))) == NULL) 61 return (NULL); 62 63 fip->fd_info.pr_fd = fd; 64 list_link(fip, next ? next : (void *)&(P->fd_head)); 65 P->num_fd++; 66 return (fip); 67 } 68 69 /* 70 * Attempt to load the open file information from a live process. 71 */ 72 static void 73 load_fdinfo(struct ps_prochandle *P) 74 { 75 /* 76 * In the unlikely case there are *no* file descriptors open, 77 * we will keep rescanning the proc directory, which will be empty. 78 * This is an edge case it isn't worth adding additional state to 79 * to eliminate. 80 */ 81 if (P->num_fd > 0) { 82 return; 83 } 84 85 if (P->state != PS_DEAD && P->state != PS_IDLE) { 86 char dir_name[PATH_MAX]; 87 char path[PATH_MAX]; 88 struct dirent *ent; 89 DIR *dirp; 90 int fd; 91 92 /* 93 * Try to get the path information first. 94 */ 95 (void) snprintf(dir_name, sizeof (dir_name), 96 "%s/%d/path", procfs_path, (int)P->pid); 97 dirp = opendir(dir_name); 98 if (dirp == NULL) { 99 return; 100 } 101 ent = NULL; 102 while ((ent = readdir(dirp)) != NULL) { 103 fd_info_t *fip; 104 prfdinfo_t *info; 105 int len; 106 struct stat64 stat; 107 108 if (!isdigit(ent->d_name[0])) 109 continue; 110 111 fd = atoi(ent->d_name); 112 113 fip = Pfd2info(P, fd); 114 info = &fip->fd_info; 115 info->pr_fd = fd; 116 117 if (pr_fstat64(P, fd, &stat) == 0) { 118 info->pr_mode = stat.st_mode; 119 info->pr_uid = stat.st_uid; 120 info->pr_gid = stat.st_gid; 121 info->pr_major = major(stat.st_dev); 122 info->pr_minor = minor(stat.st_dev); 123 info->pr_rmajor = major(stat.st_rdev); 124 info->pr_rminor = minor(stat.st_rdev); 125 info->pr_size = stat.st_size; 126 info->pr_ino = stat.st_ino; 127 } 128 129 info->pr_fileflags = pr_fcntl(P, fd, F_GETXFL, 0); 130 info->pr_fdflags = pr_fcntl(P, fd, F_GETFD, 0); 131 info->pr_offset = pr_llseek(P, fd, 0, SEEK_CUR); 132 133 /* attempt to determine the path to it */ 134 (void) snprintf(path, sizeof (path), 135 "%s/%d/path/%d", procfs_path, (int)P->pid, fd); 136 len = readlink(path, info->pr_path, 137 sizeof (info->pr_path) - 1); 138 139 if (len < 0) { 140 info->pr_path[0] = 0; 141 } else { 142 info->pr_path[len] = 0; 143 } 144 } 145 (void) closedir(dirp); 146 147 } 148 } 149 150 int 151 Pfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd) 152 { 153 fd_info_t *fip; 154 int rv; 155 156 /* Make sure we have live data, if appropriate */ 157 load_fdinfo(P); 158 159 /* NB: We walk the list backwards. */ 160 161 for (fip = list_prev(&P->fd_head); 162 fip != (void *)&P->fd_head; 163 fip = list_prev(fip)) { 164 if ((rv = func(cd, &fip->fd_info)) != 0) 165 return (rv); 166 } 167 return (0); 168 } 169