home *** CD-ROM | disk | FTP | other *** search
- /* IsOn... Copyright 1990, 1991 NCEMRSoft. Use at your own risk!
-
- To compile: "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.
-
- 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.0 (31 Oct 91)"
-
- #include <sys/types.h>
- #include <sys/time.h>
- #include <utmp.h>
- #include <stdio.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 */
-
- #ifndef UTMP_FILE /* Most define this in utmp.h; SunOS 4.1.1 doesn't. */
- # define UTMP_FILE "/etc/utmp"
- #endif
-
- #ifndef INDEX
- # ifdef _SYSTYPE_SYSV
- # define INDEX strchr
- # else /* bsd */
- # define INDEX index
- # endif
- #endif
-
- extern size_t fread();
- extern FILE *fopen(), *popen();
- extern char *INDEX();
- 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;
- 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, "advs: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 '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) */
- if (Nice (getpid()))
- perror ("Nice");
- #endif
-
- #ifdef AUTOBG
- 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
-
- /* 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)
- 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
-
- 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] username | -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\n\
- %s by Phil Dietz & Mike Gleason, NCEMRSoft.\n\
- This is TuitionWare. Please send a buck to help us through school!\n\
- \tPhil Dietz, Box 306, Yutan, NE 68073, USA... Thanks!\n\n",
- progname,
- #ifdef AUTOBG
- "",
- #else
- "&",
- #endif
- DEFAULT_LOCAL_SLEEP,
- DEFAULT_REMOTE_SLEEP,
- DFINGER,
- VERSION_STR);
- exit (1);
- } /* usage */
-
-
-
- #ifdef NICE
- # include <sys/resource.h>
- # define DEFAULT_NICE_INCREMENT 10
-
- int Nice(pid)
- pid_t pid;
- {
- extern int errno;
- register int priority;
-
- errno = 0; /* clear it, since priority can be -1! */
- priority = getpriority(PRIO_PROCESS, pid);
- if (errno == 0) {
- priority += DEFAULT_NICE_INCREMENT;
- if (priority > PRIO_MAX)
- priority = PRIO_MAX;
- (void) setpriority(PRIO_PROCESS, pid, priority);
- }
- return (errno);
- } /* Nice */
- #endif
-
- /* eof */
-