home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-19 | 57.7 KB | 2,225 lines |
- Newsgroups: comp.sources.misc
- From: mgleason@cse.unl.edu (Mike Gleason)
- Subject: v41i031: ison - Network user logon monitor, Part01/01
- Message-ID: <1993Dec14.042025.3559@sparky.sterling.com>
- X-Md4-Signature: 0b1c189ea02d39d78e8740738e61edb2
- Sender: kent@sparky.sterling.com (Kent Landfield)
- Organization: NCEMRSoft
- Date: Tue, 14 Dec 1993 04:20:25 GMT
- Approved: kent@sparky.sterling.com
-
- Submitted-by: mgleason@cse.unl.edu (Mike Gleason)
- Posting-number: Volume 41, Issue 31
- Archive-name: ison/part01
- Environment: UNIX, finger, optionally rpcsvc
- Supersedes: ison: Volume 34, Issue 4
-
- Version 5.0 changes:
- + Complete rewrite; numerous minor changes.
- + RPC support added, drastically improving efficiency.
- + Can detect idle time (even for Finger), and can poll until not-idle.
- + Multiple hosts, Multiple users!
- + Monitor mode, where ison prints logon and logoff messages
- + Commands can contain %flags that are expanded to the appropriate value
- before the command is run, i.e. "write %u %t" executes
- "write <username> <tty>"
- + Powerful user files can be used, to use one ison process to do
- different things with different users.
- + If the information is available, ison can tell you the actual
- logon time and tty of remote (and local) users.
- + More detailed output printed.
- + Manual page rewritten.
-
- IsOn's primary purpose is to let you know when someone logs on. You could
- always sit there at your terminal typing 'finger' or 'who' every 5 minutes,
- but that's boring and unproductive. IsOn makes this easy. If you wanted to
- know the instant I logged on, all it would take is a simple:
-
- ison mgleason@cse.unl.edu
-
- When I do log on, ison would respond:
-
- ** IsOn: mgleason@cse.unl.edu logged on to ttyq28 since 8:41 PM
- and is not idle.
-
- IsOn lowers it's priority automatically, so it takes very little CPU,
- and spares you the trouble of remembering to use 'nice.' It also puts
- itself in the background automatically. For remote addresses (those in
- dude@machine.domain format) the rusers function from the rpcsvc library
- is used, or the 'finger' utility if it has to, and for a user on the same
- machine that you are on, IsOn will simply walk the 'utmp' file.
-
- Enjoy!
- --mike gleason = mgleason@cse.unl.edu
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: INSTALL patchlevel.h ison.1 config.h ison.h Makefile
- # ison.c
- # Wrapped by mgleason@cse on Thu Dec 9 23:37:31 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'INSTALL' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'INSTALL'\"
- else
- echo shar: Extracting \"'INSTALL'\" \(701 characters\)
- sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
- XIf you're lazy, just type "make" and see if compiles. Otherwise read
- Xand edit config.h, then the Makefile.
- X
- XThe two biggest problems I could imagine would be (1) the variable-arguments
- Xpart (you MUST have one of <stdarg.h> or <varargs.h>), and (2) Getting the
- Xcode to link with your RPC libraries. config.h lets you choose for (1),
- Xbut for (2) you MUST have the rpcsvc library, and you MAY need an additional
- Xlibrary or two that the rpcsvc library requires to link. For my system I
- Xneed both the "rpcsvc" library and the "sun" library. The program can
- Xlive without RPC, but it is MUCH more efficient net-friendly, so I
- Xhighly recommend it. config.h will let you try compiling without it,
- Xthough.
- END_OF_FILE
- if test 701 -ne `wc -c <'INSTALL'`; then
- echo shar: \"'INSTALL'\" unpacked with wrong size!
- fi
- # end of 'INSTALL'
- fi
- if test -f 'patchlevel.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'patchlevel.h'\"
- else
- echo shar: Extracting \"'patchlevel.h'\" \(795 characters\)
- sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
- X/*
- X
- Xv5.0.0 -- December 7, 1993. Initial release of version 5.
- X + Complete rewrite; numerous minor changes.
- X + RPC support added, drastically improving efficiency.
- X + Can detect idle time (even for Finger), and can poll until not-idle.
- X + Multiple hosts, Multiple users!
- X + Monitor mode, where ison prints logon and logoff messages
- X + Commands can contain %flags that are expanded to the appropriate value
- X before the command is run, i.e. "write %u %t" executes
- X "write <username> <tty>"
- X + Powerful user files can be used, to use one ison process to do
- X different things with different users.
- X + If the information is available, ison can tell you the actual
- X logon time and tty of remote (and local) users.
- X + More detailed output printed.
- X + Manual page rewritten.
- X
- X*/
- END_OF_FILE
- if test 795 -ne `wc -c <'patchlevel.h'`; then
- echo shar: \"'patchlevel.h'\" unpacked with wrong size!
- fi
- # end of 'patchlevel.h'
- fi
- if test -f 'ison.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ison.1'\"
- else
- echo shar: Extracting \"'ison.1'\" \(7904 characters\)
- sed "s/^X//" >'ison.1' <<'END_OF_FILE'
- X.\" IsOn
- X.\"
- X.\" Dd distance to space vertically before a "display"
- X.\" These are what n/troff use for interparagraph distance
- X.\"-------
- X.if t .nr Dd .4v
- X.if n .nr Dd 1v
- X.\"-------
- X.\" Sp space down the interparagraph distance
- X.\"-------
- X.de Sp
- X.sp \\n(Ddu
- X..
- X.\"-------
- X.\" Ds begin a display, indented .5 inches from the surrounding text.
- X.\"
- X.\" Note that uses of Ds and De may NOT be nested.
- X.\"-------
- X.de Ds
- X.Sp
- X.in +0.5i
- X.nf
- X..
- X.\"-------
- X.\" De end a display (no trailing vertical spacing)
- X.\"-------
- X.de De
- X.fi
- X.in
- X..
- X.TH IsOn 1 "" NCEMRSoft
- X.\"-------
- X.SH "NAME"
- X.\"-------
- XIsOn \(em Network user logon monitor
- X.\"-------
- X.SH "SYNOPSIS"
- X.\"-------
- X.HP
- X.B ison
- X.RI [ "\-bdFIjLmoq" ]
- X.RI [ "\-p" "\ "\c
- X.BR seconds ]
- X.RI [ "\-i" "\ "\c
- X.BR num ]
- X.RI [ "\-o" "\ "\c
- X.BR "outfile" ]
- X.RI [ "\-c" "\ "\c
- X.BR "command" ]
- X.RI [ "\-f" "\ "\c
- X.BR "userlist" ]
- X.RI [ "usernames..." ]
- X.\"-------
- X.SH "DESCRIPTION"
- X.\"-------
- X.PP
- XYou can use
- X.I IsOn
- Xto detect when a certain user logs on, and optionally run another program
- Xor shell script in response.
- X.I IsOn
- Xcan detect when a user becomes active (i.e. has no idle time) or logs off.
- XYou can use
- X.I IsOn
- Xto continually monitor a user's logons and logoffs, if you just want to
- Xknow when someone is online.
- X.PP
- X.I IsOn
- Xcan do all of this with multiple users and multiple remote or local hosts.
- XFor the local machine,
- X.I IsOn
- Xmonitors the
- X.I utmp
- Xfile for optimal performance. For the remote hosts,
- X.I IsOn
- Xtries to use the
- X.I rusers
- Xfunction from the
- X.I Remote Procedure Call Services
- Xlibrary if it is available for optimal perfomance and minimal network
- Xtraffic. Otherwise it can use the
- X.I finger
- Xprogram as plan B.
- X.PP
- X.I IsOn
- Xlowers it's priority automatically, so it takes very little CPU time, and
- Xspares you the trouble of remembering to use
- X.IR "nice" "(1)."
- XIt also puts itself in the background automatically.
- X.\"-------
- X.SH "OPTIONS"
- X.\"-------
- X.TP
- X.B \-b
- XToggles beeping on important messages the program prints.
- X.TP
- X.B \-d
- XPrints debugging information during operation.
- X.TP
- X.B \-F
- XTells the program not to bother trying
- X.I rusers
- Xfor the given remote hosts and try
- X.I finger
- Xinstead. By default the program tries
- X.IR rusers,
- Xand if the remote host does not support
- X.IR RPC,
- Xit then falls back to
- X.IR finger.
- X.TP
- X.BI \-i " x"
- XSets the maximum number of iterations before giving up to
- X.I x.
- XBy default the program doesn't give up until all users have been detected
- Xor you log out.
- X.TP
- X.B \-I
- XTells the program to keep polling the given users until they have no idle
- Xtime. If you supply this option,
- X.I IsOn
- Xwill print a message when the person logs on, and print another message
- Xlater when the user becomes active.
- X.TP
- X.B \-j
- XThis toggles daemon behavior. Depending on how the program was compiled, this
- Xwill allow you do the opposite. If the default is to go into the background,
- Xsupplying this option tells the program not to go into the background, and
- Xvice-versa.
- X.TP
- X.B \-L
- XThis tells the program not to exit when you log off. Normally the program
- Xterminates when all the given users have logged on, or you log off, since you
- Xwould not be online to read the logon notices. This option is usually used
- Xwith the
- X.B "\-c"
- Xoption, described below.
- X.TP
- X.B \-m
- XSupplying this option makes the program keep monitoring all users, telling
- Xyou each time any of them log on or off. This feature is similar to the
- X.I tcsh
- Xshell's
- X.I watch
- Xvariable, except that
- X.I IsOn
- Xactually works (but
- X.I tcsh
- Xis a great shell nonetheless).
- X.TP
- X.BI \-o " x"
- XSpecifies that output should be written to the file
- X.I x
- Xinstead of to your screen.
- X.TP
- X.BI \-p " x"
- XSets the pause between iterations to
- X.I x
- Xseconds.
- X.TP
- X.B \-q
- XQuiet mode, no output at all will be written. Usually used with the
- X.B "\-c"
- Xoption, described below.
- X.TP
- X.BI \-c " command"
- XThis tells the program to execute
- X.I command
- Xeach time a user logs on. In addition, the program also expands certain
- Xflags within
- X.I command
- Xbefore executing:
- X.RS
- X.TP
- X.BR "%h" " inserts the name of the user's host machine."
- X.TP
- X.BR "%i" " inserts user's idletime, or zero if not idle."
- X.TP
- X.BR "%m" " inserts which was polling method was used."
- X.TP
- X.BR "%t" " inserts the user's tty name."
- X.TP
- X.BR "%u" " inserts the user's username."
- X.TP
- X.BR "%U" " inserts the user's complete user@host address."
- X.RE
- X.TP
- X.BI \-f " file"
- XThis tells the program to read
- X.I file
- Xto get the list of users. Besides convenience, as an added benefit you can
- Xhave the program perform differently for each user, instead of having the
- Xcommand line options apply to all users.
- X.RS
- X.PP
- XEach line in the file should contain one username, a set of user flags, and
- Xthe command to execute when this user logs on. The exact format is a username
- Xfollowed by whitespace, followed by the user flags, followed by whitespace,
- Xand the command which continues until the end of the line. The command itself
- Xcan contain whitespace and percent flags to be expanded. You may omit either
- Xthe user flags, command, or both if you wish.
- X.PP
- XThere are only three user flags as of this writing, and
- Xthey are
- X.BR "\-F" ", " "\-I" ", and "\-m"
- Xwhich perform as described above, except that they apply only to the
- Xspecifed user. If you do not want to use any user flags,
- Xjust use a plain ``\-'' to signify no flags at all. See below for an
- Xexample which will explain everything.
- X.RE
- X.PP
- XIf you do not supply a userfile, you can type the users on the command
- Xline along with the options, or do neither and you will be prompted for
- Xa single user by the program (handy if you don't want that to show up
- Xin
- X.IR "ps" " or " "w" ")."
- X.PP
- XThe usernames themselves can be in two formats. If you give a complete
- X``username@remote.host'' type specification, the program assumes that is not
- Xthe machine you are on and tries the remote methods. Otherwise you can
- Xjust give ``username'' to tell the program to search the same machine you
- Xare on.
- X.\"-------
- X.SH "SAMPLE USER FILE"
- X.\"-------
- X.nf
- Xtmcmille@scott.skidmore.edu \-IF date >> /users/me/Tara.log
- Xpdietz \-m /usr/bsd/w | fgrep %u | mail me
- Xshari@cse.unl.edu \-
- Xspyros \- write %u %t < /users/me/memo
- X.fi
- X.\"-------
- X.SH "EXAMPLES"
- X.\"-------
- X.PP
- X.nf
- Xison mgleason
- Xison -I mgleason
- Xison -dF -i 100 -p 60 tmcmille@scott.skidmore.edu
- Xison -c "echo Tara is on %t." tmcmille@scott.skidmore.edu
- Xison -f userfile
- Xison -o pdietz humphrey brooke hgleason pnellor enellor kera bretn
- X.fi
- X.PP
- XNote that it doesn't matter how many users you track, but the number of
- Xhosts does. The more hosts, the more network traffic. Also, the longer
- Xyou set the iteration delay, the better.
- X.\"-------
- X.SH "BUGS"
- X.\"-------
- X.PP
- XIt is possible that a user could both log on and off while
- X.I IsOn
- Xis sleeping between tries. Similarly, it is also possible when you've
- Xspecified to poll users until they become active, to have an idle user
- Xsuddenly activate just long enough to log out while
- X.I IsOn
- Xsleeps.
- X.PP
- XWhen
- X.I IsOn
- Xis using
- X.I finger
- Xas it's remote polling method, sometimes it will not be able to determine
- Xa user's idle time or TTY because of a non-standard remote
- X.I finger
- Xserver.
- X.\"-------
- X.SH "FILES"
- X.\"-------
- X.PP
- X.I /etc/utmp
- X.\"-------
- X.SH "AUTHORS"
- X.\"-------
- X.PP
- XThe original concept and first and second versions by
- X.IR "Phil Dietz" " of " "NCEMRSoft"
- X(pdietz@cse.unl.edu);
- X.PP
- XAll subsequent versions, including this one, by
- X.IR "Mike Gleason" " of " "NCEMRSoft"
- X(mgleason@cse.unl.edu);
- X.PP
- X.RI "Copyright 1990\-94 by " "NCEMRSoft" "."
- X.\"-------
- X.SH "SEE ALSO"
- X.\"-------
- X.HP
- X.IR "RFC 1288" ", ``The Finger User Information Protocol''"
- X.HP
- X.IR "RFC 1057" ", ``RPC: Remote Procedure Call Protocol Specification: Version 2''"
- X.HP
- X.IR "rusers" "(3),"
- X.IR "finger" "(1),"
- X.IR "rusers" "(1),"
- X.IR "nice" "(1),"
- X.IR "nice" "(2),"
- X.IR "ps" "(1),"
- X.IR "w" "(1),"
- X.IR "who" "(1),"
- X.IR "write" "(1),"
- X.IR "talk" "(1),"
- X.IR "tcsh" "(1),"
- X.IR "ncftp" "(1)."
- X.\" end of file
- END_OF_FILE
- if test 7904 -ne `wc -c <'ison.1'`; then
- echo shar: \"'ison.1'\" unpacked with wrong size!
- fi
- # end of 'ison.1'
- fi
- if test -f 'config.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'config.h'\"
- else
- echo shar: Extracting \"'config.h'\" \(4199 characters\)
- sed "s/^X//" >'config.h' <<'END_OF_FILE'
- X/* IsOn's config.h */
- X
- X/* Change what you like. Everything is surrounded in #ifndef blocks,
- X * so you can just add them to the command line if you like, such
- X * as -DBEEP=0. Note that you should not comment out the whole #define
- X * line. The code uses #if's and not #ifdef's so just change a 1 to a
- X * 0, etc., instead of #undef'ing the symbol.
- X *
- X * After browsing this whole file, and making the changes needed for your
- X * system, it should compile cleanly. If not, re-edit this file, and
- X * make sure you have your compiler and flags set up correctly in the
- X * Makefile.
- X */
- X
- X/* Define this 1 if you want to use RPC's rusers() call (highly
- X * recommended). Otherwise 0.
- X */
- X#ifndef RPC
- X#define RPC 1 /* 1 or 0 */
- X#endif
- X
- X/* For best results, define FINGER to the full path leading to your
- X * finger executable. If you don't, we'll have to hope that the path
- X * is in the user's PATH.
- X */
- X#ifndef FINGER
- X#define FINGER "finger"
- X#endif
- X
- X/* If you define DAEMON to be 1, then by default, ison is a daemon,
- X * and the user must use -j to prevent ison from going into the back-
- X * ground by default. If you define DAEMON to 0, then the user must
- X * supply -j to have ison go into the background by itself, and runs
- X * as a normal program.
- X */
- X#ifndef DAEMON
- X#define DAEMON 1 /* Daemon by default? (1 or 0) */
- X#endif
- X
- X/* Do you want ison processes to nice themselves?
- X * I recommend it, since ison is usually a less important process.
- X */
- X#ifndef NICE
- X#define NICE 1 /* 1 or 0 */
- X#endif
- X
- X/* Do you mind if the program uses ^G's by default to get your attention?
- X * The user can use -b to not do the default of what you choose here. */
- X#ifndef BEEP
- X#define BEEP 1 /* 1 or 0 */
- X#endif
- X
- X/* Do you have strchr()? More than likely you do, unless you're running
- X * an older BSD system that still only has index() (the BSD equivalent)
- X * and not strchr too
- X */
- X#ifndef HAVE_STRCHR
- X#define HAVE_STRCHR 1
- X#endif
- X
- X/* You should only define this to 0 if you don't have the strstr()
- X * call. We can do without it, but you won't be able to detect
- X * the idle time when using Finger.
- X */
- X#ifndef HAVE_STRSTR
- X#define HAVE_STRSTR 1 /* 1 or 0 */
- X#endif
- X
- X/* Similarly, if you don't have both strftime() AND localtime()
- X * stick a 0 here. We can work around this too.
- X */
- X#ifndef HAVE_STRFTIME
- X#define HAVE_STRFTIME 1
- X#endif
- X
- X/* Do you have <stdlib.h>? Most recent systems do. */
- X#ifndef HAVE_STDLIBH
- X#define HAVE_STDLIBH 1
- X#endif
- X
- X/* Similarly, do you have <stdarg.h>? If you define HAVE_STDARGH to 0,
- X * we'll try <varargs.h> instead. Older versions of SunOS will need
- X * <varargs.h>
- X */
- X#ifndef HAVE_STDARGH
- X#define HAVE_STDARGH 1
- X#endif
- X
- X/* You can enable some extra debugging messages if you set this to
- X * 1, or save a few bytes and leave it 0.
- X */
- X#ifndef DEBUG
- X#define DEBUG 0 /* 0 or 1 */
- X#endif
- X
- X/* These are the two checks ison tries to see if you've logged off so ison
- X * can kill itself. I usually use both of them, but if one or both don't
- X * work correctly use undef here.
- X */
- X#ifndef CHECK_PARENT
- X#define CHECK_PARENT 1 /* (1 or 0) check to see if our parent is alive */
- X#endif
- X
- X#ifndef CHECK_STDERR
- X#define CHECK_STDERR 1 /* (1 or 0) check to see if stderr is a tty */
- X#endif
- X
- X#ifndef DEFAULT_LOCAL_SLEEP
- X#define DEFAULT_LOCAL_SLEEP 10 /* seconds to sleep between Utmp()'s */
- X#endif
- X
- X#ifndef DEFAULT_REMOTE_SLEEP
- X#define DEFAULT_REMOTE_SLEEP 45 /* secs to sleep between Finger/RUsers */
- X#endif
- X
- X/* You can put an actual number for this one, but I recommend leaving
- X * it a -1L. This way it will poll forever until you logoff, it finds
- X * everyone, or the user supplies the max iterations.
- X */
- X#ifndef MAXITER
- X#define MAXITER (-1L) /* Default is -1L */
- X#endif
- X
- X/* You can define a default command, but I don't recommend it. This
- X * command will be executed each time a user is found, unless the
- X * user who ran the program supplied their own command instead.
- X */
- X#ifndef COMMAND
- X#define COMMAND NULL /* Default is NULL */
- X#endif
- X
- X/* If you're debugging the program (then you're probably me), you
- X * may want to use a debugging malloc library to help out.
- X */
- X#ifndef DBMALLOC
- X#define DBMALLOC 0 /* (0 or 1) Linking w/ a debugging malloc library? */
- X#endif
- X
- X/* eof config.h */
- END_OF_FILE
- if test 4199 -ne `wc -c <'config.h'`; then
- echo shar: \"'config.h'\" unpacked with wrong size!
- fi
- # end of 'config.h'
- fi
- if test -f 'ison.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ison.h'\"
- else
- echo shar: Extracting \"'ison.h'\" \(5825 characters\)
- sed "s/^X//" >'ison.h' <<'END_OF_FILE'
- X/* ison.h */
- X
- X#define VERSION_STR "Version 5.0 (December 7, 1993)"
- X
- X/* IsOn is Copyright 1990-1994 by NCEMRSoft. */
- X
- X#define SZ(expr) ((size_t) (expr))
- X
- X/* Various ways to tweak PrintF(): */
- X#define DEBUG_MSG 001
- X#define NO_HEADER_MSG 002
- X#define NO_BEEP_MSG 004
- X#define FLUSH_MSG 010
- X
- X/* Arbitrary "hostname" for this machine. But it usually works if you use
- X * it as a hostname anyway.
- X */
- X#define ISLOCALHOST "localhost"
- X
- X#define NOT_IDLE (0) /* User is active, and has no idletime. */
- X#define IDLETIME_UNKNOWN (-1) /* We can't determine if idle or not. */
- X#define IS_IDLE (-2) /* User is idle, but don't know exact #minutes. */
- X
- X/* This is used to tell the program there is no maximum number of
- X * iterations.
- X */
- X#define NO_LIMIT (-1L)
- X
- X/* You can have comment lines in the data file. Lines starting with
- X * this character are skipped.
- X */
- X#define COMMENT_CHAR '#'
- X
- X/* Return codes for exit(): */
- X#define EXIT_SUCCESSFUL 0
- X#define EXIT_MAX_ITERATIONS 1
- X#define EXIT_NOT_LOGGED_IN 2
- X#define EXIT_USAGE 3
- X#define EXIT_PARENT 4
- X#define EXIT_FATAL_ERROR (-1)
- X
- X#ifndef UTMP_FILE /* Most define this in utmp.h; SunOS
- X * 4.1.1 doesn't. */
- X# define UTMP_FILE "/etc/utmp"
- X#endif
- X
- X#ifndef INDEX
- X# if HAVE_STRCHR
- X# define INDEX strchr /* ANSI, System V */
- X# define RINDEX strrchr
- X# else
- X# define INDEX index /* BSD */
- X# define RINDEX rindex
- X# endif
- X#endif
- X
- X#define DONEWITHHOST(hp) hp->usersDone = hp->nUsers
- X#define CALLOC1(siz) calloc((size_t)1, siz)
- X
- Xtypedef struct User *UserPtr;
- Xtypedef struct User {
- X UserPtr next;
- X int idlemsg; /* Only say this user is idle one time. */
- X time_t tyme; /* This user's login date, if we know it. */
- X int idletime; /* Idle time of user, in minutes (maybe). */
- X int wasOn; /* If the user was on before the current iter. */
- X int wasIdle; /* If user was idle for current iter. */
- X int isOn; /* If this user is on for the current iter. */
- X int logons; /* Mostly for debugging. */
- X int pollUntilActive; /* Wait until user is not idle? */
- X int detectLogoffs; /* Monitor logoffs too? */
- X char *cmd; /* What to do if this person is on. */
- X char username[12]; /* This user's login name. */
- X char dev[12]; /* This user's tty. */
- X char idlestr[8]; /* only used by Finger. */
- X} User;
- X
- Xtypedef struct Host *HostPtr;
- X
- X/* This may cause some compilation problems :-( */
- X#ifdef ansi
- Xtypedef void (*pollproc_t)(IsonParams *g, HostPtr hp);
- X#else
- Xtypedef int (*pollproc_t)();
- X#endif
- X
- Xtypedef struct Host {
- X HostPtr next;
- X char *hostname; /* FQDN name of the this host, if remote. */
- X pollproc_t pollproc; /* Which polling routine in use. */
- X UserPtr firstUser; /* List of users on this machine to look for. */
- X UserPtr lastUser;
- X size_t nUsers; /* Number of users in list. */
- X size_t usersDone; /* Number we've detected already. */
- X int idleCol; /* For Finger(); where to look for idle time. */
- X int ttyCol; /* Same, but for the TTY. */
- X} Host;
- X
- X/* This program started out by not using any global variables. I kept
- X * the tradition alive by using this trick. We keep one of the following
- X * structures on the stack, and then pass a pointer to it around to the
- X * various sub-routines. That way this program is re-entrant if you
- X * know how to compile it that way. Of course the tradeoff is that there
- X * are going to be plenty of extra pointer dereferences.
- X */
- Xtypedef struct IsonParams {
- X FILE *outfile; /* Stream to print messages on. */
- X char *progname; /* Short name of this program. */
- X long maxIters; /* An upperbound, if any, on iterations. */
- X long iter; /* The current iteration number. */
- X int sleep; /* How long to delay between iterations. */
- X int daemon; /* Are we a background process? */
- X int debug; /* Printing diagnostic output? */
- X int canBeep; /* Printing ^G's with important messages? */
- X int memInUse; /* Dynamic memory in use; used to detect leaks. */
- X int pid; /* PID of this process. */
- X int parentPid; /* The parent PID of ison. */
- X int stdinatty; /* Were we run from a shell script? */
- X int pollmsg; /* Print startup message? */
- X int autodie; /* exit() when you logoff? */
- X int detectLogoffs; /* Staying on, reporting log ons/offs? */
- X FILE *utmpfp; /* Used by Utmp() for localhost's utmp file. */
- X int nHosts; /* How many hosts we're polling. */
- X int nRemoteHosts; /* How many of them are remote, if any. */
- X int hostsDone; /* How many are totally finished. */
- X HostPtr firstHost; /* The host list. */
- X HostPtr lastHost;
- X} IsonParams;
- X
- Xextern int optind; /* getopt() stuff */
- Xextern char *optarg;
- X
- Xextern int errno;
- X
- X#if defined(__STDC__) || defined(__cplusplus) || defined(__EXTENSIONS__)
- X#define Pr(s) s
- X#define ansi 1
- X#include <unistd.h> /* just for prototypes... can be omitted. */
- X#ifndef __EXTENSIONS__
- Xextern FILE * popen(const char *, const char *);
- X#endif
- X#else
- X#define Pr(s) ()
- X#define ansi 0
- Xextern FILE *popen();
- X#endif
- X
- X/* Function prototypes... */
- Xint Strncasecmp Pr((char *a, char *b, size_t n));
- Xvoid DoneWithUser Pr((IsonParams *g, HostPtr hp, UserPtr up));
- Xvoid RunCommand Pr((HostPtr hp, UserPtr up));
- Xvoid MakeSureIAmLoggedIn Pr((IsonParams *g));
- Xchar *UserAddress Pr((char *buf, HostPtr hp, UserPtr up));
- Xchar *TimeStr Pr((char *buf, size_t siz, time_t t));
- Xvoid Delay Pr((IsonParams *g));
- Xvoid IterationDebugMsg Pr((IsonParams *g, char *whichproc, HostPtr hp));
- Xvoid UserIsIdle Pr((IsonParams *g, HostPtr hp, UserPtr up));
- Xvoid Utmp Pr((IsonParams *g, HostPtr hp));
- Xvoid Finger Pr((IsonParams *g, HostPtr hp));
- Xvoid RUsers Pr((IsonParams *g, HostPtr hp));
- Xint AddUser Pr((IsonParams *g, char *username, int F, int noIdle, int mon, char *cmd));
- Xvoid Poll Pr((IsonParams *g));
- Xvoid ReadDataFile Pr((IsonParams *g, char *fname));
- Xvoid Usage Pr((IsonParams *g));
- X
- X/* eof ison.h */
- END_OF_FILE
- if test 5825 -ne `wc -c <'ison.h'`; then
- echo shar: \"'ison.h'\" unpacked with wrong size!
- fi
- # end of 'ison.h'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(2144 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X# IsOn's Makefile
- X#
- X# As usual comment lines are those beginning with a # character; I've
- X# left some extra comments in there to give more example values for some
- X# Make variables.
- X
- X# Your favorite C Compiler, and flags.
- XCC=cc
- X#CC=gcc
- X
- XCFLAGS=-O
- X#CFLAGS=-O2
- X#CFLAGS=-g
- X#CFLAGS=-ansi -fullwarn -woff 211,269,270,303,309 -g -I.. -L..
- X#CFLAGS=-g -Wall -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes
- X
- X
- X# Link flags -- add the RPC library(s) here if you want to use it.
- X#
- X# For SunOS, you just need -lrpcsvc. That may do it for most systems.
- X#
- X# My system needs to libraries, because the librpcsvc library relies on
- X# functions not included in libc (it needs the XDR routines).
- X# So I add -lrpcsvc -lsun here to get it to link correctly.
- X#
- X# If you aren't using RPC, you can just set LFLAGS to empty.
- X
- X
- XLFLAGS=-lrpcsvc
- X#LFLAGS=-lrpcsvc -lsun
- X#LFLAGS=-lrpcsvc -lsun -lc_s
- X#LFLAGS=
- X
- X
- X# Set STRIP to -s if you want a much smaller binary (stripped of debugging
- X# symbols).
- X
- XSTRIP=-s
- X#STRIP=
- X
- X
- X# Definitions. EDIT config.h! PLEASE read through that whole file,
- X# and make the necessary changes!
- X
- XDEFS= #-DHAVE_STDARGH=0 -DRPC=1 -DDEBUG=1
- X
- X
- X
- X
- X### SHOULD NOT NEED TO EDIT BEYOND THIS POINT ###
- X
- X# Source file name minus .c, and compiled exectuable's pathname.
- XPROG=ison
- XOFILE=ison
- XVERS=5.0
- XTARNAME=$(PROG)$(VERS).tar
- X
- XBLURB=Blurb
- XPACKAGE=INSTALL patchlevel.h $(PROG).1 config.h ison.h Makefile $(PROG).c
- X
- Xall: $(PROG)
- X
- X$(PROG): $(PROG).c config.h ison.h
- X $(CC) $(CFLAGS) $(DEFS) $(PROG).c -o $(OFILE) $(LFLAGS) $(STRIP)
- X -@ls -l $(OFILE)
- X
- X# For my system:
- Xirix:
- X cc -O3 -DRPC=1 $(PROG).c -o $(OFILE) -lrpcsvc -lsun -lc_s -s
- X @-rm -f *.[ou]
- X @-chmod 755 $(OFILE)
- X @ls -l $(OFILE)
- X mv ./$(OFILE) $(HOME)/bin
- X
- Xdebug:
- X cc -g -DRPC=1 -DDEBUG=1 $(PROG).c -o $(OFILE) -lrpcsvc -lsun
- X
- Xshar:
- X shar $(PACKAGE) | cat $(BLURB) - > $(PROG).shar
- X
- Xtar:
- X ( cd .. ; tar cvf ./$(PROG).tar ison )
- X mv ../$(TARNAME) .
- X -@ls -l $(TARNAME)
- X
- Xtar2:
- X tar cvf $(PROG).tar $(PACKAGE)
- X
- Xgz: tar
- X gzip -v $(TARNAME)
- X -@ls -l $(TARNAME).gz
- X
- Xfinst: gz
- X cp $(TARNAME).gz /usr/people/ftp/pub/mgleason
- X
- Xclean:
- X rm -f core $(OFILE)
- X
- Xclobber: clean
- X rm -i $(PACKAGE)
- END_OF_FILE
- if test 2144 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'ison.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ison.c'\"
- else
- echo shar: Extracting \"'ison.c'\" \(30133 characters\)
- sed "s/^X//" >'ison.c' <<'END_OF_FILE'
- X/* IsOn... Copyright 1990-94 NCEMRSoft. Use at your own risk.
- X * This version by Mike Gleason, NCEMRSoft (mgleason@cse.unl.edu).
- X * Original version by Phil Dietz, NCEMRSoft (pdietz@cse.unl.edu).
- X */
- X
- X#include <sys/types.h>
- X#include <sys/time.h>
- X#include <sys/stat.h>
- X#include <utmp.h>
- X#include <stdio.h>
- X#include <string.h>
- X#include <ctype.h>
- X#include <signal.h>
- X
- X#include "config.h"
- X#include "ison.h"
- X
- X#if HAVE_STDLIBH
- X#include <stdlib.h>
- X#else
- Xextern void *malloc(), *calloc();
- X#endif
- X
- X#if HAVE_STDARGH
- X#include <stdarg.h>
- X#else
- X#include <varargs.h>
- X#endif
- X
- X#if RPC
- X#include <sys/socket.h>
- X#include <rpc/rpc.h>
- X#include <rpcsvc/rusers.h>
- X#endif /* RPC */
- X
- X#if DBMALLOC
- X#include <malloc.h>
- X#endif
- X
- X#if ansi
- Xint Strncasecmp(register char *a, register char *b, register size_t n)
- X#else
- Xint Strncasecmp(a, b, n)
- X register char *a, *b;
- X register size_t n;
- X#endif
- X{
- X register int A, B;
- X register int fullcompare;
- X
- X /* You can supply a 0 to mean just do a regular Strcasecmp. */
- X fullcompare = (n == (size_t) 0);
- X while ((fullcompare) || (n-- > (size_t) 0)) {
- X A = islower(*a) ? tolower((int) *a++) : *a++;
- X B = islower(*b) ? tolower((int) *b++) : *b++;
- X if (A > B)
- X return (A - B);
- X if (B > A)
- X return (B - A);
- X if (A == 0 && B == 0)
- X return (0);
- X }
- X return (0); /* equal to n characters if we get
- X * here */
- X} /* Strncasecmp */
- X
- X
- X
- X
- X#if ansi
- Xchar *TimeStr(char *buf, size_t siz, time_t t)
- X#else
- Xchar *TimeStr(buf, siz, t)
- X char *buf;
- X size_t siz;
- X time_t t;
- X#endif
- X{
- X#if HAVE_STRFTIME
- X char buf2[128];
- X
- X if (t == (time_t)0)
- X time(&t);
- X (void) strftime(buf2, SZ(127), "%I:%M %p", localtime(&t));
- X if (buf2[0] == '0' && buf[1] == '0') {
- X buf2[0] = '1';
- X buf2[1] = '2';
- X }
- X (void) strncpy(buf, buf2[0] == '0' ? buf2 + 1 : buf2 , siz);
- X#else
- X if (t == (time_t)0)
- X time(&t);
- X (void) strncpy(buf, ctime(&t), siz);
- X if (t == (time_t)0)
- X time(&t);
- X buf[strlen(buf) - 1] = '\0'; /* Get rid of the \n. */
- X#endif
- X return (buf);
- X} /* TimeStr */
- X
- X
- X
- X
- X#if ansi && HAVE_STDARGH
- Xstatic void PrintF(IsonParams *g0, int flags0, char *fmt0, ...)
- X#else
- X#if HAVE_STDARGH
- Xstatic void PrintF(g0, flags0, fmt0, ...)
- X IsonParams *g0;
- X int flags0;
- X char *fmt0;
- X#else
- Xstatic void PrintF(va_alist)
- X va_dcl
- X#endif /* !HAVE_STDARGH*/
- X#endif /* !ansi */
- X{
- X va_list ap;
- X char tmstr[40];
- X IsonParams *g;
- X int flags;
- X char *fmt;
- X
- X#if (HAVE_STDARGH == 0)
- X va_start(ap);
- X g = va_arg(ap, IsonParams *);
- X flags = va_arg(ap, int);
- X fmt = va_arg(ap, char *);
- X#else
- X va_start(ap, fmt0);
- X g = g0; flags = flags0; fmt = fmt0;
- X#endif
- X
- X if (g->outfile == NULL)
- X return;
- X#if DEBUG
- X if (((flags & DEBUG_MSG) != 0) && (!g->debug))
- X return;
- X#endif
- X if ((flags & FLUSH_MSG) != 0) {
- X (void) fflush(g->outfile);
- X return;
- X }
- X
- X if ((flags & NO_HEADER_MSG) == 0) {
- X tmstr[0] = '\0';
- X if (g->outfile != stderr) { /* Log file. */
- X tmstr[0] = ' ';
- X (void) TimeStr(tmstr+1, sizeof(tmstr)-1, (time_t) 0);
- X }
- X (void) fprintf(g->outfile, "\r\n%s%s%s IsOn: ",
- X (((flags & (NO_BEEP_MSG|DEBUG_MSG)) != 0) ||
- X (g->canBeep == 0)) ? "" : "\007",
- X ((flags & DEBUG_MSG) != 0) ? "#DB#" : "**",
- X tmstr
- X );
- X }
- X
- X (void) vfprintf(g->outfile, fmt, ap);
- X va_end(ap);
- X} /* PrintF */
- X
- X
- X#if ansi
- Xvoid MakeSureIAmLoggedIn(IsonParams *g)
- X#else
- Xvoid MakeSureIAmLoggedIn(g)
- X IsonParams *g;
- X#endif
- X{
- X if (g->autodie) {
- X#if CHECK_PARENT
- X /* Don't kill ourself if stdin was not a tty in the first place,
- X * which means we were probably called from a shell script, and
- X * the shell will exit before we finish.
- X */
- X if (g->stdinatty && kill(g->parentPid, 0)) {
- X /* we've lost our shell! */
- X PrintF(g, 0, "Lost our parent!\n");
- X exit(EXIT_NOT_LOGGED_IN);
- X }
- X#endif
- X#if CHECK_STDERR
- X if (!isatty(2)) {
- X /* Hmm... wonder where this is going? */
- X PrintF(g, 0, "Stderr is not a tty!\n");
- X exit(EXIT_NOT_LOGGED_IN);
- X }
- X#endif
- X }
- X} /* MakeSureIAmLoggedIn */
- X
- X
- X
- X#if ansi
- Xvoid Delay(IsonParams *g)
- X#else
- Xvoid Delay(g)
- X IsonParams *g;
- X#endif
- X{
- X unsigned int sl;
- X
- X /* Kill some time so more important processes can run. */
- X g->iter++;
- X#if DEBUG
- X#if DBMALLOC
- X {
- X int inuse = (int) malloc_inuse(NULL);
- X if (inuse > g->memInUse) {
- X g->memInUse = inuse;
- X PrintF(g, DEBUG_MSG, "malloc_inuse: %d\n", inuse);
- X }
- X }
- X#endif
- X#endif
- X if ((g->maxIters > 0L) && (g->iter > g->maxIters)) {
- X PrintF(g, 0, "Giving up after %ld iterations.\n", g->maxIters);
- X exit(EXIT_MAX_ITERATIONS);
- X }
- X if (g->iter == 1L) {
- X if (g->stdinatty && g->pollmsg) {
- X /* Print a message if you ran us from an interactive shell. */
- X PrintF(g, NO_BEEP_MSG, "Polling.");
- X if (g->daemon)
- X PrintF(g, NO_HEADER_MSG, " Type \"kill %d\" to terminate.\n", g->pid);
- X else
- X PrintF(g, NO_HEADER_MSG, "..\n");
- X }
- X } else {
- X if (g->sleep > 0) {
- X /* The user supplied a value to give to sleep. */
- X sl = (unsigned int) g->sleep;
- X } else if (g->sleep < 0) {
- X /* Use one of the defaults. If you supplied a remote host,
- X * wait a little longer, otherwise use the local delay
- X * which is shorter.
- X */
- X sl = (unsigned int) ((g->nRemoteHosts > 0) ? DEFAULT_REMOTE_SLEEP :
- X DEFAULT_LOCAL_SLEEP);
- X }
- X#if DEBUG
- X PrintF(g, DEBUG_MSG, "Sleeping %3d%s",
- X sl,
- X (g->daemon == 0) ? ": " : "...\r\n"
- X );
- X PrintF(g, FLUSH_MSG, "");
- X#endif
- X (void) sleep(sl);
- X#if DEBUG
- X PrintF(g, DEBUG_MSG|NO_HEADER_MSG, "done.\n");
- X#endif
- X }
- X} /* Delay */
- X
- X
- X
- X#if DEBUG
- X/* If we have debug mode on, we can print a message to the screen telling
- X * the user that we are getting ready to do another check.
- X */
- X#if ansi
- Xvoid IterationDebugMsg(IsonParams *g, char *whichproc, HostPtr hp)
- X#else
- Xvoid IterationDebugMsg(g, whichproc, hp)
- X IsonParams *g;
- X char *whichproc;
- X HostPtr hp;
- X#endif
- X{
- X char tmstr[40];
- X
- X PrintF(g, DEBUG_MSG, "Checking %s on %s (try #%ld) at %s\n",
- X whichproc, hp->hostname, g->iter,
- X TimeStr(tmstr, sizeof(tmstr), (time_t)0)
- X );
- X} /* IterationDebugMsg */
- X#else
- X#define IterationDebugMsg(a,b,c)
- X#endif /* DEBUG */
- X
- X
- X
- X#if ansi
- Xvoid RunCommand(HostPtr hp, UserPtr up)
- X#else
- Xvoid RunCommand(hp, up)
- X HostPtr hp;
- X UserPtr up;
- X#endif
- X{
- X char buf[256];
- X char str[64];
- X char *catstr;
- X char *cp, *dp;
- X size_t n;
- X
- X if (up->cmd != NULL) {
- X for (dp = buf, cp = up->cmd, n = sizeof(buf) - 1; *cp != '\0'; cp++) {
- X if (*cp == '%') {
- X ++cp;
- X switch (*cp) {
- X case '\0':
- X --cp;
- X break;
- X case 'h':
- X catstr = hp->hostname;
- X goto cat;
- X case 'i':
- X if (up->idletime != IS_IDLE) {
- X (void) sprintf(str, "%d",
- X up->idletime == IS_IDLE ? 0 : up->idletime);
- X catstr = str;
- X } else catstr = up->idlestr;
- X goto cat;
- X case 'm':
- X if (hp->pollproc == (pollproc_t) Utmp)
- X catstr = "utmp";
- X else if (hp->pollproc == (pollproc_t) Finger)
- X catstr = "finger";
- X else
- X catstr = "rusers";
- X goto cat;
- X case 'n':
- X case 'u':
- X catstr = up->username;
- X goto cat;
- X case 'N':
- X case 'U':
- X if (hp->hostname != ISLOCALHOST) {
- X (void) sprintf(str, "%s@%s", up->username,
- X hp->hostname);
- X catstr = str;
- X } else
- X catstr = up->username;
- X goto cat;
- X case 't':
- X catstr = up->dev;
- X goto cat;
- X cat:
- X for (; (n > 0) && (*catstr != '\0'); --n)
- X *dp++ = *catstr++;
- X break;
- X default:
- X if (n > 0) {
- X --n;
- X *dp++ = *cp;
- X }
- X }
- X } else if (n > 0) {
- X --n;
- X *dp++ = *cp;
- X }
- X }
- X *dp = 0;
- X
- X if (fork() == 0) {
- X (void) sleep(1);
- X (void) execlp("/bin/sh", "sh", "-c", buf, NULL);
- X (void) perror(buf);
- X exit(EXIT_FATAL_ERROR); /* Rarely reached... */
- X }
- X }
- X} /* RunCommand */
- X
- X
- X
- X
- X#if ansi
- Xchar *UserAddress(char *buf, HostPtr hp, UserPtr up)
- X#else
- Xchar *UserAddress(buf, hp, up)
- X char *buf;
- X HostPtr hp;
- X UserPtr up;
- X#endif
- X{
- X (void) strcpy(buf, up->username);
- X if (Strncasecmp(hp->hostname, ISLOCALHOST, SZ(0)) != 0) {
- X (void) strcat(buf, "@");
- X (void) strcat(buf, hp->hostname);
- X }
- X return (buf);
- X} /* UserAddress */
- X
- X
- X
- X
- X#if ansi
- Xvoid UserIsIdle(IsonParams *g, HostPtr hp, UserPtr up)
- X#else
- Xvoid UserIsIdle(g, hp, up)
- X IsonParams *g;
- X HostPtr hp;
- X UserPtr up;
- X#endif
- X{
- X char uabuf[128];
- X
- X up->wasIdle = 1;
- X if (++up->idlemsg == 1) {
- X PrintF(g, 0, "%s is logged in,\r\n but has been idle ",
- X UserAddress(uabuf, hp, up)
- X );
- X if (up->idletime > 0)
- X PrintF(g, NO_HEADER_MSG, "%d minute%s.\n\n",
- X up->idletime,
- X (up->idletime > 1 ? "s" : "")
- X );
- X else
- X PrintF(g, NO_HEADER_MSG, "%s.\n\n", up->idlestr);
- X }
- X} /* UserIsIdle */
- X
- X
- X
- X
- X#if ansi
- Xvoid DoneWithUser(IsonParams *g, HostPtr hp, UserPtr up)
- X#else
- Xvoid DoneWithUser(g, hp, up)
- X IsonParams *g;
- X HostPtr hp;
- X UserPtr up;
- X#endif
- X{
- X char tmstr[40];
- X char useraddr[128];
- X char TTY[32];
- X char since[10];
- X
- X up->isOn = 1;
- X if (up->wasOn) /* Yeah, we know already. */
- X return;
- X
- X up->logons++;
- X up->wasOn = 1;
- X
- X (void) UserAddress(useraddr, hp, up);
- X
- X if (up->tyme == (time_t)0) {
- X since[0] = '\0';
- X /* tmstr will contain the time _here_ after the TimeStr() then. */
- X } else {
- X (void) strcpy(since, " since ");
- X }
- X (void) TimeStr(tmstr, sizeof(tmstr), up->tyme);
- X
- X TTY[0] = '\0';
- X if (up->dev[0] != '\0')
- X (void) sprintf(TTY, " to %s", up->dev);
- X
- X /* We don't want to print the idle message after we print this
- X * next message.
- X */
- X ++up->idlemsg;
- X if (up->idletime > 0) {
- X PrintF(g, 0,
- X "%s logged on%s%s%s,\r\n but has been idle %d min.\n",
- X useraddr,
- X TTY,
- X since,
- X since[0] == '\0' ? since : tmstr,
- X up->idletime
- X );
- X } else if (up->idletime == NOT_IDLE) {
- X up->wasIdle = 0;
- X PrintF(g, 0,
- X "%s logged on%s%s%s\r\n and is not idle.\n",
- X useraddr,
- X TTY,
- X since,
- X since[0] == '\0' ? since : tmstr
- X );
- X } else if (up->idletime == IDLETIME_UNKNOWN) {
- X /* Probably using Finger. Since not all finger servers spew
- X * their output in the same format, we may not be able to find
- X * out if the user is idle or not.
- X */
- X up->wasIdle = 0;
- X PrintF(g, 0,
- X "Detected login of %s at %s.\n",
- X useraddr,
- X tmstr
- X );
- X } else if (up->idletime == IS_IDLE) {
- X /* Again, from Finger. We don't bother trying to figure out
- X * the exact number of minutes since there are various ways
- X * it prints that figure. We just know it's there is some
- X * idletime, which is good enough. Hopefully we won't be
- X * using Finger very much anyway. We just tell them the
- X * exact same thing Finger told us.
- X */
- X PrintF(g, 0,
- X "Detected login of %s%s at %s,\r\n but has been idle %s.\n",
- X useraddr,
- X TTY,
- X tmstr,
- X up->idlestr
- X );
- X }
- X
- X if (!up->detectLogoffs) {
- X /* If we are running detect logoffs mode, we want to run forever,
- X * so we don't want to increment the done-users counter. If we
- X * did that, we would exit once all users had logged on at least
- X * once. With this mode, we don't want to exit.
- X */
- X if (++hp->usersDone == hp->nUsers) {
- X ++g->hostsDone;
- X }
- X }
- X
- X /* Run a command (script) if the user requested to. */
- X RunCommand(hp, up);
- X} /* DoneWithUser */
- X
- X
- X
- X
- X#if ansi
- Xvoid Utmp(IsonParams *g, HostPtr hp)
- X#else
- Xvoid Utmp(g, hp)
- X IsonParams *g;
- X HostPtr hp;
- X#endif
- X{
- X struct utmp info;
- X int idletime;
- X struct stat st;
- X char ttypath[128];
- X UserPtr up;
- X
- X /* Open the utmp file, which is a list of all logged on users. */
- X if ((g->utmpfp == NULL) && ((g->utmpfp = fopen(UTMP_FILE, "r")) == NULL)) {
- X (void) perror(UTMP_FILE);
- X DONEWITHHOST(hp);
- X }
- X
- X /* Reset the utmp file and re-read it. */
- X (void) rewind(g->utmpfp);
- X
- X IterationDebugMsg(g, "Utmp", hp);
- X
- X /* Cycle through all 'users' logged in. */
- X while (fread(&info, SZ(sizeof(info)), SZ(1), g->utmpfp) == SZ(1)) {
- X /* See if this guy matches any of the users we are looking for. */
- X for (up = hp->firstUser; up != NULL; up = up->next) {
- X if (Strncasecmp(up->username, info.ut_name, SZ(8)) == 0) {
- X /* This user is logged on. But is the user active? */
- X (void) time(&up->tyme);
- X
- X up->isOn = 1;
- X (void) strcat(strcpy(ttypath, "/dev/"), info.ut_line);
- X idletime = IDLETIME_UNKNOWN;
- X if (stat(ttypath, &st) == 0) {
- X idletime = (int) (up->tyme - st.st_mtime) - 0;
- X if (idletime < 0) idletime = NOT_IDLE;
- X else idletime /= 60;
- X }
- X
- X up->idletime = idletime;
- X if (up->pollUntilActive && idletime > 0) {
- X UserIsIdle(g, hp, up);
- X } else {
- X /* The user is not idle; use the real login time. */
- X up->tyme = info.ut_time;
- X
- X /* Note the tty the user is on. */
- X (void) strcpy(up->dev, info.ut_line);
- X
- X DoneWithUser(g, hp, up);
- X }
- X }
- X }
- X }
- X} /* Utmp */
- X
- X
- X
- X
- X#if ansi
- Xvoid Finger(IsonParams *g, HostPtr hp)
- X#else
- Xvoid Finger(g, hp)
- X IsonParams *g;
- X HostPtr hp;
- X#endif
- X{
- X FILE *in;
- X register char *cp;
- X int piperesult, pipelines, i;
- X char buf[160], pipename[128];
- X UserPtr up;
- X
- X (void) strcat(strcpy(pipename, FINGER), " @");
- X (void) strcat(pipename, hp->hostname);
- X
- X if ((in = popen(pipename, "r")) == NULL) {
- X perror(FINGER);
- X exit(EXIT_FATAL_ERROR);
- X }
- X
- X IterationDebugMsg(g, "Finger", hp);
- X
- X /* Cycle through all 'users' logged in. */
- X pipelines = 0;
- X while (fgets(buf, (int) sizeof(buf), in) != NULL) {
- X pipelines++;
- X
- X#if HAVE_STRSTR
- X /* We would like to determine if a user is idle if possible.
- X * Since not all finger daemons format their output the same
- X * way, we may not be able to get the idle time. We can
- X * find it if the other side prints a column header line.
- X * From my experience almost all of them being with "Login" as
- X * the very first column, and if there is an idle time column,
- X * the word "Idle" will appear on that header line. If that's
- X * the case, we remember the offset into the line where the
- X * word "Idle" occurred. Later when we find a user on our list,
- X * we look at the offset into the line. If a user is idle,
- X * some sort of text will appear usually a number. If not, it
- X * should be just whitespace.
- X */
- X if (Strncasecmp("Login", buf, SZ(5)) == 0) {
- X if (hp->idleCol == 0) {
- X cp = strstr(buf, "Idle");
- X if (cp != NULL)
- X hp->idleCol = (int) (cp - buf);
- X }
- X
- X /* Same thing for the TTY. */
- X if (hp->ttyCol == 0) {
- X cp = strstr(buf, "TTY");
- X if (cp != NULL)
- X hp->ttyCol = (int) (cp - buf);
- X }
- X }
- X#endif /* HAVE_STRSTR */
- X
- X /* put a \0 in the first space after the username for Strncasecmp */
- X cp = buf;
- X while (*cp && isspace(*cp) == 0)
- X cp++;
- X *cp = '\0';
- X
- X /* See if this guy matches any of the users we are looking for. */
- X for (up = hp->firstUser; up != NULL; up = up->next) {
- X if (Strncasecmp(up->username, buf, SZ(8)) == 0) {
- X up->tyme = (time_t)0; /* Don't know login time. */
- X up->idletime = IDLETIME_UNKNOWN;
- X if (hp->idleCol != 0) {
- X cp = buf + hp->idleCol;
- X cp[4] = 0;
- X up->idletime = NOT_IDLE;
- X for (i=0; i<4; i++)
- X if (!isspace(cp[i])) {
- X up->idletime = IS_IDLE;
- X /* Well, just save the same string finger
- X * said for later use.
- X */
- X while (isspace(*cp) && *cp != '\0')
- X cp++;
- X (void) strcpy(up->idlestr, cp);
- X }
- X }
- X if (hp->ttyCol != 0) {
- X cp = buf + hp->ttyCol;
- X cp[3] = 0;
- X while (isspace(*cp) && *cp != '\0')
- X cp++;
- X if (Strncasecmp(cp, "co", SZ(2)) == 0)
- X (void) strcpy(up->dev, "console");
- X else
- X (void) strcat(strcpy(up->dev, "tty"), cp);
- X }
- X up->isOn = 1;
- X if (up->pollUntilActive && up->idletime == IS_IDLE) {
- X UserIsIdle(g, hp, up);
- X } else {
- X DoneWithUser(g, hp, up);
- X }
- X }
- X }
- X }
- X
- X piperesult = pclose(in); /* close pipe */
- X if (piperesult) {
- X PrintF(g, 0,
- X "%sFinger unsuccessful with %s, so no users from it can be polled.\n",
- X hp->hostname
- X );
- X DONEWITHHOST(hp);
- X }
- X if (pipelines <= 1) {
- X /* finger probably puked */
- X PrintF(g, 0,
- X "%s did not supply any Finger output, so no users from it can be polled.\n",
- X hp->hostname
- X );
- X DONEWITHHOST(hp);
- X }
- X} /* Finger */
- X
- X
- X
- X
- X#if RPC
- X
- X#if ansi
- Xvoid RUsers(IsonParams *g, HostPtr hp)
- X#else
- Xvoid RUsers(g, hp)
- X IsonParams *g;
- X HostPtr hp;
- X#endif
- X{
- X struct utmpidlearr uti;
- X UserPtr up;
- X int i;
- X
- X IterationDebugMsg(g, "RUsers", hp);
- X uti.uia_cnt = 0; uti.uia_arr = 0;
- X
- X if (rusers(hp->hostname, &uti) != 0) {
- X if (g->iter == 1) {
- X /* This remote site probably doesn't support RPC at all, so
- X * try finger instead.
- X */
- X#if DEBUG
- X PrintF(g, DEBUG_MSG, "RPC failed with %s, will try Finger next time.\n",
- X hp->hostname);
- X#endif
- X } else {
- X /* We were able to use RPC at least once, but it isn't working
- X * anymore. We can still try using finger, and if that doesn't
- X * work, we'll have to give up on this host.
- X */
- X PrintF(g, 0, "RPC not reliable with %s, falling back to Finger for this host.\n",
- X hp->hostname);
- X }
- X hp->pollproc = (pollproc_t) Finger;
- X Finger(g, hp);
- X return;
- X }
- X
- X/* I prefer to use my own temp variable, but the internal structure names
- X * differ across different versions of RPCSVC :-(
- X */
- X#define R_UTMP(a) ((*uti.uia_arr[i]).ui_utmp)
- X
- X /* Cycle through each entry in the remote utmp list, and see if any
- X * of the entries match the users we are looking for.
- X */
- X for (i=0; i<uti.uia_cnt; i++) {
- X for (up = hp->firstUser; up != NULL; up = up->next) {
- X if (Strncasecmp(up->username, R_UTMP(uti).ut_name,
- X SZ(8)) == 0)
- X {
- X /* We have found one of our users. */
- X
- X /* We can print exact login time, unlike Finger. */
- X up->tyme = R_UTMP(uti).ut_time;
- X
- X /* We can also get the exact idletime for this user,
- X * without any hassle.
- X */
- X up->idletime = (int) uti.uia_arr[i]->ui_idle;
- X
- X up->isOn = 1;
- X if (up->pollUntilActive && up->idletime > 0) {
- X UserIsIdle(g, hp, up);
- X } else {
- X /* Note the tty the user is on. */
- X (void) strcpy(up->dev, R_UTMP(uti).ut_line);
- X DoneWithUser(g, hp, up);
- X }
- X }
- X }
- X }
- X
- X /* We're done with this chunk, so get rid of it and get a new one
- X * at the next iteration.
- X */
- X xdr_free(xdr_utmpidlearr, &uti);
- X} /* RUsers */
- X#endif /* RPC */
- X
- X
- X
- X
- X#if ansi
- Xint AddUser(IsonParams *g, char *username, int F, int noIdle, int mon, char *cmd)
- X#else
- Xint AddUser(g, username, F, noIdle, mon, cmd)
- X IsonParams *g;
- X char *username, *cmd;
- X int F, mon, noIdle;
- X#endif
- X{
- X HostPtr hp;
- X UserPtr up;
- X int isLocal;
- X char *cp;
- X char *hostname;
- X char userandhost[128];
- X
- X (void) strcpy(userandhost, username); /* Don't modify original. */
- X
- X /*
- X * Check the username for an @, which would suggest that it is a
- X * domain-style address.
- X */
- X if ((cp = INDEX(userandhost, '@')) != NULL) {
- X *cp = 0; /* now will contain only the username. */
- X hostname = cp + 1; /* points to the part after the @. */
- X isLocal = 0;
- X } else {
- X isLocal = 1;
- X hostname = ISLOCALHOST; /* Give it an arbitrary name, so we can
- X * group all the local users together.
- X */
- X }
- X
- X for (hp=g->firstHost; hp != NULL; hp = hp->next) {
- X if (Strncasecmp(hostname, hp->hostname, 0) == 0) {
- X /* We already have a host in the list by this name. */
- X break;
- X }
- X }
- X
- X if (hp == NULL) {
- X /* If we didn't have the hostname in question in our host list,
- X * add a new one.
- X */
- X hp = (HostPtr) CALLOC1(sizeof(Host));
- X if (hp == NULL) goto memerr;
- X hp->hostname = (char *) malloc(strlen(hostname) + 1);
- X if (hp->hostname == NULL) goto memerr;
- X (void) strcpy(hp->hostname, hostname);
- X
- X /* Attach hp to the host list. */
- X if (g->firstHost == NULL)
- X g->firstHost = g->lastHost = hp;
- X else {
- X g->lastHost->next = hp;
- X g->lastHost = hp;
- X }
- X
- X hp->nUsers = 0;
- X hp->firstUser = hp->lastUser = NULL;
- X g->nHosts++;
- X }
- X
- X if (isLocal)
- X hp->pollproc = (pollproc_t) Utmp;
- X else {
- X g->nRemoteHosts++;
- X#if RPC
- X /* Try RPC first, unless you said not to. */
- X hp->pollproc = (pollproc_t) (F ? Finger : RUsers);
- X#else
- X hp->pollproc = (pollproc_t) Finger;
- X#endif
- X }
- X
- X up = (UserPtr) CALLOC1(sizeof(User));
- X if (up == NULL) goto memerr;
- X up->next = NULL;
- X (void) strncpy(up->username, userandhost, sizeof(up->username) - 1);
- X up->cmd = NULL;
- X if (cmd != NULL) {
- X up->cmd = (char *) malloc(strlen(cmd) + 1);
- X if (up->cmd == NULL) goto memerr;
- X (void) strcpy(up->cmd, cmd);
- X }
- X up->pollUntilActive = noIdle;
- X up->detectLogoffs = mon;
- X
- X if (hp->lastUser == NULL)
- X hp->firstUser = hp->lastUser = up;
- X else {
- X hp->lastUser->next = up;
- X hp->lastUser = up;
- X }
- X hp->nUsers++;
- X
- X return (0);
- X
- Xmemerr:
- X return (-1);
- X} /* AddUser */
- X
- X
- X
- X
- X#if ansi
- Xvoid Poll(IsonParams *g)
- X#else
- Xvoid Poll(g)
- X IsonParams *g;
- X#endif
- X{
- X HostPtr hp;
- X UserPtr up;
- X char uabuf[128], tmstr[40];
- X
- X do {
- X Delay(g); /* Delay a little so we won't hog the CPU */
- X MakeSureIAmLoggedIn(g);
- X
- X#if DEBUG
- X if (g->debug) {
- X PrintF(g, NO_HEADER_MSG,
- X "\r\nIsOn's PID: %d; Parent: %d.\n", g->pid, g->parentPid);
- X
- X for (hp=g->firstHost; hp != NULL; hp = hp->next) {
- X PrintF(g, NO_HEADER_MSG, "\r\nHost: %-40s Mode: %c\n",
- X hp->hostname,
- X hp->pollproc == (pollproc_t) Finger ? 'F'
- X : (hp->pollproc == (pollproc_t) Utmp ? 'U' : 'R')
- X );
- X for (up = hp->firstUser; up != NULL; up = up->next) {
- X PrintF(g, NO_HEADER_MSG,
- X "\r %-8s %c %-3s logons=%-2d idle=%-2d",
- X up->username,
- X up->pollUntilActive ? 'I' : ' ',
- X up->isOn ? "ON" : "off",
- X up->logons,
- X up->idletime
- X );
- X if (up->cmd != NULL)
- X PrintF(g, NO_HEADER_MSG, " cmd='%s'", up->cmd);
- X PrintF(g, NO_HEADER_MSG, "\n");
- X }
- X }
- X }
- X#endif /* DEBUG */
- X
- X for (hp=g->firstHost; hp != NULL; hp = hp->next) {
- X if (hp->nUsers > hp->usersDone) {
- X for (up = hp->firstUser; up != NULL; up = up->next)
- X up->isOn = 0;
- X (*hp->pollproc)(g, hp);
- X
- X /* Now go through and see if any users were logged on
- X * the last time, but were no longer detected on.
- X * If not, we can print a msg saying that this user
- X * logged out.
- X *
- X * Note that we always do this, no matter what
- X * up->detectLogoffs is set to, because we want to
- X * report the rare instance where a user has been
- X * idle, but sneaks on and logs off during ison's
- X * sleep period.
- X *
- X * Basically we print the message if the user was
- X * already on but idle then logs off before we
- X * noticed that she wasn't idle, OR you said to
- X * report logoffs.
- X */
- X for (up = hp->firstUser; up != NULL; up = up->next) {
- X if ((up->wasOn || up->wasIdle) && (!up->isOn) &&
- X (up->detectLogoffs || up->logons == 0)) {
- X PrintF(g, 0,
- X "Detected log off of %s at %s.\n",
- X UserAddress(uabuf, hp, up),
- X TimeStr(tmstr, sizeof(tmstr), (time_t)0)
- X );
- X up->wasOn = up->wasIdle = 0;
- X up->idletime = 0;
- X }
- X }
- X }
- X }
- X } while (g->nHosts > g->hostsDone);
- X
- X if (g->utmpfp != NULL)
- X (void) fclose(g->utmpfp);
- X PrintF(g, NO_BEEP_MSG, "Done!\n");
- X} /* Poll */
- X
- X
- X
- X
- X#if ansi
- Xvoid ReadDataFile(IsonParams *g, char *fname)
- X#else
- Xvoid ReadDataFile(g, fname)
- X IsonParams *g;
- X char *fname;
- X#endif
- X{
- X FILE *fp;
- X int usersAdded, linenum;
- X int fingerOnly, pollUntilActive, detectLogoffs;
- X char buf[256], username[64], *cp, *dp, *cmd;
- X
- X if ((fp = fopen(fname, "r")) == NULL) {
- X perror(fname);
- X exit(EXIT_FATAL_ERROR);
- X }
- X
- X usersAdded = linenum = 0;
- X while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
- X ++linenum;
- X for (cp = buf; ; cp++) { /* Skip whitespace. */
- X if (*cp == '\0') goto skip; /* Blank line? */
- X if (!isspace(*cp)) break;
- X }
- X if (*cp == COMMENT_CHAR) goto skip;
- X for (dp = cp; ; dp++) {
- X if (*dp == '\0') goto syntax;
- X if (isspace(*dp)) break;
- X }
- X *dp++ = 0;
- X (void) strcpy(username, cp);
- X
- X for (; ; dp++) { /* Skip whitespace. */
- X if (*dp == '\0') goto addUsr; /* No flags or cmd. */
- X if (!isspace(*dp)) break;
- X }
- X
- X fingerOnly = pollUntilActive = detectLogoffs = 0;
- X cmd = NULL;
- X
- X if (*dp == '-') {
- X /* Collect options for this user. */
- X for (++dp; ; dp++) {
- X if (*dp == '\0') goto addUsr; /* no EOLN? */
- X if (isspace(*dp)) break;
- X
- X /* Check options. */
- X if (*dp == 'I')
- X pollUntilActive = 1;
- X else if (*dp == 'F')
- X fingerOnly = 1;
- X else if (*dp == 'm')
- X detectLogoffs = 1;
- X else {
- X PrintF(g, 0, "Illegal option '%c' on line %d.\n",
- X (int) *dp, linenum);
- X goto skip;
- X }
- X }
- X }
- X
- X for (; ; dp++) { /* Skip whitespace. */
- X if (*dp == '\0') goto addUsr; /* No command given. */
- X if (!isspace(*dp)) break;
- X }
- X
- X /* The command is what's left, if any. */
- X cmd = dp;
- X
- X /* But let's strip off the EOLN. */
- X cp = dp + strlen(dp) - 1;
- X if (isspace(*cp))
- X *cp-- = '\0';
- X if (isspace(*cp))
- X *cp = '\0';
- X
- XaddUsr:
- X if (AddUser(g, username, fingerOnly, pollUntilActive,
- X detectLogoffs, cmd) < 0) {
- X PrintF(g, 0, "Too many users, out of memory!\n");
- X break;
- X }
- X ++usersAdded;
- X continue;
- Xsyntax:
- X PrintF(g, 0, "Syntax error on line %d.\n", linenum);
- Xskip:
- X continue;
- X }
- X if (usersAdded == 0) {
- X PrintF(g, 0, "No users in data file.\n");
- X exit(EXIT_USAGE);
- X }
- X} /* ReadDataFile */
- X
- X
- X
- X
- X
- X#if ansi
- Xvoid Usage(IsonParams *g)
- X#else
- Xvoid Usage(g)
- X IsonParams *g;
- X#endif
- X{
- X (void) fprintf(stderr, "\n\
- XIsOn Usage:\n\
- X %s [-bq%s%sILmP] [-p N] [-i N] [-o outfile] [-c cmd] [-f userfile] [users]%s\n\
- XUsernames:\n\
- X They can be in the form \"user@remote.host\" to poll remote hosts, or\n\
- X just \"user\" for the local host. You can also use the -f option to\n\
- X supply a data file with many users (see the manual for the format).\n",
- X g->progname,
- X#if RPC
- X "F",
- X#else
- X "",
- X#endif
- X#if DEBUG
- X "d",
- X#else
- X "",
- X#endif
- X#if DAEMON
- X ""
- X#else
- X " &"
- X#endif
- X );
- X
- X (void) fprintf(stderr, "\
- XFlags:\n\
- X -I : Poll until users are both logged on and not idle.\n\
- X -L : Live (don't exit) when you log off. Usually used with -c.\n%s%s\
- X -q : Don't print any output at all.\n\
- X -P : Don't print 'Polling...' message.\n\
- X -b : %seep when IsOn prints an important message.\n\
- X -j : %sly.\n",
- X#if RPC
- X " -F : Use finger right away, don't bother with RPC.\n",
- X#else
- X "",
- X#endif
- X#if DEBUG
- X " -d : Print debugging information while running.\n",
- X#else
- X "",
- X#endif
- X#if BEEP
- X "Don't b",
- X#else
- X "B",
- X#endif
- X#if DAEMON
- X "Don't go into the background automatical"
- X#else
- X "Go into the background immediate"
- X#endif
- X );
- X
- X (void) fprintf(stderr, "\
- X -m : Report logons and logoffs of specified users forever.\n\
- X -p N : Seconds between iterations (defaults: local=%d, remote=%d).\n\
- X -i N : Give up after 'N' iterations (default is ",
- X DEFAULT_LOCAL_SLEEP,
- X DEFAULT_REMOTE_SLEEP
- X );
- X#if (MAXITER == NO_LIMIT)
- X (void) fprintf(stderr, "infinity");
- X#else
- X (void) fprintf(stderr, "%ld", MAXITER);
- X#endif
- X
- X (void) fprintf(stderr, ").\n\
- X -o fil : Send output to 'fil' instead of the screen.\n\
- X -c cmd : Command to run for each user found (e.g. \"write %%u %%t <msg\").\
- X\n%s by Phil Dietz & Mike Gleason, NCEMRSoft.\n",
- X VERSION_STR);
- X
- X exit(EXIT_USAGE);
- X} /* Usage */
- X
- X
- X
- X#if ansi
- Xvoid main(int argc, char **argv)
- X#else
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X#endif
- X{
- X IsonParams g;
- X int flag;
- X char *cp, promptedName[64];
- X char validOpts[32];
- X char *cmd = COMMAND;
- X int fingerOnly = 0;
- X int pollUntilActive = 0;
- X int dataFileUsed = 0;
- X int detectLogoffs = 0;
- X int i;
- X
- X g.sleep = -1;
- X g.progname = argv[0];
- X if ((cp = RINDEX(g.progname, '/')) != NULL)
- X g.progname = cp + 1;
- X g.daemon = DAEMON;
- X g.debug = 0;
- X g.nRemoteHosts = 0;
- X g.memInUse = 0;
- X g.autodie = 1;
- X g.maxIters = MAXITER;
- X g.iter = 0;
- X g.pollmsg = 1;
- X g.utmpfp = NULL;
- X g.parentPid = getppid();
- X g.stdinatty = isatty(0);
- X g.nHosts = g.nRemoteHosts = g.hostsDone = 0;
- X g.firstHost = g.lastHost = NULL;
- X g.canBeep = BEEP;
- X g.outfile = stderr;
- X
- X (void) strcpy(validOpts, "bIjqPmLc:o:p:f:i:");
- X#if RPC
- X (void) strcat(validOpts, "F");
- X#endif
- X#if DEBUG
- X (void) strcat(validOpts, "d");
- X#endif
- X
- X while ((flag = getopt(argc, argv, validOpts)) != EOF) {
- X switch (flag) {
- X case 'b':
- X g.canBeep = !g.canBeep;
- X break;
- X case 'f':
- X ReadDataFile(&g, optarg);
- X dataFileUsed = 1;
- X break;
- X case 'F':
- X fingerOnly++;
- X break;
- X case 'd':
- X g.debug++;
- X break;
- X case 'j':
- X g.daemon = !g.daemon;
- X break;
- X case 'm':
- X detectLogoffs = 1;
- X break;
- X case 'o':
- X if ((g.outfile = fopen(optarg, "a")) == NULL) {
- X perror(optarg);
- X exit(EXIT_FATAL_ERROR);
- X }
- X break;
- X case 'q':
- X g.outfile = NULL;
- X break;
- X case 'L':
- X g.autodie = 0;
- X break;
- X case 'c':
- X cmd = optarg;
- X break;
- X case 'P':
- X g.pollmsg = !g.pollmsg;
- X break;
- X case 'p':
- X g.sleep = atoi(optarg);
- X break;
- X case 'i':
- X g.maxIters = atol(optarg);
- X break;
- X case 'I':
- X pollUntilActive = 1;
- X break;
- X default:
- X Usage(&g);
- X }
- X }
- X
- X if ((argv[optind] == NULL) && (dataFileUsed == 0)) {
- X /* No users supplied on the command line. */
- X if (g.stdinatty) {
- X (void) fprintf(stderr, "User to poll: ");
- X (void) fgets(promptedName, sizeof(promptedName), stdin);
- X promptedName[strlen(promptedName) - 1] = '\0';
- X if (promptedName[0] == '\0')
- X Usage(&g); /* They just hit return. */
- X (void) AddUser(&g, promptedName, fingerOnly, pollUntilActive,
- X detectLogoffs, cmd);
- X } else
- X Usage(&g); /* Can't prompt from a shell script, etc. */
- X } else {
- X for (i=optind; i<argc; i++) {
- X if (AddUser(&g, argv[i], fingerOnly, pollUntilActive,
- X detectLogoffs, cmd) < 0) {
- X PrintF(&g, 0, "Too many users, out of memory!\n");
- X break;
- X }
- X }
- X }
- X
- X
- X /* Print a warning if the user chose a scenario where we know we
- X * will never exit!
- X */
- X if (detectLogoffs && !g.autodie) {
- X PrintF(&g, 0,
- X"NOTE: since you enabled continuous log on/off detection and turned off\n\
- Xself-termination when you logoff, ison will run forever! You will have to\n\
- Xuse 'ps -u yourname' or some such to kill it later.");
- X }
- X
- X /* Don't leave ^G's in actual files. */
- X if (g.outfile != stderr)
- X g.canBeep = 0;
- X
- X#if NICE
- X /* lower our process' priority (nice) */
- X (void) nice(20);
- X#endif
- X
- X if (g.daemon) {
- X if (fork()) /* automatically puts this task in
- X * background! */
- X exit(EXIT_PARENT);
- X
- X (void) signal(SIGINT, SIG_IGN);
- X (void) signal(SIGQUIT, SIG_IGN);
- X }
- X
- X (void) sleep(1); /* wait for your shell prompt to catch up. */
- X (void) signal(SIGHUP, SIG_DFL);
- X
- X g.pid = getpid();
- X
- X Poll(&g); /* Finally, get down to business. */
- X
- X exit(EXIT_SUCCESSFUL);
- X} /* main */
- X
- X/* eof ison.c */
- END_OF_FILE
- if test 30133 -ne `wc -c <'ison.c'`; then
- echo shar: \"'ison.c'\" unpacked with wrong size!
- fi
- # end of 'ison.c'
- fi
- echo shar: End of shell archive.
- exit 0
- --
- --mg mgleason@cse.unl.edu
-
- exit 0 # Just in case...
-