diff options
Diffstat (limited to 'utils/w.c')
-rw-r--r-- | utils/w.c | 195 |
1 files changed, 137 insertions, 58 deletions
@@ -1,8 +1,8 @@ /* Hurdish w - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995,96,97,98,99,2001,02 Free Software Foundation, Inc. - Written by Miles Bader <miles@gnu.ai.mit.edu> + Written by Miles Bader <miles@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -22,6 +22,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include <paths.h> #include <ctype.h> @@ -29,6 +30,7 @@ #include <pwd.h> #include <grp.h> #include <netdb.h> +#include <version.h> #include <sys/fcntl.h> @@ -42,13 +44,13 @@ #include "psout.h" -#define DEFAULT_FMT_STRING "%^%user %tty %from %login %idle %what" +#define DEFAULT_FMT_STRING "%^%user %tty %from %login %idle %pid %what" extern char *canon_host (char *host); extern char *shared_domain (char *host1, char *host2); extern char *localhost (); -char *argp_program_version = "w 1.0 (GNU " HURD_RELEASE ")"; +const char *argp_program_version = STANDARD_HURD_VERSION (w); #define OA OPTION_ARG_OPTIONAL @@ -71,7 +73,7 @@ static struct argp_option options[] = {0, 0} }; static char *args_doc = "[USER...]"; -static char *doc = 0; +static char *doc = "Show logged in users and what they are doing"; /* The current time of day. */ static struct timeval now; @@ -93,6 +95,14 @@ struct w_hook #define W_PSTAT_LOGIN (PSTAT_USER_BASE << 3) static ps_flags_t +w_deps (ps_flags_t flags) +{ + if (flags & W_PSTAT_IDLE) + flags |= PSTAT_TTY; + return flags; +} + +static ps_flags_t w_fetch (struct proc_stat *ps, ps_flags_t need, ps_flags_t have) { struct w_hook *hook = ps->hook; @@ -121,23 +131,34 @@ w_fetch (struct proc_stat *ps, ps_flags_t need, ps_flags_t have) if (sd) *sd = '\0'; } - - have |= W_PSTAT_HOST; } + have |= W_PSTAT_HOST; } if (need & W_PSTAT_IDLE) { - struct stat stat; - struct ps_tty *tty = ps->tty; - - hook->idle.tv_usec = 0; - if (io_stat (tty->port, &stat) == 0) + if (have & PSTAT_TTY) { - hook->idle.tv_sec = now.tv_sec - stat.st_mtime; - if (hook->idle.tv_sec > 0) - have |= W_PSTAT_IDLE; + struct stat stat; + struct ps_tty *tty = ps->tty; + + hook->idle.tv_usec = 0; + if (! tty) + { + hook->idle.tv_sec = 0; + have |= W_PSTAT_IDLE; + } + else + { + if (io_stat (tty->port, &stat) == 0) + { + hook->idle.tv_sec = now.tv_sec - stat.st_atime; + have |= W_PSTAT_IDLE; + } + } } + else if (ps->inapp & PSTAT_TTY) + ps->inapp |= W_PSTAT_IDLE; } if (need & W_PSTAT_USER) @@ -204,21 +225,22 @@ w_get_host (struct proc_stat *ps, char **host, unsigned *host_len) { struct w_hook *hook = ps->hook; *host = hook->host; - *host_len = strlen (*host); + *host_len = *host ? strlen (*host) : 0; } const struct ps_getter w_host_getter = {"host", W_PSTAT_HOST, w_get_host}; extern error_t ps_emit_past_time (), ps_emit_string (), ps_emit_minutes (); extern error_t ps_emit_user_name (); -extern int ps_cmp_times (), ps_cmp_strings (); +extern int ps_cmp_times (), ps_cmp_strings (), ps_cmp_unames (); +extern int ps_nominal_string (); const struct ps_fmt_spec _w_specs[] = { {"User", 0, 8, -1,0, &w_uname_getter,ps_emit_string, ps_cmp_strings}, - {"Name", 0, 20, -1,0, &w_user_getter, ps_emit_user_name,ps_cmp_strings}, + {"Name", 0, 16, -1,0, &w_user_getter, ps_emit_user_name,ps_cmp_unames,ps_nominal_string}, {"Login","Login@", -7, -1,0,&w_login_getter,ps_emit_past_time,ps_cmp_times}, - {"From", 0, 16, -1,0, &w_host_getter, ps_emit_string, ps_cmp_strings}, - {"Idle", 0, -5, -1,0, &w_idle_getter, ps_emit_minutes,ps_cmp_times}, + {"From", 0, 14, -1,0, &w_host_getter, ps_emit_string, ps_cmp_strings, ps_nominal_string}, + {"Idle", 0, -5, -1,PS_FMT_FIELD_COLON_MOD, &w_idle_getter, ps_emit_minutes,ps_cmp_times}, {"What=args"}, {0} }; @@ -231,7 +253,7 @@ static void add_utmp_procs (struct proc_stat_list *procs, struct utmp *u) { /* The tty name, with space for '\0' termination and an - appropiate prefix. */ + appropriate prefix. */ char tty[sizeof _PATH_DEV + sizeof u->ut_line]; io_t tty_node; error_t err; @@ -239,6 +261,19 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u) int pos; struct proc_stat *ps; + switch (u->ut_type) + { + case LOGIN_PROCESS: + case USER_PROCESS: + /* These are the types that indicate a user job that we might + find processes for. */ + if (u->ut_name[0] != '\0' && u->ut_line[0] != '\0') + break; + default: + /* This entry is not for a user, skip it. */ + return; + } + strncpy (tty, u->ut_line, sizeof u->ut_line); tty[sizeof u->ut_line] = '\0'; /* Ensure it's '\0' terminated. */ @@ -271,7 +306,7 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u) else { struct proc_stat **pgrp_procs; - unsigned num_procs; + size_t num_procs; err = proc_stat_list_add_pgrp (procs, -pid, &pgrp_procs, &num_procs); if (! err) @@ -301,62 +336,74 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u) tty, pid < 0 ? "pgrp" : "pid", pid < 0 ? -pid : pid); } -/* Read into PROCS from the utmp file called NAME. */ -static void -read_utmp_procs (struct proc_stat_list *procs, char *name) +/* Find the absolute timestamp of when the system was booted. + We define "system boot time" as the task creation time of PID 1 (init). */ + +static error_t +fetch_boot_time (struct timeval *when) { - int rd, fd; - struct utmp buf[64]; + struct ps_context *context; + struct proc_stat *ps; + error_t err; - fd = open (name, O_RDONLY); - if (fd < 0) - error (9, errno, "%s", name); + err = ps_context_create (getproc (), &context); + if (err) + error (2, err, "ps_context_create"); + + err = ps_context_find_proc_stat (context, 1, &ps); + if (err) + error (3, err, "ps_context_find_proc_stat"); - while ((rd = read (fd, buf, sizeof (buf))) > 0) + err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC); + if (!err && !(ps->flags & PSTAT_TASK_BASIC)) + err = EGRATUITOUS; + if (err) { - struct utmp *u = buf; - while (rd >= sizeof (*u)) - { - if (*u->ut_name && *u->ut_line) - /* An active entry. */ - add_utmp_procs (procs, u); - rd -= sizeof (*u); - u++; - } + error (0, err, "cannot find boot time"); + return err; + } + else + { + time_value_t *const tv = &proc_stat_task_basic_info (ps)->creation_time; + when->tv_sec = tv->seconds; + when->tv_usec = tv->microseconds; } - close (fd); + ps_context_free (context); + + return 0; } - + static void uptime (struct proc_stat_list *procs) { - struct stat st; + error_t err; + struct timeval boot_time; char uptime_rep[20], tod_rep[20]; struct host_load_info *load; unsigned nusers = 0; - int maybe_add_user (struct proc_stat *ps) { if (ps->hook) nusers++; return 0; } + int maybe_add_user (struct proc_stat *ps) + { if (ps->hook) nusers++; return 0; } proc_stat_list_for_each (procs, maybe_add_user); - /* Until we get a better way of finding out how long the system's been - up... XXX */ - if (stat ("/var/run/uptime", &st) != 0) + if (fetch_boot_time (&boot_time)) strcpy (uptime_rep, "chuck"); else { - struct timeval uptime = { now.tv_sec - st.st_ctime, 0 }; + struct timeval uptime; + timersub (&now, &boot_time, &uptime); fmt_named_interval (&uptime, 0, uptime_rep, sizeof (uptime_rep)); } - strftime (tod_rep, sizeof (tod_rep), "%r", + strftime (tod_rep, sizeof (tod_rep), "%r", localtime ((time_t *)&now.tv_sec)); if (tod_rep[0] == '0') tod_rep[0] = ' '; /* Get rid of bletcherous leading 0. */ - errno = ps_host_load_info (&load); - if (errno) - error (0, errno, "ps_host_load_info"); + err = ps_host_load_info (&load); + if (err) + error (0, err, "ps_host_load_info"); printf ("%s up %s, %u user%s, load averages: %.2f, %.2f, %.2f\n", tod_rep, uptime_rep, nusers, nusers == 1 ? "" : "s", @@ -365,10 +412,11 @@ uptime (struct proc_stat_list *procs) (double)load->avenrun[2] / (double)LOAD_SCALE); } -void +int main(int argc, char *argv[]) { error_t err; + struct utmp *ut; struct ps_context *context; int output_width = -1; char *fmt_string = DEFAULT_FMT_STRING, *sort_key_name = NULL; @@ -378,12 +426,23 @@ main(int argc, char *argv[]) #if 0 char *tty_names = 0; unsigned num_tty_names = 0; - struct idvec *only_uids = make_idvec (), *not_uids = make_idvec (); #endif - struct ps_user_hooks ps_hooks = { 0, w_fetch, w_cleanup }; + uid_t *users = 0; + size_t num_users = 0; + struct ps_user_hooks ps_hooks = { w_deps, w_fetch, w_cleanup }; int has_hook (struct proc_stat *ps) { return ps->hook != 0; } + int keep_users (struct proc_stat *ps) + { + int i; + struct w_hook *h = ps->hook; + for (i = 0; i < num_users; i++) + if (users[i] == h->user->uid) + return 1; + return 0; + } + /* Parse our options... */ error_t parse_opt (int key, char *arg, struct argp_state *state) { @@ -400,6 +459,19 @@ main(int argc, char *argv[]) case 'w': output_width = arg ? atoi (arg) : 0; break; case ARGP_KEY_ARG: + num_users++; + users = realloc (users, num_users * sizeof (*users)); + if (! users) + argp_failure (state, 5, ENOMEM, "%s", arg); + else if (isdigit (*arg)) + users[num_users - 1] = atoi (arg); + else + { + struct passwd *pw = getpwnam (arg); + if (! pw) + argp_failure (state, 6, 0, "%s: Unknown user", arg); + users[num_users - 1] = pw->pw_uid; + } break; default: @@ -424,18 +496,25 @@ main(int argc, char *argv[]) /* Parse our options. */ argp_parse (&argp, argc, argv, 0, 0, 0); - read_utmp_procs (procs, _PATH_UTMP); + /* Read the utmp file. */ + setutent (); + while ((ut = getutent ()) != NULL) + add_utmp_procs (procs, ut); + endutent (); /* Keep only processes that have our hooks attached. */ proc_stat_list_filter1 (procs, has_hook, 0, 0); + if (num_users > 0) + proc_stat_list_filter1 (procs, keep_users, W_PSTAT_USER, 0); + if (show_uptime) uptime (procs); if (show_entries) psout (procs, fmt_string, 0, &w_specs, sort_key_name, sort_reverse, output_width, print_heading, - squash_bogus_fields, squash_nominal_fields); + squash_bogus_fields, squash_nominal_fields, 0); - exit(0); + return 0; } |