osdep-freebsd.c revision 1.1.1.9
1/* $OpenBSD$ */ 2 3/* 4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/proc.h> 21#include <sys/stat.h> 22#include <sys/sysctl.h> 23#include <sys/user.h> 24 25#include <err.h> 26#include <errno.h> 27#include <stdint.h> 28#include <stdlib.h> 29#include <string.h> 30#include <unistd.h> 31#include <libutil.h> 32 33#include "compat.h" 34 35struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *); 36char *osdep_get_name(int, char *); 37char *osdep_get_cwd(int); 38struct event_base *osdep_event_init(void); 39 40#ifndef nitems 41#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 42#endif 43 44#define is_runnable(p) \ 45 ((p)->ki_stat == SRUN || (p)->ki_stat == SIDL) 46#define is_stopped(p) \ 47 ((p)->ki_stat == SSTOP || (p)->ki_stat == SZOMB) 48 49struct kinfo_proc * 50cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2) 51{ 52 if (is_runnable(p1) && !is_runnable(p2)) 53 return (p1); 54 if (!is_runnable(p1) && is_runnable(p2)) 55 return (p2); 56 57 if (is_stopped(p1) && !is_stopped(p2)) 58 return (p1); 59 if (!is_stopped(p1) && is_stopped(p2)) 60 return (p2); 61 62 if (p1->ki_estcpu > p2->ki_estcpu) 63 return (p1); 64 if (p1->ki_estcpu < p2->ki_estcpu) 65 return (p2); 66 67 if (p1->ki_slptime < p2->ki_slptime) 68 return (p1); 69 if (p1->ki_slptime > p2->ki_slptime) 70 return (p2); 71 72 if (strcmp(p1->ki_comm, p2->ki_comm) < 0) 73 return (p1); 74 if (strcmp(p1->ki_comm, p2->ki_comm) > 0) 75 return (p2); 76 77 if (p1->ki_pid > p2->ki_pid) 78 return (p1); 79 return (p2); 80} 81 82char * 83osdep_get_name(int fd, char *tty) 84{ 85 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0 }; 86 struct stat sb; 87 size_t len; 88 struct kinfo_proc *buf, *newbuf, *bestp; 89 u_int i; 90 char *name; 91 92 buf = NULL; 93 94 if (stat(tty, &sb) == -1) 95 return (NULL); 96 if ((mib[3] = tcgetpgrp(fd)) == -1) 97 return (NULL); 98 99retry: 100 if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1) 101 return (NULL); 102 len = (len * 5) / 4; 103 104 if ((newbuf = realloc(buf, len)) == NULL) 105 goto error; 106 buf = newbuf; 107 108 if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) { 109 if (errno == ENOMEM) 110 goto retry; 111 goto error; 112 } 113 114 bestp = NULL; 115 for (i = 0; i < len / sizeof (struct kinfo_proc); i++) { 116 if (buf[i].ki_tdev != sb.st_rdev) 117 continue; 118 if (bestp == NULL) 119 bestp = &buf[i]; 120 else 121 bestp = cmp_procs(&buf[i], bestp); 122 } 123 124 name = NULL; 125 if (bestp != NULL) 126 name = strdup(bestp->ki_comm); 127 128 free(buf); 129 return (name); 130 131error: 132 free(buf); 133 return (NULL); 134} 135 136static char * 137osdep_get_cwd_fallback(int fd) 138{ 139 static char wd[PATH_MAX]; 140 struct kinfo_file *info = NULL; 141 pid_t pgrp; 142 int nrecords, i; 143 144 if ((pgrp = tcgetpgrp(fd)) == -1) 145 return (NULL); 146 147 if ((info = kinfo_getfile(pgrp, &nrecords)) == NULL) 148 return (NULL); 149 150 for (i = 0; i < nrecords; i++) { 151 if (info[i].kf_fd == KF_FD_TYPE_CWD) { 152 strlcpy(wd, info[i].kf_path, sizeof wd); 153 free(info); 154 return (wd); 155 } 156 } 157 158 free(info); 159 return (NULL); 160} 161 162#ifdef KERN_PROC_CWD 163char * 164osdep_get_cwd(int fd) 165{ 166 static struct kinfo_file info; 167 static int fallback; 168 int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_CWD, 0 }; 169 size_t len = sizeof info; 170 171 if (fallback) 172 return (osdep_get_cwd_fallback(fd)); 173 174 if ((name[3] = tcgetpgrp(fd)) == -1) 175 return (NULL); 176 177 if (sysctl(name, 4, &info, &len, NULL, 0) == -1) { 178 if (errno == ENOENT) { 179 fallback = 1; 180 return (osdep_get_cwd_fallback(fd)); 181 } 182 return (NULL); 183 } 184 return (info.kf_path); 185} 186#else /* !KERN_PROC_CWD */ 187char * 188osdep_get_cwd(int fd) 189{ 190 return (osdep_get_cwd_fallback(fd)); 191} 192#endif /* KERN_PROC_CWD */ 193 194struct event_base * 195osdep_event_init(void) 196{ 197 struct event_base *base; 198 199 /* 200 * On some versions of FreeBSD, kqueue doesn't work properly on tty 201 * file descriptors. This is fixed in recent FreeBSD versions. 202 */ 203 setenv("EVENT_NOKQUEUE", "1", 1); 204 205 base = event_init(); 206 unsetenv("EVENT_NOKQUEUE"); 207 return (base); 208} 209