diff --git a/libproc/Makefile b/libproc/Makefile deleted file mode 100644 index 6d72070b..00000000 --- a/libproc/Makefile +++ /dev/null @@ -1,111 +0,0 @@ -# Auto-adaptive C library Makefile adapted for libproc, Chuck Blake. -# Assumptions are basically that all the .c files in the CWD are modules -# for the library and that all .h files are the interface to the library. - -# PROJECT SPECIFIC MACROS -NAME = proc - -# INSTALLATION OPTIONS -TOPDIR = /usr -HDRDIR = $(TOPDIR)/include/$(NAME)# where to put .h files -LIBDIR = $(TOPDIR)/lib# where to put library files -SHLIBDIR = /lib# where to put shared library files -HDROWN = -o root -g root # owner of header files -LIBOWN = -o root -g root # owner of library files -INSTALL = install - -# COMPILATION OPTIONS -CC = gcc -O2 -D_GNU_SOURCE #-ggdb # easy to command-line override -CFLAGS = -I.. -Wall - -# ----------------------------------------------------------------# -# The rest is the auto-magic section -- highly GNU make dependent # -# You should never need to edit this. # -# ----------------------------------------------------------------# - -VC_SUF = ,v -VC_PFX = RCS/ -RCSFILES = $(patsubst $(VC_PFX)%$(VC_SUF),%,$(wildcard $(VC_PFX)*$(VC_SUF))) - -# We take the union of RCS files and other files in CWD so that new files do -# not need to alter this makefile. 'sort' removes duplicates. This allows the -# convenience of compiling and testing new files before the initial check-in. - -SRC = $(sort $(wildcard *.c) $(filter %.c,$(RCSFILES))) -HDR = $(sort $(wildcard *.h) $(filter %.h,$(RCSFILES))) - -OBJ = $(SRC:.c=.o) -SONAME = lib$(NAME).so.$(LIBVERSION) - -ifeq ($(SHARED),1) -CFLAGS += -fpic -all: lib$(NAME).a $(SONAME) -else -all: lib$(NAME).a -endif - -lib$(NAME).a: $(OBJ) - $(AR) rcs $@ $^ - -$(SONAME): $(OBJ) - gcc -Wl,-shared -Wl,-soname,$(SONAME) -o $@ $^ -lc - ln -sf $(SONAME) lib$(NAME).so - -# AUTOMATIC DEPENDENCY GENERATION -- GCC AND GNUMAKE DEPENDENT - -.depend: - $(strip $(CC) $(CFLAGS) -MM -MG $(SRC) > .depend) -include .depend - -# INSTALLATION - -install: all - if ! [ -d $(HDRDIR) ] ; then mkdir $(HDRDIR) ; fi - $(INSTALL) $(HDROWN) $(HDR) $(TOPDIR)/include/$(NAME) - $(INSTALL) $(LIBOWN) lib$(NAME).a $(LIBDIR) -ifeq ($(SHARED),1) - $(INSTALL) $(LIBOWN) $(SONAME) $(SHLIBDIR) - ln -sf $(SHLIBDIR)/$(SONAME) $(SHLIBDIR)/lib$(NAME).so - ldconfig -endif - -# VARIOUS SHORT CUT TARGETS -.PHONY: all install dep clean distclean checkout checkclean - -dep: .depend - -clean: - $(RM) lib$(NAME).* *.o - -distclean: clean - $(RM) .depend signames.h - -checkout: - $(CO) $(RCSFILES) - -checkclean: - $(RM) $(RCSFILES) - -# CUSTOM c -> o rule so that command-line has minimal whitespace - -%.o : %.c - $(strip $(CC) $(CFLAGS) -c $<) - -# PROJECT SPECIFIC DEPENDENCIES/BUILD RULES - - -version.o: version.c version.h -ifdef MINORVERSION - $(strip $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -DSUBVERSION=\"$(SUBVERSION)\" -DMINORVERSION=\"$(MINORVERSION)\" -c version.c) -else - $(strip $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -DSUBVERSION=\"$(SUBVERSION)\" -c version.c) -endif - -signals.o : signames.h - -signames.h ../proc/signames.h : /usr/include/signal.h - /lib/cpp -dM signames.h - diff --git a/libproc/alloc.c b/libproc/alloc.c deleted file mode 100644 index 92fba2c5..00000000 --- a/libproc/alloc.c +++ /dev/null @@ -1,49 +0,0 @@ -/***********************************************************************\ -* Copyright (C) 1992 by Michael K. Johnson, johnsonm@sunsite.unc.edu * -* * -* This file is placed under the conditions of the GNU public * -* license, version 2, or any later version. See file COPYING * -* for information on distribution conditions. * -\***********************************************************************/ -#include -#include - -void *xcalloc(void *pointer, int size) { - void * ret; - if (pointer) - free(pointer); - if (!(ret = calloc(1, size))) { - fprintf(stderr, "xcalloc: allocation error, size = %d\n", size); - exit(1); - } else { - return ret; - } -} - -void *xmalloc(unsigned int size) { - void *p; - - if (size == 0) - ++size; - p = malloc(size); - if (!p) { - fprintf(stderr, "xmalloc: malloc(%d) failed", size); - perror(NULL); - exit(1); - } - return(p); -} - -void *xrealloc(void *oldp, unsigned int size) { - void *p; - - if (size == 0) - ++size; - p = realloc(oldp, size); - if (!p) { - fprintf(stderr, "xrealloc: realloc(%d) failed", size); - perror(NULL); - exit(1); - } - return(p); -} diff --git a/libproc/compare.c b/libproc/compare.c deleted file mode 100644 index 4049077e..00000000 --- a/libproc/compare.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * - * Copyright 1994 Charles Blake and Michael K. Johnson - * This file is a part of procps, which is distributable - * under the conditions of the GNU Public License. See the - * file COPYING for details. - * - */ - -#include /* for strcmp */ -#include /* for parse error output */ -#include "readproc.h" /* for proc_t */ -#include "tree.h" /* for struct tree_node */ - -/* - This module was written by Charles Blake for procps. - -mult_lvl_cmp: - slick general purpose multi-level compare function I invented. -sort_depth: - the number of levels of functions *to use*. This means many more levels - can be defined than mult_lvl_cmp tres out. If this is 1 then mult_lvl_cmp - is just a trivial wrapper around (*sort_function[0]). -sort_direction: - multiplicative factor for the output of cmp_whatever. - 1 ==> default order, -1 ==> reverse order, 0 ==> forced equality - The 0 bit is the neat part. Since a value of zero is the code for equality - multiplying the output of cmp_foo(a,b) forces a==b to be true. This is a - convenient way to turn sorting off in middle levels of a multi-level sort. - If time is a problem, reforming the whole sort_function array to not include - these unsorted middle levels will be faster since then cmp_foo won't even - be called. It might simplify some code depending upon how you organize it. -sort_function[]: - array of function pointers that points to our family of comparison functions - (I have named them cmp_* but mult_lvl_cmp doesn't care what they're named). - This may be declared and initialized like so: - int (*sort_function[])(void* a, void* b)={&cmp_foo, &cmp_bar, &cmp_hiho}; - You could also use my command line '-O' parser below. - -Note that we only descend levels until the order is determined. If we descend -all levels, that means that the items are equal at all levels, so we return 0. -Otherwise we return whatever the level's cmp_foo function would have returned. -This allows whatever default behavior you want for cmp_foo. sort_direction[] -reverses this default behavior, but mult_lvl_cmp doesn't decide that ascending -or descending is the default. That is the job of your cmp_foo's. -*/ - -/* the only reason these are global is because qsort(3) likes it that way. - It's also a little more efficient if mult_lvl_cmp() is called many times. -*/ - -typedef int (*cmp_t)(void*,void*); /* for function pointer casts */ - -int sort_depth = 0; -int sort_direction[10]; /* storage for 10 levels, but 4 would be plenty!*/ -int (*sort_function[10])(void* a, void* b); - -int mult_lvl_cmp(void* a, void* b) { - int i, cmp_val; - for(i = 0; i < sort_depth; i++) { - cmp_val = sort_direction[i] * (*sort_function[i])(a,b); - if (cmp_val != 0) - return cmp_val; - } - return 0; -} - -int node_mult_lvl_cmp(void* a, void* b) { - int i, cmp_val; - for(i = 0; i < sort_depth; i++) { - cmp_val = sort_direction[i] * (*sort_function[i])(&(((struct tree_node *)a)->proc),&(((struct tree_node *)b)->proc)); - if (cmp_val != 0) - return cmp_val; - } - return 0; -} - -/* qsort(3) compliant comparison functions for all members of the ps_proc - structure (in the same order in which they appear in the proc_t declaration) - return is {-1,0,1} as {ab} - default ordering is ascending for all members. (flip 1,-1 to reverse) -*/ -/* pre-processor macros to cut down on source size (and typing!) - Note the use of the string concatenation operator ## -*/ -#define CMP_STR(NAME) \ -int cmp_ ## NAME(proc_t** P, proc_t** Q) { \ - return strcmp((*P)-> ## NAME, (*Q)-> ## NAME); \ -} - -#define CMP_INT(NAME) \ -int cmp_ ## NAME (proc_t** P, proc_t** Q) { \ - if ((*P)-> ## NAME < (*Q)-> ## NAME) return -1; \ - if ((*P)-> ## NAME > (*Q)-> ## NAME) return 1; \ - return 0; \ -} - -/* Define the (46!) cmp_ functions with the above macros for every element - of proc_t. If the binary gets too big, we could nuke inessentials. -*/ - -/* CMP_STR(cmdline) */ -CMP_STR(user) -CMP_STR(cmd) -/* CMP_INT(state) */ -/* CMP_STR(ttyc) */ -CMP_INT(uid) -CMP_INT(pid) -CMP_INT(ppid) -CMP_INT(pgrp) -CMP_INT(session) -CMP_INT(tty) -CMP_INT(tpgid) -CMP_INT(utime) -CMP_INT(stime) -CMP_INT(cutime) -CMP_INT(cstime) -/* CMP_INT(priority) */ -CMP_INT(nice) -CMP_INT(start_time) -/* CMP_INT(signal) */ -/* CMP_INT(blocked) */ -/* CMP_INT(sigignore) */ -/* CMP_INT(sigcatch) */ -CMP_INT(flags) -CMP_INT(min_flt) -CMP_INT(cmin_flt) -CMP_INT(maj_flt) -CMP_INT(cmaj_flt) -/* CMP_INT(timeout) */ -CMP_INT(vsize) -CMP_INT(rss) -/* CMP_INT(rss_rlim) */ -/* CMP_INT(start_code) */ -/* CMP_INT(end_code) */ -/* CMP_INT(start_stack) */ -/* CMP_INT(kstk_esp) */ -/* CMP_INT(kstk_eip) */ -/* CMP_INT(wchan) */ -CMP_INT(pcpu) -CMP_INT(size) -CMP_INT(resident) -CMP_INT(share) -/* CMP_INT(trs) */ -/* CMP_INT(lrs) */ -/* CMP_INT(drs) */ -/* CMP_INT(dt) */ - -/* define user interface to sort keys. Fairly self-explanatory. */ - -struct cmp_fun_struct { - char letter; /* single option-letter for key */ - char name[15]; /* long option name for key */ - int (*fun)(proc_t**, proc_t**); /* pointer to cmp_key */ -} cmp[] = { -/* { '?', "cmdline", &cmp_cmdline }, */ - { 'u', "user", &cmp_user }, - { 'c', "cmd", &cmp_cmd }, -/* { '?', "state", &cmp_state }, */ -/* { '?', "ttyc", &cmp_ttyc }, */ - { 'U', "uid", &cmp_uid }, - { 'p', "pid", &cmp_pid }, - { 'P', "ppid", &cmp_ppid }, - { 'g', "pgrp", &cmp_pgrp }, - { 'o', "session", &cmp_session }, - { 't', "tty", &cmp_tty }, - { 'G', "tpgid", &cmp_tpgid }, - { 'k', "utime", &cmp_utime }, - { 'K', "stime", &cmp_stime }, - { 'j', "cutime", &cmp_cutime }, - { 'J', "cstime", &cmp_cstime }, -/* { '?', "counter", &cmp_counter }, */ - { 'y', "priority", &cmp_nice }, - { 'T', "start_time", &cmp_start_time }, -/* { '?', "signal", &cmp_signal }, */ -/* { '?', "blocked", &cmp_blocked }, */ -/* { '?', "sigignore", &cmp_sigignore }, */ -/* { '?', "sigcatch", &cmp_sigcatch }, */ - { 'f', "flags", &cmp_flags }, - { 'm', "min_flt", &cmp_min_flt }, - { 'n', "cmin_flt", &cmp_cmin_flt }, - { 'M', "maj_flt", &cmp_maj_flt }, - { 'N', "cmaj_flt", &cmp_cmaj_flt }, -/* { 'C', "timeout", &cmp_timeout }, */ - { 'v', "vsize", &cmp_vsize }, - { 'r', "rss", &cmp_rss }, -/* { '?', "rss_rlim", &cmp_rss_rlim }, */ -/* { '?', "start_code", &cmp_start_code }, */ -/* { '?', "end_code", &cmp_end_code }, */ -/* { '?', "start_stack", &cmp_start_stack }, */ -/* { '?', "kstk_esp", &cmp_kstk_esp }, */ -/* { '?', "kstk_eip", &cmp_kstk_eip }, */ -/* { '?', "wchan", &cmp_wchan }, */ - { 'C', "pcpu", &cmp_pcpu }, - { 's', "size", &cmp_size }, - { 'R', "resident", &cmp_resident }, - { 'S', "share", &cmp_share }, -/* { '?', "trs", &cmp_trs }, */ -/* { '?', "lrs", &cmp_lrs }, */ -/* { '?', "drs", &cmp_drs }, */ -/* { '?', "dt", &cmp_dt }, */ - { '\0',"terminator", NULL } -}; - -void dump_keys(void) { - int i; - for(i=0; cmp[i].letter; i++) - fprintf(stderr, "%s-O%c , --sort:%-15.15s%s", - i%2?"":" ", - cmp[i].letter, cmp[i].name, - i%2?"\n":""); - if (i%2) - fprintf(stderr, "\n"); -} - -/* command line option parsing. Assign sort_{depth,direction[],function[]} - based upon a string of the form: - [+-]a[+-]b[+-]c... - with a,b,c,... being letter flags corresponding to a particular sort - key and the optional '-' specifying a reverse sort on that key. + doesn't - mean anything, but it keeps things looking balanced... -*/ -int parse_sort_opt(char* opt) { - int i, next_dir=1; - for(; *opt ; ++opt) { - if (*opt == '-' || *opt == '+') { - if (*opt == '-') - next_dir = -1; - opt++; - continue; - } - for (i = 0; cmp[i].letter; i++) - if (*opt == cmp[i].letter) - break; - if (!cmp[i].letter) { - fprintf(stderr, - "ps: no such sort key -- %c. Possibilities are:\n", *opt); - dump_keys(); - return -1; - } else { -#ifdef DEBUG - fprintf(stderr, - "sort level %d: key %s, direction % d\n", - sort_depth, cmp[i].name, next_dir); -#endif - sort_function[sort_depth] = (cmp_t)cmp[i].fun; - sort_direction[sort_depth++] = next_dir; - next_dir = 1; - } - } - return 0; -} - -int parse_long_sort(char* opt) { - char* comma; - int i, more_keys, next_dir=1; - do { - if (*opt == '-' || *opt == '+') { - if (*opt == '-') - next_dir = -1; - more_keys = 1; - opt++; - continue; - } - more_keys = ((comma=index(opt,',')) != NULL); - /* keys are ',' delimited */ - if (more_keys) - *comma='\0'; /* terminate for strcmp() */ - for(i = 0; cmp[i].letter; ++i) - if (strcmp(opt, cmp[i].name) == 0) - break; - if (!cmp[i].letter) { - fprintf(stderr, - "ps: no such sort key -- %s. Possibilities are:\n", opt); - dump_keys(); - return -1; - } else { -#ifdef DEBUG - fprintf(stderr, - "sort level %d: key %s, direction % d\n", - sort_depth, cmp[i].name, next_dir); -#endif - sort_function[sort_depth] = (cmp_t)cmp[i].fun; - sort_direction[sort_depth++] = next_dir; - next_dir = 1; - } - opt = comma + 1; /* do next loop on next key, if more keys, else done*/ - } while (more_keys); - return 0; -} - -void reset_sort_options (void) -{ - int i; - - sort_depth=0; - for (i=0;i<10;i++){ - sort_direction[i]=0; - sort_function[i]=(cmp_t)NULL; - } -} - -void register_sort_function (int dir, cmp_t func) -{ - sort_function[sort_depth] = func; - sort_direction[sort_depth++] = dir; -} diff --git a/libproc/devname.c b/libproc/devname.c deleted file mode 100644 index f81af2dc..00000000 --- a/libproc/devname.c +++ /dev/null @@ -1,269 +0,0 @@ -/* device name <-> number map system optimized for rapid, constant time lookup. - Copyright Charles Blake, 1996, see COPYING for details. -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __KERNEL__ -#include -#undef __KERNEL__ - -#define DEVDIR "/dev" -#define DEVTAB "psdevtab" -static char *devtab_paths[] = { - "/etc/" DEVTAB, - "%s/." DEVTAB, - NULL -}; -#define DEVINITIALMODE 0664 -#define DEV_MAX_PATH (5+256) -#define DEV_NAME_MAX 8 - -static dev_t major[] = { 2, 3, 4, 5, 19, 20, 22, 23, 24, 25, 32, 33, - 46, 47, 48, 49 }; -#define Nminor 256 -#define Nmajor (sizeof(major)/sizeof(dev_t)) -#define Ndev (Nmajor*Nminor) -#define Ndevtab (Ndev*DEV_NAME_MAX) - -static char* devtab; /* the memory buffer holding all the name strings */ - -/* This macro evaluates to the address into the table of the string of - DEV_NAME_MAX chars for the device with major m, minor n. */ -#define TAB(m,n) (devtab + (m)*(Nminor*DEV_NAME_MAX) + (n)*DEV_NAME_MAX) - -static int devtab_initialized = 0; - -static char* name_to_path(char* name); /* forward declarations */ -static int init_devtab (void); - -/* Device Name -> Number Map - many-to-one: -1 on failed match. -*/ -dev_t name_to_dev(char* name) { - static struct stat sbuf; - return (stat(name_to_path(name), &sbuf) < 0) ? -1 : sbuf.st_rdev; -} - -/* find m in a[] assuming a is sorted into ascending order */ -/* in-line linear search placeholder until more majors warrant binary search */ -static __inline__ int lookup(dev_t m, dev_t* a, int n) { - int k; - for(k=0; k < n && a[k] != m; k++) - ; - return (k < n) ? k : -1; -} - -/* Device Number -> Name Map - one-to-many: first directory order match in DEVDIR, "" on failed match. -*/ -char* dev_to_name(dev_t num) { - static char rval[DEV_NAME_MAX+1]; - dev_t m = MAJOR(num), n = MINOR(num), tmp; - if (!devtab_initialized && !init_devtab()) - return ""; - if ((tmp = lookup(m, major, Nmajor)) == (dev_t)-1) - return ""; - strncpy(rval, TAB(tmp,n), DEV_NAME_MAX); - rval[DEV_NAME_MAX] = '\0'; - return rval; -} - -static int dev_to_devtab(int); - -static int init_devtab(void) { - static struct stat sbuf, lbuf; - static int fd; - char **fmt, path[64], *HOME = getenv("HOME") ? getenv("HOME") : ""; - for (fmt = devtab_paths; *fmt; fmt++) { - snprintf(path, sizeof path, *fmt, HOME); - lbuf.st_ino = 0; /* initialize for test later */ - if (lstat(path, &lbuf) >= 0 && S_ISLNK(lbuf.st_mode)) - /* don't follow symlinks */ - continue; - if ( (fd = open(path, O_RDONLY)) < 0 /* open DEVTAB file */ - || fstat(fd, &sbuf) < 0 /* fstat it */ - || (lbuf.st_ino && (sbuf.st_ino != lbuf.st_ino)) /* race */ - || sbuf.st_nlink > 1 /* hardlink attack */ - || sbuf.st_size != Ndevtab /* make sure it's the right size */ - || (devtab = mmap(0, Ndevtab, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t) -1 - || close(fd) == -1) - { /* could not open for read, attempt to fix/create */ - int oumsk = umask(0); - if (devtab) - munmap(devtab, Ndevtab); - if (((fd = open(path, O_RDWR|O_TRUNC|O_CREAT, DEVINITIALMODE)) == -1 && - (unlink(path), fd = open(path, O_RDWR|O_TRUNC|O_CREAT, DEVINITIALMODE)) == -1) - || !dev_to_devtab(fd)) { - close(fd); /* either both opens failed or the constructor failed */ - unlink(path); /* in case we created but could not fill a file */ - umask(oumsk); - continue; - } else { - devtab_initialized = 1; - close(fd); - umask(oumsk); - return 1; - } - } - else - return devtab_initialized = 1; - } - return devtab_initialized; -} - -/* stat every file in DEVDIR saving its basename in devtab[] if it has - a MAJOR(st_rdev) in our list of majors. return 0 on error otherwise 1. */ -static int dev_to_devtab(int fd) { - static struct stat sbuf; - int i; - dev_t m; - struct dirent* ent; - DIR* dev; - - if (!(dev = opendir(DEVDIR))) { - fprintf(stderr, "%s: %s\nCannot generate device number -> name mapping.\n", - DEVDIR, sys_errlist[errno]); - return 0; - } - if (!(devtab = malloc(Ndevtab))) { - fprintf(stderr, "%s: could not allocate memory\n", sys_errlist[errno]); - return 0; - } - memset((void*)devtab, 0, Ndevtab); - while ((ent = readdir(dev))) { /* loop over all dirents in DEVDIR */ - if (lstat(name_to_path(ent->d_name), &sbuf) < 0 - || !S_ISCHR(sbuf.st_mode)) /* only look for char special devs */ - continue; /* due to overloading of majors */ - m = MAJOR(sbuf.st_rdev); /* copy name to appropriate spot */ - if ((i = lookup(m, major, Nmajor)) != -1) - strncpy(TAB(i,MINOR(sbuf.st_rdev)), ent->d_name, DEV_NAME_MAX); - } - closedir(dev); - if (write(fd, devtab, Ndevtab) != Ndevtab) /* probably no disk space */ - return 0; - return 1; -} - -static char path[DEV_MAX_PATH]; - -static char* name_to_path(char* name) { - static char* Path; - if (!Path) { - strcpy(path, DEVDIR); /* copy DEVDIR */ - path[sizeof(DEVDIR) - 1] = '/'; /* change NUL to '/' */ - Path = path + sizeof(DEVDIR); /* put Path at start of basename */ - } - strncpy(Path, name, DEV_MAX_PATH - sizeof(DEVDIR)); - return path; -} - -#ifdef TEST_DEVNAME -int main(int argc, char** argv) { /* usage: cmd [ |] */ - dev_t tmp; - if (argc < 2) { - printf("%s: [ maj min... | name ... ]\n", argv[0]); - return 0; - } - if (argv[1][0] >= '0' && argv[1][0] <= '9') - for(argv++ ; argv[0] && argv[1] ; argv+=2) - printf("%s\n", dev_to_name(MKDEV( atoi(argv[0]), atoi(argv[1]) ))); - else - for(argv++ ; *argv ; argv++) { - tmp = name_to_dev(*argv); - printf("%d, %d\n", MAJOR(tmp), MINOR(tmp)); - } - return 0; -} -#endif -/* -Using this program on over 700 files in /dev to perform number->name resolution -took well under 300 microsecs per device number pair on a Pentium 90. It is -somewhat tough to time because once the 3 pages have been mapped in, the time is -almost zero. For things like top, this method may even be faster in the long -run. Those interested can gprof it for me. This system has the virtue of being -nearly perfectly adaptable to individual systems, self updating when /dev -changes and pretty darn fast when it hasn't. It will be slow for users without -perms to change the psdevtab file, though. So this is what I decided was -reasonable. If the process does not have perms to create or update -/etc/psdevtab and it is out of date, we try /tmp/psdevtab. If /tmp/psdevtab is -either out of date or unreadable (malicious user creates it and chmods it), -$HOME/.psdevtab is used. This secondarily allows for per-user naming of ttys, -but is really so that at most one user sees only a single delay per /dev -modification. - -To do the timings I did something like this with zsh: - a=(`ls -l *(%^@/) | awk '{print $5 $6}' | sed 's/,/ /'`); - time ./test $a - -Finally, for lack of a better file for these to be in, I have collected the -old algorithmic device number <-> device name mappings. - Let m = major device number and n = minor device number satisfy: - devno = m<<8 + n , m = devno>>8 , n = devno && 0x00FF, and let - char L[32]="pqrstuvwxyzABCDEFGHIJKLMNOPQRSTU", H[16]="01234567890abcdef"; - DEVICE NUMBERS SPECIAL FILE NAMES - OLD SYSTEM (64 pseudoterminal devices): - m=4: - n=0..63: tty + itoa_dec(n+1) - n=128..191: pty + L[(n-128)/16] + H[(n-128)%16] - n=192..255: tty + L[(n-192)/16] + H[(n-192)%16] - NEW SYSTEM (256/512 pseudoterminal devices): - m=2, n: pty + L[n/16] + H[n%16] - m=3, n: tty + L[n/16] + H[n%16] - m=4, n: tty + itoa_dec(n+1) - m=49, n: pty + L[16+n/16] + H[n%16] - m=50, n: tty + L[16+n/16] + H[n%16] - (THE SAME IN EITHER SYSTEM) - CALL-UNIX AND CONTROLLING TERMINAL DEVICES - m=5: - n=0: tty - n=64..128: cua + {'0' + (n-64)} - CYCLADES MULTIPORT: - m=19, n: ttyC + itoa_hex(n) - m=20, n: cub + itoa_hex(n) */ - -/* Re-implementation of old interface with the new generic functions. */ - -/* This does exactly the same thing as name_to_dev only now a full "ttyXX" - specification will work as well. -*/ -int tty_to_dev(char *tty) { - static char pref_name_1[32] = "tty", *pnam1 = pref_name_1 + 3, - pref_name_2[32] = "cu", *pnam2 = pref_name_2 + 2; - dev_t num; - if ((num = name_to_dev(tty)) != (dev_t) -1) /* try tty straight up */ - return num; - strncpy(pnam1, tty, 32 - 3); /* try with "tty" prepended */ - if ((num = name_to_dev(pref_name_1)) != (dev_t) -1) - return num; - strncpy(pnam2, tty, 32 - 2); /* try with "cu" prepended */ - if ((num = name_to_dev(pref_name_2)) != (dev_t) -1) - return num; - return -1; /* no match */ -} - -/* new abstraction that can maybe be generalized a little better. */ -char* abbrev_of_tty(char *tty) { - static char temp[32]; /* return buf: good only until next call */ - char *pos = strpbrk(tty, "yu"); /* end of (presumed) prefices: tty*, cu* */ - temp[0] = 0; - if (tty && tty[0] && pos && pos[0] && pos[1]) - sprintf(temp, "%*.*s", 3, 3, pos + 1); - else - strncpy(temp, " ? ", 31); - return temp; -} - -/* Do in-place modification of the 4-buffer `tty' based upon `dev' */ -void dev_to_tty(char *tty, int dev) { - char* new = abbrev_of_tty(dev_to_name(dev)); - strncpy(tty, new, 4); -} diff --git a/libproc/devname.h b/libproc/devname.h deleted file mode 100644 index e1371f45..00000000 --- a/libproc/devname.h +++ /dev/null @@ -1,10 +0,0 @@ - -#include - -dev_t name_to_dev(char* name); -char* dev_to_name(dev_t num); - -dev_t tty_to_dev(char *tty); -void dev_to_tty(char *tty, int dev); - -char* abbrev_of_tty(char *tty); diff --git a/libproc/ksym.c b/libproc/ksym.c deleted file mode 100644 index d8b085d4..00000000 --- a/libproc/ksym.c +++ /dev/null @@ -1,252 +0,0 @@ -/* kernel address -> symbol with next lower address. Charles Blake, 1996. - * Written to obviate the need for psdatabase initialization based upon kernel - * binary formats, etc. - * - * The basic algorithm is an approximate (intervals split vaguely 50-50) binary - * search taking advantage of the fact the System.map is already sorted in - * ascending order by the kernel makefile. It needs to assume an average symbol - * record length to avoid scanning the entire symbol table, but in practice the - * search time does not seem to be especially sensitive to this choice. - * - * The search could be an exact binary search if the lines of System.map were - * padded with blanks to the right. awk '{printf "%8s%2s %-21.21s\n",$1,$2,$3}' - * would do the trick for this but either makes the file large or truncates - * symbols. The approximate method seems to be plenty fast enough, costing - * only about as much as one extra fstat() or so per process. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "psdata.h" -#include "ps.h" -#include "version.h" - -#define MAX_ADDR_SZ 32 -static char *sysmap, *sysmap_last, sysmap_fmt[10]; -static int sysmap_len, sysmap_mean = 32, sysmap_addrsz; - -/* scan backward in a string no further than address beg looking for c */ -static char *strchrrev(char *a, char *beg, char c) { - if (a) - while (--a > beg && *a != c) ; - return a; -} - -/* return ptr to the beg of approximately the i-th record */ -static char *addr_str(int i) { - char *guess = sysmap + sysmap_mean * i; - if (!i) return sysmap; - if (guess - sysmap > sysmap_len - 2) guess = sysmap + sysmap_len - 2; - for ( ; *guess != '\n' && guess > sysmap; guess--) - ; - return guess + 1; - -} - -/* return ptr to symbol string (\n terminated) given beg of record ptr */ -static char *sym_put(char *buf, int len, char *addrptr) { - char *s; - while (*addrptr++ != ' ') ; - while (*addrptr++ != ' ') ; - strncpy(buf, addrptr, len); - for (s = buf; s < buf + len; s++) - if (*s == '\n') - *s = '\0'; - buf[len - 1] = '\0'; - return buf; -} - -/* Try to open and mmap a single symbol table file and initialize globals */ -int sysmap_mmap(char *path) { - int fd; - struct stat sbuf; - char *p; - if (sysmap) /* do nothing if already mapped */ - return 1; - if ((fd = open(path, O_RDONLY)) < 0 - || fstat(fd, &sbuf) < 0 - || (sysmap = mmap(0, sbuf.st_size, - PROT_READ, MAP_SHARED, - fd, 0)) == (caddr_t) -1) - { - close(fd); - sysmap = NULL; - return 0; - } - sysmap_len = sbuf.st_size; - sysmap_last = strchrrev(sysmap + sysmap_len - 2, sysmap, '\n') + 1; - - /* Now check first line of sysmap for hex numbers in first column. Note: - 0x/0X prefixes are disallowed, but easily addable. Capitalization is - irrelevant because strncasecmp(3) is used below instead of strncmp. */ - for (p = sysmap; *p != ' ' - && ((*p >= '0' && *p <= '9') || - (*p >= 'A' && *p <= 'F') || - (*p >= 'a' && *p <= 'f')) - && p < sysmap + MAX_ADDR_SZ; - p++) /* no-op */ ; - if (*p != ' ') { /* uh-oh: cannot understand format */ - fprintf(stderr, "warning: %s not parseable as a System.map.\n", path); - munmap(sysmap, sysmap_len); - sysmap = NULL; - close(fd); - return 0; - } - sysmap_addrsz = p - sysmap; - snprintf(sysmap_fmt, sizeof sysmap_fmt, "%%0%dlx", sysmap_addrsz); - close(fd); - return 1; -} - -/* kernel address -> name resolver. - returned value is only good until the next call to the function. - */ -char *sysmap_symbol(unsigned long address) { - static char rval[128], *pc, addr[MAX_ADDR_SZ]; - int i, p, n = sysmap_len / (double)sysmap_mean; - - sprintf(addr, sysmap_fmt, address); - p = 0; pc = sysmap; - while (n) { - i = p + (n >> 1); - if (strncasecmp(addr, pc = addr_str(i), sysmap_addrsz) > 0) - p = i + 1; - n >>= 1; - } - if (pc == sysmap_last) /* scan forward but not past end */ - return sym_put(rval, sizeof rval, pc); - while (strncasecmp(addr, pc, sysmap_addrsz) > 0) - pc = strchr(pc, '\n') + 1; - if (pc == sysmap) /* scan backward but not past beg */ - return sym_put(rval, sizeof rval, pc); - while (strncasecmp(addr, pc, sysmap_addrsz) < 0) - pc = strchrrev(pc - 1, sysmap, '\n') + 1; - return sym_put(rval, sizeof rval, pc); -} - -/* extern struct nlist *namelist; */ -struct tbl_s vars, fncs; -struct psdb_hdr db_hdr; -int psdb = -1; - -int open_psdb(void) { - static char *sysmap_paths[] = { - "/boot/System.map-%s", - "/boot/System.map", - "/lib/modules/%s/System.map", - NULL - }; - static char *psdb_paths[] = { - "/etc/psdatabase", - "/boot/psdatabase-%s", - "/boot/psdatabase", - "/lib/modules/%s/psdatabase", - NULL - }; - char **fmt, *env, path[64]; - struct utsname uts; - uname(&uts); - if ((env = getenv("PS_SYSMAP")) && sysmap_mmap(env)) - return 0; - for (fmt = sysmap_paths; *fmt; fmt++) { - snprintf(path, sizeof path, *fmt, uts.release); - if (sysmap_mmap(path)) - return 0; - } - for (fmt = psdb_paths; *fmt; fmt++) { - snprintf(path, sizeof path, *fmt, uts.release); - if ((psdb = open(path, O_RDONLY)) != -1 && - read(psdb, (char*)&db_hdr, sizeof db_hdr) == sizeof db_hdr && - strncmp(db_hdr.magic, procps_version, sizeof(db_hdr.magic)) == 0) - /* && version_cmp(kernel,psdatabase) */ - return 0; - if (psdb != -1) - fprintf(stderr, - "psdatabase has magic no. %*s instead of %*s\n", - (int) sizeof db_hdr.magic, db_hdr.magic, - (int) sizeof db_hdr.magic, procps_version); - close(psdb); - } - return -1; -} - -void close_psdb(void) { - if (sysmap) - munmap(sysmap, sysmap_len); - else if (psdb != -1) - close(psdb); - psdb = -1; - sysmap = NULL; -} - -int read_tbl(struct dbtbl_s *dbtbl, struct tbl_s *tbl) { - lseek(psdb, dbtbl->off, SEEK_SET); - tbl->tbl = (struct sym_s *) xmalloc(dbtbl->size); - if (read(psdb, (char *) tbl->tbl, dbtbl->size) != dbtbl->size) { - perror(PSDATABASE); - exit(1); - } - tbl->nsym = dbtbl->nsym; - tbl->strings = (char *) (tbl->tbl + tbl->nsym); - return 0; -} - -char * find_func(unsigned long address) { - int n; - struct sym_s *p; - char *s; - - if (sysmap) - return sysmap_symbol(address); - if (psdb == -1) - return "(no psdb)"; - if (fncs.tbl == NULL) - read_tbl(&db_hdr.fncs, &fncs); - p = fncs.tbl; - n = fncs.nsym; - while (n) { - int i = n / 2; - if (p[i].addr < address) { - p = &p[i+1]; - if (p->addr > address) { - --p; - break; - } - --n; - } - n /= 2; - } - s = p->name + fncs.strings; - return *s=='_' ? s+1 : s; -} - -char * wchan(unsigned long address) { - static char zero = 0; - char *p; - - if (address) { - p = find_func(address); - if (strncmp(p, "sys_", 4) == 0) - p += 4; - while (*p == '_' && *p) - ++p; - } else /* 0 address means not in kernel space */ - p = &zero; - return p; -} - -#ifdef SYSMAP_TEST -int main(int ac, char** av) { - if (ac < 3) {printf("%s System.map lines hexaddr ...\n",av[0]); return 1;} - if (!sysmap_mmap(av[1])) return 1; - if ((sysmap_mean = atoi(av[2])) <= 0) return 1; - for (av += 3; *av; av++) - printf("%s %s\n", *av, sysmap_symbol(strtoul(*av, NULL, 16))); - return 0; -} -#endif diff --git a/libproc/output.c b/libproc/output.c deleted file mode 100644 index 66e4e407..00000000 --- a/libproc/output.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - Some output conversion routines for libproc - Copyright (C) 1996, Charles Blake. See COPYING for details. -*/ -#include -#include -#include - -/* output a string, converting unprintables to octal as we go, and stopping after - processing max chars of output (accounting for expansion due to octal rep). -*/ -unsigned print_str(FILE* file, char *s, unsigned max) { - int i; - for (i=0; s[i] && i < max; i++) - if (isprint(s[i]) || s[i] == ' ') - fputc(s[i], file); - else { - if (max - i > 3) { - fprintf(file, "\\%03o", s[i]); - i += 3; /* 4 printed, but i counts one */ - } else - return max - i; - } - return max - i; -} - -/* output an argv style NULL-terminated string list, converting unprintables - to octal as we go, separating items of the list by 'sep' and stopping after - processing max chars of output (accounting for expansion due to octal rep). -*/ -unsigned print_strlist(FILE* file, char **strs, char* sep, unsigned max) { - int i, n, seplen = strlen(sep); - for (n=0; *strs && n < max; strs++) { - for (i=0; strs[0][i] && n+i < max; i++) - if (isprint(strs[0][i]) || strs[0][i] == ' ') - fputc(strs[0][i], file); - else { - if (max-(n+i) > 3) { - fprintf(file, "\\%03o", strs[0][i]); - n += 3; /* 4 printed, but i counts one */ - } else - return max - n; - } - n += i; - if (n + seplen < max) { - fputs(sep, file); - n += seplen; - } else - return max - n; - } - return max - n; -} diff --git a/libproc/ps.h b/libproc/ps.h deleted file mode 100644 index aa065cbf..00000000 --- a/libproc/ps.h +++ /dev/null @@ -1,30 +0,0 @@ -/* The shadow of the original with only common prototypes now. */ -#include -#include - -/* get definition of HZ */ -#include - -/* get page info */ -#include - -char *wchan(unsigned long); -char *find_func(unsigned long address); -void *xcalloc(void *pointer, int size); -void *xmalloc(unsigned int size); -void *xrealloc(void *oldp, unsigned int size); - -int mult_lvl_cmp(void* a, void* b); -int node_mult_lvl_cmp(void* a, void* b); -void dump_keys(void); - -char *user_from_uid(int uid); - -int open_sysmap(void); -int open_psdb(void); -void close_psdb(void); -void make_fnctbl(void); - -unsigned print_str (FILE* file, char *s, unsigned max); -unsigned print_strlist(FILE* file, char **strs, char* sep, unsigned max); -unsigned snprint_strlist(char *buf, int max, char **strs, char *sep); diff --git a/libproc/psdata.h b/libproc/psdata.h deleted file mode 100644 index a6c480e8..00000000 --- a/libproc/psdata.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * psdata.h - * - * Jeffrey A. Uphoff , 1995, 1996. - * Michael K. Johnson. - * Bruno Lankester. - * (And others I'm sure...) - * - */ - -/* - * Capabilities are for reading system images and producing maps for - * WCHAN output. - * - * AOUT_CAPABLE and ELF_CAPABLE may have 32-bit word size limitations - * and have only been tested by the maintainer on Intel systems. They - * are retained in the source tree in case they are useful; they are - * intended to be generally deprecated. - * - * BFD_CAPABLE should work on any system with BFD. - * - * Set the capabilities in the top-level Makefile. - */ - -#if defined(ELF_CAPABLE) -# define ELF_OBJECT 1 -# define ELF_FUNC 2 -#endif - -#include -#include - -#define PSDATABASE "/etc/psdatabase" - -struct dbtbl_s { - off_t off; /* offset in psdatabase */ - int nsym; /* # symbols */ - int size; /* size of array + strings */ -}; - -/* - * header of psdatabase - */ -struct psdb_hdr { - /* Current procps package version goes here. kmemps doesn't like this. */ - char magic[32]; - /* - * These are not functional--they only reside in the database for - * informational purposes (i.e. if you want to look at the raw - * database and see what kernel it's for). - */ - char uts_release[__NEW_UTS_LEN]; - char uts_version[__NEW_UTS_LEN]; - /* - * Again, this is not functional, it's just there for information: it - * shows the path to the uncompressed kernel image that was used to - * generate this database. - */ - char sys_path[128]; - /* List of all functions. */ - struct dbtbl_s fncs; - /* - * This is currently only used to look up system_utsname while - * psupdate is building the database--it really should be phased out! - */ - /* List of all bss and data symbols. */ - struct dbtbl_s vars; - /* - * The list of tty names that kmemps likes/uses in no longer present - * in the procps psdatabase--it was never being built by procps' - * psupdate anyway, so I removed the entry from the database header. - */ -}; - -struct sym_s { - unsigned long addr; /* core address in kernel */ - int name; /* offset from strings ptr */ -}; - -struct tbl_s { - struct sym_s *tbl; - int nsym; - char *strings; /* ptr to start of strings */ -}; - -extern struct psdb_hdr db_hdr; -extern struct tbl_s fncs, vars; - -int read_tbl (struct dbtbl_s *, struct tbl_s *); -void *xmalloc (unsigned int); -void *xrealloc (void *, unsigned int); - -#define MLSEEK(FD, WHERE, WHENCE, ERROR)\ -if (lseek ((FD), (WHERE), (WHENCE)) == -1) {\ - perror ((ERROR));\ - exit (errno);\ -} - -#define MREAD(FD, WHAT, SIZE, ERROR)\ -if (read ((FD), (WHAT), (SIZE)) != (SIZE)) {\ - perror ((ERROR));\ - exit (errno);\ -} diff --git a/libproc/pwcache.c b/libproc/pwcache.c deleted file mode 100644 index c28ac7b4..00000000 --- a/libproc/pwcache.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include "ps.h" - -#define HASHSIZE 16 /* power of 2 */ -#define HASH(x) ((x) & (HASHSIZE - 1)) - - -static struct pwbuf { - int uid; - char name[12]; - struct pwbuf *next; -} *pwhash[HASHSIZE]; - -char *user_from_uid(int uid) -{ - struct pwbuf **p; - struct passwd *pw; - - p = &pwhash[HASH(uid)]; - while (*p) { - if ((*p)->uid == uid) - return((*p)->name); - p = &(*p)->next; - } - *p = (struct pwbuf *) xmalloc(sizeof(struct pwbuf)); - (*p)->uid = uid; - if ((pw = getpwuid(uid)) == NULL) - sprintf((*p)->name, "#%d", uid); - else - sprintf((*p)->name, "%-.8s", pw->pw_name); - (*p)->next = NULL; - return((*p)->name); -} - -void bad_user_access_length() { } diff --git a/libproc/readproc.c b/libproc/readproc.c deleted file mode 100644 index 5155e217..00000000 --- a/libproc/readproc.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * New Interface to Process Table -- PROCTAB Stream (a la Directory streams) - * Copyright(C) 1996. Charles L. Blake. - */ -#include "version.h" -#include "readproc.h" -#include "devname.h" -#include "ps.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define Do(x) (flags & PROC_ ## x) /* convenient shorthand */ - -/* initiate a process table scan - */ -PROCTAB* openproc(int flags, ...) { - va_list ap; - PROCTAB* PT = xmalloc(sizeof(PROCTAB)); - - if (!Do(PID) && !(PT->procfs = opendir("/proc"))) - return NULL; - PT->flags = flags; - va_start(ap, flags); /* Init args list */ - if (Do(PID)) - PT->pids = va_arg(ap, pid_t*); - else if (Do(TTY)) - PT->ttys = va_arg(ap, dev_t*); - else if (Do(UID)) { - PT->uids = va_arg(ap, uid_t*); - PT->nuid = va_arg(ap, int); - } else if (Do(STAT)) - PT->stats = va_arg(ap, char*); - va_end(ap); /* Clean up args list */ - if (Do(ANYTTY) && Do(TTY)) - PT->flags = PT->flags & ~PROC_TTY; /* turn off TTY flag */ - return PT; -} - -/* terminate a process table scan - */ -void closeproc(PROCTAB* PT) { - if (PT->procfs) closedir(PT->procfs); - if (PT) free(PT); -} - -/* deallocate the space allocated by readproc if the passed rbuf was NULL - */ -void freeproc(proc_t* p) { - if (!p) /* in case p is NULL */ - return; - /* ptrs are after strings to avoid copying memory when building them. */ - /* so free is called on the address of the address of strvec[0]. */ - if (p->cmdline) - free((void*)*p->cmdline); - if (p->environ) - free((void*)*p->environ); - free(p); -} - -/* stat2proc() makes sure it can handle arbitrary executable file basenames - for `cmd', i.e. those with embedded whitespace or embedded ')'s. Such names - confuse %s (see scanf(3)), so the string is split and %39c is used instead. - (except for embedded ')' "(%[^)]c)" would work. -*/ -void stat2proc(char* S, proc_t* P) { - char* tmp = strrchr(S, ')'); /* split into "PID (cmd" and "" */ - *tmp = '\0'; /* replace trailing ')' with NUL */ - /* parse these two strings separately, skipping the leading "(". */ - memset(P->cmd, 0, sizeof P->cmd); /* clear even though *P xcalloc'd ?! */ - sscanf(S, "%d (%39c", &P->pid, P->cmd); - sscanf(tmp + 2, /* skip space after ')' too */ - "%c %d %d %d %d %d %lu %lu %lu %lu %lu %ld %ld %ld %ld %d " - "%d %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %LX %LX %LX %LX %lu", - &P->state, &P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid, - &P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt, - &P->utime, &P->stime, &P->cutime, &P->cstime, &P->priority, &P->nice, - &P->timeout, &P->it_real_value, &P->start_time, &P->vsize, &P->rss, - &P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, - &P->kstk_esp, &P->kstk_eip, &P->signal, &P->blocked, &P->sigignore, - &P->sigcatch, &P->wchan); - if (P->tty == 0) - P->tty = -1; /* the old notty val, update elsewhere bef. moving to 0 */ - if (linux_version_code < LINUX_VERSION(1,3,39)) { - P->priority = 2*15 - P->priority; /* map old meanings to new */ - P->nice = 15 - P->nice; - } - if (linux_version_code < LINUX_VERSION(1,1,30) && P->tty != -1) - P->tty = 4*0x100 + P->tty; /* when tty wasn't full devno */ -} - -void statm2proc(char* s, proc_t* P) { - sscanf(s, "%ld %ld %ld %ld %ld %ld %ld", - &P->size, &P->resident, &P->share, - &P->trs, &P->lrs, &P->drs, &P->dt); -} - -void nulls2sep(char* str, int len, char sep) { - int i; - for (i = 0; i < len; i++) - if (str[i] == 0) - str[i] = sep; -} - -int file2str(char *directory, char *what, char *ret, int cap) { - static char filename[80]; - int fd, num_read; - - sprintf(filename, "%s/%s", directory, what); - if ( (fd = open(filename, O_RDONLY, 0)) == -1 ) return -1; - if ( (num_read = read(fd, ret, cap - 1)) <= 0 ) return -1; - ret[num_read] = 0; - close(fd); - return num_read; -} - -char** file2strvec(char* directory, char* what) { - char buf[2048]; /* read buf bytes at a time */ - char *p, *rbuf = 0, *endbuf, **q, **ret; - int fd, tot = 0, n, c, end_of_file = 0; - int align; - - sprintf(buf, "%s/%s", directory, what); - if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return NULL; - - /* read whole file into a memory buffer, allocating as we go */ - while ((n = read(fd, buf, sizeof buf - 1)) > 0) { - if (n < sizeof buf - 1) - end_of_file = 1; - if (n == 0 && rbuf == 0) - return NULL; /* process died between our open and read */ - if (n < 0) { - if (rbuf) - free(rbuf); - return NULL; /* read error */ - } - if (end_of_file && buf[n-1]) /* last read char not null */ - buf[n++] = '\0'; /* so append null-terminator */ - rbuf = xrealloc(rbuf, tot + n); /* allocate more memory */ - memcpy(rbuf + tot, buf, n); /* copy buffer into it */ - tot += n; /* increment total byte ctr */ - if (end_of_file) - break; - } - close(fd); - if (n <= 0 && !end_of_file) { - if (rbuf) free(rbuf); - return NULL; /* read error */ - } - endbuf = rbuf + tot; /* count space for pointers */ - align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1)); - for (c = 0, p = rbuf; p < endbuf; p++) - if (!*p) - c += sizeof(char*); - c += sizeof(char*); /* one extra for NULL term */ - - rbuf = xrealloc(rbuf, tot + c + align); /* make room for ptrs AT END */ - endbuf = rbuf + tot; /* addr just past data buf */ - q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */ - *q++ = p = rbuf; /* point ptrs to the strings */ - endbuf--; /* do not traverse final NUL */ - while (++p < endbuf) - if (!*p) /* NUL char implies that */ - *q++ = p+1; /* next string -> next char */ - - *q = 0; /* null ptr list terminator */ - return ret; -} - - -/* These are some nice GNU C expression subscope "inline" functions. - The can be used with arbitrary types and evaluate their arguments - exactly once. -*/ - -/* Test if item X of type T is present in the 0 terminated list L */ -# define XinL(T, X, L) ( { \ - T x = (X), *l = (L); \ - while (*l && *l != x) l++; \ - *l == x; \ - } ) - -/* Test if item X of type T is present in the list L of length N */ -# define XinLN(T, X, L, N) ( { \ - T x = (X), *l = (L); \ - int i = 0, n = (N); \ - while (i < n && l[i] != x) i++; \ - i < n && l[i] == x; \ - } ) - -/* readproc: return a pointer to a proc_t filled with requested info about the - * next process available matching the restriction set. If no more such - * processes are available, return a null pointer (boolean false). Use the - * passed buffer instead of allocating space if it is non-NULL. */ - -/* This is optimized so that if a PID list is given, only those files are - * searched for in /proc. If other lists are given in addition to the PID list, - * the same logic can follow through as for the no-PID list case. This is - * fairly complex, but it does try to not to do any unnecessary work. - * Unfortunately, the reverse filtering option in which any PID *except* the - * ones listed is pursued. - */ -#define flags (PT->flags) -proc_t* readproc(PROCTAB* PT, proc_t* rbuf) { - static struct direct *ent; /* dirent handle */ - static struct stat sb; /* stat buffer */ - static char path[32], sbuf[256]; /* bufs for stat,statm */ - int allocated = 0, matched = 0; /* flags */ - proc_t *p = NULL; - - /* loop until a proc matching restrictions is found or no more processes */ - /* I know this could be a while loop -- this way is easier to indent ;-) */ -next_proc: /* get next PID for consideration */ - if (Do(PID)) { - if (!*PT->pids) /* set to next item in pids */ - return NULL; - sprintf(path, "/proc/%d", *(PT->pids)++); - matched = 1; - } else { /* get next numeric /proc ent */ - while ((ent = readdir(PT->procfs)) && - (*ent->d_name < '0' || *ent->d_name > '9')) - ; - if (!ent || !ent->d_name) - return NULL; - sprintf(path, "/proc/%s", ent->d_name); - } - if (stat(path, &sb) == -1) /* no such dirent (anymore) */ - goto next_proc; - if (Do(UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid)) - goto next_proc; /* not one of the requested uids */ - - if (!allocated) { /* assign mem for return buf */ - p = rbuf ? rbuf : xcalloc(p, sizeof *p); /* passed buf or alloced mem */ - allocated = 1; /* remember space is set up */ - } - p->uid = sb.st_uid; /* need a way to get real uid */ - - if ((file2str(path, "stat", sbuf, sizeof sbuf)) == -1) - goto next_proc; /* error reading /proc/#/stat */ - stat2proc(sbuf, p); /* parse /proc/#/stat */ - - if (!matched && Do(TTY) && !XinL(dev_t, p->tty, PT->ttys)) - goto next_proc; /* not one of the requested ttys */ - - if (!matched && Do(ANYTTY) && p->tty == -1) - goto next_proc; /* no controlling terminal */ - - if (!matched && Do(STAT) && !strchr(PT->stats,p->state)) - goto next_proc; /* not one of the requested states */ - - if (Do(FILLMEM)) { /* read, parse /proc/#/statm */ - if ((file2str(path, "statm", sbuf, sizeof sbuf)) != -1 ) - statm2proc(sbuf, p); /* ignore statm errors here */ - } /* statm fields just zero */ - - /* some number->text resolving which is time consuming */ - if (Do(FILLTTY)) - dev_to_tty(p->ttyc, p->tty); - if (Do(FILLUSR)) - strncpy(p->user, user_from_uid(p->uid), sizeof p->user); - - if (Do(FILLCMD)) /* read+parse /proc/#/cmdline */ - p->cmdline = file2strvec(path, "cmdline"); - if (Do(FILLENV)) /* read+parse /proc/#/environ */ - p->environ = file2strvec(path, "environ"); - - if (p->state == 'Z') /* fixup cmd for zombies */ - strncat(p->cmd," ", sizeof p->cmd); - - return p; -} -#undef flags - -/* Convenient wrapper around openproc and readproc to slurp in the whole process - * tree subset satisfying the constraints of flags and the optional PID list. - * Free allocated memory with freeproctree(). The tree structure is a classic - * left-list children + right-list siblings. The algorithm is a two-pass of the - * process table. Since most process trees will have children with strictly - * increasing PIDs, most of the structure will be picked up in the first pass. - * The second loop then cleans up any nodes which turn out to have preceeded - * their parent in /proc order. - */ - -/* Traverse tree 't' breadth-first looking for a process with pid p */ -proc_t* LookupPID(proc_t* t, pid_t p) { - proc_t* tmp = NULL; - if (!t) - return NULL; - if (t->pid == p) /* look here/terminate recursion */ - return t; - if ((tmp = LookupPID(t->l, p))) /* recurse over children */ - return tmp; - for (; t; t=t->r) /* recurse over siblings */ - if ((tmp = LookupPID(tmp, p))) - return tmp; - return NULL; -} - -proc_t* readproctree(int flags, ...) { - static proc_t tree; - PROCTAB* PT = NULL; - proc_t *node, *tmp=NULL, *tmp2=NULL; - va_list ap; - - /* pass through apropriate arguments to openproc */ - va_start(ap, flags); - if (Do(UID)) { - /* temporary variables to ensure that va_arg() instances - * are called in the right order - */ - uid_t* u; - int i; - - u = va_arg(ap, uid_t*); - i = va_arg(ap, int); - PT = openproc(flags, u, i); - } - else if (Do(PID) || Do(TTY) || Do(STAT)) - PT = openproc(flags, va_arg(ap, void*)); - else - PT = openproc(flags); - va_end(ap); - - /* first pass: build tree, putting orphans on the first level */ - tree.l = tree.r = NULL; - while ((node = readproc(PT,0))) - if ((tmp = LookupPID(&tree, node->ppid))) { - node->r = tmp->l->r; /* node --> left list of parent */ - tmp->l->r = node; - } else { - node->r = tree.r; /* node --> right list of 'tree' */ - tree.r = node; - } - /* second pass: scan tree for PPIDs of level-1 nodes moving links as necessary */ - for (node = &tree; node; node = node->r) - if ((tmp = LookupPID(&tree, node->r->ppid))) { - tmp2 = node->r; /* unlink from right list of 'tree' */ - node->r = node->r->r; - tmp2->r = tmp->l->r; /* insert as child of found node */ - tmp->l->r = node; - } - closeproc(PT); - return &tree; -} - -/* Convenient wrapper around openproc and readproc to slurp in the whole process - * table subset satisfying the constraints of flags and the optional PID list. - * Free allocated memory with freeproctab(). Access via tab[N]->member. The - * pointer list is NULL terminated. - */ -proc_t** readproctab(int flags, ...) { - PROCTAB* PT = NULL; - proc_t** tab = NULL; - int n = 0; - va_list ap; - - va_start(ap, flags); /* pass through args to openproc */ - if (Do(UID)) { - /* temporary variables to ensure that va_arg() instances - * are called in the right order - */ - uid_t* u; - int i; - - u = va_arg(ap, uid_t*); - i = va_arg(ap, int); - PT = openproc(flags, u, i); - } - else if (Do(PID) || Do(TTY) || Do(STAT)) - PT = openproc(flags, va_arg(ap, void*)); /* assume ptr sizes same */ - else - PT = openproc(flags); - va_end(ap); - do { /* read table: */ - tab = xrealloc(tab, (n+1)*sizeof(proc_t*));/* realloc as we go, using */ - tab[n] = readproc(PT, NULL); /* final null to terminate */ - } while (tab[n++]); /* stop when NULL reached */ - closeproc(PT); - return tab; -} - -/* deallocate a table of pointers to proc structures - */ -void freeproctab(proc_t** tab) { - proc_t** p; - for(p = tab; *p; p++) - freeproc(*p); - free(tab); -} diff --git a/libproc/readproc.h b/libproc/readproc.h deleted file mode 100644 index b93f0198..00000000 --- a/libproc/readproc.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * New Interface to Process Table -- PROCTAB Stream (a la Directory streams) - * Copyright(C) 1996. Charles L. Blake. - */ - -/* Basic data structure which holds all information we can get about a process. - * (unless otherwise specified, fields are read from /proc/#/stat) - */ -typedef struct proc_s { - char - user[10], /* user name corresponding to owner of process */ - cmd[40], /* basename of executable file in call to exec(2) */ - state, /* single-char code for process state (S=sleeping) */ - ttyc[5], /* string representation of controlling tty device */ - **environ, /* environment string vector (/proc/#/environ) */ - **cmdline; /* command line string vector (/proc/#/cmdline) */ - int - uid, /* user id */ - pid, /* process id */ - ppid, /* pid of parent process */ - pgrp, /* process group id */ - session, /* session id */ - tty, /* full device number of controlling terminal */ - tpgid, /* terminal process group id */ - priority, /* kernel scheduling priority */ - nice; /* standard unix nice level of process */ - long long - signal, /* mask of pending signals */ - blocked, /* mask of blocked signals */ - sigignore, /* mask of ignored signals */ - sigcatch; /* mask of caught signals */ - long - start_time, /* start time of process -- seconds since 1-1-70 */ - utime, /* user-mode CPU time accumulated by process */ - stime, /* kernel-mode CPU time accumulated by process */ - cutime, /* cumulative utime of process and reaped children */ - cstime, /* cumulative stime of process and reaped children */ - /* the next 7 members come from /proc/#/statm */ - size, /* total # of pages of memory */ - resident, /* number of resident set (non-swapped) pages (4k) */ - share, /* number of pages of shared (mmap'd) memory */ - trs, /* text resident set size */ - lrs, /* shared-lib resident set size */ - drs, /* data resident set size */ - dt; /* dirty pages */ - unsigned - pcpu; /* %CPU usage (is not filled in by readproc!!!) */ - unsigned long - vsize, /* number of pages of virtual memory ... */ - rss, /* resident set size from /proc/#/stat */ - rss_rlim, /* resident set size ... ? */ - timeout, /* ? */ - it_real_value, /* ? */ - flags, /* kernel flags for the process */ - min_flt, /* number of minor page faults since process start */ - maj_flt, /* number of major page faults since process start */ - cmin_flt, /* cumulative min_flt of process and child processes */ - cmaj_flt, /* cumulative maj_flt of process and child processes */ - start_code, /* address of beginning of code segment */ - end_code, /* address of end of code segment */ - start_stack, /* address of the bottom of stack for the process */ - kstk_esp, /* kernel stack pointer */ - kstk_eip, /* kernel stack pointer */ - wchan; /* address of kernel wait channel proc is sleeping in */ - struct proc_s *l, /* ptrs for building arbitrary linked structs */ - *r; /* (i.e. singly/doubly-linked lists and trees */ -} proc_t; - -/* PROCTAB: data structure holding the persistent information readproc needs - * from openproc(). The setup is intentionally similar to the dirent interface - * and other system table interfaces (utmp+wtmp come to mind). - */ -#include -#include -#include -typedef struct { - DIR* procfs; - int flags; - pid_t* pids; /* pids of the procs */ - dev_t* ttys; /* devnos of the cttys */ - uid_t* uids; /* uids of procs */ - int nuid; /* cannot really sentinel-terminate unsigned short[] */ - char* stats; /* status chars (actually output into /proc//stat) */ -} PROCTAB; - -/* initialize a PROCTAB structure holding needed call-to-call persistent data - */ -PROCTAB* openproc(int flags, ... /* pid_t*|uid_t*|dev_t*|char* [, int n] */ ); - -/* Convenient wrapper around openproc and readproc to slurp in the whole process - * table subset satisfying the constraints of flags and the optional PID list. - * Free allocated memory with freeproctab(). Access via tab[N]->member. The - * pointer list is NULL terminated. - */ -proc_t** readproctab(int flags, ... /* same as openproc */ ); - -/* Convenient wrapper around openproc and readproc to slurp in the whole process - * tree subset satisfying the constraints of flags and the optional PID list. - */ -proc_t* readproctree(int flags, ... /* same as openproc */ ); - -/* clean-up open files, etc from the openproc() - */ -void closeproc(PROCTAB* PT); - -/* retrieve the next process matching the criteria set by the openproc() - */ -proc_t* readproc(PROCTAB* PT, proc_t* return_buf); - -/* deallocate space allocated by readproc - */ -void freeproc(proc_t* p); - -/* deallocate space allocated by readproctab - */ -void freeproctab(proc_t** p); - -/* openproc/readproctab: - * - * Return PROCTAB* / *proc_t[] or NULL on error ((probably) "/proc" cannot be - * opened.) By default readproc will consider all processes as valid to parse - * and return, but not actually fill in the cmdline, environ, and /proc/#/statm - * derived memory fields. - * - * `flags' (a bitwise-or of PROC_* below) modifies the default behavior. The - * "fill" options will cause more of the proc_t to be filled in. The "filter" - * options all use the second argument as the pointer to a list of objects: - * process status', process id's, user id's, and tty device numbers. The third - * argument is the length of the list (currently only used for lists of user - * id's since unsigned short[] supports no convenient termination sentinel.) - */ -#define PROC_FILLMEM 0x1 /* read statm into the appropriate proc_t entries */ -#define PROC_FILLCMD 0x2 /* alloc and fill in `cmdline' part of proc_t */ -#define PROC_FILLENV 0x4 /* alloc and fill in `environ' part of proc_t */ -#define PROC_FILLTTY 0x8 /* resolve device number -> tty name via psdevtab */ -#define PROC_FILLUSR 0x10 /* resolve user id number -> user name via passwd */ - /* consider only processes with one of the passed: */ -#define PROC_PID 0x100 /* process id numbers ( 0 terminated) */ -#define PROC_TTY 0x200 /* ctty device nos. ( 0 terminated) */ -#define PROC_UID 0x400 /* user id numbers ( length needed ) */ -#define PROC_STAT 0x800 /* status fields ('\0' terminated) */ -#define PROC_ANYTTY 0x1000 /* proc must have a controlling terminal */ - -/* utility functions which may be of general interest: */ - -/* slurp /proc/DIR/FILE into a single large string into the passed - buffer. return the number of bytes actually used. used for stat,statm - */ -int file2str(char *dir, char *file, char *buf, int buf_size); - -/* convert a file of null terminated strings into an argv-style string vector - * which may be de-allocated with a single free() on a dereference of the return - * value, e.g. free(*ret). used for cmdline, environ. - */ -char** file2strvec(char* directory, char* what); - -/* parse /proc/#/stat entries in string s into a proc_t - */ -void stat2proc(char* S, proc_t*); - -/* parse /proc/#/statm entries in string s into a proc_t - */ -void statm2proc(char* s, proc_t*); - -/* convert a memory buffer with nulls into a single string, - replacing the nulls with sep. No longer used. - */ -void nulls2sep(char* str, int len, char sep); diff --git a/libproc/signals.c b/libproc/signals.c deleted file mode 100644 index d85edf26..00000000 --- a/libproc/signals.c +++ /dev/null @@ -1,65 +0,0 @@ -/* signals.c - signal name handling */ - -#include -#include -#include -#include -#include "signals.h" - - -typedef struct { - int number; - char *name; -} SIGNAME; - - -static SIGNAME signals[] = { -#include "signames.h" /* should be in same dir as this file */ - { 0,NULL }}; - - -void list_signals(void) -{ - SIGNAME *walk; - int col; - - col = 0; - for (walk = signals; walk->name; walk++) { - if (col+strlen(walk->name)+1 > 80) { - putchar('\n'); - col = 0; - } - printf("%s%s",col ? " " : "",walk->name); - col += strlen(walk->name)+1; - } - putchar('\n'); -} - - -int get_signal(char *name,char *cmd) -{ - SIGNAME *walk; - - if (isdigit(*name)) - return atoi(name); - for (walk = signals; walk->name; walk++) - if (!strcmp(walk->name,name)) break; - if (walk->name) return walk->number; - fprintf(stderr,"%s: unknown signal; %s -l lists signals.\n",name,cmd); - exit(1); -} - -/* get_signal2 is by Michael Shields. 1994/04/25. */ -int get_signal2(char *name) -{ - SIGNAME *walk; - - if (!name) - return(-1); - if (isdigit(*name)) - return atoi(name); - for (walk = signals; walk->name; walk++) - if (!strcmp(walk->name,name)) - return(walk->number); - return(-1); -} diff --git a/libproc/signals.h b/libproc/signals.h deleted file mode 100644 index c793fae0..00000000 --- a/libproc/signals.h +++ /dev/null @@ -1,12 +0,0 @@ -/* signals.h - signal name handling */ - -void list_signals(void); - -/* Lists all known signal names on standard output. */ - -int get_signal(char *name,char *cmd); -int get_signal2(char *name); - -/* Returns the signal number of NAME. If no such signal exists, an error - message is displayed and the program is terminated. CMD is the name of the - application. */ diff --git a/libproc/signames.h b/libproc/signames.h deleted file mode 100644 index edcd6a38..00000000 --- a/libproc/signames.h +++ /dev/null @@ -1,32 +0,0 @@ -{ 1,"HUP" }, -{ 2,"INT" }, -{ 3,"QUIT" }, -{ 4,"ILL" }, -{ 5,"TRAP" }, -{ 6,"ABRT" }, -{ 6,"IOT" }, -{ 7,"BUS" }, -{ 8,"FPE" }, -{ 9,"KILL" }, -{ 10,"USR1" }, -{ 11,"SEGV" }, -{ 12,"USR2" }, -{ 13,"PIPE" }, -{ 14,"ALRM" }, -{ 15,"TERM" }, -{ 16,"STKFLT" }, -{ 17,"CHLD" }, -{ 18,"CONT" }, -{ 19,"STOP" }, -{ 20,"TSTP" }, -{ 21,"TTIN" }, -{ 22,"TTOU" }, -{ 23,"URG" }, -{ 24,"XCPU" }, -{ 25,"XFSZ" }, -{ 26,"VTALRM" }, -{ 27,"PROF" }, -{ 28,"WINCH" }, -{ 29,"IO" }, -{ 30,"PWR" }, -{ 31,"UNUSED" }, diff --git a/libproc/status.c b/libproc/status.c deleted file mode 100644 index b937bb0c..00000000 --- a/libproc/status.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "ps.h" -#include "readproc.h" - -char * status(proc_t* task) { - static char buf[4] = " "; - - buf[0] = task->state; - if (task->rss == 0 && task->state != 'Z') - buf[1] = 'W'; - else - buf[1] = ' '; - if (task->nice < 0) - buf[2] = '<'; - else if (task->nice > 0) - buf[2] = 'N'; - else - buf[2] = ' '; - - return(buf); -} diff --git a/libproc/sysinfo.c b/libproc/sysinfo.c deleted file mode 100644 index ef0c6279..00000000 --- a/libproc/sysinfo.c +++ /dev/null @@ -1,176 +0,0 @@ -/* File for parsing top-level /proc entities. */ -#include "sysinfo.h" - -#include -#include -#include -#include - -#include -#include -#include "version.h" - -#define BAD_OPEN_MESSAGE \ -"Error: /proc must be mounted\n" \ -" To mount /proc at boot you need an /etc/fstab line like:\n" \ -" /proc /proc proc defaults\n" \ -" In the meantime, mount /proc /proc -t proc\n" - -#define UPTIME_FILE "/proc/uptime" -#define LOADAVG_FILE "/proc/loadavg" -#define MEMINFO_FILE "/proc/meminfo" - -static char buf[1024]; - -/* This macro opens FILE only if necessary and seeks to 0 so that successive - calls to the functions are more efficient. It also reads the current - contents of the file into the global buf. -*/ -#define FILE_TO_BUF(FILE) { \ - static int n, fd = -1; \ - if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) { \ - fprintf(stderr, BAD_OPEN_MESSAGE); \ - close(fd); \ - return 0; \ - } \ - lseek(fd, 0L, SEEK_SET); \ - if ((n = read(fd, buf, sizeof buf - 1)) < 0) { \ - perror(FILE); \ - close(fd); \ - fd = -1; \ - return 0; \ - } \ - buf[n] = '\0'; \ -} - -#define SET_IF_DESIRED(x,y) if (x) *(x) = (y) /* evals 'x' twice */ - -int uptime(double *uptime_secs, double *idle_secs) { - double up=0, idle=0; - - FILE_TO_BUF(UPTIME_FILE) - if (sscanf(buf, "%lf %lf", &up, &idle) < 2) { - fprintf(stderr, "bad data in " UPTIME_FILE "\n"); - return 0; - } - SET_IF_DESIRED(uptime_secs, up); - SET_IF_DESIRED(idle_secs, idle); - return up; /* assume never be zero seconds in practice */ -} - -int loadavg(double *av1, double *av5, double *av15) { - double avg_1=0, avg_5=0, avg_15=0; - - FILE_TO_BUF(LOADAVG_FILE) - if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) { - fprintf(stderr, "bad data in " LOADAVG_FILE "\n"); - exit(1); - } - SET_IF_DESIRED(av1, avg_1); - SET_IF_DESIRED(av5, avg_5); - SET_IF_DESIRED(av15, avg_15); - return 1; -} - -/* The following /proc/meminfo parsing routine assumes the following format: - [