home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume25 / ison / part01 / ison.c next >
Encoding:
C/C++ Source or Header  |  1991-11-04  |  13.1 KB  |  411 lines

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