home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume34 / ison / part01 / ison.c < prev    next >
C/C++ Source or Header  |  1992-12-06  |  14KB  |  414 lines

  1. /*  IsOn... Copyright 1990-92 NCEMRSoft.  Use at your own risk!
  2.  
  3.     To compile:
  4.         BSD:      "cc -O -DBSD ison.c -o ison"
  5.         System V: "cc -O ison.c -o ison"
  6.  
  7.     Version History:
  8.     - v1.0 : 1990      : Phil Dietz, NCEMRSoft.
  9.                        : Original release.
  10.     - v2.0 : 05 Feb 91 : Phil Dietz, NCEMRSoft.
  11.                        : Added 'finger'ing remote machines.
  12.                        : Names and searches are now case insensitive.
  13.     - v3.0 : 04 Aug 91 : Mike Gleason, NCEMRSoft.
  14.                        : Complete rewrite, using unix system calls.
  15.                        : Remote addresses are recognized automatically.
  16.                        : IsOn nice's (lowers it's priority) itself.
  17.                        : Remote commands are exec'd instead of subshelled.
  18.                        : Uses handy getopt() function.
  19.                        : Added -f option, in case you don't have finger,
  20.                        :   our finger flags don't work, or want to try
  21.                        :   it with rwho, etc.
  22.                        : Added -d debugging option, so you can watch
  23.                        :   ison's progress.  This is also useful if you
  24.                        :   want to log to a file.
  25.     - v4.0 : 31 Oct 91 : Mike Gleason, Mark Galassi, Tim Wilson.
  26.                        : Added UTMP_FILE definition for SunOS.
  27.                        : IsOn sends itself into the background!
  28.                        : Added -a option, so you can specify a username
  29.                        :   from a prompt, instead of on the command line,
  30.                        :   to hide from ps, w, etc.
  31.                        : IsOn should die if it's parent is killed (i.e.
  32.                        :   you logout or hangup the serial line).
  33.                        : Fixed big bug in stricmp().
  34.                        : Should quit when finger gives an error; could
  35.                        :   have done this earlier if finger would exit(1)
  36.                        :   on an error like a nice program does.
  37.                        : Changed default delay into two distincy delays,
  38.                        :   one for remote (finger) and one for local.
  39.                        :   The remote delay is much longer now, to be
  40.                        :   more net friendly.
  41.     - v4.1 : 15 Nov 91 : Didn't know there was a nice() system call :-);
  42.                        :   replaced custom nice function with sys call.
  43.     - v4.2 : 20 Nov 92 : Removed some unnecessary prototypes.  Added
  44.                            CHECKSTDERR code so IsOn will die when you
  45.                            logout.  Changed so you need to define BSD
  46.                            to get index instead of having to define SYSV
  47.                            to get strchr.  Removed shareware message.
  48.                            Added -j option. 
  49.     To do:
  50.     -  Add an option to poll until the user is found AND not idle;
  51.        Could be tricky due to different OS's finger output.
  52. */
  53.  
  54. #define VERSION_STR "Version 4.2 (20 Nov 92)"
  55.  
  56. #include <sys/types.h>
  57. #include <sys/time.h>
  58. #include <utmp.h>
  59. #include <stdio.h>
  60. #include <string.h>
  61. #include <ctype.h>
  62. #include <signal.h>
  63.  
  64. #define SZ(expr) ((size_t) (expr))
  65. #define DEFAULT_LOCAL_SLEEP 10   /* seconds to sleep between Utmp()'s */
  66. #define DEFAULT_REMOTE_SLEEP 45  /* seconds to sleep between Finger()'s */
  67. #define DDEBUG 0        /* prints stuff if > 0 */
  68. #define DMAXITER -1L    /* loop forever until we find the guy */
  69. #define DCOMMAND NULL   /* command line to do when user is found */
  70. #define DFINGER "finger -fq"
  71. #define NICE            /* when defined, I try to lower my priority. */
  72. #define BEEP            /* when defined, I beep when the user is found. */
  73. #define AUTOBG          /* when defined, I try to background myself. */
  74. #define CHECKPARENT     /* check to see if our parent is alive */
  75. #define CHECKSTDERR     /* check to see if stderr is a tty */
  76.  
  77. #ifndef UTMP_FILE       /* Most define this in utmp.h;  SunOS 4.1.1 doesn't. */
  78. #   define UTMP_FILE "/etc/utmp"
  79. #endif
  80.  
  81. #ifndef INDEX
  82. #   ifdef BSD
  83. #       define INDEX index
  84. #   else
  85. #       define INDEX strchr
  86. #   endif
  87. #endif
  88.  
  89. int strnicmp(), Nice(), Utmp(), Finger();
  90.  
  91. main(argc, argv)
  92.     int argc;
  93.     char **argv;
  94. {
  95.     int                 sleep_sec = -1;
  96.     int                 debug = DDEBUG;
  97.     long                maxiter = DMAXITER;
  98.     int                 notfound, flag;
  99.     char                *username, hostname[64], *cp, prompted_name[64];
  100.     int                 prompted = 0, parent_pid;
  101.     int                 daemon = 1;
  102.     char                *fingercmd = DFINGER;
  103.     char                *cmd = DCOMMAND;
  104.     time_t              logontime;
  105.     extern int          getopt(), optind;   /* getopt() stuff */
  106.     extern char         *optarg;            /* getopt() stuff */
  107.  
  108.     if (argc <= 1)
  109.         usage (argv[0]);
  110.     parent_pid = getppid();
  111.     while ((flag = getopt (argc, argv, "adjvs:p:i:f:")) != EOF)
  112.         switch(flag) {
  113.             case 'a':           /* ask for a name */
  114.                 printf("Name to check: ");
  115.                 gets(prompted_name);
  116.                 prompted = 1;
  117.                 break;
  118.             case 'd':
  119.             case 'v':   /* debug mode, verbose mode, same thing */
  120.                 debug++;
  121.                 break;
  122.             case 'j':
  123.                 daemon = 0;
  124.                 break;
  125.             case 's':
  126.                 cmd = optarg;
  127.                 break;
  128.             case 'p':
  129.                 sleep_sec = atoi (optarg);
  130.                 break;
  131.             case 'i':
  132.                 maxiter = (long) atol (optarg);
  133.                 break;
  134.             case 'f':
  135.                 fingercmd = optarg;
  136.                 break;
  137.             default: usage (argv[0]);
  138.         }
  139.     if (prompted == 0)
  140.         username = argv[optind];
  141.     else username = prompted_name;
  142.  
  143.     if (username == NULL || strlen(username) == SZ(0))
  144.         usage (argv[0]); /* no user specified! */
  145.  
  146. #ifdef NICE
  147.     /* lower our process' priority (nice) */
  148.     (void) nice (20);
  149. #endif
  150.  
  151. #ifdef AUTOBG
  152.     if (daemon) {
  153.         if (fork())        /* automatically puts this task in background! */
  154.             exit(3);
  155.  
  156.         (void) signal(SIGINT, SIG_IGN);
  157.         (void) signal(SIGQUIT, SIG_IGN);
  158.     }
  159. #endif
  160.     (void) signal(SIGHUP, SIG_DFL);
  161.  
  162.     if (debug > 0)
  163.         printf("\nIsOn's PID: %d;  Parent: %d.\n", getpid(), parent_pid);
  164.  
  165.     /*  Check the username for an @, which would suggest that it is
  166.         a domain-style address. */
  167.     if ((cp = INDEX (username, '@')) != NULL) {
  168.         strcpy (hostname, cp);  /* @machine.domain.xxx */
  169.         *cp = '\0';             /* shorten address down to just username */
  170.         if (strlen(username) == SZ(0))
  171.             usage (argv[0]);    /* no user specified! */
  172.         if (sleep_sec < 0)
  173.             sleep_sec = DEFAULT_REMOTE_SLEEP;
  174.         notfound = Finger (username, sleep_sec, maxiter, argv[0],
  175.             hostname, fingercmd, debug, parent_pid);
  176.         time(&logontime);
  177.     } else {
  178.         if (sleep_sec < 0)
  179.             sleep_sec = DEFAULT_LOCAL_SLEEP;
  180.         notfound = Utmp (username, sleep_sec, maxiter, argv[0],
  181.             debug, &logontime, parent_pid);
  182.     }
  183.  
  184.     /* See if the user was found.  If not, explain why not. */
  185.     if (notfound != 0) {
  186.         if (notfound > 0)   /* maxiter encoutered */
  187.             (void) fprintf (stderr, "\n## %s is not on.\n", username);
  188.         else (void) fprintf (stderr,
  189.             "\n## %s: cannot go on because of errors.\n", argv[0]);
  190.     } else {
  191.         /* When we get here, the user we're looking for was detected. */
  192.         (void) fprintf (stderr, "\n** %s%s logged in since %s",
  193. #ifdef BEEP
  194.             "\007",     /* Control-G, the ascii BEL character */
  195. #else
  196.             "",
  197. #endif
  198.             username, ctime(&logontime));
  199.         if (cmd != NULL) {
  200.             /* Run a command (script) if the user requested to. */
  201.             (void) execlp ("/bin/sh", "sh", "-c", cmd, NULL);
  202.             (void) perror (cmd);
  203.         }
  204.     }
  205.     exit (notfound);
  206. }   /* main */
  207.  
  208.  
  209.  
  210.  
  211. int Utmp(username, sleep_sec, maxiter, progname, debug, tyme, parent_pid)
  212.     char                *username, *progname;
  213.     int                 sleep_sec, debug, parent_pid;
  214.     long                maxiter;
  215.     time_t              *tyme;
  216. {
  217.     struct utmp         info;
  218.     FILE                *in;
  219.     register int        not_on = 1, iter = 1;
  220.     char                theuser[16];
  221.  
  222.     /* Open the utmp file, which is a list of all logged on users. */
  223.     if ((in = fopen (UTMP_FILE, "r")) == NULL) {
  224.         (void) perror (UTMP_FILE);
  225.         return (-1);
  226.     }
  227.     
  228.     do {
  229.         if (debug > 0) {
  230.             time(tyme);
  231.             (void) printf("## %s: checking utmp (try #%d) at %s",
  232.                 progname, iter, ctime(tyme));
  233.         }
  234.  
  235.         /* Reset the utmp file and re-read it. */
  236.         (void) rewind (in);
  237.  
  238. #ifdef CHECKPARENT
  239.         if (kill(parent_pid, 0))     /* we've lost our shell! */
  240.             exit(2);
  241. #endif
  242. #ifdef CHECKSTDERR
  243.         if (!isatty(2))
  244.             exit(2);
  245. #endif
  246.  
  247.  
  248.         /* Cycle through all 'users' logged in. */
  249.         while (not_on && (fread (&info, SZ(sizeof (info)), SZ(1), in)) == SZ(1)) {
  250.             /* Inefficent, but necessary */
  251.             strncpy(theuser, info.ut_name, SZ(8));
  252.             theuser[8] = '\0';
  253.             not_on = strnicmp(username, theuser, SZ(8));
  254.             if (debug > 1 && theuser[0] != '\0')
  255.                 printf("%s\n", theuser);
  256.         }
  257.         
  258.         /* Delay a little so we won't hog the CPU */
  259.         if (not_on) {
  260.             iter++;
  261.             if ((maxiter > 0) && (iter > maxiter)) {
  262.                 not_on = 1;
  263.                 break;
  264.             }
  265.             if (iter == 2) {
  266.                 printf("\nPolling for %s...\n", username);
  267.             }
  268.             (void) sleep (sleep_sec);
  269.         }
  270.     } while (not_on);
  271.     
  272.     *tyme = info.ut_time;   /* will hold garbage if user not found! */
  273.     (void) fclose (in);
  274.     return (not_on);
  275. }   /* Utmp */
  276.  
  277.  
  278.  
  279. /* Maybe I should just break down and use a few global variables... */
  280. int Finger(username, sleep_sec, maxiter, progname, hostname, fingercmd, debug, parent_pid)
  281.     char *username, *progname, *hostname, *fingercmd;
  282.     int sleep_sec, debug, parent_pid;
  283.     long maxiter;
  284. {
  285.     FILE                *in;
  286.     register char       *cp;
  287.     register int        not_on = 1, iter = 1, piperesult, pipelines;
  288.     extern int          errno;
  289.     char                buf[160], pipename[128];
  290.     time_t              now;
  291.     
  292.     strcpy(pipename, fingercmd);
  293.     strcat(pipename, " ");
  294.     if (strnicmp("finger", fingercmd, SZ(6)) != 0)
  295.         hostname++; /* Skip the @ sign if it's not finger! */
  296.     strcat(pipename, hostname);
  297.     
  298.     do {
  299.         if (debug > 0) {        
  300.             time(&now);
  301.             (void) printf("## %s: %s (try #%d), at %s",
  302.                 progname, pipename, iter, ctime(&now));
  303.         }
  304.  
  305. #ifdef CHECKPARENT
  306.         if (kill(parent_pid, 0))     /* we've lost our shell! */
  307.             exit(2);
  308. #endif
  309. #ifdef CHECKSTDERR
  310.         if (!isatty(2))
  311.             exit(2);
  312. #endif
  313.  
  314.         if ((in = popen (pipename, "r")) == NULL) {
  315.             perror (fingercmd);
  316.             not_on = errno;    /* a negative not_on signifies an error. */
  317.             break;
  318.         }
  319.         
  320.         /* Cycle through all 'users' logged in. */
  321.         pipelines = 0;
  322.         while (not_on && fgets (buf, (int)sizeof(buf), in) != NULL) {
  323.             if (debug > 1) printf(buf);
  324.             pipelines++;
  325.             /* put a \0 in the first space after the username for strnicmp */
  326.             cp = buf;
  327.             while (*cp && isspace(*cp) == 0)
  328.                 cp++;
  329.             *cp = '\0';
  330.             not_on = strnicmp(username, buf, SZ(8));
  331.         }
  332.         
  333.         piperesult = pclose(in);            /* close pipe */
  334.         if (piperesult && not_on) {
  335.             not_on = (piperesult > 0) ? -piperesult : piperesult;
  336.             break;
  337.         }
  338.         if (pipelines <= 1) {
  339.             /* finger probably puked */
  340.             not_on = -1;
  341.             break;
  342.         }
  343.  
  344.         /* Delay a little so we won't hog the CPU */
  345.         if (not_on) {
  346.             iter++;
  347.             if ((maxiter > 0) && (iter > maxiter)) {
  348.                 not_on = 1;
  349.                 break;
  350.             }
  351.             if (iter == 2) {
  352.                 printf("\nPolling for %s...\n", username);
  353.             }
  354.             (void) sleep (sleep_sec);
  355.         }
  356.     } while (not_on);
  357.     return (not_on);
  358. }   /* Finger */
  359.  
  360.  
  361.  
  362. strnicmp(a, b, n)
  363.     register char *a, *b;
  364.     register size_t n;
  365. {
  366.     register int A, B;
  367.     
  368.     while (n-- > (size_t)0) {
  369.         A = tolower((int) *a++);
  370.         B = tolower((int) *b++);
  371.         if (A > B) return (A - B);
  372.         if (B > A) return (B - A);
  373.         if (A == 0 && B == 0) return (0);
  374.     }
  375.     return (0);    /* equal to n characters if we get here */
  376. }   /* strnicmp */
  377.  
  378.  
  379.  
  380.  
  381. usage(progname)
  382.     char *progname;
  383. {   
  384.     (void) fprintf (stderr,
  385. "\nusage: %s [-p N] [-i N] [-s cmd] [-f cmd] [-d] %susername | -a %s\n\
  386. \t-a     : Ask you for the user name, so others can't see it.\n\
  387. \t-p N   : Seconds between iterations (defaults: local=%d, remote=%d).\n\
  388. \t-i N   : Give up after 'N' iterations (default is infinity)\n\
  389. \t-s cmd : Command to execute when user is found (i.e. \"talk username\")\n\
  390. \t-f cmd : Command to execute for remote addresses (def: \"%s\")\n\
  391. \t-d     : Debugging mode. More d's, more stuff.\n%s\
  392. \n%s by Phil Dietz & Mike Gleason, NCEMRSoft.\n\n",
  393.     progname,
  394. #ifdef AUTOBG
  395.     "[-j] ",
  396.     "",
  397. #else
  398.     "",
  399.     "&",
  400. #endif
  401.     DEFAULT_LOCAL_SLEEP,
  402.     DEFAULT_REMOTE_SLEEP,
  403.     DFINGER,
  404. #ifdef AUTOBG
  405.     "\t-j     : Don't go into the background automatically.\n",
  406. #else
  407.     "",
  408. #endif
  409.     VERSION_STR);
  410.     exit (1);
  411. }   /* usage */
  412.  
  413. /* eof */
  414.