1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
4
* Copyright (C) 2007 Joe Marcus Clarke <marcus@FreeBSD.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33
#include <sys/param.h>
34
#include <sys/types.h>
36
#include <sys/sysctl.h>
38
#include <sys/ioctl.h>
40
#include <sys/consio.h>
42
#define DEV_ENCODE(M,m) ( \
43
( (M&0xfff) << 8) | ( (m&0xfff00) << 12) | (m&0xff) \
46
#include "ck-sysdeps.h"
52
/* adapted from procps */
56
int ppid; /* stat,status pid of parent process */
57
char state; /* stat,status single-char code for process state (S=sleeping) */
58
char cmd[16]; /* stat,status basename of executable file in call to exec(2) */
59
unsigned long long utime; /* stat user-mode CPU time accumulated by process */
60
unsigned long long stime; /* stat kernel-mode CPU time accumulated by process */
61
unsigned long long cutime; /* stat cumulative utime of process and reaped children */
62
unsigned long long cstime; /* stat cumulative stime of process and reaped children */
63
unsigned long long start_time; /* stat start time of process -- seconds since 1-1-70 */
64
unsigned long start_code; /* stat address of beginning of code segment */
65
unsigned long end_code; /* stat address of end of code segment */
66
unsigned long start_stack; /* stat address of the bottom of stack for the process */
67
unsigned long kstk_esp; /* stat kernel stack pointer */
68
unsigned long kstk_eip; /* stat kernel instruction pointer */
69
unsigned long wchan; /* stat (special) address of kernel wait channel proc is sleeping in */
70
long priority; /* stat kernel scheduling priority */
71
long nice; /* stat standard unix nice level of process */
72
long rss; /* stat resident set size from /proc/#/stat (pages) */
73
long alarm; /* stat ? */
74
unsigned long rtprio; /* stat real-time priority */
75
unsigned long sched; /* stat scheduling class */
76
unsigned long vsize; /* stat number of pages of virtual memory ... */
77
unsigned long rss_rlim; /* stat resident set size limit? */
78
unsigned long flags; /* stat kernel flags for the process */
79
unsigned long min_flt; /* stat number of minor page faults since process start */
80
unsigned long maj_flt; /* stat number of major page faults since process start */
81
unsigned long cmin_flt; /* stat cumulative min_flt of process and child processes */
82
unsigned long cmaj_flt; /* stat cumulative maj_flt of process and child processes */
83
int pgrp; /* stat process group id */
84
int session; /* stat session id */
85
int nlwp; /* stat number of threads, or 0 if no clue */
86
int tty; /* stat full device number of controlling terminal */
87
int tpgid; /* stat terminal process group id */
88
int exit_signal; /* stat might not be SIGCHLD */
89
int processor; /* stat current (or most recent?) CPU */
90
uintptr_t penv; /* stat address of initial environment vector */
91
char tty_text[16]; /* stat device name */
96
ck_process_stat_get_ppid (CkProcessStat *stat)
98
g_return_val_if_fail (stat != NULL, -1);
104
ck_process_stat_get_cmd (CkProcessStat *stat)
106
g_return_val_if_fail (stat != NULL, NULL);
108
return g_strdup (stat->cmd);
112
ck_process_stat_get_tty (CkProcessStat *stat)
114
g_return_val_if_fail (stat != NULL, NULL);
116
return g_strdup (stat->tty_text);
120
get_kinfo_proc (pid_t pid,
121
struct kinfo_proc *p)
127
sysctlnametomib ("kern.proc.pid", mib, &len);
129
len = sizeof(struct kinfo_proc);
132
if (sysctl (mib, 4, p, &len, NULL, 0) == -1) {
139
/* return 1 if it works, or 0 for failure */
141
stat2proc (pid_t pid,
150
if (! get_kinfo_proc (pid, &p)) {
155
if (num >= sizeof P->cmd) {
156
num = sizeof P->cmd - 1;
159
memcpy (P->cmd, p.ki_ocomm, num);
165
P->session = p.ki_sid;
166
P->rss = p.ki_rssize;
167
P->vsize = p.ki_size;
168
P->start_time = p.ki_start.tv_sec;
169
P->wchan = (unsigned long) p.ki_wchan;
170
P->state = p.ki_stat;
172
P->flags = p.ki_sflag;
173
P->tpgid = p.ki_tpgid;
174
P->processor = p.ki_oncpu;
175
P->nlwp = p.ki_numthreads;
177
/* we like it Linux-encoded :-) */
178
tty_maj = major (p.ki_tdev);
179
tty_min = minor (p.ki_tdev);
180
P->tty = DEV_ENCODE (tty_maj,tty_min);
182
snprintf (P->tty_text, sizeof P->tty_text, "%3d,%-3d", tty_maj, tty_min);
184
if (p.ki_tdev != NODEV && (ttname = devname (p.ki_tdev, S_IFCHR)) != NULL) {
185
memcpy (P->tty_text, ttname, sizeof P->tty_text);
188
if (p.ki_tdev == NODEV) {
189
memcpy (P->tty_text, " ? ", sizeof P->tty_text);
200
ck_process_stat_new_for_unix_pid (pid_t pid,
201
CkProcessStat **stat,
208
g_return_val_if_fail (pid > 1, FALSE);
214
proc = g_new0 (CkProcessStat, 1);
216
res = stat2proc (pid, proc);
220
g_propagate_error (error, local_error);
228
ck_process_stat_free (CkProcessStat *stat)
234
ck_unix_pid_get_env_hash (pid_t pid)
242
kd = kvm_openfiles (_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL);
247
if (! get_kinfo_proc (pid, &p)) {
251
penv = kvm_getenvv (kd, &p, 0);
256
hash = g_hash_table_new_full (g_str_hash,
261
for (i = 0; penv[i] != NULL; i++) {
264
vals = g_strsplit (penv[i], "=", 2);
266
g_hash_table_insert (hash,
279
ck_unix_pid_get_env (pid_t pid,
286
* Would probably be more efficient to just loop through the
287
* environment and return the value, avoiding building the hash
288
* table, but this works for now.
290
hash = ck_unix_pid_get_env_hash (pid);
291
val = g_strdup (g_hash_table_lookup (hash, var));
292
g_hash_table_destroy (hash);
298
ck_unix_pid_get_uid (pid_t pid)
304
g_return_val_if_fail (pid > 1, 0);
308
res = get_kinfo_proc (pid, &p);
318
ck_unix_pid_get_login_session_id (pid_t pid,
321
g_return_val_if_fail (pid > 1, FALSE);
327
ck_get_max_num_consoles (guint *num)
342
while ((t = getttyent ()) != NULL) {
343
if (t->ty_status & TTY_ON && strncmp (t->ty_name, "ttyv", 4) == 0)
347
/* Increment one more so that all consoles are properly counted
348
* this is arguable a bug in vt_add_watches().
365
ck_supports_activatable_consoles (void)
371
ck_get_console_device_for_num (guint num)
375
/* The device number is always one less than the VT number. */
378
device = g_strdup_printf ("/dev/ttyv%u", num);
384
ck_get_console_num_from_device (const char *device,
393
if (device == NULL) {
397
if (sscanf (device, "/dev/ttyv%u", &n) == 1) {
398
/* The VT number is always one more than the device number. */
411
ck_get_active_console_num (int console_fd,
418
g_assert (console_fd != -1);
423
res = ioctl (console_fd, VT_GETACTIVE, &active);
425
perror ("ioctl VT_GETACTIVE");
429
g_debug ("Active VT is: %d (ttyv%d)", active, active - 1);