xref: /netbsd-src/external/bsd/tmux/dist/osdep-freebsd.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
15494e770Schristos /* $OpenBSD$ */
2698d5317Sjmmv 
3698d5317Sjmmv /*
4ed4e6cd4Schristos  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5698d5317Sjmmv  *
6698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
7698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
8698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
9698d5317Sjmmv  *
10698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15698d5317Sjmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16698d5317Sjmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17698d5317Sjmmv  */
18698d5317Sjmmv 
19698d5317Sjmmv #include <sys/param.h>
20698d5317Sjmmv #include <sys/proc.h>
21698d5317Sjmmv #include <sys/stat.h>
22698d5317Sjmmv #include <sys/sysctl.h>
23698d5317Sjmmv #include <sys/user.h>
24698d5317Sjmmv 
25698d5317Sjmmv #include <err.h>
26698d5317Sjmmv #include <errno.h>
27698d5317Sjmmv #include <stdint.h>
28698d5317Sjmmv #include <stdlib.h>
29698d5317Sjmmv #include <string.h>
30698d5317Sjmmv #include <unistd.h>
31928fc495Schristos #include <libutil.h>
32698d5317Sjmmv 
33*ef36e747Schristos #include "compat.h"
34*ef36e747Schristos 
35698d5317Sjmmv struct kinfo_proc	*cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
36698d5317Sjmmv char			*osdep_get_name(int, char *);
37928fc495Schristos char			*osdep_get_cwd(int);
38d530c4d0Sjmmv struct event_base	*osdep_event_init(void);
39698d5317Sjmmv 
40698d5317Sjmmv #ifndef nitems
41698d5317Sjmmv #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
42698d5317Sjmmv #endif
43698d5317Sjmmv 
44698d5317Sjmmv #define is_runnable(p) \
45698d5317Sjmmv 	((p)->ki_stat == SRUN || (p)->ki_stat == SIDL)
46698d5317Sjmmv #define is_stopped(p) \
47698d5317Sjmmv 	((p)->ki_stat == SSTOP || (p)->ki_stat == SZOMB)
48698d5317Sjmmv 
49698d5317Sjmmv struct kinfo_proc *
cmp_procs(struct kinfo_proc * p1,struct kinfo_proc * p2)50698d5317Sjmmv cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2)
51698d5317Sjmmv {
52698d5317Sjmmv 	if (is_runnable(p1) && !is_runnable(p2))
53698d5317Sjmmv 		return (p1);
54698d5317Sjmmv 	if (!is_runnable(p1) && is_runnable(p2))
55698d5317Sjmmv 		return (p2);
56698d5317Sjmmv 
57698d5317Sjmmv 	if (is_stopped(p1) && !is_stopped(p2))
58698d5317Sjmmv 		return (p1);
59698d5317Sjmmv 	if (!is_stopped(p1) && is_stopped(p2))
60698d5317Sjmmv 		return (p2);
61698d5317Sjmmv 
62698d5317Sjmmv 	if (p1->ki_estcpu > p2->ki_estcpu)
63698d5317Sjmmv 		return (p1);
64698d5317Sjmmv 	if (p1->ki_estcpu < p2->ki_estcpu)
65698d5317Sjmmv 		return (p2);
66698d5317Sjmmv 
67698d5317Sjmmv 	if (p1->ki_slptime < p2->ki_slptime)
68698d5317Sjmmv 		return (p1);
69698d5317Sjmmv 	if (p1->ki_slptime > p2->ki_slptime)
70698d5317Sjmmv 		return (p2);
71698d5317Sjmmv 
72698d5317Sjmmv 	if (strcmp(p1->ki_comm, p2->ki_comm) < 0)
73698d5317Sjmmv 		return (p1);
74698d5317Sjmmv 	if (strcmp(p1->ki_comm, p2->ki_comm) > 0)
75698d5317Sjmmv 		return (p2);
76698d5317Sjmmv 
77698d5317Sjmmv 	if (p1->ki_pid > p2->ki_pid)
78698d5317Sjmmv 		return (p1);
79698d5317Sjmmv 	return (p2);
80698d5317Sjmmv }
81698d5317Sjmmv 
82698d5317Sjmmv char *
osdep_get_name(int fd,char * tty)83698d5317Sjmmv osdep_get_name(int fd, char *tty)
84698d5317Sjmmv {
85698d5317Sjmmv 	int		 mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0 };
86698d5317Sjmmv 	struct stat	 sb;
87698d5317Sjmmv 	size_t		 len;
88698d5317Sjmmv 	struct kinfo_proc *buf, *newbuf, *bestp;
89698d5317Sjmmv 	u_int		 i;
90698d5317Sjmmv 	char		*name;
91698d5317Sjmmv 
92698d5317Sjmmv 	buf = NULL;
93698d5317Sjmmv 
94698d5317Sjmmv 	if (stat(tty, &sb) == -1)
95698d5317Sjmmv 		return (NULL);
96698d5317Sjmmv 	if ((mib[3] = tcgetpgrp(fd)) == -1)
97698d5317Sjmmv 		return (NULL);
98698d5317Sjmmv 
99698d5317Sjmmv retry:
100698d5317Sjmmv 	if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1)
101698d5317Sjmmv 		return (NULL);
102698d5317Sjmmv 	len = (len * 5) / 4;
103698d5317Sjmmv 
104698d5317Sjmmv 	if ((newbuf = realloc(buf, len)) == NULL)
105698d5317Sjmmv 		goto error;
106698d5317Sjmmv 	buf = newbuf;
107698d5317Sjmmv 
108698d5317Sjmmv 	if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) {
109698d5317Sjmmv 		if (errno == ENOMEM)
110698d5317Sjmmv 			goto retry;
111698d5317Sjmmv 		goto error;
112698d5317Sjmmv 	}
113698d5317Sjmmv 
114698d5317Sjmmv 	bestp = NULL;
115698d5317Sjmmv 	for (i = 0; i < len / sizeof (struct kinfo_proc); i++) {
116698d5317Sjmmv 		if (buf[i].ki_tdev != sb.st_rdev)
117698d5317Sjmmv 			continue;
118698d5317Sjmmv 		if (bestp == NULL)
119698d5317Sjmmv 			bestp = &buf[i];
120698d5317Sjmmv 		else
121698d5317Sjmmv 			bestp = cmp_procs(&buf[i], bestp);
122698d5317Sjmmv 	}
123698d5317Sjmmv 
124698d5317Sjmmv 	name = NULL;
125698d5317Sjmmv 	if (bestp != NULL)
126698d5317Sjmmv 		name = strdup(bestp->ki_comm);
127698d5317Sjmmv 
128698d5317Sjmmv 	free(buf);
129698d5317Sjmmv 	return (name);
130698d5317Sjmmv 
131698d5317Sjmmv error:
132698d5317Sjmmv 	free(buf);
133698d5317Sjmmv 	return (NULL);
134698d5317Sjmmv }
135d530c4d0Sjmmv 
1365494e770Schristos static char *
osdep_get_cwd_fallback(int fd)1375494e770Schristos osdep_get_cwd_fallback(int fd)
138928fc495Schristos {
139928fc495Schristos 	static char		 wd[PATH_MAX];
140928fc495Schristos 	struct kinfo_file	*info = NULL;
141928fc495Schristos 	pid_t			 pgrp;
142928fc495Schristos 	int			 nrecords, i;
143928fc495Schristos 
144928fc495Schristos 	if ((pgrp = tcgetpgrp(fd)) == -1)
145928fc495Schristos 		return (NULL);
146928fc495Schristos 
147928fc495Schristos 	if ((info = kinfo_getfile(pgrp, &nrecords)) == NULL)
148928fc495Schristos 		return (NULL);
149928fc495Schristos 
150928fc495Schristos 	for (i = 0; i < nrecords; i++) {
151928fc495Schristos 		if (info[i].kf_fd == KF_FD_TYPE_CWD) {
152928fc495Schristos 			strlcpy(wd, info[i].kf_path, sizeof wd);
153928fc495Schristos 			free(info);
154928fc495Schristos 			return (wd);
155928fc495Schristos 		}
156928fc495Schristos 	}
157928fc495Schristos 
158928fc495Schristos 	free(info);
159928fc495Schristos 	return (NULL);
160928fc495Schristos }
161928fc495Schristos 
1625494e770Schristos #ifdef KERN_PROC_CWD
1635494e770Schristos char *
osdep_get_cwd(int fd)1645494e770Schristos osdep_get_cwd(int fd)
1655494e770Schristos {
1665494e770Schristos 	static struct kinfo_file	info;
1675494e770Schristos 	static int			fallback;
1685494e770Schristos 	int	name[] = { CTL_KERN, KERN_PROC, KERN_PROC_CWD, 0 };
1695494e770Schristos 	size_t	len = sizeof info;
1705494e770Schristos 
1715494e770Schristos 	if (fallback)
1725494e770Schristos 		return (osdep_get_cwd_fallback(fd));
1735494e770Schristos 
1745494e770Schristos 	if ((name[3] = tcgetpgrp(fd)) == -1)
1755494e770Schristos 		return (NULL);
1765494e770Schristos 
1775494e770Schristos 	if (sysctl(name, 4, &info, &len, NULL, 0) == -1) {
1785494e770Schristos 		if (errno == ENOENT) {
1795494e770Schristos 			fallback = 1;
1805494e770Schristos 			return (osdep_get_cwd_fallback(fd));
1815494e770Schristos 		}
1825494e770Schristos 		return (NULL);
1835494e770Schristos 	}
1845494e770Schristos 	return (info.kf_path);
1855494e770Schristos }
1865494e770Schristos #else /* !KERN_PROC_CWD */
1875494e770Schristos char *
osdep_get_cwd(int fd)1885494e770Schristos osdep_get_cwd(int fd)
1895494e770Schristos {
1905494e770Schristos 	return (osdep_get_cwd_fallback(fd));
1915494e770Schristos }
1925494e770Schristos #endif /* KERN_PROC_CWD */
1935494e770Schristos 
194d530c4d0Sjmmv struct event_base *
osdep_event_init(void)195d530c4d0Sjmmv osdep_event_init(void)
196d530c4d0Sjmmv {
1978f3b9483Schristos 	struct event_base	*base;
1988f3b9483Schristos 
199d530c4d0Sjmmv 	/*
200d530c4d0Sjmmv 	 * On some versions of FreeBSD, kqueue doesn't work properly on tty
201d530c4d0Sjmmv 	 * file descriptors. This is fixed in recent FreeBSD versions.
202d530c4d0Sjmmv 	 */
203d530c4d0Sjmmv 	setenv("EVENT_NOKQUEUE", "1", 1);
2048f3b9483Schristos 
2058f3b9483Schristos 	base = event_init();
2068f3b9483Schristos 	unsetenv("EVENT_NOKQUEUE");
2078f3b9483Schristos 	return (base);
208d530c4d0Sjmmv }
209