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