procname.c revision 1.15
1/* $OpenBSD: procname.c,v 1.15 2016/01/19 15:59:12 nicm Exp $ */
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>	/* MAXCOMLEN */
20#include <sys/types.h>
21#include <sys/proc.h>
22#include <sys/sysctl.h>
23#include <sys/stat.h>
24
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#ifndef nitems
31#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
32#endif
33
34#define is_runnable(p) \
35	((p)->p_stat == SRUN || (p)->p_stat == SIDL || (p)->p_stat == SONPROC)
36#define is_stopped(p) \
37	((p)->p_stat == SSTOP || (p)->p_stat == SDEAD)
38
39struct kinfo_proc	*cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
40char			*get_proc_name(int, char *);
41
42struct kinfo_proc *
43cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2)
44{
45	if (is_runnable(p1) && !is_runnable(p2))
46		return (p1);
47	if (!is_runnable(p1) && is_runnable(p2))
48		return (p2);
49
50	if (is_stopped(p1) && !is_stopped(p2))
51		return (p1);
52	if (!is_stopped(p1) && is_stopped(p2))
53		return (p2);
54
55	if (p1->p_estcpu > p2->p_estcpu)
56		return (p1);
57	if (p1->p_estcpu < p2->p_estcpu)
58		return (p2);
59
60	if (p1->p_slptime < p2->p_slptime)
61		return (p1);
62	if (p1->p_slptime > p2->p_slptime)
63		return (p2);
64
65	if ((p1->p_flag & P_SINTR) && !(p2->p_flag & P_SINTR))
66		return (p1);
67	if (!(p1->p_flag & P_SINTR) && (p2->p_flag & P_SINTR))
68		return (p2);
69
70	if (strcmp(p1->p_comm, p2->p_comm) < 0)
71		return (p1);
72	if (strcmp(p1->p_comm, p2->p_comm) > 0)
73		return (p2);
74
75	if (p1->p_pid > p2->p_pid)
76		return (p1);
77	return (p2);
78}
79
80char *
81get_proc_name(int fd, char *tty)
82{
83	int		 mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0,
84				    sizeof(struct kinfo_proc), 0 };
85	struct stat	 sb;
86	size_t		 len;
87	struct kinfo_proc *buf, *newbuf, *bestp;
88	u_int		 i;
89	char		*name;
90
91	buf = NULL;
92
93	if (stat(tty, &sb) == -1)
94		return (NULL);
95	if ((mib[3] = tcgetpgrp(fd)) == -1)
96		return (NULL);
97
98retry:
99	if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1)
100		goto error;
101	len = (len * 5) / 4;
102
103	if ((newbuf = realloc(buf, len)) == NULL)
104		goto error;
105	buf = newbuf;
106
107	mib[5] = (int)(len / sizeof(struct kinfo_proc));
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 ((dev_t)buf[i].p_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->p_comm);
127
128	free(buf);
129	return (name);
130
131error:
132	free(buf);
133	return (NULL);
134}
135