home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume32 / ison / part01 < prev    next >
Encoding:
Text File  |  1992-10-17  |  18.5 KB  |  561 lines

  1. Newsgroups: comp.sources.misc
  2. From: mgleason@cse.unl.edu (Mike Gleason)
  3. Subject:  v32i104:  ison - Be informed when a specified user logs on, Part01/01
  4. Message-ID: <1992Oct16.142332.8342@sparky.imd.sterling.com>
  5. X-Md4-Signature: e934d5309339276c6f4f79f459d3ea0d
  6. Date: Fri, 16 Oct 1992 14:23:32 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mgleason@cse.unl.edu (Mike Gleason)
  10. Posting-number: Volume 32, Issue 104
  11. Archive-name: ison/part01
  12. Environment: UNIX
  13. Supersedes: ison: Volume 25, Issue 16
  14.  
  15. IsOn's purpose is to let you know when someone logs on.  You could always sit
  16. there at your terminal typing 'finger' or 'who' every 5 minutes, but that's
  17. boring and unproductive.  IsOn makes this easy.  If you wanted to know the
  18. instant I logged on, all it would take is a simple:
  19.  
  20.    ison mgleason@cse.unl.edu
  21.  
  22. When I do log on, ison would respond:
  23.  
  24.    ** mgleason logged in since Wed Oct 16 02:19:33 1991
  25.  
  26. IsOn lowers it's priority automatically, so it takes very little CPU, and
  27. spares you the trouble of remembering to use 'nice.'  It also puts itself
  28. in the background automatically, as of version 4.  For remote addresses
  29. (those in dude@machine.domain format) the 'finger' utility is used, or for
  30. a user on the same machine that you are on, IsOn will simply walk the 'utmp'
  31. file.
  32.  
  33. Version 4 changes:
  34.    + Auto-backgrounding.
  35.    + Optional -a flag will prompt for a username (to hide from ps :-)
  36.    + Default remote delay is longer, to ease the load on the network.
  37.    + Quits when finger times out or barfs.
  38.    + Quits when parent is killed (logout, hangup, etc).
  39.    + Should compile without incident on SunOS.
  40.    + Obscure bugs fixed.
  41.  
  42. Enjoy!
  43. --mike gleason = mgleason@cse.unl.edu
  44.  
  45. #! /bin/sh
  46. # This is a shell archive.  Remove anything before this line, then unpack
  47. # it by saving it into a file and typing "sh file".  To overwrite existing
  48. # files, type "sh file -c".  You can also feed this as standard input via
  49. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  50. # will see the following message at the end:
  51. #        "End of shell archive."
  52. # Contents:  ison.c ison.readme Makefile
  53. # Wrapped by mgleason@cse on Thu Oct 15 15:45:16 1992
  54. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  55. if test -f 'ison.c' -a "${1}" != "-c" ; then 
  56.   echo shar: Will not clobber existing file \"'ison.c'\"
  57. else
  58. echo shar: Extracting \"'ison.c'\" \(13015 characters\)
  59. sed "s/^X//" >'ison.c' <<'END_OF_FILE'
  60. X/*  IsOn... Copyright 1990, 1991 NCEMRSoft.  Use at your own risk!
  61. X    To compile: "cc -O ison.c -o ison"
  62. X    Version History:
  63. X    - v1.0 : 1990      : Phil Dietz, NCEMRSoft.
  64. X                       : Original release.
  65. X    - v2.0 : 05 Feb 91 : Phil Dietz, NCEMRSoft.
  66. X                       : Added 'finger'ing remote machines.
  67. X                       : Names and searches are now case insensitive.
  68. X    - v3.0 : 04 Aug 91 : Mike Gleason, NCEMRSoft.
  69. X                       : Complete rewrite, using unix system calls.
  70. X                       : Remote addresses are recognized automatically.
  71. X                       : IsOn nice's (lowers it's priority) itself.
  72. X                       : Remote commands are exec'd instead of subshelled.
  73. X                       : Uses handy getopt() function.
  74. X                       : Added -f option, in case you don't have finger,
  75. X                       :   our finger flags don't work, or want to try
  76. X                       :   it with rwho, etc.
  77. X                       : Added -d debugging option, so you can watch
  78. X                       :   ison's progress.  This is also useful if you
  79. X                       :   want to log to a file.
  80. X    - v4.0 : 31 Oct 91 : Mike Gleason, Mark Galassi, Tim Wilson.
  81. X                       : Added UTMP_FILE definition for SunOS.
  82. X                       : IsOn sends itself into the background!
  83. X                       : Added -a option, so you can specify a username
  84. X                       :   from a prompt, instead of on the command line,
  85. X                       :   to hide from ps, w, etc.
  86. X                       : IsOn should die if it's parent is killed (i.e.
  87. X                       :   you logout or hangup the serial line).
  88. X                       : Fixed big bug in stricmp().
  89. X                       : Should quit when finger gives an error; could
  90. X                       :   have done this earlier if finger would exit(1)
  91. X                       :   on an error like a nice program does.
  92. X                       : Changed default delay into two distincy delays,
  93. X                       :   one for remote (finger) and one for local.
  94. X                       :   The remote delay is much longer now, to be
  95. X                       :   more net friendly.
  96. X    - v4.1 : 15 Nov 91 : Didn't know there was a nice() system call :-);
  97. X                       :   replaced custom nice function with sys call.
  98. X    To do:
  99. X    -  Add an option to poll until the user is found AND not idle;
  100. X       Could be tricky due to different OS's finger output.
  101. X*/
  102. X
  103. X#define VERSION_STR "Version 4.1 (15 Nov 91)"
  104. X
  105. X#include <sys/types.h>
  106. X#include <sys/time.h>
  107. X#include <utmp.h>
  108. X#include <stdio.h>
  109. X#include <ctype.h>
  110. X#include <signal.h>
  111. X
  112. X#define SZ(expr) ((size_t) (expr))
  113. X#define DEFAULT_LOCAL_SLEEP 10   /* seconds to sleep between Utmp()'s */
  114. X#define DEFAULT_REMOTE_SLEEP 45  /* seconds to sleep between Finger()'s */
  115. X#define DDEBUG 0        /* prints stuff if > 0 */
  116. X#define DMAXITER -1L    /* loop forever until we find the guy */
  117. X#define DCOMMAND NULL   /* command line to do when user is found */
  118. X#define DFINGER "finger -fq"
  119. X#define NICE            /* when defined, I try to lower my priority. */
  120. X#define BEEP            /* when defined, I beep when the user is found. */
  121. X#define AUTOBG          /* when defined, I try to background myself. */
  122. X#define CHECKPARENT     /* check to see if our parent is alive */
  123. X
  124. X#ifndef UTMP_FILE       /* Most define this in utmp.h;  SunOS 4.1.1 doesn't. */
  125. X#   define UTMP_FILE "/etc/utmp"
  126. X#endif
  127. X
  128. X#ifndef INDEX
  129. X#   ifdef _SYSTYPE_SYSV
  130. X#       define INDEX strchr
  131. X#   else    /* bsd */
  132. X#       define INDEX index
  133. X#   endif
  134. X#endif
  135. X
  136. Xextern size_t fread();
  137. Xextern FILE *fopen(), *popen();
  138. Xextern char *INDEX();
  139. Xint strnicmp(), Nice(), Utmp(), Finger();
  140. X
  141. Xmain(argc, argv)
  142. X    int argc;
  143. X    char **argv;
  144. X{
  145. X    int                 sleep_sec = -1;
  146. X    int                 debug = DDEBUG;
  147. X    long                maxiter = DMAXITER;
  148. X    int                 notfound, flag;
  149. X    char                *username, hostname[64], *cp, prompted_name[64];
  150. X    int                 prompted = 0, parent_pid;
  151. X    char                *fingercmd = DFINGER;
  152. X    char                *cmd = DCOMMAND;
  153. X    time_t              logontime;
  154. X    extern int          getopt(), optind;   /* getopt() stuff */
  155. X    extern char         *optarg;            /* getopt() stuff */
  156. X
  157. X    if (argc <= 1)
  158. X        usage (argv[0]);
  159. X    parent_pid = getppid();
  160. X    while ((flag = getopt (argc, argv, "advs:p:i:f:")) != EOF)
  161. X        switch(flag) {
  162. X            case 'a':           /* ask for a name */
  163. X                printf("Name to check: ");
  164. X                gets(prompted_name);
  165. X                prompted = 1;
  166. X                break;
  167. X            case 'd':
  168. X            case 'v':   /* debug mode, verbose mode, same thing */
  169. X                debug++;
  170. X                break;
  171. X            case 's':
  172. X                cmd = optarg;
  173. X                break;
  174. X            case 'p':
  175. X                sleep_sec = atoi (optarg);
  176. X                break;
  177. X            case 'i':
  178. X                maxiter = (long) atol (optarg);
  179. X                break;
  180. X            case 'f':
  181. X                fingercmd = optarg;
  182. X                break;
  183. X            default: usage (argv[0]);
  184. X        }
  185. X    if (prompted == 0)
  186. X        username = argv[optind];
  187. X    else username = prompted_name;
  188. X
  189. X    if (username == NULL || strlen(username) == SZ(0))
  190. X        usage (argv[0]); /* no user specified! */
  191. X
  192. X#ifdef NICE
  193. X    /* lower our process' priority (nice) */
  194. X    (void) nice (20);
  195. X#endif
  196. X
  197. X#ifdef AUTOBG
  198. X    if (fork())        /* automatically puts this task in background! */
  199. X        exit(3);
  200. X
  201. X    (void) signal(SIGINT, SIG_IGN);
  202. X    (void) signal(SIGQUIT, SIG_IGN);
  203. X#endif
  204. X    (void) signal(SIGHUP, SIG_DFL);
  205. X
  206. X    if (debug > 0)
  207. X        printf("\nIsOn's PID: %d;  Parent: %d.\n", getpid(), parent_pid);
  208. X
  209. X    /*  Check the username for an @, which would suggest that it is
  210. X        a domain-style address. */
  211. X    if ((cp = INDEX (username, '@')) != NULL) {
  212. X        strcpy (hostname, cp);  /* @machine.domain.xxx */
  213. X        *cp = '\0';             /* shorten address down to just username */
  214. X        if (strlen(username) == SZ(0))
  215. X            usage (argv[0]);    /* no user specified! */
  216. X        if (sleep_sec < 0)
  217. X            sleep_sec = DEFAULT_REMOTE_SLEEP;
  218. X        notfound = Finger (username, sleep_sec, maxiter, argv[0],
  219. X            hostname, fingercmd, debug, parent_pid);
  220. X        time(&logontime);
  221. X    } else {
  222. X        if (sleep_sec < 0)
  223. X            sleep_sec = DEFAULT_LOCAL_SLEEP;
  224. X        notfound = Utmp (username, sleep_sec, maxiter, argv[0],
  225. X            debug, &logontime, parent_pid);
  226. X    }
  227. X
  228. X    /* See if the user was found.  If not, explain why not. */
  229. X    if (notfound != 0) {
  230. X        if (notfound > 0)   /* maxiter encoutered */
  231. X            (void) fprintf (stderr, "\n## %s is not on.\n", username);
  232. X        else (void) fprintf (stderr,
  233. X            "\n## %s: cannot go on because of errors.\n", argv[0]);
  234. X    } else {
  235. X        /* When we get here, the user we're looking for was detected. */
  236. X        (void) fprintf (stderr, "\n** %s%s logged in since %s",
  237. X#ifdef BEEP
  238. X            "\007",     /* Control-G, the ascii BEL character */
  239. X#else
  240. X            "",
  241. X#endif
  242. X            username, ctime(&logontime));
  243. X        if (cmd != NULL) {
  244. X            /* Run a command (script) if the user requested to. */
  245. X            (void) execlp ("/bin/sh", "sh", "-c", cmd, NULL);
  246. X            (void) perror (cmd);
  247. X        }
  248. X    }
  249. X    exit (notfound);
  250. X}   /* main */
  251. X
  252. X
  253. X
  254. X
  255. Xint Utmp(username, sleep_sec, maxiter, progname, debug, tyme, parent_pid)
  256. X    char                *username, *progname;
  257. X    int                 sleep_sec, debug, parent_pid;
  258. X    long                maxiter;
  259. X    time_t              *tyme;
  260. X{
  261. X    struct utmp         info;
  262. X    FILE                *in;
  263. X    register int        not_on = 1, iter = 1;
  264. X    char                theuser[16];
  265. X
  266. X    /* Open the utmp file, which is a list of all logged on users. */
  267. X    if ((in = fopen (UTMP_FILE, "r")) == NULL) {
  268. X        (void) perror (UTMP_FILE);
  269. X        return (-1);
  270. X    }
  271. X    
  272. X    do {
  273. X        if (debug > 0) {
  274. X            time(tyme);
  275. X            (void) printf("## %s: checking utmp (try #%d) at %s",
  276. X                progname, iter, ctime(tyme));
  277. X        }
  278. X
  279. X        /* Reset the utmp file and re-read it. */
  280. X        (void) rewind (in);
  281. X
  282. X#ifdef CHECKPARENT
  283. X        if (kill(parent_pid, 0))     /* we've lost our shell! */
  284. X            exit(2);
  285. X#endif
  286. X
  287. X        /* Cycle through all 'users' logged in. */
  288. X        while (not_on && (fread (&info, SZ(sizeof (info)), SZ(1), in)) == SZ(1)) {
  289. X            /* Inefficent, but necessary */
  290. X            strncpy(theuser, info.ut_name, SZ(8));
  291. X            theuser[8] = '\0';
  292. X            not_on = strnicmp(username, theuser, SZ(8));
  293. X            if (debug > 1 && theuser[0] != '\0')
  294. X                printf("%s\n", theuser);
  295. X        }
  296. X        
  297. X        /* Delay a little so we won't hog the CPU */
  298. X        if (not_on) {
  299. X            iter++;
  300. X            if ((maxiter > 0) && (iter > maxiter)) {
  301. X                not_on = 1;
  302. X                break;
  303. X            }
  304. X            if (iter == 2) {
  305. X                printf("\nPolling for %s...\n", username);
  306. X            }
  307. X            (void) sleep (sleep_sec);
  308. X        }
  309. X    } while (not_on);
  310. X    
  311. X    *tyme = info.ut_time;   /* will hold garbage if user not found! */
  312. X    (void) fclose (in);
  313. X    return (not_on);
  314. X}   /* Utmp */
  315. X
  316. X
  317. X
  318. X/* Maybe I should just break down and use a few global variables... */
  319. Xint Finger(username, sleep_sec, maxiter, progname, hostname, fingercmd, debug, parent_pid)
  320. X    char *username, *progname, *hostname, *fingercmd;
  321. X    int sleep_sec, debug, parent_pid;
  322. X    long maxiter;
  323. X{
  324. X    FILE                *in;
  325. X    register char       *cp;
  326. X    register int        not_on = 1, iter = 1, piperesult, pipelines;
  327. X    extern int          errno;
  328. X    char                buf[160], pipename[128];
  329. X    time_t              now;
  330. X    
  331. X    strcpy(pipename, fingercmd);
  332. X    strcat(pipename, " ");
  333. X    if (strnicmp("finger", fingercmd, SZ(6)) != 0)
  334. X        hostname++; /* Skip the @ sign if it's not finger! */
  335. X    strcat(pipename, hostname);
  336. X    
  337. X    do {
  338. X        if (debug > 0) {        
  339. X            time(&now);
  340. X            (void) printf("## %s: %s (try #%d), at %s",
  341. X                progname, pipename, iter, ctime(&now));
  342. X        }
  343. X
  344. X#ifdef CHECKPARENT
  345. X        if (kill(parent_pid, 0))     /* we've lost our shell! */
  346. X            exit(2);
  347. X#endif
  348. X
  349. X        if ((in = popen (pipename, "r")) == NULL) {
  350. X            perror (fingercmd);
  351. X            not_on = errno;    /* a negative not_on signifies an error. */
  352. X            break;
  353. X        }
  354. X        
  355. X        /* Cycle through all 'users' logged in. */
  356. X        pipelines = 0;
  357. X        while (not_on && fgets (buf, (int)sizeof(buf), in) != NULL) {
  358. X            if (debug > 1) printf(buf);
  359. X            pipelines++;
  360. X            /* put a \0 in the first space after the username for strnicmp */
  361. X            cp = buf;
  362. X            while (*cp && isspace(*cp) == 0)
  363. X                cp++;
  364. X            *cp = '\0';
  365. X            not_on = strnicmp(username, buf, SZ(8));
  366. X        }
  367. X        
  368. X        piperesult = pclose(in);            /* close pipe */
  369. X        if (piperesult && not_on) {
  370. X            not_on = (piperesult > 0) ? -piperesult : piperesult;
  371. X            break;
  372. X        }
  373. X        if (pipelines <= 1) {
  374. X            /* finger probably puked */
  375. X            not_on = -1;
  376. X            break;
  377. X        }
  378. X
  379. X        /* Delay a little so we won't hog the CPU */
  380. X        if (not_on) {
  381. X            iter++;
  382. X            if ((maxiter > 0) && (iter > maxiter)) {
  383. X                not_on = 1;
  384. X                break;
  385. X            }
  386. X            if (iter == 2) {
  387. X                printf("\nPolling for %s...\n", username);
  388. X            }
  389. X            (void) sleep (sleep_sec);
  390. X        }
  391. X    } while (not_on);
  392. X    return (not_on);
  393. X}   /* Finger */
  394. X
  395. X
  396. X
  397. Xstrnicmp(a, b, n)
  398. X    register char *a, *b;
  399. X    register size_t n;
  400. X{
  401. X    register int A, B;
  402. X    
  403. X    while (n-- > (size_t)0) {
  404. X        A = tolower((int) *a++);
  405. X        B = tolower((int) *b++);
  406. X        if (A > B) return (A - B);
  407. X        if (B > A) return (B - A);
  408. X        if (A == 0 && B == 0) return (0);
  409. X    }
  410. X    return (0);    /* equal to n characters if we get here */
  411. X}   /* strnicmp */
  412. X
  413. X
  414. X
  415. X
  416. Xusage(progname)
  417. X    char *progname;
  418. X{   
  419. X    (void) fprintf (stderr,
  420. X"\nusage: %s [-p N] [-i N] [-s cmd] [-f cmd] [-d] username | -a %s\n\
  421. X\t-a     : Ask you for the user name, so others can't see it.\n\
  422. X\t-p N   : Seconds between iterations (defaults: local=%d, remote=%d).\n\
  423. X\t-i N   : Give up after 'N' iterations (default is infinity)\n\
  424. X\t-s cmd : Command to execute when user is found (i.e. \"talk username\")\n\
  425. X\t-f cmd : Command to execute for remote addresses (def: \"%s\")\n\
  426. X\t-d     : Debugging mode. More d's, more stuff.\n\n\
  427. X%s by Phil Dietz & Mike Gleason, NCEMRSoft.\n\
  428. XThis is TuitionWare.  Please send a buck to help us through school!\n\
  429. X\tPhil Dietz, Box 306, Yutan, NE  68073, USA... Thanks!\n\n",
  430. X    progname,
  431. X#ifdef AUTOBG
  432. X    "",
  433. X#else
  434. X    "&",
  435. X#endif
  436. X    DEFAULT_LOCAL_SLEEP,
  437. X    DEFAULT_REMOTE_SLEEP,
  438. X    DFINGER,
  439. X    VERSION_STR);
  440. X    exit (1);
  441. X}   /* usage */
  442. X
  443. X/* eof */
  444. END_OF_FILE
  445. if test 13015 -ne `wc -c <'ison.c'`; then
  446.     echo shar: \"'ison.c'\" unpacked with wrong size!
  447. fi
  448. # end of 'ison.c'
  449. fi
  450. if test -f 'ison.readme' -a "${1}" != "-c" ; then 
  451.   echo shar: Will not clobber existing file \"'ison.readme'\"
  452. else
  453. echo shar: Extracting \"'ison.readme'\" \(1189 characters\)
  454. sed "s/^X//" >'ison.readme' <<'END_OF_FILE'
  455. XIsOn's purpose is to let you know when someone logs on.  You could always sit
  456. Xthere at your terminal typing 'finger' or 'who' every 5 minutes, but that's
  457. Xboring and unproductive.  IsOn makes this easy.  If you wanted to know the
  458. Xinstant I logged on, all it would take is a simple:
  459. X
  460. X   ison mgleason@cse.unl.edu
  461. X
  462. XWhen I do log on, ison would respond:
  463. X
  464. X   ** mgleason logged in since Wed Oct 16 02:19:33 1991
  465. X
  466. XIsOn lowers it's priority automatically, so it takes very little CPU, and
  467. Xspares you the trouble of remembering to use 'nice.'  It also puts itself
  468. Xin the background automatically, as of version 4.  For remote addresses
  469. X(those in dude@machine.domain format) the 'finger' utility is used, or for
  470. Xa user on the same machine that you are on, IsOn will simply walk the 'utmp'
  471. Xfile.
  472. X
  473. XVersion 4 changes:
  474. X   + Auto-backgrounding.
  475. X   + Optional -a flag will prompt for a username (to hide from ps :-)
  476. X   + Default remote delay is longer, to ease the load on the network.
  477. X   + Quits when finger times out or barfs.
  478. X   + Quits when parent is killed (logout, hangup, etc).
  479. X   + Should compile without incident on SunOS.
  480. X   + Obscure bugs fixed.
  481. X
  482. XEnjoy!
  483. X--mike gleason = mgleason@cse.unl.edu
  484. X
  485. END_OF_FILE
  486. if test 1189 -ne `wc -c <'ison.readme'`; then
  487.     echo shar: \"'ison.readme'\" unpacked with wrong size!
  488. fi
  489. # end of 'ison.readme'
  490. fi
  491. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  492.   echo shar: Will not clobber existing file \"'Makefile'\"
  493. else
  494. echo shar: Extracting \"'Makefile'\" \(763 characters\)
  495. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  496. X# IsOn's Makefile
  497. X
  498. X# Source file name minus .c, and compiled exectuable's pathname.
  499. XCFILE=ison
  500. XOFILE=ison
  501. X
  502. X# Your favorite C Compiler, and flags.
  503. XCC=cc
  504. XCFLAGS=-O
  505. XLFLAGS=-s
  506. XDEFS=
  507. X
  508. XREADME=$(CFILE).readme
  509. XPACKAGE=$(CFILE).c $(README) Makefile
  510. X
  511. Xall:
  512. X    $(CC) $(CFLAGS) $(DEFS) $(CFILE).c -o $(OFILE) $(LFLAGS)
  513. X    @ls -l $(CFILE)
  514. X
  515. Xshar:
  516. X    shar $(PACKAGE) | cat $(README) - > $(CFILE).shar
  517. X
  518. Xtar:
  519. X    tar cvf - $(PACKAGE) | compress -f > $(CFILE).tar.Z
  520. X
  521. Xclean:
  522. X    rm -f core $(OFILE)
  523. X
  524. Xclobber: clean
  525. X    rm -i $(PACKAGE)
  526. X
  527. X# I use these during development:
  528. Xlint:
  529. X    lint $(CFILE).c > $(CFILE).lint
  530. X
  531. Xdebug:
  532. X    $(CC) -g $(DEFS) $(CFILE).c -o $(OFILE)
  533. X    @ls -l $(OFILE)
  534. X
  535. Xmips:
  536. X    cc -O3 -s $(DEFS) $(CFILE).c -o $(OFILE)
  537. X    @rm -f $(CFILE).u
  538. X    @ls -l $(OFILE)
  539. X
  540. Xrz:
  541. X    rm -f $(CFILE).c
  542. X    rz -e
  543. X    make
  544. X
  545. END_OF_FILE
  546. if test 763 -ne `wc -c <'Makefile'`; then
  547.     echo shar: \"'Makefile'\" unpacked with wrong size!
  548. fi
  549. # end of 'Makefile'
  550. fi
  551. echo shar: End of shell archive.
  552. exit 0
  553. --
  554. ______________________________________________________________________________
  555. mike gleason                 mgleason@cse.unl.edu             NCEMRSoft, baby!
  556.  
  557. exit 0 # Just in case...
  558.