procps/contrib/tmp-junk.c
Sami Kerola ce61089059 docs: clarification to license headers in files
Add license header to all files.  The summary of licensing is below,
taken from Craig Small's email which is referred in commit message
tail.

sysctl and pgrep are GPL 2+
The rest is LGPL 2.1+

Reference: http://www.freelists.org/post/procps/Incorrect-FSF-address-in-the-license-files,8
Bug-Redhat: https://bugzilla.redhat.com/show_bug.cgi?id=797962
CC: Craig Small <csmall@enc.com.au>
CC: Jaromir Capik <jcapik@redhat.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2012-03-03 18:41:11 +11:00

746 lines
16 KiB
C

/*
* 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;
}