#include #include #include #include #include /* * P S : Like the UN*X command of the same name, this reports on * running processes in the system. The current version only * reports CLI processes, so you don't see the filesystem * tasks. Written because I got tired of seeing the question * marks that status spits out at every opportunity. * This will build OK with 16 bit integers. * * Usage: ps [-f] * * Author: Dewi Williams ..!ihnp4!druca!dewi * Status: Public domain. */ /* Defines */ /* Change typeless BCPL BPTR to typed C (for struct pointers). Don't * use this define on an APTR, that's only a badly disguised void *. */ #define BPTR_TO_C(strtag, var) ((struct strtag *)(BADDR( (ULONG) var))) /* Use AmigaDOS i/o to keep executable size down */ #define WSTR(s) (void)Write(OutLock, s, (long)strlen(s)) #define WCHR(s) (void)Write(OutLock, s, 1L) /* char w/ d. quotes */ #define TO_ASC(n) ((n) + '0') /* make it printable! */ /* Casting conveniences */ #define PROC(task) ((struct Process *)task) #define ROOTNODE ((struct RootNode *)DOSBase->dl_Root) #define CLI(proc) (BPTR_TO_C(CommandLineInterface, proc->pr_CLI)) /* Externs */ extern struct DosLibrary *DOSBase; /* dos library base pointer */ extern struct FileLock *Output(); /* get output file handle */ /* Globals */ static struct FileLock *OutLock; /* used by WSTR define */ static int fullopt = 0; /* set by -f command line flag */ main(argc, argv) int argc; char **argv; { register ULONG *tt; /* References TaskArray */ register int count; /* loop variable */ register UBYTE *port; /* msgport & ptr arith */ register struct Task *task; /* EXEC descriptor */ char strbuf[256]; /* scratch for btocstr() */ char *btocstr(); /* BCPL BSTR to ASCIIZ */ void disp_hdr(); /* display ps header */ void display(); /* display data for one process */ OutLock = Output(); /* initialize output handle */ if (argc > 1 && strcmp(argv[1], "-f") == 0) fullopt = 1; tt = (unsigned long *)(BADDR(ROOTNODE->rn_TaskArray)); if (fullopt) disp_hdr(); Forbid(); /* need linked list consistency */ /* Loop through the data for the CLI processes. */ for (count = 1; count <= (int)tt[0] ; count++) {/* or just assume 20?*/ if (tt[count] == 0) continue; /* nobody home */ /* Start by pulling out MsgPort addresses from the TaskArray * area. By making unwarranted assumptions about the layout * of Process and Task structures, we can derive these * descriptors. Every task has an associated process, since * this loop drives off a CLI data area. */ port = (UBYTE *)tt[count]; task = (struct Task *)(port - sizeof(struct Task)); /* Sanity check just in case */ if (PROC(task)->pr_TaskNum == 0 || PROC(task)->pr_CLI == NULL) continue; /* or complain? */ /* Pass the C string version of the command name to * the display routine. */ display(count, task->tc_Node.ln_Name, btocstr(CLI(PROC(task))->cli_CommandName, strbuf), task->tc_Node.ln_Pri); } Permit(); /* outside critical region */ exit(0); } /* * Convert a BCPL string to a C string. To avoid scrogging in-memory * stuff, it copies it first. Your data area better be big enough! */ char * btocstr(b, buf) ULONG b; char *buf; { register char *s; s = (char *)BADDR(b); /* Shift & get length-prefixed str */ (void)movmem(s +1, buf, s[0]); /* a.k.a memcpy */ buf[s[0]] = '\0'; return buf; } /* * Display the header for the output. */ void disp_hdr() { WSTR("Process # CLI Type Command Name Priority\n"); } /* * Display the information for a particular CLI process. Keep the format * string in sync with that of disp_hdr(). */ void display(tnum, type, name, pri) int tnum; /* CLI process number */ char *type; /* Initial, Background or New CLI */ char *name; /* Command name if CLI's running one */ int pri; /* priority of CLI & command */ { char *psitoa(); char buf[80]; char *ext_len(); register char *p = buf; if (*name == '\0') name = ""; /* Null, nothing loaded */ if (fullopt) { p = ext_len(psitoa(tnum, p), 11); strcpy(p, type); p = ext_len(p, 17); strcpy(p, name); p = ext_len(p, 21); (void)psitoa(pri, p); } else { p = ext_len(psitoa(tnum, p), 2); *p++ = ':'; *p++ = ' '; strcpy(p, name); } WSTR(buf); WCHR("\n"); } /* * Everything after here is a hack to avoid dragging in printf. * ------------------------------------------------------------ */ /* * Limited itoa style function. Don't use it anywhere else! Used to keep * things small & avoid printf. Has a very limited range (3 digits +/- sign). * This hack avoids having to do the recursion & reverse of K&R itoa. */ char * psitoa(num, into) int num; /* number to convert */ char *into; /* write it into here */ { register char *p = into; if (num < 0) { *p++ = '-'; num = -num; } if (num > 99) { *p++ = TO_ASC(num/100); *p++ = TO_ASC((num%100)/10); *p++ = TO_ASC(num%10); } else if (num > 9) { *p++ = TO_ASC(num/10); *p++ = TO_ASC(num%10); } else *p++ = TO_ASC(num); *p = '\0'; /* end of the string */ return into; } /* * Extend to length. Assumes strlen(s) never greater than len. */ char * ext_len(s, len) char *s; /* must be large enough for extension to len */ int len; { register int leftover; register int slen = strlen(s); register char *p = s + slen; for(leftover = len - slen; leftover > 0; leftover--) *p++ = ' '; *p = '\0'; /* null terminate */ return p; /* return loc after string */ }