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
24#include <errno.h>
25#include <limits.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "tmux.h"
31
32#define is_runnable(p) \
33	((p)->p_stat == LSRUN || (p)->p_stat == SIDL)
34#define is_stopped(p) \
35	((p)->p_stat == SSTOP || (p)->p_stat == SZOMB)
36
37struct kinfo_proc2	*cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *);
38
39struct kinfo_proc2 *
40cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2)
41{
42	if (is_runnable(p1) && !is_runnable(p2))
43		return (p1);
44	if (!is_runnable(p1) && is_runnable(p2))
45		return (p2);
46
47	if (is_stopped(p1) && !is_stopped(p2))
48		return (p1);
49	if (!is_stopped(p1) && is_stopped(p2))
50		return (p2);
51
52	if (p1->p_estcpu > p2->p_estcpu)
53		return (p1);
54	if (p1->p_estcpu < p2->p_estcpu)
55		return (p2);
56
57	if (p1->p_slptime < p2->p_slptime)
58		return (p1);
59	if (p1->p_slptime > p2->p_slptime)
60		return (p2);
61
62	if (p1->p_pid > p2->p_pid)
63		return (p1);
64	return (p2);
65}
66
67char *
68osdep_get_name(int fd, __unused char *tty)
69{
70	int		 mib[6];
71	struct stat	 sb;
72	size_t		 len, i;
73	struct kinfo_proc2 *buf, *newbuf, *bestp;
74	char		*name;
75
76	if (stat(tty, &sb) == -1)
77		return (NULL);
78	if ((mib[3] = tcgetpgrp(fd)) == -1)
79		return (NULL);
80
81	buf = NULL;
82	len = sizeof bestp;
83
84	mib[0] = CTL_KERN;
85	mib[1] = KERN_PROC2;
86	mib[2] = KERN_PROC_PGRP;
87	mib[4] = sizeof *buf;
88
89retry:
90	mib[5] = 0;
91
92	if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1)
93		return (NULL);
94
95	if ((newbuf = realloc(buf, len)) == NULL)
96		goto error;
97	buf = newbuf;
98
99	mib[5] = len / (sizeof *buf);
100	if (sysctl(mib, __arraycount(mib), buf, &len, NULL, 0) == -1) {
101		if (errno == ENOMEM)
102			goto retry;
103		goto error;
104	}
105
106	bestp = NULL;
107	for (i = 0; i < len / (sizeof *buf); i++) {
108		if (buf[i].p_tdev != sb.st_rdev)
109			continue;
110		if (bestp == NULL)
111			bestp = &buf[i];
112		else
113			bestp = cmp_procs(&buf[i], bestp);
114	}
115
116	name = NULL;
117	if (bestp != NULL)
118		name = strdup(bestp->p_comm);
119
120	free(buf);
121	return (name);
122
123error:
124	free(buf);
125	return (NULL);
126}
127
128char *
129osdep_get_cwd(int fd)
130{
131	static char	target[PATH_MAX + 1];
132	pid_t		pgrp;
133#ifdef KERN_PROC_CWD
134	int		mib[4];
135	size_t		len;
136#else
137	char		*path;
138	ssize_t		n;
139#endif
140
141	if ((pgrp = tcgetpgrp(fd)) == -1)
142		return (NULL);
143
144#ifdef KERN_PROC_CWD
145	mib[0] = CTL_KERN;
146	mib[1] = KERN_PROC_ARGS;
147	mib[2] = pgrp;
148	mib[3] = KERN_PROC_CWD;
149	len = sizeof(target);
150	if (sysctl(mib, __arraycount(mib), target, &len, NULL, 0) == 0)
151		return (target);
152#else
153	xasprintf(&path, "/proc/%lld/cwd", (long long) pgrp);
154	n = readlink(path, target, sizeof(target) - 1);
155	free(path);
156	if (n > 0) {
157		target[n] = '\0';
158		return (target);
159	}
160#endif
161
162	return (NULL);
163}
164
165struct event_base *
166osdep_event_init(void)
167{
168	return (event_init());
169}
170