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 * Copyright (c) 2013 Joyent, Inc. All Rights reserved. 17 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 18 */ 19 20 #include <limits.h> 21 #include <stdio.h> 22 #include <errno.h> 23 #include <unistd.h> 24 #include <dirent.h> 25 #include <ctype.h> 26 #include <string.h> 27 #include <sys/mkdev.h> 28 29 #include "libproc.h" 30 #include "Pcontrol.h" 31 #include "proc_fd.h" 32 33 /* 34 * Pfdinfo.c - obtain open file information. 35 */ 36 37 /* 38 * Allocate an fd_info structure and stick it on the list. 39 * (Unless one already exists.) The list is sorted in 40 * reverse order. We will traverse it in that order later. 41 * This makes the usual ordered insert *fast*. 42 */ 43 fd_info_t * 44 Pfd2info(struct ps_prochandle *P, int fd) 45 { 46 fd_info_t *fip = list_next(&P->fd_head); 47 fd_info_t *next; 48 int i; 49 50 if (fip == NULL) { 51 list_link(&P->fd_head, NULL); 52 fip = list_next(&P->fd_head); 53 } 54 55 for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) { 56 if (fip->fd_info == NULL) 57 continue; 58 59 if (fip->fd_info->pr_fd == fd) { 60 return (fip); 61 } 62 if (fip->fd_info->pr_fd < fd) { 63 break; 64 } 65 } 66 67 next = fip; 68 if ((fip = calloc(1, sizeof (*fip))) == NULL) 69 return (NULL); 70 71 list_link(fip, next ? next : (void *)&(P->fd_head)); 72 P->num_fd++; 73 return (fip); 74 } 75 76 static int 77 fdwalk_cb(const prfdinfo_t *info, void *arg) 78 { 79 struct ps_prochandle *P = arg; 80 fd_info_t *fip; 81 82 fip = Pfd2info(P, info->pr_fd); 83 if (fip == NULL) { 84 errno = ENOMEM; 85 return (-1); 86 } 87 88 if (fip->fd_info == NULL) 89 fip->fd_info = proc_fdinfo_dup(info); 90 91 if (fip->fd_info == NULL) { 92 errno = ENOMEM; 93 return (-1); 94 } 95 96 return (0); 97 } 98 99 /* 100 * Attempt to load the open file information from a live process. 101 */ 102 static void 103 load_fdinfo(struct ps_prochandle *P) 104 { 105 /* 106 * In the unlikely case there are *no* file descriptors open, 107 * we will keep rescanning the proc directory, which will be empty. 108 * This is an edge case it isn't worth adding additional state to 109 * to eliminate. 110 */ 111 if (P->num_fd > 0) 112 return; 113 114 if (P->state == PS_DEAD || P->state == PS_IDLE) 115 return; 116 117 proc_fdwalk(P->pid, fdwalk_cb, P); 118 } 119 120 int 121 Pfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd) 122 { 123 fd_info_t *fip; 124 int rv; 125 126 /* Make sure we have live data, if appropriate */ 127 load_fdinfo(P); 128 129 /* NB: We walk the list backwards. */ 130 131 for (fip = list_prev(&P->fd_head); 132 fip != (void *)&P->fd_head && fip != NULL; 133 fip = list_prev(fip)) { 134 if ((rv = func(cd, fip->fd_info)) != 0) 135 return (rv); 136 } 137 return (0); 138 } 139