whodo.c revision 76e222fdcb4e5cd81e03f2d48b91c94b86526844
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* This is the new whodo command which takes advantage of
* the /proc interface to gain access to the information
* of all the processes currently on the system.
*
* Maintenance note:
*
* Much of this code is replicated in w.c. If you're
* fixing bugs here, then you should probably fix 'em there too.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <utmpx.h>
#include <dirent.h>
#include <procfs.h> /* /proc header file */
#include <locale.h>
#include <unistd.h>
#include <limits.h>
#include <priv_utils.h>
/*
* utmpx defines wider fields for user and line. For compatibility of output,
* we are limiting these to the old maximums in utmp. Define UTMPX_NAMELEN
* to use the full lengths.
*/
#ifndef UTMPX_NAMELEN
/* XXX - utmp - fix name length */
#define LMAX 12
#else /* UTMPX_NAMELEN */
#endif /* UTMPX_NAMELEN */
#ifdef ERR
#endif
#define ERR (-1)
#define DEVNAMELEN 14
#define PROCDIR "/proc"
static int ndevs; /* number of configured devices */
static int maxdev; /* slots for configured devices */
#define DNINCR 100
static struct devl { /* device list */
} *devl;
struct uproc {
char p_state; /* numeric value of process state */
int p_igintr; /* 1=ignores SIGQUIT and SIGINT */
*p_sibling, /* sibling pointer */
*p_pgrplink, /* pgrp link */
*p_link; /* hash table chain pointer */
};
/*
* define hash table for struct uproc
* Hash function uses process id
* and the size of the hash table(HSIZE)
* to determine process index into the table.
*/
static void clnarglist(char *);
static void showtotals(struct uproc *);
static void calctotals(struct uproc *);
static void checkampm(char *);
static char *prog;
static int lflag = 0; /* true if -l flag: w command format */
static char *sel_user; /* login of particular user selected */
static int nusers; /* number of users logged in now */
static int empty;
#else
#endif
int
{
char pname[64];
char *fname;
int procfd;
int i;
int entries;
/*
* This program needs the proc_owner privilege
*/
(char *)NULL);
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
while (argc > 1) {
switch (argv[1][i]) {
case 'h':
header = 0;
break;
case 'l':
lflag++;
break;
default:
"usage: %s [ -hl ] [ user ]\n"),
prog);
exit(1);
}
}
} else {
"usage: %s [ -hl ] [ user ]\n"), prog);
exit(1);
} else
}
}
/*
* read the UTMPX_FILE (contains information about
* each logged in user)
*/
exit(1);
}
exit(1);
}
(void) utmpxname(UTMPX_FILE);
/* LINTED pointer cast may result in improper alignment */
setutxent();
endutxent();
if (header) { /* print a header */
if (lflag) { /* w command format header */
nusers++;
uptime += 30;
" up %d day(s), %d hr(s), "
"%d min(s)", LC_TIME),
}
}
"login@ idle JCPU PCPU what\n", LC_TIME));
} else { /* standard whodo header */
char date_buf[100];
/*
* print current time and date
*/
/*
* print system name
*/
}
}
/*
* loop through /proc, reading info about each process
*/
exit(1);
}
continue;
continue;
goto retry;
"%s: read() failed on %s: %s\n"),
continue;
}
/* now we need the proc_owner privilege */
(void) __priv_bracket(PRIV_ON);
/* drop proc_owner privilege after open */
(void) __priv_bracket(PRIV_OFF);
if (procfd < 0)
continue;
!= sizeof (statinfo)) {
goto retry;
"%s: read() failed on %s: %s \n"),
continue;
}
/* now we need the proc_owner privilege */
(void) __priv_bracket(PRIV_ON);
/* drop proc_owner privilege after open */
(void) __priv_bracket(PRIV_OFF);
if (procfd < 0)
continue;
!= sizeof (actinfo)) {
goto retry;
"%s: read() failed on %s: %s \n"),
continue;
}
/*
* Process args if there's a chance we'll print it.
*/
if (lflag) { /* w command needs args */
}
}
}
/*
* link pgrp together in case parents go away
* Pgrp chain is a single linked list originating
* from the pgrp leader to its group member.
*/
}
/* if this is the new member, link it in */
}
}
}
/* revert to non-privileged user */
(void) __priv_relinquish();
/*
* loop through utmpx file, printing process info
* about each logged in user
*/
continue;
continue; /* we're looking for somebody else */
if (lflag) { /* -l flag format (w command) */
/* print login name of the user */
/* print tty user is on */
/* print when the user logged in */
/* print idle time */
else
} else { /* standard whodo format */
(void) printf("\n%-*.*s %-*.*s %2.1d:%2.2d\n",
}
}
return (0);
}
/*
* Used for standard whodo format.
* This is the recursive routine descending the process
* tree starting from the given process pointer(up).
* It used depth-first search strategy and also marked
* each node as printed as it traversed down the tree.
*/
static void
{
return;
/* print the data for this process */
(void) printf(" %-*.*s %5d %4.1ld:%2.2ld %s\n",
(void) printf(" %-*.*s %5d %4.1ld:%2.2ld %s\n",
}
/* descend for its children */
}
}
/* print the pgrp relation */
if (up->p_pgrplink)
}
/*
* Used for -l flag (w command) format.
* Prints the CPU time for all processes & children,
* and the cpu time for interesting process,
* and what the user is doing.
*/
static void
{
jobtime = 0;
proctime = 0;
empty = 1;
curpid = -1;
calctotals(up);
/* print CPU time for all processes & children */
/* and need to convert clock ticks to seconds first */
/* print cpu time for interesting process */
/* and need to convert clock ticks to seconds first */
/* what user is doing, current process */
}
/*
* Used for -l flag (w command) format.
* This recursive routine descends the process
* tree starting from the given process pointer(up).
* It used depth-first search strategy and also marked
* each node as visited as it traversed down the tree.
* It calculates the process time for all processes &
* children. It also finds the "interesting" process
* and determines its cpu time and command.
*/
static void
{
return;
return;
empty = 0;
curpid = -1;
}
}
/* descend for its children */
calctotals(zp);
}
}
static char *
{
if (!dp) {
gettext("%s: out of memory!: %s\n"),
exit(1);
}
}
}
/* strip off "/dev/" */
} else {
/* strip enough off the front to fit */
;
if (i == leng)
else
}
}
static char *
{
int i;
}
return (NULL);
}
/*
* This routine gives back a corresponding device name
* from the device number given.
*/
static char *
{
char devname[TTYNAME_MAX];
char *retval;
return (" ? ");
return (retval);
}
/*
* Findhash finds the appropriate entry in the process
* hash table (pr_htbl) for the given pid in case that
* pid exists on the hash chain. It returns back a pointer
* to that uproc structure. If this is a new pid, it allocates
* a new node, initializes it, links it into the chain (after
* head) and returns a structure pointer.
*/
static struct uproc *
{
return (up);
}
return (up);
}
return (tp);
}
}
if (!tp) {
exit(1);
}
return (tp);
}
/*
* prints a time in hours and minutes or minutes and seconds.
* The character string 'tail' is printed at the end, obvious
* strings to pass are "", " ", or "am".
*/
static void
{
if (tim >= 60)
else if (tim > 0)
else
(void) printf(" ");
}
/*
* prints a 12 hour time given a pointer to a time of day
*/
static void
{
struct tm *p;
char timestr[50];
char weekdaytime[20];
} else {
char monthtime[20];
}
}
/*
* find & return number of minutes current tty has been idle
*/
static time_t
{
char ttyname[64];
if (diff < 0)
diff = 0;
} else
diff = 0;
return (diff);
}
/*
* given a pointer to the argument string clean out unsavory characters.
*/
static void
clnarglist(char *arglist)
{
char *c;
int err = 0;
/* get rid of unsavory characters */
if ((*c < ' ') || (*c > 0176)) {
if (err++ > 5) {
break;
}
*c = '?';
}
}
}
static void
{
char *ampm;
}
}