1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1989-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *               Glenn Fowler <glenn.s.fowler@gmail.com>                *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * Glenn Fowler
23  * AT&T Research
24  *
25  * process status stream PSS_METHOD_info implementation
26  */
27 
28 #include "psslib.h"
29 
30 #if PSS_METHOD != PSS_METHOD_info
31 
32 NoN(pss_info)
33 
34 #else
35 
36 #include <info.h>
37 #include <sys/../proc.h>	/* clash with ast <proc.h> */
38 #include <sys/inode.h>
39 
40 typedef struct State_s
41 {
42 	int			mem;
43 	struct pentry*		pr;
44 	struct pentry*		pp;
45 	struct pentry*		pe;
46 	struct pentry		ps[1];
47 } State_t;
48 
49 static int
50 info_init(Pss_t* pss)
51 {
52 	register State_t*	state;
53 	char*			mem;
54 	int			fd;
55 	unsigned long		n;
56 	unsigned long		a;
57 
58 	mem = "/dev/mem";
59 	if ((fd = open(mem, O_RDONLY)) < 0)
60 	{
61 		if (pss->disc->errorf)
62 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%s: cannot read", mem);
63 		return -1;
64 	}
65 	n = info(_I_NPROCTAB);
66 	a = info(_I_PROCTAB);
67 	if (!(state = vmnewof(pss->vm, 0, State_t, 1, (n - 1) * sizeof(struct pentry))))
68 	{
69 		if (pss->disc->errorf)
70 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "out of space");
71 		goto bad;
72 	}
73 	if (lseek(fd, a, SEEK_SET) != a)
74 	{
75 		if (pss->disc->errorf)
76 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%s: %lu: seek error", mem, a);
77 		goto bad;
78 	}
79 	if (read(fd, state->ps, n * sizeof(state->ps[0])) != n * sizeof(state->ps[0]))
80 	{
81 		if (pss->disc->errorf)
82 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%s: %lu entry read error", mem, n);
83 		goto bad;
84 	}
85 	state->mem = fd;
86 	state->pp = state->ps;
87 	state->pe = state->ps + n;
88 	pss->data = state;
89 	return 1;
90  bad:
91 	close(fd);
92 	free(state);
93 	return -1;
94 }
95 
96 static int
97 info_read(Pss_t* pss, Pss_id_t pid)
98 {
99 	register State_t*	state = (State_t*)pss->data;
100 	int			count;
101 
102 	if (pid)
103 	{
104 		for (state->pp = state->ps; state->pp < state->pe; state->pp++)
105 			if (state->pp->pstate != PRFREE && state->pp->pid == pid)
106 				break;
107 	}
108 	else
109 		while (state->pp < state->pe && state->pp->pstate == PRFREE)
110 			state->pp++;
111 	if (state->pp >= state->pe)
112 		return 0;
113 	state->pr = state->pp++;
114 	pss->pid = state->pr->pid;
115 	return 1;
116 }
117 
118 static int
119 info_part(register Pss_t* pss, register Pssent_t* pe)
120 {
121 	State_t*		state = (State_t*)pss->data;
122 	register struct pentry*	pr = state->pr;
123 
124 	pe->pid = pr->pid;
125 	pe->pgrp = pr->pgroup;
126 	pe->tty = pr->cdevnum == -1 ? PSS_NODEV : pr->cdevnum;
127 	pe->uid = pr->uid;
128 	switch ((int)(pr->pstate & 0xf))
129 	{
130 	case PRREADY:	pe->state = 'I'; break;
131 	case PRCURR:	pe->state = pr->pid == getpid() ? 'R' : 'S'; break;
132 	case PRWAIT:	pe->state = 'W'; break;
133 	case SUSPVAL:	pe->state = 'S'; break;
134 	case PRSTOP:	pe->state = 'T'; break;
135 	case ZOMBIEVAL:	pe->state = 'Z'; break;
136 	default:	pe->state = 'O'; break;
137 	}
138 	return 1;
139 }
140 
141 static int
142 info_full(register Pss_t* pss, register Pssent_t* pe)
143 {
144 	register State_t*	state = (State_t*)pss->data;
145 	register struct pentry*	pr = state->pr;
146 	unsigned long		fields = pss->disc->fields & pss->meth->fields;
147 	char*			s;
148 	int			i;
149 	struct pssentry		px;
150 	struct st_entry		st;
151 
152 	if (pe->state != PSS_ZOMBIE)
153 	{
154 		if ((fields & (PSS_sid|PSS_size|PSS_time)) &&
155 		    lseek(state->mem, (unsigned long)pr->pss, SEEK_SET) == (unsigned long)pr->pss &&
156 		    read(state->mem, &px, sizeof(px)) == sizeof(px))
157 		{
158 			pe->sid = px.sid;
159 			pe->size = (pr->stack_total + (px.brk - px.data_start)) / 1024;
160 			pe->time = (px.pss_utime + px.stime) / 5;
161 		}
162 		if ((fields & (PSS_pri)) &&
163 		    lseek(state->mem, (unsigned long)pr->i, SEEK_SET) == (unsigned long)pr->i &&
164 		    read(state->mem, &st, sizeof(st)) == sizeof(st))
165 		{
166 			pe->pri = st.pprio;
167 			pe->nice = st.rprio;
168 		}
169 		if (fields & PSS_command)
170 			pe->command = ((s = strrchr(pr->pname, '/')) && *++s) ? s : pr->pname;
171 		pe->args = pr->pname;
172 	}
173 	pe->flags = pr->pflag;
174 	pe->ppid = pr->ppid;
175 	pe->gid = pr->gid;
176 	return 1;
177 }
178 
179 static int
180 info_done(register Pss_t* pss)
181 {
182 	register State_t*	state = (State_t*)pss->data;
183 
184 	close(state->mem);
185 	free(state);
186 	return 0;
187 }
188 
189 static Pssmeth_t info_method =
190 {
191 	"info",
192 	"[-version?@(#)$Id: pss info (AT&T Research) 2005-02-11 $\n]"
193 	"[-author?Glenn Fowler <gsf@research.att.com>]",
194 	PSS_args|PSS_command|PSS_flags|PSS_gid|PSS_nice|PSS_pgrp|PSS_pid|PSS_ppid|PSS_pri|PSS_sid|PSS_size|PSS_state|PSS_time|PSS_tty|PSS_uid,
195 	info_init,
196 	info_read,
197 	info_part,
198 	info_full,
199 	0,
200 	0,
201 	0,
202 	info_done
203 };
204 
205 Pssmeth_t*	_pss_method = &info_method;
206 
207 #endif
208