home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume34
/
ison
/
part01
/
ison.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-06
|
14KB
|
414 lines
/* IsOn... Copyright 1990-92 NCEMRSoft. Use at your own risk!
To compile:
BSD: "cc -O -DBSD ison.c -o ison"
System V: "cc -O ison.c -o ison"
Version History:
- v1.0 : 1990 : Phil Dietz, NCEMRSoft.
: Original release.
- v2.0 : 05 Feb 91 : Phil Dietz, NCEMRSoft.
: Added 'finger'ing remote machines.
: Names and searches are now case insensitive.
- v3.0 : 04 Aug 91 : Mike Gleason, NCEMRSoft.
: Complete rewrite, using unix system calls.
: Remote addresses are recognized automatically.
: IsOn nice's (lowers it's priority) itself.
: Remote commands are exec'd instead of subshelled.
: Uses handy getopt() function.
: Added -f option, in case you don't have finger,
: our finger flags don't work, or want to try
: it with rwho, etc.
: Added -d debugging option, so you can watch
: ison's progress. This is also useful if you
: want to log to a file.
- v4.0 : 31 Oct 91 : Mike Gleason, Mark Galassi, Tim Wilson.
: Added UTMP_FILE definition for SunOS.
: IsOn sends itself into the background!
: Added -a option, so you can specify a username
: from a prompt, instead of on the command line,
: to hide from ps, w, etc.
: IsOn should die if it's parent is killed (i.e.
: you logout or hangup the serial line).
: Fixed big bug in stricmp().
: Should quit when finger gives an error; could
: have done this earlier if finger would exit(1)
: on an error like a nice program does.
: Changed default delay into two distincy delays,
: one for remote (finger) and one for local.
: The remote delay is much longer now, to be
: more net friendly.
- v4.1 : 15 Nov 91 : Didn't know there was a nice() system call :-);
: replaced custom nice function with sys call.
- v4.2 : 20 Nov 92 : Removed some unnecessary prototypes. Added
CHECKSTDERR code so IsOn will die when you
logout. Changed so you need to define BSD
to get index instead of having to define SYSV
to get strchr. Removed shareware message.
Added -j option.
To do:
- Add an option to poll until the user is found AND not idle;
Could be tricky due to different OS's finger output.
*/
#define VERSION_STR "Version 4.2 (20 Nov 92)"
#include <sys/types.h>
#include <sys/time.h>
#include <utmp.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#define SZ(expr) ((size_t) (expr))
#define DEFAULT_LOCAL_SLEEP 10 /* seconds to sleep between Utmp()'s */
#define DEFAULT_REMOTE_SLEEP 45 /* seconds to sleep between Finger()'s */
#define DDEBUG 0 /* prints stuff if > 0 */
#define DMAXITER -1L /* loop forever until we find the guy */
#define DCOMMAND NULL /* command line to do when user is found */
#define DFINGER "finger -fq"
#define NICE /* when defined, I try to lower my priority. */
#define BEEP /* when defined, I beep when the user is found. */
#define AUTOBG /* when defined, I try to background myself. */
#define CHECKPARENT /* check to see if our parent is alive */
#define CHECKSTDERR /* check to see if stderr is a tty */
#ifndef UTMP_FILE /* Most define this in utmp.h; SunOS 4.1.1 doesn't. */
# define UTMP_FILE "/etc/utmp"
#endif
#ifndef INDEX
# ifdef BSD
# define INDEX index
# else
# define INDEX strchr
# endif
#endif
int strnicmp(), Nice(), Utmp(), Finger();
main(argc, argv)
int argc;
char **argv;
{
int sleep_sec = -1;
int debug = DDEBUG;
long maxiter = DMAXITER;
int notfound, flag;
char *username, hostname[64], *cp, prompted_name[64];
int prompted = 0, parent_pid;
int daemon = 1;
char *fingercmd = DFINGER;
char *cmd = DCOMMAND;
time_t logontime;
extern int getopt(), optind; /* getopt() stuff */
extern char *optarg; /* getopt() stuff */
if (argc <= 1)
usage (argv[0]);
parent_pid = getppid();
while ((flag = getopt (argc, argv, "adjvs:p:i:f:")) != EOF)
switch(flag) {
case 'a': /* ask for a name */
printf("Name to check: ");
gets(prompted_name);
prompted = 1;
break;
case 'd':
case 'v': /* debug mode, verbose mode, same thing */
debug++;
break;
case 'j':
daemon = 0;
break;
case 's':
cmd = optarg;
break;
case 'p':
sleep_sec = atoi (optarg);
break;
case 'i':
maxiter = (long) atol (optarg);
break;
case 'f':
fingercmd = optarg;
break;
default: usage (argv[0]);
}
if (prompted == 0)
username = argv[optind];
else username = prompted_name;
if (username == NULL || strlen(username) == SZ(0))
usage (argv[0]); /* no user specified! */
#ifdef NICE
/* lower our process' priority (nice) */
(void) nice (20);
#endif
#ifdef AUTOBG
if (daemon) {
if (fork()) /* automatically puts this task in background! */
exit(3);
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGQUIT, SIG_IGN);
}
#endif
(void) signal(SIGHUP, SIG_DFL);
if (debug > 0)
printf("\nIsOn's PID: %d; Parent: %d.\n", getpid(), parent_pid);
/* Check the username for an @, which would suggest that it is
a domain-style address. */
if ((cp = INDEX (username, '@')) != NULL) {
strcpy (hostname, cp); /* @machine.domain.xxx */
*cp = '\0'; /* shorten address down to just username */
if (strlen(username) == SZ(0))
usage (argv[0]); /* no user specified! */
if (sleep_sec < 0)
sleep_sec = DEFAULT_REMOTE_SLEEP;
notfound = Finger (username, sleep_sec, maxiter, argv[0],
hostname, fingercmd, debug, parent_pid);
time(&logontime);
} else {
if (sleep_sec < 0)
sleep_sec = DEFAULT_LOCAL_SLEEP;
notfound = Utmp (username, sleep_sec, maxiter, argv[0],
debug, &logontime, parent_pid);
}
/* See if the user was found. If not, explain why not. */
if (notfound != 0) {
if (notfound > 0) /* maxiter encoutered */
(void) fprintf (stderr, "\n## %s is not on.\n", username);
else (void) fprintf (stderr,
"\n## %s: cannot go on because of errors.\n", argv[0]);
} else {
/* When we get here, the user we're looking for was detected. */
(void) fprintf (stderr, "\n** %s%s logged in since %s",
#ifdef BEEP
"\007", /* Control-G, the ascii BEL character */
#else
"",
#endif
username, ctime(&logontime));
if (cmd != NULL) {
/* Run a command (script) if the user requested to. */
(void) execlp ("/bin/sh", "sh", "-c", cmd, NULL);
(void) perror (cmd);
}
}
exit (notfound);
} /* main */
int Utmp(username, sleep_sec, maxiter, progname, debug, tyme, parent_pid)
char *username, *progname;
int sleep_sec, debug, parent_pid;
long maxiter;
time_t *tyme;
{
struct utmp info;
FILE *in;
register int not_on = 1, iter = 1;
char theuser[16];
/* Open the utmp file, which is a list of all logged on users. */
if ((in = fopen (UTMP_FILE, "r")) == NULL) {
(void) perror (UTMP_FILE);
return (-1);
}
do {
if (debug > 0) {
time(tyme);
(void) printf("## %s: checking utmp (try #%d) at %s",
progname, iter, ctime(tyme));
}
/* Reset the utmp file and re-read it. */
(void) rewind (in);
#ifdef CHECKPARENT
if (kill(parent_pid, 0)) /* we've lost our shell! */
exit(2);
#endif
#ifdef CHECKSTDERR
if (!isatty(2))
exit(2);
#endif
/* Cycle through all 'users' logged in. */
while (not_on && (fread (&info, SZ(sizeof (info)), SZ(1), in)) == SZ(1)) {
/* Inefficent, but necessary */
strncpy(theuser, info.ut_name, SZ(8));
theuser[8] = '\0';
not_on = strnicmp(username, theuser, SZ(8));
if (debug > 1 && theuser[0] != '\0')
printf("%s\n", theuser);
}
/* Delay a little so we won't hog the CPU */
if (not_on) {
iter++;
if ((maxiter > 0) && (iter > maxiter)) {
not_on = 1;
break;
}
if (iter == 2) {
printf("\nPolling for %s...\n", username);
}
(void) sleep (sleep_sec);
}
} while (not_on);
*tyme = info.ut_time; /* will hold garbage if user not found! */
(void) fclose (in);
return (not_on);
} /* Utmp */
/* Maybe I should just break down and use a few global variables... */
int Finger(username, sleep_sec, maxiter, progname, hostname, fingercmd, debug, parent_pid)
char *username, *progname, *hostname, *fingercmd;
int sleep_sec, debug, parent_pid;
long maxiter;
{
FILE *in;
register char *cp;
register int not_on = 1, iter = 1, piperesult, pipelines;
extern int errno;
char buf[160], pipename[128];
time_t now;
strcpy(pipename, fingercmd);
strcat(pipename, " ");
if (strnicmp("finger", fingercmd, SZ(6)) != 0)
hostname++; /* Skip the @ sign if it's not finger! */
strcat(pipename, hostname);
do {
if (debug > 0) {
time(&now);
(void) printf("## %s: %s (try #%d), at %s",
progname, pipename, iter, ctime(&now));
}
#ifdef CHECKPARENT
if (kill(parent_pid, 0)) /* we've lost our shell! */
exit(2);
#endif
#ifdef CHECKSTDERR
if (!isatty(2))
exit(2);
#endif
if ((in = popen (pipename, "r")) == NULL) {
perror (fingercmd);
not_on = errno; /* a negative not_on signifies an error. */
break;
}
/* Cycle through all 'users' logged in. */
pipelines = 0;
while (not_on && fgets (buf, (int)sizeof(buf), in) != NULL) {
if (debug > 1) printf(buf);
pipelines++;
/* put a \0 in the first space after the username for strnicmp */
cp = buf;
while (*cp && isspace(*cp) == 0)
cp++;
*cp = '\0';
not_on = strnicmp(username, buf, SZ(8));
}
piperesult = pclose(in); /* close pipe */
if (piperesult && not_on) {
not_on = (piperesult > 0) ? -piperesult : piperesult;
break;
}
if (pipelines <= 1) {
/* finger probably puked */
not_on = -1;
break;
}
/* Delay a little so we won't hog the CPU */
if (not_on) {
iter++;
if ((maxiter > 0) && (iter > maxiter)) {
not_on = 1;
break;
}
if (iter == 2) {
printf("\nPolling for %s...\n", username);
}
(void) sleep (sleep_sec);
}
} while (not_on);
return (not_on);
} /* Finger */
strnicmp(a, b, n)
register char *a, *b;
register size_t n;
{
register int A, B;
while (n-- > (size_t)0) {
A = tolower((int) *a++);
B = tolower((int) *b++);
if (A > B) return (A - B);
if (B > A) return (B - A);
if (A == 0 && B == 0) return (0);
}
return (0); /* equal to n characters if we get here */
} /* strnicmp */
usage(progname)
char *progname;
{
(void) fprintf (stderr,
"\nusage: %s [-p N] [-i N] [-s cmd] [-f cmd] [-d] %susername | -a %s\n\
\t-a : Ask you for the user name, so others can't see it.\n\
\t-p N : Seconds between iterations (defaults: local=%d, remote=%d).\n\
\t-i N : Give up after 'N' iterations (default is infinity)\n\
\t-s cmd : Command to execute when user is found (i.e. \"talk username\")\n\
\t-f cmd : Command to execute for remote addresses (def: \"%s\")\n\
\t-d : Debugging mode. More d's, more stuff.\n%s\
\n%s by Phil Dietz & Mike Gleason, NCEMRSoft.\n\n",
progname,
#ifdef AUTOBG
"[-j] ",
"",
#else
"",
"&",
#endif
DEFAULT_LOCAL_SLEEP,
DEFAULT_REMOTE_SLEEP,
DFINGER,
#ifdef AUTOBG
"\t-j : Don't go into the background automatically.\n",
#else
"",
#endif
VERSION_STR);
exit (1);
} /* usage */
/* eof */