EXTRA_DIST = \
.version \
autogen.sh \
- contrib \
COPYING.LIB \
misc/git-version-gen \
Documentation/CodingStyle.md \
+++ /dev/null
-/*
- * This is to test the compiler.
- * Copyright (C) Albert Cahalan
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <curses.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Foul POS defines all sorts of stuff... */
-#include <term.h>
-#undef tab
-
-#include <termios.h>
-#include <time.h>
-#include <unistd.h>
-#include <values.h>
-
-int main(int argc, char *argv[]){
- (void)argc;
- (void)argv;
- return 0;
-}
+++ /dev/null
-/*
- * Copyright 1998,2004 by Albert Cahalan
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/* This is a minimal /bin/ps, designed to be smaller than the old ps
- * while still supporting some of the more important features of the
- * new ps. (for total size, note that this ps does not need libproc)
- * It is suitable for Linux-on-a-floppy systems only.
- *
- * Maintainers: do not compile or install for normal systems.
- * Anyone needing this will want to tweak their compiler anyway.
- */
-
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-
-#define DEV_ENCODE(M,m) ( \
- ( (M&0xfff) << 8) | ( (m&0xfff00) << 12) | (m&0xff) \
-)
-
-///////////////////////////////////////////////////////
-#ifdef __sun__
-#include <sys/mkdev.h>
-#define _STRUCTURED_PROC 1
-#include <sys/procfs.h>
-#define NO_TTY_VALUE DEV_ENCODE(-1,-1)
-#define HZ 1 // only bother with seconds
-#endif
-
-///////////////////////////////////////////////////////
-#ifdef __FreeBSD__
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <sys/stat.h>
-#include <sys/proc.h>
-#include <sys/user.h>
-#define NO_TTY_VALUE DEV_ENCODE(-1,-1)
-#define HZ 1 // only bother with seconds
-#endif
-
-///////////////////////////////////////////////////////
-#ifdef __linux__
-#include <asm/param.h> /* HZ */
-#include <asm/page.h> /* PAGE_SIZE */
-#define NO_TTY_VALUE DEV_ENCODE(0,0)
-#ifndef HZ
-#warning HZ not defined, assuming it is 100
-#define HZ 100
-#endif
-#endif
-
-///////////////////////////////////////////////////////////
-
-#ifndef PAGE_SIZE
-#warning PAGE_SIZE not defined, using sysconf() to determine correct value
-#define PAGE_SIZE (sysconf(_SC_PAGESIZE))
-#endif
-
-
-
-static char P_tty_text[16];
-static char P_cmd[16];
-static char P_state;
-static int P_euid;
-static int P_pid;
-static int P_ppid, P_pgrp, P_session, P_tty_num, P_tpgid;
-static unsigned long P_flags, P_min_flt, P_cmin_flt, P_maj_flt, P_cmaj_flt, P_utime, P_stime;
-static long P_cutime, P_cstime, P_priority, P_nice, P_timeout, P_alarm;
-static unsigned long P_start_time, P_vsize;
-static long P_rss;
-static unsigned long P_rss_rlim, P_start_code, P_end_code, P_start_stack, P_kstk_esp, P_kstk_eip;
-static unsigned P_signal, P_blocked, P_sigignore, P_sigcatch;
-static unsigned long P_wchan, P_nswap, P_cnswap;
-
-
-
-#if 0
-static int screen_cols = 80;
-static int w_count;
-#endif
-
-static int want_one_pid;
-static const char *want_one_command;
-static int select_notty;
-static int select_all;
-
-static int ps_format;
-static int old_h_option;
-
-/* we only pretend to support this */
-static int show_args; /* implicit with -f and all BSD options */
-static int bsd_c_option; /* this option overrides the above */
-
-static int ps_argc; /* global argc */
-static char **ps_argv; /* global argv */
-static int thisarg; /* index into ps_argv */
-static char *flagptr; /* current location in ps_argv[thisarg] */
-
-
-
-
-static void usage(void){
- fprintf(stderr,
- "-C select by command name (minimal ps only accepts one)\n"
- "-p select by process ID (minimal ps only accepts one)\n"
- "-e all processes (same as ax)\n"
- "a all processes w/ tty, including other users\n"
- "x processes w/o controlling ttys\n"
- "-f full format\n"
- "-j,j job control format\n"
- "v virtual memory format\n"
- "-l,l long format\n"
- "u user-oriented format\n"
- "-o user-defined format (limited support, only \"ps -o pid=\")\n"
- "h no header\n"
-/*
- "-A all processes (same as ax)\n"
- "c true command name\n"
- "-w,w wide output\n"
-*/
- );
- exit(1);
-}
-
-/*
- * Return the next argument, or call the usage function.
- * This handles both: -oFOO -o FOO
- */
-static const char *get_opt_arg(void){
- const char *ret;
- ret = flagptr+1; /* assume argument is part of ps_argv[thisarg] */
- if(*ret) return ret;
- if(++thisarg >= ps_argc) usage(); /* there is nothing left */
- /* argument is the new ps_argv[thisarg] */
- ret = ps_argv[thisarg];
- if(!ret || !*ret) usage();
- return ret;
-}
-
-
-/* return the PID, or 0 if nothing good */
-static void parse_pid(const char *str){
- char *endp;
- int num;
- if(!str) goto bad;
- num = strtol(str, &endp, 0);
- if(*endp != '\0') goto bad;
- if(num<1) goto bad;
- if(want_one_pid) goto bad;
- want_one_pid = num;
- return;
-bad:
- usage();
-}
-
-/***************** parse SysV options, including Unix98 *****************/
-static void parse_sysv_option(void){
- do{
- switch(*flagptr){
- /**** selection ****/
- case 'C': /* end */
- if(want_one_command) usage();
- want_one_command = get_opt_arg();
- return; /* can't have any more options */
- case 'p': /* end */
- parse_pid(get_opt_arg());
- return; /* can't have any more options */
- case 'A':
- case 'e':
- select_all++;
- select_notty++;
-case 'w': /* here for now, since the real one is not used */
- break;
- /**** output format ****/
- case 'f':
- show_args = 1;
- /* FALL THROUGH */
- case 'j':
- case 'l':
- if(ps_format) usage();
- ps_format = *flagptr;
- break;
- case 'o': /* end */
- /* We only support a limited form: "ps -o pid=" (yes, just "pid=") */
- if(strcmp(get_opt_arg(),"pid=")) usage();
- if(ps_format) usage();
- ps_format = 'o';
- old_h_option++;
- return; /* can't have any more options */
- /**** other stuff ****/
-#if 0
- case 'w':
- w_count++;
- break;
-#endif
- default:
- usage();
- } /* switch */
- }while(*++flagptr);
-}
-
-/************************* parse BSD options **********************/
-static void parse_bsd_option(void){
- do{
- switch(*flagptr){
- /**** selection ****/
- case 'a':
- select_all++;
- break;
- case 'x':
- select_notty++;
- break;
- case 'p': /* end */
- parse_pid(get_opt_arg());
- return; /* can't have any more options */
- /**** output format ****/
- case 'j':
- case 'l':
- case 'u':
- case 'v':
- if(ps_format) usage();
- ps_format = 0x80 | *flagptr; /* use 0x80 to tell BSD from SysV */
- break;
- /**** other stuff ****/
- case 'c':
- bsd_c_option++;
-#if 0
- break;
-#endif
- case 'w':
-#if 0
- w_count++;
-#endif
- break;
- case 'h':
- old_h_option++;
- break;
- default:
- usage();
- } /* switch */
- }while(*++flagptr);
-}
-
-#if 0
-#include <termios.h>
-/* not used yet */
-static void choose_dimensions(void){
- struct winsize ws;
- char *columns;
- /* screen_cols is 80 by default */
- if(ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col>30) screen_cols = ws.ws_col;
- columns = getenv("COLUMNS");
- if(columns && *columns){
- long t;
- char *endptr;
- t = strtol(columns, &endptr, 0);
- if(!*endptr && (t>30) && (t<(long)999999999)) screen_cols = (int)t;
- }
- if(w_count && (screen_cols<132)) screen_cols=132;
- if(w_count>1) screen_cols=999999999;
-}
-#endif
-
-static void arg_parse(int argc, char *argv[]){
- int sel = 0; /* to verify option sanity */
- ps_argc = argc;
- ps_argv = argv;
- thisarg = 0;
- /**** iterate over the args ****/
- while(++thisarg < ps_argc){
- flagptr = ps_argv[thisarg];
- switch(*flagptr){
- case '0' ... '9':
- show_args = 1;
- parse_pid(flagptr);
- break;
- case '-':
- flagptr++;
- parse_sysv_option();
- break;
- default:
- show_args = 1;
- parse_bsd_option();
- break;
- }
- }
- /**** sanity check and clean-up ****/
- if(want_one_pid) sel++;
- if(want_one_command) sel++;
- if(select_notty || select_all) sel++;
- if(sel>1 || select_notty>1 || select_all>1 || bsd_c_option>1 || old_h_option>1) usage();
- if(bsd_c_option) show_args = 0;
-}
-
-#ifdef __sun__
-/* return 1 if it works, or 0 for failure */
-static int stat2proc(int pid) {
- struct psinfo p; // /proc/*/psinfo, struct psinfo, psinfo_t
- char buf[32];
- int num;
- int fd;
- int tty_maj, tty_min;
- snprintf(buf, sizeof buf, "/proc/%d/psinfo", pid);
- if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return 0;
- num = read(fd, &p, sizeof p);
- close(fd);
- if(num != sizeof p) return 0;
-
- num = PRFNSZ;
- if (num >= sizeof P_cmd) num = sizeof P_cmd - 1;
- memcpy(P_cmd, p.pr_fname, num); // p.pr_fname or p.pr_lwp.pr_name
- P_cmd[num] = '\0';
-
- P_pid = p.pr_pid;
- P_ppid = p.pr_ppid;
- P_pgrp = p.pr_pgid;
- P_session = p.pr_sid;
- P_euid = p.pr_euid;
- P_rss = p.pr_rssize;
- P_vsize = p.pr_size;
- P_start_time = p.pr_start.tv_sec;
- P_wchan = p.pr_lwp.pr_wchan;
- P_state = p.pr_lwp.pr_sname;
- P_nice = p.pr_lwp.pr_nice;
- P_priority = p.pr_lwp.pr_pri; // or pr_oldpri
-// P_ruid = p.pr_uid;
-// P_rgid = p.pr_gid;
-// P_egid = p.pr_egid;
-
-#if 0
- // don't support these
- 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_timeout, P_alarm;
- 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_nswap, P_cnswap;
-#endif
-
- // we like it Linux-encoded :-)
- tty_maj = major(p.pr_ttydev);
- tty_min = minor(p.pr_ttydev);
- P_tty_num = DEV_ENCODE(tty_maj,tty_min);
-
- snprintf(P_tty_text, sizeof P_tty_text, "%3d,%-3d", tty_maj, tty_min);
-#if 1
- if (tty_maj == 24) snprintf(P_tty_text, sizeof P_tty_text, "pts/%-3u", tty_min);
- if (P_tty_num == NO_TTY_VALUE) memcpy(P_tty_text, " ? ", 8);
- if (P_tty_num == DEV_ENCODE(0,0)) memcpy(P_tty_text, "console", 8);
-#endif
-
- if(P_pid != pid) return 0;
- return 1;
-}
-#endif
-
-#ifdef __FreeBSD__
-/* return 1 if it works, or 0 for failure */
-static int stat2proc(int pid) {
- char buf[400];
- int num;
- int fd;
- char* tmp;
- int tty_maj, tty_min;
- snprintf(buf, 32, "/proc/%d/status", pid);
- if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return 0;
- num = read(fd, buf, sizeof buf - 1);
- close(fd);
- if(num<43) return 0;
- buf[num] = '\0';
-
- P_state = '-';
-
- // FreeBSD /proc/*/status is seriously fucked. Unlike the Linux
- // files, we can't use strrchr to find the end of a command name.
- // Spaces in command names do not get escaped. To avoid spoofing,
- // one may skip 20 characters and then look _forward_ only to
- // find a pattern of entries that are {with,with,without} a comma.
- // The entry without a comma is wchan. Then count backwards!
- //
- // Don't bother for now. FreeBSD isn't worth the trouble.
-
- tmp = strchr(buf,' ');
- num = tmp - buf;
- if (num >= sizeof P_cmd) num = sizeof P_cmd - 1;
- memcpy(P_cmd,buf,num);
- P_cmd[num] = '\0';
-
- num = sscanf(tmp+1,
- "%d %d %d %d "
- "%d,%d "
- "%*s "
- "%ld,%*d "
- "%ld,%*d "
- "%ld,%*d "
- "%*s "
- "%d %d ",
- &P_pid, &P_ppid, &P_pgrp, &P_session,
- &tty_maj, &tty_min,
- /* SKIP funny flags thing */
- &P_start_time, /* SKIP microseconds */
- &P_utime, /* SKIP microseconds */
- &P_stime, /* SKIP microseconds */
- /* SKIP &P_wchan, for now -- it is a string */
- &P_euid, &P_euid // don't know which is which
- );
-/* fprintf(stderr, "stat2proc converted %d fields.\n",num); */
-
- snprintf(P_tty_text, sizeof P_tty_text, "%3d,%-3d", tty_maj, tty_min);
- P_tty_num = DEV_ENCODE(tty_maj,tty_min);
-// tty decode is 224 to 256 bytes on i386
-#if 1
- tmp = NULL;
- if (tty_maj == 5) tmp = " ttyp%c ";
- if (tty_maj == 12) tmp = " ttyv%c ";
- if (tty_maj == 28) tmp = " ttyd%c ";
- if (P_tty_num == NO_TTY_VALUE) tmp = " ? ";
- if (P_tty_num == DEV_ENCODE(0,0)) tmp = "console";
- if (P_tty_num == DEV_ENCODE(12,255)) tmp = "consolectl";
- if (tmp) {
- snprintf(
- P_tty_text,
- sizeof P_tty_text,
- tmp,
- "0123456789abcdefghijklmnopqrstuvwxyz"[tty_min&31]
- );
- }
-#endif
-
- if(num < 9) return 0;
- if(P_pid != pid) return 0;
- return 1;
-}
-#endif
-
-#ifdef __linux__
-/* return 1 if it works, or 0 for failure */
-static int stat2proc(int pid) {
- char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
- int num;
- int fd;
- char* tmp;
- struct stat sb; /* stat() used to get EUID */
- snprintf(buf, 32, "/proc/%d/stat", pid);
- if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return 0;
- num = read(fd, buf, sizeof buf - 1);
- fstat(fd, &sb);
- P_euid = sb.st_uid;
- close(fd);
- if(num<80) return 0;
- buf[num] = '\0';
- tmp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
- *tmp = '\0'; /* replace trailing ')' with NUL */
- /* parse these two strings separately, skipping the leading "(". */
- memset(P_cmd, 0, sizeof P_cmd); /* clear */
- sscanf(buf, "%d (%15c", &P_pid, P_cmd); /* comm[16] in kernel */
- num = sscanf(tmp + 2, /* skip space after ')' too */
- "%c "
- "%d %d %d %d %d "
- "%lu %lu %lu %lu %lu %lu %lu "
- "%ld %ld %ld %ld %ld %ld "
- "%lu %lu "
- "%ld "
- "%lu %lu %lu %lu %lu %lu "
- "%u %u %u %u " /* no use for RT signals */
- "%lu %lu %lu",
- &P_state,
- &P_ppid, &P_pgrp, &P_session, &P_tty_num, &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_alarm,
- &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, &P_nswap, &P_cnswap
- );
-/* fprintf(stderr, "stat2proc converted %d fields.\n",num); */
- P_vsize /= 1024;
- P_rss *= (PAGE_SIZE/1024);
-
- memcpy(P_tty_text, " ? ", 8);
- if (P_tty_num != NO_TTY_VALUE) {
- int tty_maj = (P_tty_num>>8)&0xfff;
- int tty_min = (P_tty_num&0xff) | ((P_tty_num>>12)&0xfff00);
- snprintf(P_tty_text, sizeof P_tty_text, "%3d,%-3d", tty_maj, tty_min);
- }
-
- if(num < 30) return 0;
- if(P_pid != pid) return 0;
- return 1;
-}
-#endif
-
-static const char *do_time(unsigned long t){
- int hh,mm,ss;
- static char buf[32];
- int cnt = 0;
- t /= HZ;
- ss = t%60;
- t /= 60;
- mm = t%60;
- t /= 60;
- hh = t%24;
- t /= 24;
- if(t) cnt = snprintf(buf, sizeof buf, "%d-", (int)t);
- snprintf(cnt + buf, sizeof(buf)-cnt, "%02d:%02d:%02d", hh, mm, ss);
- return buf;
-}
-
-static const char *do_user(void){
- static char buf[32];
- static struct passwd *p;
- static int lastuid = -1;
- if(P_euid != lastuid){
- p = getpwuid(P_euid);
- if(p) snprintf(buf, sizeof buf, "%-8.8s", p->pw_name);
- else snprintf(buf, sizeof buf, "%5d ", P_euid);
- }
- return buf;
-}
-
-static const char *do_cpu(int longform){
- static char buf[8];
- strcpy(buf," - ");
- if(!longform) buf[2] = '\0';
- return buf;
-}
-
-static const char *do_mem(int longform){
- static char buf[8];
- strcpy(buf," - ");
- if(!longform) buf[2] = '\0';
- return buf;
-}
-
-static const char *do_stime(void){
- static char buf[32];
- strcpy(buf," - ");
- return buf;
-}
-
-static void print_proc(void){
- switch(ps_format){
- case 0:
- printf("%5d %s %s", P_pid, P_tty_text, do_time(P_utime+P_stime));
- break;
- case 'o':
- printf("%d\n", P_pid);
- return; /* don't want the command */
- case 'l':
- printf(
- "0 %c %5d %5d %5d %s %3d %3d - "
- "%5ld %06x %s %s",
- P_state, P_euid, P_pid, P_ppid, do_cpu(0),
- (int)P_priority, (int)P_nice, P_vsize/(PAGE_SIZE/1024),
- (unsigned)(P_wchan&0xffffff), P_tty_text, do_time(P_utime+P_stime)
- );
- break;
- case 'f':
- printf(
- "%8s %5d %5d %s %s %s %s",
- do_user(), P_pid, P_ppid, do_cpu(0), do_stime(), P_tty_text, do_time(P_utime+P_stime)
- );
- break;
- case 'j':
- printf(
- "%5d %5d %5d %s %s",
- P_pid, P_pgrp, P_session, P_tty_text, do_time(P_utime+P_stime)
- );
- break;
- case 'u'|0x80:
- printf(
- "%8s %5d %s %s %5ld %4ld %s %c %s %s",
- do_user(), P_pid, do_cpu(1), do_mem(1), P_vsize, P_rss, P_tty_text, P_state,
- do_stime(), do_time(P_utime+P_stime)
- );
- break;
- case 'v'|0x80:
- printf(
- "%5d %s %c %s %6d - - %5d %s",
- P_pid, P_tty_text, P_state, do_time(P_utime+P_stime), (int)P_maj_flt,
- (int)P_rss, do_mem(1)
- );
- break;
- case 'j'|0x80:
- printf(
- "%5d %5d %5d %5d %s %5d %c %5d %s",
- P_ppid, P_pid, P_pgrp, P_session, P_tty_text, P_tpgid, P_state, P_euid, do_time(P_utime+P_stime)
- );
- break;
- case 'l'|0x80:
- printf(
- "0 %5d %5d %5d %3d %3d "
- "%5ld %4ld %06x %c %s %s",
- P_euid, P_pid, P_ppid, (int)P_priority, (int)P_nice,
- P_vsize, P_rss, (unsigned)(P_wchan&0xffffff), P_state, P_tty_text, do_time(P_utime+P_stime)
- );
- break;
- default:
- ;
- }
- if(show_args) printf(" [%s]\n", P_cmd);
- else printf(" %s\n", P_cmd);
-}
-
-
-int main(int argc, char *argv[]){
- arg_parse(argc, argv);
-#if 0
- choose_dimensions();
-#endif
- if(!old_h_option){
- const char *head;
- switch(ps_format){
- default: /* can't happen */
- case 0: head = " PID TTY TIME CMD"; break;
- case 'l': head = "F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD"; break;
- case 'f': head = "USER PID PPID C STIME TTY TIME CMD"; break;
- case 'j': head = " PID PGID SID TTY TIME CMD"; break;
- case 'u'|0x80: head = "USER PID %CPU %MEM VSZ RSS TTY S START TIME COMMAND"; break;
- case 'v'|0x80: head = " PID TTY S TIME MAJFL TRS DRS RSS %MEM COMMAND"; break;
- case 'j'|0x80: head = " PPID PID PGID SID TTY TPGID S UID TIME COMMAND"; break;
- case 'l'|0x80: head = "F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND"; break;
- }
- printf("%s\n",head);
- }
- if(want_one_pid){
- if(stat2proc(want_one_pid)) print_proc();
- else exit(1);
- }else{
- struct dirent *ent; /* dirent handle */
- DIR *dir;
- int ouruid;
- int found_a_proc;
- found_a_proc = 0;
- ouruid = getuid();
- dir = opendir("/proc");
- while(( ent = readdir(dir) )){
- if(*ent->d_name<'0' || *ent->d_name>'9') continue;
- if(!stat2proc(atoi(ent->d_name))) continue;
- if(want_one_command){
- if(strcmp(want_one_command,P_cmd)) continue;
- }else{
- if(!select_notty && P_tty_num==NO_TTY_VALUE) continue;
- if(!select_all && P_euid!=ouruid) continue;
- }
- found_a_proc++;
- print_proc();
- }
- closedir(dir);
- exit(!found_a_proc);
- }
- return 0;
-}
+++ /dev/null
-See http://www.freelists.org/post/procps/Scan-results,5
-
-
- based on:
-filtered-with-patches.err
-
- these are the categories i've assigned:
-defect_was_fixed
- EVALUATION_ORDER
- pmap
- TAINTED_STRING
- tload
-
-possibly_filter_out_?
- MISSING_BREAK
- slabtop
- ps/output
-
-avoidable_false_positive
- DEADCODE
- proc/readproc
- FORWARD_NULL
- top
- vmstat
- RESOURCE_LEAK
- ps/parser (3)
- STRING_NULL
- pwdx
- proc/readproc
- TAINTED_SCALAR
- pgrep
- slabtop
- top (3)
- TAINTED_STRING
- watch (2)
- TOCTOU
- sysctl (2)
- UNINIT
- ps/output (2)
-
-unavoidable_false_positive_?
- UNREACHABLE
- ps/sortformat
-
-unavoidable_false_positive_but_patched_anyway
- OVERRUN_STATIC
- top (no defect, but i yield)
-
-
-
- pgrep ------------------------------------------------------------------------
-Error: TAINTED_SCALAR:
- agree that argv might be tainted
- but the (int)argv[1][1] index is being passed to isdigit() function (and glibc safely indexes into array sized at 384 bytes)
- my_category: avoidable_false_positive (out of step with current glibc implementation)
-pgrep.c:720: tainted_data: Passing tainted variable "argv" to a tainted sink.
-pgrep.c:558: data_index: Using tainted variable "(int)argv[1][1]" as an index to pointer "*__ctype_b_loc()".
-
-
- pmap -------------------------------------------------------------------------
-Error: EVALUATION_ORDER:
- agree that there is a problem.
- moreover, it deals with an undocumented command line argument (but sami has documentation addition pending)
- the logic was altered in line with intent, hopefully avoids this warning
- my_category: defect_was_fixed
-pmap.c:314: write_write_order: In "arg2 = (arg2 ? arg2++ : arg1)", "arg2" is written in "arg2" (the assignment left-hand side) and written in "arg2 ? arg2++ : arg1" but the order in which the side effects take place is undefined because there is no intervening sequence point.
-
-
-
- pwdx -------------------------------------------------------------------------
-Error: STRING_NULL:
- static buffer is initialized to 0
- it is +1 larger than size passed to readlink
- was fixed in previous analysis
- my_category: avoidable_false_positive
-pwdx.c:86: string_null_argument: Function "readlink" does not terminate string "*buf".
-pwdx.c:73: var_assign_var: Assigning: "s" = "buf". Both now point to the same unterminated string.
-pwdx.c:73: var_assign_var: Assigning: "s" = "buf". Both now point to the same unterminated string.
-pwdx.c:73: var_assign_var: Assigning: "s" = "buf". Both now point to the same unterminated string.
-pwdx.c:92: string_null: Passing unterminated string "s" to "printf".
-
-
-
- slabtop ----------------------------------------------------------------------
-Error: MISSING_BREAK:
- intentional fall through after setting return code
- no change made
- my_category: possibly_filter_out_?
-slabtop.c:314: unterminated_case: This case (value 104) is not terminated by a 'break' statement.
-slabtop.c:316: fallthrough: The above case falls through to this one.
-
-Error: TAINTED_SCALAR:
- read limited to single byte signed 'char'
- ultimately passed to toupper() function (and glibc safely indexes into array sized at 384 bytes)
- my_category: avoidable_false_positive (out of step with current glibc implementation)
-slabtop.c:387: tainted_data_argument: Calling function "read" taints argument "c".
-slabtop.c:389: tainted_data: Passing tainted variable "c" to a tainted sink.
-slabtop.c:233: data_index: Using tainted variable "(int)c" as an index to pointer "*__ctype_toupper_loc()".
-
-
-
- sysctl -----------------------------------------------------------------------
-Error: TOCTOU:
- the pathlength between these two events cannot be reduced further
- instead of assessing intervening lines of code, perhaps tool should assess 'if' statements (2)
- my_category: avoidable_false_positive
-sysctl.c:149: fs_check_call: Calling function "stat" to perform check on "tmpname".
-sysctl.c:168: toctou: Calling function "fopen" that uses "tmpname" after a check function. This can cause a time-of-check, time-of-use race condition.
-
-Error: TOCTOU:
- the pathlength between these two events cannot be reduced further
- instead of assessing intervening lines of code, perhaps tool should assess 'if' statements (2)
- my_category: avoidable_false_positive
-sysctl.c:327: fs_check_call: Calling function "stat" to perform check on "tmpname".
-sysctl.c:345: toctou: Calling function "fopen" that uses "tmpname" after a check function. This can cause a time-of-check, time-of-use race condition.
-
-
-
- tload ------------------------------------------------------------------------
-Error: TAINTED_STRING:
- altered perror call to provide an untainted string
- my_category: defect_was_fixed
-tload.c:89: tainted_string: Passing tainted string "argv[optind]" to a function that cannot accept tainted data.
-
-
-
- top --------------------------------------------------------------------------
-Error: FORWARD_NULL:
- cpus cannot be NULL without fp also being NULL
- the very next 'if (!fp)' ensures cpus will be allocated
- my_category: avoidable_false_positive
-top.c:1790: assign_zero: Assigning: "cpus" = 0.
-top.c:1807: var_deref_op: Dereferencing null variable "cpus".
-
-Error: OVERRUN_STATIC:
- This "error" is centered around the following code:
- f = w->pflgsall[i + w->begpflg];
- w->procflgs[i] = f;
- #ifndef USE_X_COLHDR
- if (P_MAXPFLGS < f) continue;
- #endif
- h = Fieldstab[f].head;
-
- The enum P_MAXPFLGS is strictly a fencepost and can *never* appear in the arrays pflgsall or procflgs.
- Thus it (39th element) cannot be used in referencing Fieldstab.
- However, two enums of higher value (X_XON=40 and X_XOF=41) *can* appear in those arrays.
- But the test against the fencepost ensures that those two enums are *never* used in referencing Fieldstab.
-
- When the analyzer sees the conditional using '<' and not '<=' it reports a false positive.
-
- i'm tired of explaining this so the program was changed to accommodate the tool's deficiency
- my_category: unavoidable_false_positive_but_patched_anyway
-top.c:1417: overrun-local: Overrunning static array "Fieldstab", with 39 elements, at position 39 with index variable "f".
-
-Error: TAINTED_SCALAR:
- the index is used subordinate to a case statement ensuring a value between '1' and '4'
- my_category: avoidable_false_positive
-top.c:2442: tainted_data_argument: Calling function "chin" taints argument "ch".
-top.c:848: tainted_data_argument: Calling function "read" taints parameter "*buf".
-top.c:2452: tainted_data: Using tainted variable "ch - 49" as an index into an array "Winstk".
-
-Error: TAINTED_SCALAR:
- the index is used subordinate to as case statement ensuring a value between '1' and '4'
- my_category: avoidable_false_positive
-top.c:2719: tainted_data_argument: Calling function "chin" taints argument "ch".
-top.c:848: tainted_data_argument: Calling function "read" taints parameter "*buf".
-top.c:2720: tainted_data: Passing tainted variable "ch" to a tainted sink.
-top.c:2452: data_index: Using tainted variable "ch - 49" as an index to array "Winstk".
-
-Error: TAINTED_SCALAR:
- buf tainted by chin is zero terminated
- single char is ultimately passed to isprintf() function (and glibc safely indexes into array sized at 384 bytes)
- my_category: avoidable_false_positive (out of step with current glibc implementation)
-top.c:972: tainted_data_return: Function "keyin" returns tainted data.
-top.c:912: tainted_data_argument: Function "chin" taints argument "buf".
-top.c:848: tainted_data_argument: Calling function "read" taints parameter "*buf".
-top.c:926: return_tainted_data: Returning tainted variable "buf[0]".
-top.c:972: var_assign: Assigning: "key" = "keyin", which taints "key".
-top.c:1001: tainted_data: Using tainted variable "(int)key" as an index to pointer "*__ctype_b_loc()".
-
-
-
- vmstat -----------------------------------------------------------------------
-Error: FORWARD_NULL:
- partition made non-null with optarg for -p where statMode |= PARTITIONSTAT
- if no optarg then program exits with usage
- thus call to diskpartition_format will be with non-null pointer
- my_category: avoidable_false_positive
-vmstat.c:593: assign_zero: Assigning: "partition" = 0.
-vmstat.c:669: var_deref_model: Passing null variable "partition" to function "diskpartition_format", which dereferences it.
-vmstat.c:301: deref_parm_in_call: Function "strcmp" dereferences parameter "partition_name". (The dereference is assumed on the basis of the 'nonnull' parameter attribute.)
-
-
-
- watch ------------------------------------------------------------------------
-Error: TAINTED_STRING:
- even though the environment variable COLUMNS might begin tainted, from my analysis, the tool is totally mistaken
- strtol actually untaints data in the form of 't' and 'endptr' then the environment variable COLUMNS is potentially purified with -1
- my_category: avoidable_false_positive
-watch.c:95: tainted_string_return_content: "getenv" returns tainted string content.
-watch.c:95: var_assign: Assigning: "s" = "getenv("COLUMNS")", which taints "s".
-watch.c:100: tainted_data_transitive: Call to function "strtol" with tainted argument "s" returns tainted data.
-watch.c:100: var_assign: Assigning: "t" = "strtol(s, &endptr, 0)", which taints "t".
-watch.c:101: var_assign_var: Assigning: "incoming_cols" = "(int)t". Both are now tainted.
-watch.c:102: var_assign_var: Assigning: "width" = "incoming_cols". Both are now tainted.
-watch.c:103: vararg_transitive: Call to "snprintf" with tainted argument "width" taints "env_col_buf".
-watch.c:104: tainted_string: Passing tainted string "env_col_buf" to a function that cannot accept tainted data.
-
-Error: TAINTED_STRING:
- even though the environment variable LINES might begin tainted, from my analysis, the tool is totally mistaken
- strtol actually untaints data in the form of 't' and 'endptr' then the environment variable LINES is potentially purified with -1
- my_category: avoidable_false_positive
-watch.c:108: tainted_string_return_content: "getenv" returns tainted string content.
-watch.c:108: var_assign: Assigning: "s" = "getenv("LINES")", which taints "s".
-watch.c:113: tainted_data_transitive: Call to function "strtol" with tainted argument "s" returns tainted data.
-watch.c:113: var_assign: Assigning: "t" = "strtol(s, &endptr, 0)", which taints "t".
-watch.c:114: var_assign_var: Assigning: "incoming_rows" = "(int)t". Both are now tainted.
-watch.c:115: var_assign_var: Assigning: "height" = "incoming_rows". Both are now tainted.
-watch.c:116: vararg_transitive: Call to "snprintf" with tainted argument "height" taints "env_row_buf".
-watch.c:117: tainted_string: Passing tainted string "env_row_buf" to a function that cannot accept tainted data.
-
-
-
- proc/readproc ----------------------------------------------------------------
-Error: DEADCODE:
- the tool does not understand gperf and the pseudo case labels preceded by goto
- the following code snippets illustrate the deficiency:
- goto *(&&base + entry.offset);
- ...
- case_Threads:
- Threads = strtol(S,&S,10);
- continue;
- my_category: avoidable_false_positive
-proc/readproc.c:387: dead_error_condition: On this path, the condition "Threads" cannot be true.
-proc/readproc.c:115: const: After this line, the value of "Threads" is equal to 0.
-proc/readproc.c:115: assignment: Assigning: "Threads" = "0L".
-proc/readproc.c:388: dead_error_begin: Execution cannot reach this statement "P->nlwp = Threads;".
-
-Error: STRING_NULL:
- read is asked to retrieve -1 bytes than passed capacity: num_read = read(fd, ret, cap - 1);
- file2str does indeed null terminate sbuf: ret[num_read] = '\0';
- my_category: avoidable_false_positive
-proc/readproc.c:1193: string_null_argument: Function "file2str" does not terminate string "*sbuf".
-proc/readproc.c:514: string_null_argument: Function "read" fills array "*ret" with a non-terminated string.
-proc/readproc.c:1197: string_null: Passing unterminated string "sbuf" to a function expecting a null-terminated string.
-proc/readproc.c:447: string_null_sink_parm_call: Passing parameter "S" to "strchr" which expects a null-terminated string.
-
-
-
- ps/output --------------------------------------------------------------------
-Error: MISSING_BREAK:
- intentional fall through
- my_category: possibly_filter_out_?
-ps/output.c:1983: unterminated_default: The default case is not terminated by a 'break' statement.
-ps/output.c:1984: fallthrough: The above case falls through to this one.
-
-Error: UNINIT:
- the first member is initialized in the very next statement, sufficient for bsearch callback
- key.spec = findme;
- my_category: avoidable_false_positive
-ps/output.c:1737: var_decl: Declaring variable "key" without initializer.
-ps/output.c:1739: uninit_use_in_call: Using uninitialized value "key": field "key".flags is uninitialized when calling "bsearch".
-
-Error: UNINIT:
- the first member is initialized in the very next statement, sufficient for bsearch callback
- key.spec = findme;
- my_category: avoidable_false_positive
-ps/output.c:1745: var_decl: Declaring variable "key" without initializer.
-ps/output.c:1747: uninit_use_in_call: Using uninitialized value "key": field "key".head is uninitialized when calling "bsearch".
-
-
-
- ps/parser --------------------------------------------------------------------
-Error: RESOURCE_LEAK:
- intentional omission
- abexit shortly
- my_category: avoidable_false_positive
-ps/parser.c:1021: alloc_fn: Calling allocation function "malloc".
-ps/parser.c:1021: var_assign: Assigning: "pidnode" = storage returned from "malloc(sizeof (selection_node) /*24*/)".
-ps/parser.c:1041: leaked_storage: Variable "pidnode" going out of scope leaks the storage it points to.
-ps/parser.c:1062: leaked_storage: Variable "pidnode" going out of scope leaks the storage it points to.
-
-Error: RESOURCE_LEAK:
- intentional omission
- abexit shortly
- my_category: avoidable_false_positive
-ps/parser.c:1025: alloc_fn: Calling allocation function "malloc".
-ps/parser.c:1025: var_assign: Assigning: "grpnode" = storage returned from "malloc(sizeof (selection_node) /*24*/)".
-ps/parser.c:1041: leaked_storage: Variable "grpnode" going out of scope leaks the storage it points to.
-ps/parser.c:1062: leaked_storage: Variable "grpnode" going out of scope leaks the storage it points to.
-
-Error: RESOURCE_LEAK:
- intentional omission
- abexit shortly
- my_category: avoidable_false_positive
-ps/parser.c:1029: alloc_fn: Calling allocation function "malloc".
-ps/parser.c:1029: var_assign: Assigning: "sidnode" = storage returned from "malloc(sizeof (selection_node) /*24*/)".
-ps/parser.c:1041: leaked_storage: Variable "sidnode" going out of scope leaks the storage it points to.
-ps/parser.c:1062: leaked_storage: Variable "sidnode" going out of scope leaks the storage it points to.
-
-
-
- ps/sortformat ----------------------------------------------------------------
-Error: UNREACHABLE:
- the tool does not understand the following 'label' usage (nor do i - perhaps some obscure compiler/platform warning/quirk)
- goto unknown;
- ...
- if(0) unknown: err=errbuf;
- my_category: unavoidable_false_positive_?
-ps/sortformat.c:312: unreachable: This code cannot be reached: "if (0){
- unknown:
- err = ...".
+++ /dev/null
-/*
- * w.c - show logged users and what they are doing
- *
- * Copyright (c) Dec 1993, Oct 1994 Steve "Mr. Bassman" Bryant
- * bassman@hpbbi30.bbn.hp.com (Old address)
- * bassman@muttley.soc.staffs.ac.uk
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/* An alternative "w" program for Linux.
- * Shows users and their processes.
- *
- * Info:
- * I starting writing as an improvement of the w program included
- * with linux. The idea was to add in some extra functionality to the
- * program, and see if I could fix a couple of bugs which seemed to
- * occur.
- * Mr. Bassman, 10/94
- *
- * Acknowledgments:
- *
- * The original version of w:
- * Copyright (c) 1993 Larry Greenfield (greenfie@gauss.rutgers.edu)
- *
- * Uptime routine and w mods:
- * Michael K. Johnson (johnsonm@stolaf.edu)
- *
- *
- * Distribution:
- * This program is freely distributable under the terms of copyleft.
- * No warranty, no support, use at your own risk etc.
- *
- * Compilation:
- * gcc -O -o w sysinfo.c whattime.c w.c
- *
- * Usage:
- * w [-hfusd] [user]
- *
- *
- * $Log: tmp-junk.c,v $
- * Revision 1.1 2002/02/01 22:46:37 csmall
- * Initial revision
- *
- * Revision 1.5 1994/10/26 17:57:35 bassman
- * Loads of stuff - see comments.
- *
- * Revision 1.4 1994/01/01 12:57:21 johnsonm
- * Added RCS, and some other fixes.
- *
- * Revision history:
- * Jan 01, 1994 (mkj): Eliminated GCC warnings, took out unnecessary
- * dead variables in fscanf, replacing them with
- * *'d format qualifiers. Also added RCS stuff.
- * Oct 26, 1994 (bass): Tidied up the code, fixed bug involving corrupt
- * utmp records. Added switch for From field;
- * default is compile-time set. Added -d option
- * as a remnant from BSD 'w'. Fixed bug so it now
- * behaves if the first process on a tty isn't owned
- * by the person first logged in on that tty, and
- * also detects su'd users. Changed the tty format
- * to the short one.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <time.h>
-#include <utmp.h>
-#include <unistd.h>
-#include <errno.h>
-#include <pwd.h>
-#include "proc/whattime.h"
-
-
-#define TRUE 1
-#define FALSE 0
-/*
- * Default setting for whether to have a From field. The -f switch
- * toggles this - if the default is to have it, using -f will turn
- * it off; if the default is not to have it, the -f switch will put
- * it in. Possible values are TRUE (to have the field by default),
- * and FALSE.
- */
-#define DEFAULT_FROM TRUE
-#define ZOMBIE "<zombie>"
-
-
-void put_syntax();
-char *idletime();
-char *logintime();
-
-static char rcsid[]="$Id: tmp-junk.c,v 1.1 2002/02/01 22:46:37 csmall Exp $";
-
-
-void main (argc, argv)
-
-int argc;
-char *argv[];
-
-{
- int header=TRUE, long_format=TRUE, ignore_user=TRUE,
- from_switch=DEFAULT_FROM, show_pid=FALSE, line_length;
- int i, j;
- struct utmp *utmp_rec;
- struct stat stat_rec;
- struct passwd *passwd_entry;
- uid_t uid;
- char username[9], tty[13], rhost[17], login_time[27];
- char idle_time[7], what[1024], pid[10];
- char out_line[1024], file_name[256];
- char search_name[9];
- int jcpu, pcpu, tpgid, curr_pid, utime, stime, cutime, cstime;
- char /*ch,*/ state, comm[1024], *columns_ptr;
- FILE *fp;
-
-
- search_name[0] = '\0';
-
-
- /*
- * Process the command line
- */
- if (argc > 1)
- {
- /*
- * Args that start with '-'
- */
- for (i = 1; ((i < argc) && (argv[i][0] == '-')); i ++)
- {
- for (j = 1; argv[i][j] != '\0'; j++)
- {
- switch (argv[i][j])
- {
- case 'h':
- header = FALSE;
- break;
- case 's':
- long_format = FALSE;
- break;
- case 'u':
- ignore_user = FALSE;
- break;
- case 'd':
- show_pid = TRUE;
- break;
- case 'f':
- if (DEFAULT_FROM == TRUE)
- from_switch = FALSE;
- else
- from_switch = TRUE;
- break;
- default:
- fprintf (stderr, "w: unknown option: '%c'\n",
- argv[i][j]);
- put_syntax ();
- break;
- }
- }
- }
-
-
- /*
- * Check for arg not starting with '-' (ie: username)
- */
- if (argc > i)
- {
- strncpy (search_name, argv[i], 8);
- search_name[8] = '\0';
- i ++;
-
- if (argc > i)
- {
- fprintf (stderr, "w: syntax error\n");
- put_syntax ();
- }
- }
- }
-
-
-
- /*
- * Check that /proc is actually there, or else we can't
- * get all the information.
- */
- if (chdir ("/proc"))
- {
- fprintf (stderr, "w: fatal error: cannot access /proc\n");
- perror (strerror(errno));
- exit (-1);
- }
-
-
-
- /*
- * Find out our screen width from $COLUMNS
- */
- columns_ptr = getenv ("COLUMNS");
- if (columns_ptr == NULL)
- {
- struct winsize window;
-
- /*
- * Try getting it directly
- */
- if ((ioctl (1, TIOCGWINSZ, &window) != 1) && (window.ws_col > 0))
- line_length = window.ws_col;
- else
- line_length = 80; /* Default length assumed */
- }
- else
- line_length = atoi (columns_ptr);
-
- /*
- * Maybe we should check whether there is enough space on
- * the lines for the options selected...
- */
- if (line_length < 60)
- long_format = FALSE;
-
- line_length --;
-
-
- /*
- * Print whatever headers
- */
- if (header == TRUE)
- {
- /*
- * uptime: from MKJ's uptime routine,
- * found in whattime.c
- */
- print_uptime();
-
-
- /*
- * Print relevant header bits
- */
- printf ("User tty ");
-
- if (long_format == TRUE)
- {
- if (from_switch == TRUE)
- printf ("From ");
-
- printf (" login@ idle JCPU PCPU ");
-
- if (show_pid == TRUE)
- printf (" PID ");
-
- printf ("what\n");
- }
- else
- {
- printf (" idle ");
-
- if (show_pid == TRUE)
- printf (" PID ");
-
- printf ("what\n");
- }
- }
-
-
-
-
- /*
- * Process user information.
- */
- while ((utmp_rec = getutent()))
- {
- /*
- * Check we actually want to see this record.
- * It must be a valid active user process,
- * and match a specified search name.
- */
- if ( (utmp_rec->ut_type == USER_PROCESS)
- && (strcmp(utmp_rec->ut_user, ""))
- && ( (search_name[0] == '\0')
- || ( (search_name[0] != '\0')
- && !strncmp(search_name, utmp_rec->ut_user, 8) ) ) )
- {
- /*
- * Get the username
- */
- strncpy (username, utmp_rec->ut_user, 8);
- username[8] = '\0'; /* Set end terminator */
-
-
- /*
- * Find out the uid of that user (from their
- * passwd entry)
- */
- uid = -1;
- if ((passwd_entry = getpwnam (username)) != NULL)
- {
- uid = passwd_entry->pw_uid;
- }
-
- /*
- * Get (and clean up) the tty line
- */
- for (i = 0; (utmp_rec->ut_line[i] > 32) && (i < 6); i ++)
- tty[i] = utmp_rec->ut_line[i];
-
- utmp_rec->ut_line[i] = '\0';
- tty[i] = '\0';
-
-
- /*
- * Don't bother getting info if it's not asked for
- */
- if (long_format == TRUE)
- {
-
- /*
- * Get the remote hostname; this can be up to 16 chars,
- * but if any chars are invalid (ie: [^a-zA-Z0-9\.])
- * then the char is changed to a string terminator.
- */
- if (from_switch == TRUE)
- {
- strncpy (rhost, utmp_rec->ut_host, 16);
- rhost[16] = '\0';
-
- }
-
-
- /*
- * Get the login time
- * (Calculated by LG's routine, below)
- */
- strcpy (login_time, logintime(utmp_rec->ut_time));
- }
-
-
-
- /*
- * Get the idle time.
- * (Calculated by LG's routine, below)
- */
- strcpy (idle_time, idletime (tty));
-
-
-
- /*
- * That's all the info out of /etc/utmp.
- * The rest is more difficult. We use the pid from
- * utmp_rec->ut_pid to look in /proc for the info.
- * NOTE: This is not necessarily the active pid, so we chase
- * down the path of parent -> child pids until we find it,
- * according to the information given in /proc/<pid>/stat.
- */
-
- sprintf (pid, "%d", utmp_rec->ut_pid);
-
- what[0] = '\0';
- strcpy (file_name, pid);
- strcat (file_name, "/stat");
- jcpu = 0;
- pcpu = 0;
-
- if ((fp = fopen(file_name, "r")))
- {
- while (what[0] == '\0')
- {
- /*
- * Check /proc/<pid>/stat to see if the process
- * controlling the tty is the current one
- */
- fscanf (fp, "%d %s %c %*d %*d %*d %*d %d "
- "%*u %*u %*u %*u %*u %d %d %d %d",
- &curr_pid, comm, &state, &tpgid,
- &utime, &stime, &cutime, &cstime);
-
- fclose (fp);
-
- if (comm[0] == '\0')
- strcpy (comm, "-");
-
- /*
- * Calculate jcpu and pcpu.
- * JCPU is the time used by all processes and their
- * children, attached to the tty.
- * PCPU is the time used by the current process
- * (calculated once after the loop, using last
- * obtained values).
- */
- if (!jcpu)
- jcpu = cutime + cstime;
-
- /*
- * Check for a zombie first...
- */
- if (state == 'Z')
- strcpy (what, ZOMBIE);
- else if (curr_pid == tpgid)
- {
- /*
- * If it is the current process, read cmdline
- * If that's empty, then the process is swapped out,
- * or is a zombie, so we use the command given in stat
- * which is in normal round brackets, ie: "()".
- */
- strcpy (file_name, pid);
- strcat (file_name, "/cmdline");
- if ((fp = fopen(file_name, "r")))
- {
- i = 0;
- j = fgetc (fp);
- while ((j != EOF) && (i < 256))
- {
- if (j == '\0')
- j = ' ';
-
- what[i] = j;
- i++;
- j = fgetc (fp);
- }
- what[i] = '\0';
- fclose (fp);
- }
-
- if (what[0] == '\0')
- strcpy (what, comm);
- }
- else
- {
- /*
- * Check out the next process
- * If we can't open it, use info from this process,
- * so we have to check out cmdline first.
- *
- * If we're not using "-u" then should we just
- * say "-" (or "-su") instead of a command line ?
- * If so, we should strpcy(what, "-"); when we
- * fclose() in the if after the stat() below.
- */
- strcpy (file_name, pid);
- strcat (file_name, "/cmdline");
-
- if ((fp = fopen (file_name, "r")))
- {
- i = 0;
- j = fgetc (fp);
- while ((j != EOF) && (i < 256))
- {
- if (j == '\0')
- j = ' ';
-
- what[i] = j;
- i++;
- j = fgetc (fp);
- }
- what[i] = '\0';
- fclose (fp);
- }
-
- if (what[0] == '\0')
- strcpy (what, comm);
-
- /*
- * Now we have something in the what variable,
- * in case we can't open the next process.
- */
- sprintf (pid, "%d", tpgid);
- strcpy (file_name, pid);
- strcat (file_name, "/stat");
-
- fp = fopen (file_name, "r");
-
- if (fp && (ignore_user == FALSE))
- {
- /*
- * We don't necessarily go onto the next process,
- * unless we are either ignoring who the effective
- * user is, or it's the same uid
- */
- stat (file_name, &stat_rec);
-
- /*
- * If the next process is not owned by this
- * user finish the loop.
- */
- if (stat_rec.st_uid != uid)
- {
- fclose (fp);
-
- strcpy (what, "-su");
- /*
- * See comment above somewhere; I've used
- * "-su" here, as the next process is owned
- * by someone else; this is generally
- * because the user has done an "su" which
- * then exec'd something else.
- */
- }
- else
- what[0] = '\0';
- }
- else if (fp) /* else we are ignoring uid's */
- what[0] = '\0';
- }
- }
- }
- else /* Could not open first process for user */
- strcpy (what, "?");
-
-
- /*
- * There is a bug somewhere in my version of linux
- * which means that utmp records are not cleaned
- * up properly when users log out. However, we
- * can detect this, by the users first process
- * not being there when we look in /proc.
- */
-
-
- /*
- * Don't output a line for "dead" users.
- * This gets round a bug which doesn't update utmp/wtmp
- * when users log out.
- */
- if (what[0] != '?')
- {
-#ifdef 0
-/* This makes unix98 pty's not line up, so has been disabled - JEH. */
- /*
- * Remove the letters 'tty' from the tty id
- */
- if (!strncmp (tty, "tty", 3))
- {
- for (i = 3; tty[i - 1] != '\0'; i ++)
- tty[i - 3] = tty[i];
- }
-#endif
-
- /*
- * Common fields
- */
- sprintf (out_line, "%-9.8s%-6.7s ", username, tty);
-
-
- /*
- * Format the line for output
- */
- if (long_format == TRUE)
- {
- /*
- * Calculate CPU usage
- */
- pcpu = utime + stime;
- jcpu /= 100;
- pcpu /= 100;
-
- if (from_switch == TRUE)
- sprintf (out_line, "%s %-16.15s", out_line, rhost);
-
- sprintf (out_line, "%s%8.8s ", out_line, login_time);
-
- }
-
- sprintf (out_line, "%s%6s", out_line, idle_time);
-
-
- if (long_format == TRUE)
- {
- if (!jcpu)
- strcat (out_line, " ");
- else if (jcpu/60)
- sprintf (out_line, "%s%3d:%02d", out_line,
- jcpu/60, jcpu%60);
- else
- sprintf (out_line, "%s %2d", out_line, jcpu);
-
- if (!pcpu)
- strcat (out_line, " ");
- else if (pcpu/60)
- sprintf (out_line, "%s%3d:%02d", out_line,
- pcpu/60, pcpu%60);
- else
- sprintf (out_line, "%s %2d", out_line, pcpu);
- }
-
- if (show_pid == TRUE)
- sprintf (out_line, "%s %5.5s", out_line, pid);
-
-
- strcat (out_line, " ");
- strcat (out_line, what);
-
-
- /*
- * Try not to exceed the line length
- */
- out_line[line_length] = '\0';
-
- printf ("%s\n", out_line);
- }
- }
- }
-}
-
-
-
-/*
- * put_syntax()
- *
- * Routine to print the correct syntax to call this program,
- * and then exit out appropriately
- */
-void put_syntax ()
-{
- fprintf (stderr, "usage: w [-hfsud] [user]\n");
- exit (-1);
-}
-
-
-
-/*
- * idletime()
- *
- * Routine which returns a string containing
- * the idle time of a given user.
- *
- * This routine was lifted from the original w program
- * by Larry Greenfield (greenfie@gauss.rutgers.edu)
- * Copyright (c) 1993 Larry Greenfield
- *
- */
-char *idletime (tty)
-
-char *tty;
-
-{
- struct stat terminfo;
- unsigned long idle;
- char ttytmp[40];
- static char give[20];
- time_t curtime;
-
- curtime = time (NULL);
-
- sprintf (ttytmp, "/dev/%s", tty);
- stat (ttytmp, &terminfo);
- idle = (unsigned long) curtime - (unsigned long) terminfo.st_atime;
-
- if (idle >= (60 * 60)) /* more than an hour */
- {
- if (idle >= (60 * 60 * 48)) /* more than two days */
- sprintf (give, "%2ludays", idle / (60 * 60 * 24));
- else
- sprintf (give, " %2lu:%02u", idle / (60 * 60),
- (unsigned) ((idle / 60) % 60));
- }
- else
- {
- if (idle / 60)
- sprintf (give, "%6lu", idle / 60);
- else
- give[0]=0;
- }
-
- return give;
-}
-
-
-
-/*
- * logintime()
- *
- * Returns the time given in a suitable format
- *
- * This routine was lifted from the original w program
- * by Larry Greenfield (greenfie@gauss.rutgers.edu)
- * Copyright (c) 1993 Larry Greenfield
- *
- */
-
-#undef ut_time
-
-char *logintime(ut_time)
-
-time_t ut_time;
-
-{
- time_t curtime;
- struct tm *logintime, *curtm;
- int hour, am, curday, logday;
- static char give[20];
- static char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
- "Sat" };
- static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
- "Aug", "Sep", "Oct", "Nov", "Dec" };
-
- curtime = time(NULL);
- curtm = localtime(&curtime);
- curday = curtm->tm_yday;
- logintime = localtime(&ut_time);
- hour = logintime->tm_hour;
- logday = logintime->tm_yday;
- am = (hour < 12);
-
- if (!am)
- hour -= 12;
-
- if (hour == 0)
- hour = 12;
-
- /*
- * This is a newer behavior: it waits 12 hours and the next day, and then
- * goes to the 2nd time format. This should reduce confusion.
- * It then waits only 6 days (not till the last moment) to go the last
- * time format.
- */
- if ((curtime > (ut_time + (60 * 60 * 12))) && (logday != curday))
- {
- if (curtime > (ut_time + (60 * 60 * 24 * 6)))
- sprintf(give, "%2d%3s%2d", logintime->tm_mday,
- month[logintime->tm_mon], (logintime->tm_year % 100));
- else
- sprintf(give, "%*s%2d%s", 3, weekday[logintime->tm_wday],
- hour, am ? "am" : "pm");
- }
- else
- sprintf(give, "%2d:%02d%s", hour, logintime->tm_min, am ? "am" : "pm");
-
- return give;
-}
-
+++ /dev/null
-/*
- * utmp.c - utmp printing command
- * Copyright (C) Albert Cahalan
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <time.h>
-#include <utmp.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-/* examine and fix utmp entries. Note that the code for fixing entries
- is not complete, and indeed does nothing at all at this time. No bug
- reports, please, as I am still actively working on this. It is not
- here for general use, but only so that I can ferret out any bugs that
- exist on other peoples systems without having to log in to their systems
- myself ;-) */
-
-
-int main (int argc, char **argv) {
-
- FILE *ut; /* /var/run/utmp */
- struct utmp uts; /* utmp record */
- char user[UT_NAMESIZE + 1];
- char host[17];
- char ch;
- int print_all = 0, list = 0, fix = 0;
-
-/* get options */
- while ((ch = getopt(argc, argv, "laf")) != EOF)
- switch (ch) {
- case 'a':
- print_all = 1;
- break;
- case 'l':
- list = 1;
- break;
- case 'f':
- fix = 1;
- break;
- }
-
-/* check argument options */
- if ( (!list && !print_all && !fix)) {
- fprintf(stderr, "You must specify a command line option:\n\tl = list\n\
-\tf = fix\n\ta = all (requires l or f)\n");
- exit(1);
- }
-
-
- if (list) {
- ut = fopen(UTMP_FILE, "r");
- while (fread(&uts, sizeof(uts), 1, ut))
- if (((uts.ut_type == USER_PROCESS) && (uts.ut_name[0] != '\000'))
- || print_all) {
- strncpy(user, uts.ut_user, UT_NAMESIZE);
- user[UT_NAMESIZE]=0;
- strncpy(host, uts.ut_host, 16);
- host[16]=0;
- printf("ut_type: %d\n", uts.ut_type);
- printf("ut_pid: %d\n", uts.ut_pid);
- printf("ut_line: %s\n", uts.ut_line);
- printf("ut_id: %2s\n", uts.ut_id);
- printf("ut_time: %d\n", uts.ut_time);
- printf("ut_user: %s\n", user);
- printf("ut_host: %s\n", host);
- printf("ut_addr: %d\n\n", uts.ut_addr);
- }
- fclose(ut);
- }
-
-
- if (fix) {
- ut = fopen(UTMP_FILE, "r");
- while (fread(&uts, sizeof(uts), 1, ut))
- if (((uts.ut_type == USER_PROCESS) && (uts.ut_name[0] != '\000'))
- || print_all) {
- /* Display entry in utmp */
- strncpy(user, uts.ut_user, UT_NAMESIZE);
- user[UT_NAMESIZE]=0;
- strncpy(host, uts.ut_host, 16);
- host[16]=0;
- printf("ut_type: %d\n", uts.ut_type);
- printf("ut_pid: %d\n", uts.ut_pid);
- printf("ut_line: %s\n", uts.ut_line);
- printf("ut_id: %s2\n", uts.ut_id);
- printf("ut_time: %d\n", uts.ut_time);
- printf("ut_user: %s\n", user);
- printf("ut_host: %s\n", host);
- printf("ut_addr: %d\n\n", uts.ut_addr);
-
- printf("Modify this record? (y/N): "); fflush(stdout);
- /* Ask if to delete or no */
- if ((ch = getchar()) == 'y' || ch == 'Y') {
- while (getchar() != '\n');
- printf("Change ut_type? "); fflush(stdout);
- if ((ch = getchar()) == 'y' || ch == 'Y') {
- while (getchar() != '\n');
- printf("INIT, LOGIN, USER, or DEAD_PROCESS? (I/L/U/D): ");
- fflush(stdout);
- ch = getchar();
- switch (ch) {
- case 'i':
- case 'I':
- uts.ut_type = INIT_PROCESS;
- break;
- case 'l':
- case 'L':
- uts.ut_type = LOGIN_PROCESS;
- break;
- case 'u':
- case 'U':
- uts.ut_type = USER_PROCESS;
- break;
- case 'd':
- case 'D':
- uts.ut_type = DEAD_PROCESS;
- break;
- default:
- printf("Invalid choice: %c\n", ch);
- }
- if (ch != '\n') while ((ch = getchar()) != '\n');
- }
- if (ch != '\n') while ((ch = getchar()) != '\n');
- printf("Change ut_id field? (y/N): "); fflush(stdout);
- if ((ch = getchar()) == 'y' || ch == 'Y') {
- while (getchar() != '\n');
- printf("Please enter the two characters for ut_id: ");
- fflush(stdout);
- uts.ut_id[0] = getchar();
- uts.ut_id[1] = getchar();
- while ((ch = getchar()) != '\n');
- }
- if (ch != '\n') while ((ch = getchar()) != '\n');
- printf("Change the ut_user field? (y/N): "); fflush(stdout);
- if ((ch = getchar()) == 'y' || ch == 'Y') {
- int i;
- while (getchar() != '\n');
- printf("Please enter the new ut_name, up to %c characters: ",
- UT_NAMESIZE);
- fflush(stdout);
- for (i=0; i<UT_NAMESIZE; i++) {
- ch = getchar();
- uts.ut_user[i] = (ch != '\n') ? ch : i = UT_NAMESIZE, (char) 0;
- }
- }
- if (ch != '\n') while ((ch = getchar()) != '\n');
- printf("Change the ut_host field? (y/N): "); fflush(stdout);
- if ((ch = getchar()) == 'y' || ch == 'Y') {
- int i;
- while (getchar() != '\n');
- printf("Please enter the new ut_host, up to 16 characters: ");
- fflush(stdout);
- for (i=0; i<16; i++) {
- ch = getchar();
- uts.ut_user[i] = (ch != '\n') ? ch : i = 16, (char) 0;
- }
- if (ch != '\n') while ((ch = getchar()) != '\n');
- }
-
- /* Here go the changes...*/
-/* utmpname(UTMP_FILE);
- setutent();
- pututline(&uts);
- endutent(); */
-/* But they don't work... */
-
- }
- if (ch != '\n') while ((ch = getchar()) != '\n');
- /* here we should write the utmp entry */
- }
- fclose(ut);
- }
-
-
- return 0;
-
-
-}