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_procfs implementation 26 */ 27 28 #include "psslib.h" 29 30 #if PSS_METHOD != PSS_METHOD_procfs 31 32 NoN(pss_procfs) 33 34 #else 35 36 #if !defined(pr_clname) && !_mem_pr_clname_prpsinfo 37 #undef PSS_sched 38 #define PSS_sched 0 39 #endif 40 41 #if !defined(pr_gid) && !_mem_pr_gid_prpsinfo 42 #undef PSS_gid 43 #define PSS_gid 0 44 #endif 45 46 #if !defined(pr_lttydev) && !_mem_pr_lttydev_prpsinfo 47 #undef _mem_pr_lttydev_prpsinfo 48 #define _mem_pr_lttydev_prpsinfo 0 49 #endif 50 51 #if !_mem_pr_npid_prpsinfo 52 #if !defined(pr_ntpid) && !_mem_pr_ntpid_prpsinfo 53 #undef PSS_npid 54 #define PSS_npid 0 55 #else 56 #define pr_npid pr_ntpid 57 #endif 58 #endif 59 60 #if !defined(pr_pgrp) && !_mem_pr_pgrp_prpsinfo 61 #if _mem_pr_pgid_prpsinfo 62 #undef _mem_pr_pgrp_prpsinfo 63 #define _mem_pr_pgrp_prpsinfo 1 64 #define pr_pgrp pr_pgid 65 #else 66 #undef PSS_pgrp 67 #define PSS_pgrp 0 68 #endif 69 #endif 70 71 #if !defined(pr_psargs) && !_mem_pr_psargs_prpsinfo 72 #undef _mem_pr_psargs_prpsinfo 73 #define _mem_pr_psargs_prpsinfo 0 74 #endif 75 76 #if !defined(pr_refcount) && !_mem_pr_refcount_prpsinfo 77 #undef PSS_refcount 78 #define PSS_refcount 0 79 #endif 80 81 #if !defined(pr_rssize) && !_mem_pr_rssize_prpsinfo 82 #undef PSS_rss 83 #define PSS_rss 0 84 #endif 85 86 #if !defined(pr_sonproc) && !_mem_pr_sonproc_prpsinfo 87 #undef PSS_proc 88 #define PSS_proc 0 89 #endif 90 91 #if !defined(pr_sid) && !_mem_pr_sid_prpsinfo 92 #undef PSS_sid 93 #define PSS_sid 0 94 #define pr_sid pr_tgrp 95 #endif 96 97 #if !defined(pr_tgrp) && !_mem_pr_tgrp_prpsinfo 98 #undef PSS_tgrp 99 #define PSS_tgrp 0 100 #define pr_tgrp pr_pgrp 101 #endif 102 103 typedef struct State_s 104 { 105 struct prpsinfo pr; 106 DIR* dir; 107 } State_t; 108 109 static int 110 procfs_init(Pss_t* pss) 111 { 112 register State_t* state; 113 int fd; 114 115 sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, (unsigned long)1, _PS_status); 116 if ((fd = open(pss->buf, O_RDONLY|O_BINARY)) < 0) 117 return -1; 118 close(fd); 119 if (!(state = vmnewof(pss->vm, 0, State_t, 1, 0))) 120 { 121 if (pss->disc->errorf) 122 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "out of space"); 123 return -1; 124 } 125 if (!(state->dir = opendir(_PS_dir))) 126 { 127 if (pss->disc->errorf) 128 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|1, "%s: cannot open", _PS_dir); 129 return -1; 130 } 131 pss->data = state; 132 return 1; 133 } 134 135 static int 136 procfs_done(Pss_t* pss) 137 { 138 register State_t* state = (State_t*)pss->data; 139 140 closedir(state->dir); 141 return 1; 142 } 143 144 static int 145 procfs_read(Pss_t* pss, Pss_id_t pid) 146 { 147 register State_t* state = (State_t*)pss->data; 148 struct dirent* ent; 149 char* e; 150 151 if (pid) 152 pss->pid = pid; 153 else 154 do 155 { 156 if (!(ent = readdir(state->dir))) 157 return 0; 158 pss->pid = (Pss_id_t)strtol(ent->d_name, &e, 10); 159 } while (*e); 160 return 1; 161 } 162 163 static int 164 procfs_part(register Pss_t* pss, register Pssent_t* pe) 165 { 166 register State_t* state = (State_t*)pss->data; 167 register struct prpsinfo* pr = &state->pr; 168 register int fd; 169 int n; 170 #if defined(_PS_scan_binary) || defined(_PS_scan_format) 171 struct stat st; 172 #endif 173 174 sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, (unsigned long)pss->pid, _PS_status); 175 if ((fd = open(pss->buf, O_RDONLY|O_BINARY)) < 0) 176 { 177 if (pss->disc->errorf && ((pss->disc->flags & PSS_VERBOSE) || errno != ENOENT)) 178 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%lu: cannot stat process", pss->pid); 179 return 0; 180 } 181 #ifdef _PS_scan_format 182 if ((n = read(fd, pss->buf, sizeof(pss->buf))) <= 0 || fstat(fd, &st)) 183 { 184 n = -1; 185 errno = EINVAL; 186 } 187 else 188 { 189 memset(pr, sizeof(*pr), 0); 190 n = sfsscanf(pss->buf, _PS_scan_format, _PS_scan_args(pr)); 191 if (n < _PS_scan_count) 192 { 193 register char* s; 194 195 for (s = pss->buf; *s; s++) 196 if (*s == '(') 197 { 198 for (; *s && *s != ')'; s++) 199 if (isspace(*s)) 200 *s = '_'; 201 break; 202 } 203 n = sfsscanf(pss->buf, _PS_scan_format, _PS_scan_args(pr)); 204 if (n < _PS_scan_count) 205 error(1, "%lu: scan count %d, expected at least %d", (unsigned long)pss->pid, n, _PS_scan_count); 206 } 207 #ifdef _PS_scan_fix 208 _PS_scan_fix(pr, pe); 209 #endif 210 #ifdef _PS_task 211 sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, (unsigned long)pss->pid, _PS_task); 212 (void)stat(pss->buf, &st); 213 #endif 214 pr->pr_uid = st.st_uid; 215 pr->pr_gid = st.st_gid; 216 pr->pr_nice = pr->pr_priority - 15; 217 pr->pr_size /= 1024; 218 #if _mem_pr_rssize_prpsinfo 219 pr->pr_rssize /= 1024; 220 #endif 221 #ifdef _PS_scan_boot 222 if (!pss->boot) 223 { 224 register char* s; 225 Sfio_t* fp; 226 227 pss->boot = 1; 228 if (fp = sfopen(NiL, "/proc/stat", "r")) 229 { 230 while (s = sfgetr(fp, '\n', 0)) 231 if (strneq(s, "btime ", 6)) 232 { 233 pss->boot = strtol(s + 6, NiL, 10); 234 break; 235 } 236 sfclose(fp); 237 } 238 if (!(pss->hz = (int)strtol(astconf("CLK_TCK", NiL, NiL), NiL, 0))) 239 pss->hz = PR_HZ; 240 } 241 pr->pr_start = pss->boot + pr->pr_start / pss->hz; 242 #endif 243 } 244 #else 245 #ifdef _PS_scan_binary 246 n = read(fd, pr, sizeof(*pr)) == sizeof(*pr) ? 1 : -1; 247 #else 248 n = ioctl(fd, PIOCPSINFO, pr); 249 #endif 250 #endif 251 close(fd); 252 if (n < 0) 253 { 254 if (pss->disc->errorf) 255 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%lu: cannot get process info", pss->pid); 256 return 0; 257 } 258 #if _UTS 259 if (pr->pr_pri > 99) 260 pr->pr_pri = 99; 261 else if (pr->pr_pri < 0) 262 pr->pr_pri = 0; 263 pr->pr_ttydev = makedev((pr->pr_ttydev >> 18) & ((1<<14)-1), pr->pr_ttydev & ((1<<18)-1)); 264 #endif 265 #if PSS_gid 266 pe->gid = pr->pr_gid; 267 #endif 268 #if PSS_pgrp 269 pe->pgrp = pr->pr_pgrp; 270 #endif 271 pe->pid = pr->pr_pid; 272 #if PSS_sid 273 pe->sid = pr->pr_sid; 274 #endif 275 pe->state = PR_ZOMBIE(pr) ? PSS_ZOMBIE : pr->pr_sname; 276 #if PSS_tgrp 277 pe->tgrp = pr->pr_tgrp; 278 #endif 279 pe->tty = (pr->pr_ttydev == (Pss_dev_t)PRNODEV) ? PSS_NODEV : pr->pr_ttydev; 280 pe->uid = pr->pr_uid; 281 return 1; 282 } 283 284 static int 285 procfs_full(register Pss_t* pss, register Pssent_t* pe) 286 { 287 register State_t* state = (State_t*)pss->data; 288 register struct prpsinfo* pr = &state->pr; 289 unsigned long fields = pss->disc->fields & pss->meth->fields; 290 char* s; 291 int i; 292 293 if (pe->state != PSS_ZOMBIE) 294 { 295 if (fields & PSS_args) 296 { 297 #if _mem_pr_psargs_prpsinfo 298 s = pr->pr_psargs; 299 #else 300 #ifdef _PS_args 301 s = "<unknown>"; 302 sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, pe->pid, _PS_args); 303 if ((i = open(pss->buf, O_RDONLY|O_BINARY)) >= 0) 304 { 305 int n; 306 307 n = read(i, pss->buf, sizeof(pss->buf) - 1); 308 close(i); 309 if (n > 0) 310 { 311 s = pss->buf; 312 for (i = 0; i < n; i++) 313 if (!s[i]) 314 s[i] = ' '; 315 s[i] = 0; 316 } 317 } 318 #else 319 s = pr->pr_fname; 320 if (s[0] == '(' && s[i = strlen(s) - 1] == ')') 321 { 322 s[i] = 0; 323 s++; 324 } 325 #endif 326 #endif 327 pe->args = s; 328 } 329 if (fields & PSS_command) 330 { 331 s = pr->pr_fname; 332 if (s[0] == '(' && s[i = strlen(s) - 1] == ')') 333 { 334 s[i] = 0; 335 s++; 336 } 337 pe->command = s; 338 } 339 } 340 pe->addr = (void*)pr->pr_addr; 341 #if _mem_pr_clname_prpsinfo 342 pe->sched = pr->pr_clname; 343 #endif 344 pe->cpu = PR_CPU(pr); 345 pe->flags = pr->pr_flag; 346 pe->nice = pr->pr_nice; 347 #if _mem_pr_npid_prpsinfo 348 pe->npid = pr->pr_npid; 349 #else 350 #if _mem_pr_ntpid_prpsinfo 351 pe->npid = pr->pr_ntpid; 352 #endif 353 #endif 354 pe->ppid = pr->pr_ppid; 355 pe->pri = pr->pr_pri; 356 #if _mem_pr_sonproc_prpsinfo 357 pe->proc = pr->pr_sonproc; 358 #endif 359 #if _mem_pr_refcount_prpsinfo 360 pe->refcount = pr->pr_refcount; 361 #endif 362 #if _mem_pr_rssize_prpsinfo 363 pe->rss = pr->pr_rssize; 364 #endif 365 pe->size = pr->pr_size; 366 pe->start = PR_START(pr); 367 pe->time = PR_TIME(pr); 368 pe->wchan = (void*)pr->pr_wchan; 369 return 1; 370 } 371 372 static Pssmeth_t procfs_method = 373 { 374 "/proc", 375 "[-version?@(#)$Id: pss /proc (AT&T Research) 2011-12-13 $\n]" 376 "[-author?Glenn Fowler <gsf@research.att.com>]", 377 PSS_all, 378 procfs_init, 379 procfs_read, 380 procfs_part, 381 procfs_full, 382 0, 383 0, 384 0, 385 procfs_done 386 }; 387 388 Pssmeth_t* _pss_method = &procfs_method; 389 390 #endif 391