|
|
1.1 root 1: #include <stdio.h>
2: #include <string.h>
3: #include <sys/coherent.h>
4: #include <sys/coh_ps.h>
5: #include <fcntl.h>
6: #include <sys/types.h>
7: #include <sys/stat.h>
8: #include <dirent.h>
9: #include <pwd.h>
10: #include "ps.h"
11:
12: #define PROC_NUM 64 /* Number of processes */
13: #define CON_SIZE 8 /* max # of bytes in contrl terminal filed */
14:
15: extern char *malloc();
16: void vGetData(); /* Read the data about all processes */
17: void vCvtArgs(); /* Process command line */
18: void vPrintPs(); /* Print data */
19: void vPrintHeader(); /* Print ps header */
20: void vPrintLine(); /* Print ps data */
21: dev_t dvtGetTerminal();/* Get ps controlling terminal */
22: int iState(); /* Is the process asleep, running, or zombie? */
23: void ReadDevDir(); /* Read device directory */
24: unsigned uOkToPrint(); /* Is the process one we want to display? */
25:
26: stMonitor *pMonData = NULL; /* Pointer to an array of data for ps */
27: int iRet; /* Number of bytes read */
28: dev_t dvtPs; /* ps device */
29:
30: #define MAXPROCESSES 40 /* # max number of precesses */
31:
32: unsigned auProcessP[MAXPROCESSES]; /* List of process to print */
33: int iNumProcessP = 0; /* Number of process to print */
34:
35: static stDevices *pstDevFirst= NULL; /* List of character devices. */
36:
37: /* Flags for input command options */
38: int iaFlag, /* Display information from all terminals */
39: idFlag, /* Status of loadable drivers */
40: ifFlag, /* Blank fields have '-' */
41: igFlag, /* Print group leader if l given */
42: ilFlag, /* Long format */
43: imFlag, /* Scheduling fields */
44: inFlag, /* Suppress header line */
45: ipFlag, /* Print only specified processes */
46: irFlag, /* Print real size of processes */
47: itFlag, /* Print elapsed CPU time */
48: iwFlag, /* Wide format (print 132 columns) */
49: ixFlag; /* Display processes without controlling terminals */
50:
51: /*
52: * Print out process status.
53: */
54: main(argc, argv)
55: int argc;
56: char *argv[];
57: {
58: /*
59: * To preserve compatibility with older versions of COHERENT ps
60: * we will fake minus here. Be aware that it adds '-' not only to
61: * the command line options but to their arguments as well ;-(
62: * See 'p' case.
63: */
64: fakeMinus(argc, argv);
65: /*
66: * Digest the command line.
67: *
68: * This routine will not return if there are errors in
69: * the command line.
70: */
71: vCvtArgs(argc, argv);
72:
73: /* This function will not return if error occurs */
74: vGetData();
75:
76: /* Get dev_t value for device from which ps was fired */
77: dvtPs = dvtGetTerminal();
78:
79: /* We have our data and all flags are set. So, we can print it */
80: vPrintPs();
81: }
82:
83: /*
84: * Fetch all data for ps from the kernel.
85: */
86: void vGetData()
87: {
88: int fd; /* File descriptor to /dev/ps*/
89: int iCnt; /* number of attempt to read */
90:
91: /* Open process device */
92: if ((fd = open("/dev/ps", O_RDONLY)) < 0) {
93: fflush(stdout);
94: perror("ps: cannot open /dev/ps");
95: exit(1);
96: }
97:
98: /* This is our main engine. At this point we do not know the
99: * total number of processes. So, we start from our gess PROC_NUM.
100: * If we get close enough, do realloc and try again.
101: */
102: for (iCnt = 0, iRet = 0; iCnt - iRet <= sizeof(stMonitor); ) {
103: iCnt += sizeof(stMonitor) * PROC_NUM;
104: if (pMonData != NULL)
105: free(pMonData);
106: if ((pMonData = (stMonitor *) malloc(iCnt)) == NULL) {
107: fflush(stdout);
108: perror("ps");
109: exit(1);
110: }
111: if ((iRet = read(fd, (char *) pMonData, iCnt)) < 0) {
112: fflush(stdout);
113: perror("ps");
114: exit(1);
115: }
116: }
117:
118: close(fd);
119: fflush(stdout);
120:
121: } /* main() */
122:
123: /*
124: * Digest the command line.
125: */
126: void
127: vCvtArgs(argc, argv)
128: int argc;
129: char *argv[];
130: {
131: char *opstring = "ac:defgk:lmnp:rtwx";
132: extern char *optarg;
133: int c;
134: char *token;
135:
136: while ((c = getopt(argc, argv, opstring)) != EOF)
137: switch (c) {
138: case 'a':
139: case 'e':
140: iaFlag = 1;
141: break;
142: case 'c': /* We will just ignore it */
143: break;
144: case 'd':
145: idFlag = 1;
146: break;
147: case 'f':
148: ifFlag = 1;
149: break;
150: case 'g':
151: igFlag = 1;
152: break;
153: case 'k': /* We will just ignore it */
154: break;
155: case 'l':
156: ilFlag = 1;
157: break;
158: case 'm':
159: imFlag = 1;
160: break;
161: case 'n':
162: inFlag = 1;
163: break;
164: case 'p':
165: ipFlag = iaFlag = 1;
166:
167: /* Take out the '-' that fakeMinus puts in */
168: while (*optarg == '-')
169: optarg++;
170:
171: token = strtok(optarg, ",");
172: while((token != NULL) && (iNumProcessP < MAXPROCESSES))
173: {
174: auProcessP[iNumProcessP++] = atoi(token);
175: token = strtok(NULL, ",");
176: }
177: if (iNumProcessP == 0)
178: ipFlag = 0;
179: break;
180: case 'r':
181: irFlag = 1;
182: break;
183: case 't':
184: itFlag = 1;
185: break;
186: case 'w':
187: iwFlag = 1;
188: break;
189: case 'x':
190: ixFlag = 1;
191: break;
192: default:
193: usage(c);
194: }
195: if (ilFlag && igFlag)
196: igFlag = 1;
197: else
198: igFlag = 0;
199: } /* cvt_args() */
200:
201: void vPrintPs()
202: {
203: register stMonitor *pMonTmp;
204:
205: /* Read device directory only once */
206: ReadDevDir(); /* We may not return from ReadDevDir */
207:
208: /* Print the header line */
209: vPrintHeader();
210:
211: for (pMonTmp = pMonData + iRet / sizeof(stMonitor) - 1;
212: pMonTmp >= pMonData; pMonTmp--) {
213: if (uOkToPrint(pMonTmp->p_pid))
214: vPrintLine(pMonTmp);
215: }
216: }
217:
218: void vPrintHeader()
219: {
220: /* If header suppressed */
221: if (inFlag)
222: return;
223: /* Now we can print */
224: printf("%-8s%5s", "TTY", "PID");
225: if (igFlag)
226: printf(" %5s", "GROUP");
227: if (ilFlag)
228: printf(" %5s%9s%5s%5s%2s%9s",
229: "PPID", "UID", "K", "F", "S", "EVENT");
230: #if 0
231: if (imFlag)
232: printf(" %8s %8s %8s %8s", "CVAL", "SVAL", "IVAL", "RVAL");
233: #endif
234: if (itFlag)
235: printf(" UTIME STIME");
236: puts(" COMMAND");
237: }
238:
239: /*
240: * Print next line.
241: */
242: void vPrintLine(pMonLine)
243: stMonitor *pMonLine;
244: {
245: char *cpFindTerminal();
246: char *cpTty;
247:
248: /* Check controling terminal */
249: if (major(pMonLine->p_ttdev) == 0) {
250: if (minor(pMonLine->p_ttdev) == 0)
251: cpTty = "null";
252: } else {
253: if (major(pMonLine->p_ttdev) == 0x0FF) {
254: if (minor(pMonLine->p_ttdev) == 255) {
255: cpTty = "-------";
256: }
257: } else {
258: if ((cpTty=cpFindTerminal(pMonLine->p_ttdev)) == NULL)
259: cpTty = "?";
260: }
261: }
262:
263: /* Do we have to skip this line? */
264: if (!iaFlag && (dvtPs != pMonLine->p_ttdev)) {
265: if (!ixFlag || strcmp("-------", cpTty))
266: return;
267: } else
268: if (!ixFlag && !strcmp("-------", cpTty))
269: return;
270: printf("%-8s%5u", cpTty, pMonLine->p_pid);
271:
272: if (igFlag)
273: printf(" %5d", pMonLine->p_rgid);
274:
275: if (ilFlag) {
276: int c;
277: struct passwd *pstPasswd;
278:
279: if ((pstPasswd = getpwuid(pMonLine->p_uid)) == NULL) {
280: fflush(stdout);
281: perror("\nps: cannot get user name");
282: exit(1);
283: }
284: printf("%6d%9s", pMonLine->p_ppid, pstPasswd->pw_name);
285: if (irFlag)
286: printf("%5d", pMonLine->rsize);
287: else
288: printf("%5d", pMonLine->size);
289: printf("%5o", pMonLine->p_flags);
290: c = iState(pMonLine);
291: printf(" %c", c);
292: if (c == 'S') {
293: if (pMonLine->u_sleep[0] != '\0')
294: printf("%9s", pMonLine->u_sleep);
295: else
296: printf("%9x", pMonLine->p_event);
297: } else
298: if (ifFlag)
299: printf(" -");
300: else
301: printf(" ");
302:
303: }
304:
305: /* Scheduling fields */
306: #if 0
307: if (imFlag)
308: printf(" %8x %8x %8x %8x", pMonLine->p_cval,
309: pMonLine->p_sval,
310: pMonLine->p_ival,
311: pMonLine->p_rval);
312: #endif
313: if (itFlag) {
314: ptime(pMonLine->p_utime);
315: ptime(pMonLine->p_stime);
316: }
317:
318: printf(" %.*s\n", U_COMM_LEN, pMonLine->u_comm);
319: }
320:
321: /*
322: * Given a time in HZ, print it out.
323: */
324: ptime(l)
325: long l;
326: {
327: register unsigned m;
328:
329: if ((l=(l+HZ/2)/HZ) == 0) {
330: if (ifFlag)
331: printf(" -");
332: else
333: printf(" ");
334: return;
335: }
336: if ((m=l/60) >= 100) {
337: printf("%6d", m);
338: return;
339: }
340: printf(" %2d:%02d", m, (unsigned)l%60);
341: }
342:
343: /*
344: * Find status of a proces. If sleep, reason why.
345: */
346: int iState(pMon)
347: stMonitor *pMon;
348: {
349:
350: if (ASLEEP(pMon)) {
351: if (pMon->rrun)
352: return 'S';
353: if ((pMon->p_flags & PFSTOP) != 0)
354: return 'T';
355: if (pMon->p_state == PSSLEEP)
356: return 'W';
357: else
358: return 'w';
359: }
360:
361: if (pMon->p_state == PSRUN)
362: return 'R';
363: if (pMon->p_state == PSDEAD)
364: return 'Z';
365: return '?';
366: }
367:
368: /*
369: * Find a device. Return device name or NULL if device was not found.
370: */
371: char *cpFindTerminal(dev)
372: dev_t dev;
373: {
374: register stDevices *pstDev;
375:
376: /* Find a proper device */
377: for (pstDev = pstDevFirst; pstDev != NULL; pstDev = pstDev->next) {
378: if (dev == pstDev->dev) {
379: return pstDev->pDevName;
380: }
381: }
382: /* Device not found */
383: return NULL;
384: }
385:
386: /*
387: * Read device directory and store data in memory.
388: * This function will not return if it cannot open /dev or run
389: * out of memory.
390: */
391: void ReadDevDir()
392: {
393: register DIR *pDir;
394: register stDevices *pstDevNext;
395: static stDevices *pstDevPrev;
396: register struct dirent *pDrnt;
397: struct stat stStat;
398: char pFileName[32]; /* File name buffer */
399:
400: if ((pDir = opendir( "/dev" )) == NULL) {
401: fflush(stdout);
402: perror("ps");
403: exit(1);
404: }
405:
406: while ( (pDrnt = readdir( pDir )) != NULL ) {
407: sprintf(pFileName, "/dev/%.*s", DIRSIZ, pDrnt->d_name);
408: /* We may skip silent the file that we cannot stat.
409: */
410: if (stat(pFileName, &stStat) < 0)
411: continue;
412: if ((stStat.st_mode & S_IFMT) != S_IFCHR)
413: continue;
414:
415: if ((pstDevNext = malloc(sizeof(struct DEVICES))) == NULL) {
416: fflush(stdout);
417: perror("ps");
418: exit(1);
419: }
420: if (pstDevFirst == NULL)
421: pstDevFirst = pstDevPrev = pstDevNext;
422: else
423: pstDevPrev->next = pstDevNext;
424:
425: pstDevNext->dev = stStat.st_rdev;
426: strncpy(pstDevNext->pDevName, pDrnt->d_name, DIRSIZ);
427: pstDevNext->next = NULL;
428: pstDevPrev = pstDevNext;
429: }
430: closedir(pDir);
431: }
432:
433: /*
434: * Get dev_t value for ps controlling terminal.
435: * Return 0 is a flag was set or controlling terminal was not found.
436: */
437: dev_t dvtGetTerminal()
438: {
439: register stMonitor *pMonTmp;
440: register int iPid; /* Our process id */
441:
442: if (iaFlag)
443: return 0;
444:
445: iPid = getpid();
446:
447: /* Go through all data until ps id will be found */
448: for (pMonTmp = pMonData + iRet / sizeof(stMonitor) - 1;
449: pMonTmp >= pMonData; pMonTmp--)
450: if (pMonTmp->p_pid == iPid)
451: return pMonTmp->p_ttdev;
452:
453: return 0;
454: }
455:
456: /*
457: * Return 1 if ipFlag is not set or ipFlag is set and process is specified,
458: * 0 otherwise.
459: */
460: unsigned uOkToPrint(pnum)
461: unsigned pnum;
462: {
463: int i;
464:
465: if (!ipFlag)
466: return 1;
467:
468: for (i = 0; i < iNumProcessP; i++)
469: if (auProcessP[i] == pnum)
470: return 1;
471: return 0;
472: }
473:
474: usage()
475: {
476: printf("usage: ps [-][aefglmnrtwx][p#[,#]...]\n");
477: exit(1);
478: }
479:
480: fakeMinus(argc, argv)
481: int argc;
482: char * argv[];
483: {
484: int argn;
485: char * malloc();
486:
487: for (argn = 1; argn < argc; argn++) {
488: if (argv[argn][0] && argv[argn][0] != '-') {
489: char * temp = malloc(strlen(argv[argn])+2);
490: temp[0] = '-';
491: strcpy(temp+1, argv[argn]);
492: argv[argn] = temp;
493: }
494: }
495: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.