1 /*
2  * Copyright (c) 2006, William Yodlowsky <bsd@openbsd.rutgers.edu>
3  * This file is free software; it can be modified and/or
4  * redistributed under the same terms as Perl itself
5  */
6 
7 #include <sys/types.h>
8 #include <sys/param.h>
9 #include <sys/mount.h>
10 #include <sys/proc.h>
11 #include <sys/stat.h>
12 #include <sys/sysctl.h>
13 #include <sys/syslimits.h>
14 #include <sys/user.h>
15 
16 #include <ctype.h>
17 #include <fcntl.h>
18 #include <kvm.h>
19 #include <limits.h>
20 #include <math.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 
27 void ppt_croak(const char *pat, ...);
28 
29 /* No need for the procstat structure since we don't use /proc */
30 
31 /* We need to pass in a cap for ignore, lower for store on object */
32 /* We can just lc these! */
33 static char Defaultformat[] = "liiiiiiiiiiiillssss";
34 
35 /* Mapping of field to type */
36 static char* Fields[] = {
37 	"ttynum",
38 	"uid",
39 	"gid",
40 	"euid",
41 	"egid",
42 	"pid",
43 	"ppid",
44 	"pgrp",
45 	"sess",
46 	"time",
47 	"utime",
48 	"stime",
49 	"start",
50 	"size",
51 	"rss",
52 	"fname",
53 	"state",
54 	"ttydev",
55 	"cmndline"
56 };
57 #define F_LASTFIELD 18
58 
59 /* Set up simple bounds checking */
60 #define STRLCPY(num,targ,src) if (strlcpy(targ,src,sizeof(targ)) >= sizeof(targ)) \
61 	ppt_croak("call:%d source string is too big to copy into buffer", num);
62 
63 #define STRLCAT(num,targ,src) if (strlcat(targ,src,sizeof(targ)) >= sizeof(targ)) \
64 	ppt_croak("call:%d source string is too big to append to buffer", num);
65 
66 extern void bless_into_proc(char* format, char** fields, ...);
67 
OS_initialize()68 char* OS_initialize() {
69 	return(NULL);
70 }
71 
OS_get_table()72 void OS_get_table() {
73 	kvm_t *kd;
74 	char errbuf[_POSIX2_LINE_MAX];
75 	struct kinfo_proc *procs;
76 	int count;
77 	int i, argcount;
78 	int ttynum;
79 	long start;
80 	unsigned long vsize;
81 	unsigned long rss;
82 	char *ttydev;
83 	char cmndline[ARG_MAX+1];
84 	char **pargv;
85 
86 	/* for bless_into_proc */
87 	static char format[F_LASTFIELD + 2];
88 	char state[20];
89 
90 	/* open the kvm interface */
91 	if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) {
92 		ppt_croak("kvm_open: %s", errbuf);
93 	}
94 
95 	/* get processes */
96 	if ((procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*procs), &count)) == NULL) {
97 		kvm_close(kd);
98 		ppt_croak("kvm_getprocs: %s", kvm_geterr(kd));
99 	}
100 
101 	/* bless_into_proc each process's information */
102 	for (i=0; i < count; i++) {
103 		STRLCPY(1,format,Defaultformat);
104 
105 		/* get ttydev */
106 		ttynum=procs[i].p_tdev;
107 		ttydev=devname(ttynum, S_IFCHR);
108 		if (ttydev == NULL) ttydev = "??";
109 
110 		/* process state */
111 		switch (procs[i].p_stat) {
112 			case SIDL:
113 				STRLCPY(2,state,"IDLE");
114 				break;
115 			case SRUN:
116 				STRLCPY(3,state,"RUN");
117 				break;
118 			case SSLEEP:
119 				STRLCPY(4,state,"SLEEP");
120 				break;
121 			case SSTOP:
122 				STRLCPY(5,state,"STOP");
123 				break;
124 			case SZOMB:
125 				STRLCPY(6,state,"ZOMBIE");
126 				break;
127 			default:
128 				STRLCPY(7,state,"UNKNOWN");
129 				break;
130 		}
131 
132 		vsize = getpagesize() * (procs[i].p_vm_dsize + procs[i].p_vm_ssize + procs[i].p_vm_tsize);
133 		rss   = getpagesize() * procs[i].p_vm_rssize;
134 
135 		/* arguments */
136 		cmndline[0] = '\0';
137 		pargv = kvm_getargv(kd, (const struct kinfo_proc *) &(procs[i]), 0);
138 		if (pargv) {
139 			argcount = 0;
140 			while (pargv[argcount] && strlen(cmndline)+strlen(pargv[argcount])+1 <= ARG_MAX) {
141 				STRLCAT(1,cmndline,pargv[argcount]);
142 				if (pargv[argcount+1]) {
143 					STRLCAT(2,cmndline," ");
144 				}
145 				argcount++;
146 			}
147 		}
148 
149 		/* everything else is straightforward, bless the lot */
150 		bless_into_proc( format,
151 			Fields,
152 			ttynum,
153 			procs[i].p_ruid,
154 			procs[i].p_rgid,
155 			procs[i].p_uid,
156 			procs[i].p_gid,
157 			procs[i].p_pid,
158 			procs[i].p_ppid,
159 			procs[i].p__pgid,
160 			procs[i].p_sid,
161 			procs[i].p_rtime_sec,
162 			procs[i].p_uutime_sec,
163 			procs[i].p_ustime_sec,
164 			procs[i].p_ustart_sec,
165 			vsize,
166 			rss,
167 			procs[i].p_comm,
168 			state,
169 			ttydev,
170 			cmndline
171 		);
172 	}
173 	if (kd) {
174 		kvm_close(kd);
175 	}
176 }
177