|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 26262 (0x6696)
Types: TextFile
Names: »top.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec8/top/top.c«
char *copyright =
"Top, version 2.0, copyright (c) 1984, 1986, William LeFebvre";
/*
* Top users display for Berkeley Unix
* Version 2.0
*
* This program may be freely redistributed to other Unix sites, but this
* entire comment MUST remain intact.
*
* Copyright (c) 1984, 1986, William LeFebvre, Rice University
*
* This program is designed to run on either Berkeley 4.1 or 4.2 Unix.
* Compile with the preprocessor constant "FOUR_ONE" set to get an
* executable that will run on Berkeley 4.1 Unix.
*
* The Sun kernel uses scaled integers instead of floating point.
* Compilation with the preprocessor variable "sun" gets an executable
* that will run on Sun Unix version 1.1 or later ("sun" is automatically
* set by the Sun C compiler).
*
* The Pyramid splits the stack size (p_ssize) into control stack and user
* stack sizes. Compilation with the preprocessor variable "pyr" gets an
* executable that will run on Pyramids ("pyr" is automatically set by the
* Pyramid C compiler).
*
* See the file "Changes" for more information on version-to-version changes.
*/
#include <stdio.h>
#include <pwd.h>
#include <nlist.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/dk.h>
#include <sys/vm.h>
/* includes specific to top */
#include "layout.h"
#include "screen.h" /* interface to screen package */
#include "top.h"
#include "top.local.h"
#include "boolean.h"
/* Special atoi routine returns either a non-negative number or one of: */
#define Infinity -1
#define Invalid -2
/* Size of the stdio buffer given to stdout */
#define Buffersize 2048
/* The buffer the stdio will use */
char stdoutbuf[Buffersize];
/* wish list for kernel symbols */
struct nlist nlst[] = {
{ "_avenrun" },
#define X_AVENRUN 0
{ "_ccpu" },
#define X_CCPU 1
{ "_cp_time" },
#define X_CP_TIME 2
{ "_hz" },
#define X_HZ 3
{ "_mpid" },
#define X_MPID 4
{ "_nproc" },
#define X_NPROC 5
{ "_proc" },
#define X_PROC 6
{ "_total" },
#define X_TOTAL 7
{ 0 },
};
/* build Signal masks */
#define Smask(s) (1 << ((s) - 1))
/* for system errors */
extern int errno;
/* for getopt: */
extern int optind;
extern char *optarg;
/* signal handling routines */
int leave();
int onalrm();
int tstop();
int nproc;
int mpid;
/* kernel "hz" variable -- clock rate */
long hz;
/* All this is to calculate the cpu state percentages */
long cp_time[CPUSTATES];
long cp_old[CPUSTATES];
long cp_change[CPUSTATES];
long total_change;
long mpid_offset;
long avenrun_offset;
long cp_time_offset;
long total_offset;
#ifdef sun
long ccpu;
long avenrun[3];
#else
double ccpu;
double avenrun[3];
#endif
double logcpu;
struct vmtotal total;
struct proc *proc;
struct proc *pbase;
int bytes;
int initialized = No;
char *myname = "top";
jmp_buf jmp_int;
char input_waiting = No;
/* routines that don't return int */
struct passwd *getpwent();
char *username();
char *itoa();
char *ctime();
char *rindex();
char *kill_procs();
char *renice_procs();
int proc_compar();
long time();
/* different routines for displaying the user's identification */
/* (values assigned to get_userid) */
char *username();
char *itoa7();
/* display routines that need to be predeclared */
int i_loadave();
int u_loadave();
int i_procstates();
int u_procstates();
int i_cpustates();
int u_cpustates();
int i_memory();
int u_memory();
int i_header();
int u_header();
int i_process();
int u_process();
/* pointers to display routines */
int (*d_loadave)() = i_loadave;
int (*d_procstates)() = i_procstates;
int (*d_cpustates)() = i_cpustates;
int (*d_memory)() = i_memory;
int (*d_header)() = i_header;
int (*d_process)() = i_process;
/* buffer of proc information lines for display updating */
/* unfortunate that this must be declared globally */
char (* screenbuf)[Display_width];
main(argc, argv)
int argc;
char *argv[];
{
register struct proc *pp;
register struct proc **prefp;
register int i;
register int active_procs;
register int change;
static struct proc **pref;
static char tempbuf1[50];
static char tempbuf2[50];
int total_procs;
int old_sigmask;
int proc_brkdn[7];
int topn = Default_TOPN;
int delay = Default_DELAY;
int displays = 0; /* indicates unspecified */
long curr_time;
char *(*get_userid)() = username;
char *uname_field = "USERNAME";
#ifndef FOUR_ONE
char ch;
char msg_showing = 0;
int readfds;
struct timeval timeout;
#endif
char dostates = No;
char do_unames = Yes;
char do_init = No;
char interactive = Maybe;
char show_sysprocs = No;
char topn_specified = No;
char warnings = 0;
/* set the buffer for stdout */
setbuffer(stdout, stdoutbuf, Buffersize);
/* get our name */
if (argc > 0)
{
if ((myname = rindex(argv[0], '/')) == 0)
{
myname = argv[0];
}
else
{
myname++;
}
}
/* process options */
while ((i = getopt(argc, argv, "Sbinus:d:")) != EOF)
{
switch(i)
{
case 'u': /* display uid instead of name */
do_unames = No;
uname_field = " UID ";
get_userid = itoa7;
break;
case 'S': /* show system processes */
show_sysprocs = Yes;
break;
case 'i': /* go interactive regardless */
interactive = Yes;
break;
case 'n': /* batch, or non-interactive */
case 'b':
interactive = No;
break;
case 'd': /* number of displays to show */
if ((i = atoiwi(optarg)) == Invalid || i == 0)
{
fprintf(stderr,
"%s: warning: display count should be positive -- option ignored\n",
myname);
warnings++;
}
else
{
displays = i;
}
break;
case 's':
if ((delay = atoi(optarg)) < 0)
{
fprintf(stderr,
"%s: warning: seconds delay should be non-negative -- using default\n",
myname);
delay = Default_DELAY;
warnings++;
}
break;
default:
fprintf(stderr,
"Usage: %s [-Sbinu] [-d x] [-s x] [number]\n",
myname);
exit(1);
}
}
/* get count of top processes to display (if any) */
if (optind < argc)
{
if ((topn = atoiwi(argv[optind])) == Invalid)
{
fprintf(stderr,
"%s: warning: process display count should be non-negative -- using default\n",
myname);
topn = Default_TOPN;
warnings++;
}
else
{
topn_specified = Yes;
}
}
/* initialize the kernel memory interface */
init_kernel();
if (initialized != 1)
{
/* get the list of symbols we want to access in the kernel */
/* errno = 0; ??? */
nlist(VMUNIX, nlst);
if (nlst[0].n_type == 0)
{
fprintf(stderr, "%s: can't nlist image\n", VMUNIX);
exit(2);
}
/* get the symbol values out of kmem */
getkval(nlst[X_PROC].n_value, &proc, sizeof(int),
nlst[X_PROC].n_name);
getkval(nlst[X_NPROC].n_value, &nproc, sizeof(int),
nlst[X_NPROC].n_name);
getkval(nlst[X_HZ].n_value, &hz, sizeof(int),
nlst[X_HZ].n_name);
getkval(nlst[X_CCPU].n_value, &ccpu, sizeof(int),
nlst[X_CCPU].n_name);
/* some calculations we use later */
mpid_offset = nlst[X_MPID].n_value;
avenrun_offset = nlst[X_AVENRUN].n_value;
cp_time_offset = nlst[X_CP_TIME].n_value;
total_offset = nlst[X_TOTAL].n_value;
/* this is used in calculating WCPU -- calculate it ahead of time */
#ifdef sun
logcpu = log((double)ccpu / FSCALE);
#else
logcpu = log(ccpu);
#endif
/* allocate space for proc structure array and array of pointers */
bytes = nproc * sizeof(struct proc);
pbase = (struct proc *)sbrk(bytes);
pref = (struct proc **)sbrk(nproc * sizeof(struct proc *));
/* Just in case ... */
if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
{
fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
exit(3);
}
/* initialize the hashing stuff */
if (do_unames)
{
init_hash();
}
if (do_init)
{
initialized = 1;
kill(0, SIGQUIT);
exit(99);
}
}
/* initialize termcap */
init_termcap();
/*
* Smart terminals can only display so many processes, precisely
* "screen_length - Header_lines". When run on dumb terminals, nothing
* fancy is done anyway, so we can display as many processes as the
* system can make. But since we never need to remember what is on the
* screen, we only allocate a buffer for one screen line.
*/
if (smart_terminal)
{
/* can only display (screen_length - Header_lines) processes */
i = screen_length - Header_lines;
if (topn > i) /* false even when topn == Infinity */
{
fprintf(stderr,
"%s: warning: this terminal can only display %d processes.\n",
myname, screen_length - Header_lines);
topn = i;
warnings++;
}
}
else
{
i = 1;
screen_length = nproc + Header_lines;
}
/* allocate space for the screen buffer */
screenbuf = (char (*)[])sbrk(i * Display_width);
if (screenbuf == (char (*)[])NULL)
{
fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
exit(4);
}
/* adjust for topn == Infinity */
if (topn == Infinity)
{
/*
* For smart terminals, infinity really means everything that can
* be displayed (which just happens to be "i" at this point).
* On dumb terminals, infinity means every process in the system!
* We only really want to do that if it was explicitly specified.
* This is always the case when "Default_TOPN != Infinity". But if
* topn wasn't explicitly specified and we are on a dumb terminal
* and the default is Infinity, then (and only then) we use
* "Nominal_TOPN" instead.
*/
#if Default_TOPN == Infinity
topn = smart_terminal ? i :
(topn_specified ? nproc : Nominal_TOPN);
#else
topn = smart_terminal ? i : nproc;
#endif
}
/* determine interactive state */
if (interactive == Maybe)
{
interactive = smart_terminal;
}
/* if # of displays not specified, fill it in */
if (displays == 0)
{
displays = smart_terminal ? Infinity : 1;
}
/* hold interrupt signals while setting up the screen and the handlers */
#ifndef FOUR_ONE
old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP));
#endif
init_screen();
signal(SIGINT, leave);
signal(SIGQUIT, leave);
signal(SIGTSTP, tstop);
#ifndef FOUR_ONE
sigsetmask(old_sigmask);
#endif
if (warnings)
{
fprintf(stderr, "....");
fflush(stderr); /* why must I do this? */
sleep(3 * warnings);
}
clear();
/* setup the jump buffer for stops */
if (setjmp(jmp_int) != 0)
{
/* control ends up here after an interrupt */
clear();
reset_display();
}
/*
* main loop -- repeat while display count is positive or while it
* indicates infinity (by being -1)
*/
while ((displays == -1) || (displays-- > 0))
{
/* read all the proc structures in one fell swoop */
getkval(proc, pbase, bytes, "proc array");
/* get the cp_time array */
getkval(cp_time_offset, cp_time, sizeof(cp_time), "_cp_time");
/* get load average array */
getkval(avenrun_offset, avenrun, sizeof(avenrun), "_avenrun");
/* get mpid -- process id of last process */
getkval(mpid_offset, &mpid, sizeof(mpid), "_mpid");
/* get total -- systemwide main memory usage structure */
getkval(total_offset, &total, sizeof(total), "_total");
/* count up process states and get pointers to interesting procs */
total_procs = 0;
active_procs = 0;
bzero(proc_brkdn, sizeof(proc_brkdn));
prefp = pref;
for (pp = pbase, i = 0; i < nproc; pp++, i++)
{
/*
* Place pointers to each valid proc structure in pref[].
* Process slots that are actually in use have a non-zero
* status field. Processes with SSYS set are system
* processes---these get ignored unless show_sysprocs is set.
*/
if (pp->p_stat != 0 &&
(show_sysprocs || ((pp->p_flag & SSYS) == 0)))
{
total_procs++;
proc_brkdn[pp->p_stat]++;
if (pp->p_stat != SZOMB)
{
*prefp++ = pp;
active_procs++;
}
}
}
/* display the load averages */
(*d_loadave)(mpid, avenrun);
/*
* Display the current time.
* "ctime" always returns a string that looks like this:
*
* Sun Sep 16 01:03:52 1973
* 012345678901234567890123
* 1 2
*
* We want indices 11 thru 18 (length 8).
*/
curr_time = time(0);
if (smart_terminal)
{
Move_to(screen_width - 8, 0);
}
else
{
fputs(" ", stdout);
}
printf("%-8.8s\n", &(ctime(&curr_time)[11]));
/* display process state breakdown */
(*d_procstates)(total_procs, proc_brkdn);
/* calculate percentage time in each cpu state */
if (dostates) /* but not the first time */
{
total_change = 0;
for (i = 0; i < CPUSTATES; i++)
{
/* calculate changes for each state and overall change */
if (cp_time[i] < cp_old[i])
{
/* this only happens when the counter wraps */
change = (int)
((unsigned long)cp_time[i]-(unsigned long)cp_old[i]);
}
else
{
change = cp_time[i] - cp_old[i];
}
total_change += (cp_change[i] = change);
cp_old[i] = cp_time[i];
}
(*d_cpustates)(cp_change, total_change);
}
else
{
/* we'll do it next time */
if (smart_terminal)
{
z_cpustates();
}
else
{
putchar('\n');
}
dostates = Yes;
bzero(cp_old, sizeof(cp_old));
}
/* display main memory statistics */
(*d_memory)(
pagetok(total.t_rm), pagetok(total.t_arm),
pagetok(total.t_vm), pagetok(total.t_avm),
pagetok(total.t_free));
i = 0;
if (topn > 0)
{
/* update the header area */
(*d_header)(uname_field);
/* sort by cpu percentage (pctcpu) */
qsort(pref, active_procs, sizeof(struct proc *), proc_compar);
/* adjust for a lack of processes */
if (active_procs > topn)
{
active_procs = topn;
}
/*
* Now, show the top "n" processes. The method is slightly
* different for dumb terminals, so we will just use two very
* similar loops; this increases speed but also code size.
*/
if (smart_terminal)
{
for (prefp = pref, i = 0; i < active_procs; prefp++, i++)
{
pp = *prefp;
(*d_process)(i, pp, get_userid);
}
}
else for (prefp = pref, i = 0; i < active_procs; prefp++, i++)
{
pp = *prefp;
/* (only one buffer lien with dumb terminals) */
(*d_process)(0, pp, get_userid);
}
}
/* do end-screen processing */
u_endscreen(i);
/* now, flush the output buffer */
fflush(stdout);
/* only do the rest if we have more displays to show */
if (displays)
{
/* switch out for new display on smart terminals */
if (smart_terminal)
{
d_loadave = u_loadave;
d_procstates = u_procstates;
d_cpustates = u_cpustates;
d_memory = u_memory;
d_header = u_header;
d_process = u_process;
}
#ifndef FOUR_ONE
if (!interactive)
#endif
{
/* set up alarm */
signal(SIGALRM, onalrm);
alarm(delay);
/* wait for the rest of it .... */
pause();
}
#ifndef FOUR_ONE
else
{
/* wait for either input or the end of the delay period */
readfds = 1; /* for standard input */
timeout.tv_sec = delay;
timeout.tv_usec = 0;
if (select(32, &readfds, 0, 0, &timeout) > 0)
{
int newval;
char *errmsg;
/* something to read -- clear the message area first */
if (msg_showing)
{
if (smart_terminal)
{
putcap(clear_line);
}
msg_showing = No;
}
/* now read it and act on it */
read(0, &ch, 1);
switch(ch)
{
case '\f': /* redraw screen */
reset_display();
clear();
break;
case ' ': /* merely update display */
break;
case 'q': /* quit */
quit(0);
break;
case 'h': /* help */
case '?':
reset_display();
clear();
show_help();
standout("Hit any key to continue: ");
fflush(stdout);
read(0, &ch, 1);
clear();
break;
case 'e': /* show errors */
if (error_count() == 0)
{
standout(" Currently no errors to report.");
msg_showing = Yes;
}
else
{
reset_display();
clear();
show_errors();
standout("Hit any key to continue: ");
fflush(stdout);
read(0, &ch, 1);
clear();
}
break;
case 'n': /* new number */
case '#':
standout("Number of processes to show: ");
newval = readline(tempbuf1, 8, Yes);
putchar('\r');
if (newval > -1)
{
if (newval > (i = screen_length - Header_lines))
{
standout(
" This terminal can only display %d processes.",
i);
newval = i;
msg_showing = Yes;
break;
}
if (newval > topn)
{
/* zero fill appropriate part of screenbuf */
bzero(screenbuf[topn],
(newval - topn) * Display_width);
/* redraw header if need be */
if (topn == 0)
{
d_header = i_header;
}
}
topn = newval;
}
putcap(clear_line);
break;
case 's': /* new seconds delay */
standout("Seconds to delay: ");
if ((i = readline(tempbuf1, 8, Yes)) > -1)
{
delay = i;
}
putchar('\r');
putcap(clear_line);
break;
case 'd': /* change display count */
standout("Displays to show (currently %s): ",
displays == -1 ? "infinite" :
itoa(displays));
if ((i = readline(tempbuf1, 10, Yes)) > 0)
{
displays = i;
}
else if (i == 0)
{
quit(0);
}
putchar('\r');
putcap(clear_line);
break;
case 'k': /* kill program */
fputs("kill ", stdout);
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
{
if ((errmsg = kill_procs(tempbuf2)) != NULL)
{
putchar('\r');
standout(errmsg);
}
msg_showing = Yes;
}
else
{
putchar('\r');
}
putcap(clear_line);
break;
case 'r': /* renice program */
fputs("renice ", stdout);
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
{
if ((errmsg = renice_procs(tempbuf2)) != NULL)
{
putchar('\r');
standout(errmsg);
msg_showing = Yes;
}
}
else
{
putchar('\r');
}
putcap(clear_line);
break;
default:
standout(" Command not understood");
msg_showing = Yes;
}
}
else if (msg_showing)
{
if (smart_terminal)
{
putcap(clear_line);
}
msg_showing = No;
}
}
#endif
}
}
quit(0);
}
/*
* reset_display() - reset all the display routine pointers so that entire
* screen will get redrawn.
*/
reset_display()
{
d_loadave = i_loadave;
d_procstates = i_procstates;
d_cpustates = i_cpustates;
d_memory = i_memory;
d_header = i_header;
d_process = i_process;
}
readline(buffer, size, numeric)
char *buffer;
int size;
int numeric;
{
register char *ptr = buffer;
register char ch;
register char cnt = 0;
size -= 1;
while ((fflush(stdout), read(0, ptr, 1) > 0))
{
if ((ch = *ptr) == '\n')
{
break;
}
if (ch == ch_kill)
{
*buffer = '\0';
return(-1);
}
else if (ch == ch_erase)
{
if (cnt <= 0)
{
putchar('\7');
}
else
{
fputs("\b \b", stdout);
ptr--;
cnt--;
}
}
else if (cnt == size || (numeric && (ch < '0' || ch > '9')))
{
putchar('\7');
}
else
{
putchar(ch);
ptr++;
cnt++;
}
}
*ptr = '\0';
return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
}
/*
* signal handlers
*/
leave() /* exit under normal conditions -- INT handler */
{
end_screen();
exit(0);
}
tstop()
{
/* move to the lower left */
end_screen();
fflush(stdout);
#ifdef FOUR_ONE /* a 4.1 system */
/* send a STOP (uncatchable) to everyone in the process group */
kill(0, SIGSTOP);
/* reset the signal handler */
signal(SIGTSTP, tstop);
#else /* assume it is a 4.2 system */
/* default the signal handler action */
signal(SIGTSTP, SIG_DFL);
/* unblock the signal and send ourselves one */
sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1)));
kill(0, SIGTSTP);
/* reset the signal handler */
signal(SIGTSTP, tstop);
#endif
/* reinit screen */
reinit_screen();
/* jump to appropriate place */
longjmp(jmp_int, 1);
/*NOTREACHED*/
}
quit(status) /* exit under duress */
int status;
{
end_screen();
exit(status);
}
onalrm()
{
return(0);
}
/*
* proc_compar - comparison function for "qsort"
* Compares the resource consumption of two processes using five
* distinct keys. The keys (in descending order of importance) are:
* percent cpu, cpu ticks, state, resident set size, total virtual
* memory usage. The process states are ordered as follows (from least
* to most important): WAIT, zombie, sleep, stop, start, run. The
* array declaration below maps a process state index into a number
* that reflects this ordering.
*/
unsigned char sorted_state[] =
{
0, /* not used */
3, /* sleep */
1, /* ABANDONED (WAIT) */
6, /* run */
5, /* start */
2, /* zombie */
4 /* stop */
};
proc_compar(pp1, pp2)
struct proc **pp1;
struct proc **pp2;
{
register struct proc *p1;
register struct proc *p2;
register int result;
#ifndef sun
register double dresult;
#endif
/* remove one level of indirection */
p1 = *pp1;
p2 = *pp2;
/* compare percent cpu (pctcpu) */
#ifdef sun
if ((result = p2->p_pctcpu - p1->p_pctcpu) == 0)
#else
if ((dresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
#endif
{
/* use cpticks to break the tie */
if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
{
/* use process state to break the tie */
if ((result = sorted_state[p2->p_stat] -
sorted_state[p1->p_stat]) == 0)
{
/* use priority to break the tie */
if ((result = p2->p_pri - p1->p_pri) == 0)
{
/* use resident set size (rssize) to break the tie */
if ((result = p2->p_rssize - p1->p_rssize) == 0)
{
/* use total memory to break the tie */
#ifdef pyr
result = (p2->p_tsize + p2->p_dsize + p2->p_ussize) -
(p1->p_tsize + p1->p_dsize + p1->p_ussize);
#else
result = (p2->p_tsize + p2->p_dsize + p2->p_ssize) -
(p1->p_tsize + p1->p_dsize + p1->p_ssize);
#endif
}
}
}
}
}
#ifndef sun
else
{
result = dresult < 0.0 ? -1 : 1;
}
#endif
return(result);
}
/* routines to translate uids into a string */
char *user_name(euid, ruid)
int euid, ruid;
{
return(username(euid));
}
char *user_uid(euid, ruid)
int euid, ruid;
{
return(itoa7(euid));
}
/*
* These routines handle uid to username mapping.
* They use a hashing table scheme to reduce reading overhead.
*/
struct hash_el {
int uid;
char name[8];
};
#define H_empty -1
/* simple minded hashing function */
#define hashit(i) ((i) % Table_size)
struct hash_el hash_table[Table_size];
init_hash()
{
register int i;
register struct hash_el *h;
for (h = hash_table, i = 0; i < Table_size; h++, i++)
{
h->uid = H_empty;
}
}
char *username(uid)
register int uid;
{
register int index;
register int found;
register char *name;
/* This is incredibly naive, but it'll probably get changed anyway */
index = hashit(uid);
while ((found = hash_table[index].uid) != uid)
{
if (found == H_empty)
{
/* not here -- get it out of passwd */
index = get_user(uid);
break; /* out of while */
}
index = (index + 1) % Table_size;
}
return(hash_table[index].name);
}
enter_user(uid, name)
register int uid;
register char *name;
{
register int length;
register int index;
register int try;
static int uid_count = 0;
/* avoid table overflow -- insure at least one empty slot */
if (++uid_count >= Table_size)
{
fprintf(stderr, "table overflow: too many users\n");
quit(10);
}
index = hashit(uid);
while ((try = hash_table[index].uid) != H_empty)
{
if (try == uid)
{
return(index);
}
index = (index + 1) % Table_size;
}
hash_table[index].uid = uid;
strncpy(hash_table[index].name, name, 8);
return(index);
}
get_user(uid)
register int uid;
{
struct passwd *pwd;
register int last_index;
while ((pwd = getpwent()) != NULL)
{
last_index = enter_user(pwd->pw_uid, pwd->pw_name);
if (pwd->pw_uid == uid)
{
return(last_index);
}
}
return(enter_user(uid, itoa7(uid)));
}
atoiwi(str)
char *str;
{
register int len;
len = strlen(str);
if (len != 0)
{
if (strncmp(str, "infinity", len) == 0 ||
strncmp(str, "all", len) == 0 ||
strncmp(str, "maximum", len) == 0)
{
return(Infinity);
}
else if (str[0] == '-')
{
return(Invalid);
}
else
{
return(atoi(str));
}
}
return(0);
}
/*
* itoa - convert integer (decimal) to ascii string for positive numbers
* only (we don't bother with negative numbers since we know we
* don't use them).
*/
static char buffer[16]; /* shared by the next two routines */
char *itoa(val)
register int val;
{
register char *ptr;
ptr = buffer + sizeof(buffer);
*--ptr = '\0';
if (val == 0)
{
*--ptr = '0';
}
else while (val != 0)
{
*--ptr = (val % 10) + '0';
val /= 10;
}
return(ptr);
}
/*
* itoa7(val) - like itoa, except the number is right justified in a 7
* character field. This code is a duplication of itoa instead of
* a front end to a more general routine for efficiency.
*/
char *itoa7(val)
register int val;
{
register char *ptr;
ptr = buffer + sizeof(buffer);
*--ptr = '\0';
if (val == 0)
{
*--ptr = '0';
}
else while (val != 0)
{
*--ptr = (val % 10) + '0';
val /= 10;
}
while (ptr > buffer + sizeof(buffer) - 7)
{
*--ptr = ' ';
}
return(ptr);
}