w.c revision 1eabc4bec6d2a5ad71f6a1f0c019af5438d8b1bf
/*
* 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 (c) 2013 Gary Mills
*
* 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 w command which takes advantage of
* the /proc interface to gain access to the information
* of all the processes currently on the system.
*
* This program also implements 'uptime'.
*
* Maintenance note:
*
* Much of this code is replicated in whodo.c. If you're
* fixing bugs here, then you should probably fix 'em there too.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.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>
/*
* Use the full lengths from utmpx for user and line.
*/
/* Print minimum field widths. */
#define LOGIN_WIDTH 8
#define LINE_WIDTH 8
#ifdef ERR
#endif
#define ERR (-1)
#define PROCDIR "/proc"
exit(1); }
struct uproc {
char p_state; /* numeric value of process state */
int p_igintr; /* 1 = ignores SIGQUIT and SIGINT */
*p_sibling, /* sibling pointer */
*p_pgrpl, /* 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 char *prog; /* pointer to invocation name */
static char *sel_user; /* login of particular user selected */
static char firstchar; /* first char of name of prog invoked as */
static int login; /* true if invoked as login shell */
static int nusers; /* number of users logged in now */
static int add_times; /* boolean: add the cpu times or not */
#else
#endif
int
{
char pname[64];
char *fname;
int procfd;
char *cp;
int i;
int entries;
double loadavg[3];
/*
* 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;
case 's':
lflag = 0;
break;
case 'u':
case 'w':
break;
default:
"%s: bad flag %s\n"),
exit(1);
}
}
} else {
"usage: %s [ -hlsuw ] [ 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);
setutxent();
endutxent();
if (header) { /* print a header */
nusers++;
uptime += 30;
if (days > 0)
" %d day(s),"), days));
} else {
if (hrs > 0)
" %d hr(s),"), hrs));
if (mins > 0)
" %d min(s),"), mins));
}
}
}
/*
* Print 1, 5, and 15 minute load averages.
*/
loadavg[LOADAVG_15MIN]));
exit(0);
if (lflag) {
"login@ idle JCPU PCPU what\n",
LC_TIME)));
} else {
"User tty idle what\n",
LC_TIME)));
}
exit(1);
}
}
/*
* 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.
*/
}
}
/*
* 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 after opening */
(void) __priv_relinquish();
/*
* loop through utmpx file, printing process info
* about each logged in user
*/
continue;
continue; /* we're looking for somebody else */
/* print login name of the user */
/* print tty user is on */
if (lflag) {
} else {
} else {
}
}
/* print when the user logged in */
if (lflag) {
}
/* print idle time */
}
exit(1);
}
return (0);
}
/*
* 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;
add_times = 1;
calctotals(up);
if (lflag) {
/* 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 */
}
/*
* 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
{
/*
* Once a node has been visited, stop adding cpu times
* for its children so they don't get totalled twice.
* Still look for the interesting job for this utmp
* entry, however.
*/
add_times = 0;
return;
empty = 0;
curpid = -1;
}
if (lflag)
else
}
if (add_times == 1) {
}
/* descend for its children */
calctotals(zp);
}
}
/*
* 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);
}
/*
* Prttime prints an elapsed time in hours, minutes, or seconds,
* right-justified with the rightmost column always blank.
* The second argument is the minimum field width.
*/
static void
{
char value[36];
} else if (tim >= 60) {
} else if (tim > 0) {
} else {
}
}
/*
* Prints the ISO date or time given a pointer to a time of day,
* left-justfied in a 12-character expanding field with the
* rightmost column always blank.
* Includes a dcgettext() override in case a message catalog is needed.
*/
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 get rid of 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 = '?';
}
}
}