home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8707 / 62 / finger.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-13  |  12.9 KB  |  635 lines

  1. #ifndef lint
  2. static char rcsid[] =
  3.     "@(#) $Header: finger.c,v 1.13 87/04/21 17:50:03 leres Exp $ (LBL)";
  4. #endif
  5. /*
  6.  * VAX/VMS finger
  7.  *
  8.  * Craig Leres, Lawrence Berkeley Laboratory
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <string.h>
  14. #include <pwd.h>
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <netdb.h>
  18. #include <netinet/in.h>
  19. #include <arpa/inet.h>
  20.  
  21. #include <eunice/eunice.h>
  22.  
  23. #include "vms/jpidef.h"
  24. #include "vms/dvidef.h"
  25. #include "vms/ttdef.h"
  26. #include "vms/tt2def.h"
  27. #include "vms/ssdef.h"
  28. #include "vms/statedef.h"
  29.  
  30. #include "item_list_3.h"
  31. #include "dsc.h"
  32.  
  33. /* People list */
  34. struct plist {
  35.     struct plist *p_next;
  36.     char *p_realname;
  37.     char *p_location;
  38.     u_long p_logintime;
  39.     long p_idletime;
  40.     u_long p_pid;
  41.     u_long p_state;
  42.     u_long p_net;
  43.     int p_nomesg;
  44.     char p_username[16];
  45.     char p_terminal[8];
  46. };
  47.  
  48. /* Remote locations */
  49. static struct rlist {
  50.     struct rlist *r_next;
  51.     u_long r_net;
  52.     char *r_location;
  53. };
  54.  
  55. /* Variables for jpi call */
  56. static char busername[13];
  57. static short lusername;
  58. static char bterminal[8];
  59. static short lterminal;
  60. static u_long blogintime[2];
  61. static u_long bstate;
  62.  
  63. static struct item_list_3 itmlst[] = {
  64.     sizeof(busername) - 1, JPI$_USERNAME, busername, &lusername,
  65.     sizeof(bterminal) - 1, JPI$_TERMINAL, bterminal, <erminal,
  66.     sizeof(blogintime), JPI$_LOGINTIM, (char *)blogintime, 0,
  67.     sizeof(bstate), JPI$_STATE, (char *)&bstate, 0,
  68.     0, 0, 0, 0
  69. };
  70.  
  71. /* Variables for dvi call */
  72. static u_long bdevdepend, bdevdepend2;
  73.  
  74. static struct item_list_3 dvilst[] = {
  75.     sizeof(bdevdepend), DVI$_DEVDEPEND, (char *)&bdevdepend, 0,
  76.     sizeof(bdevdepend2), DVI$_DEVDEPEND2, (char *)&bdevdepend2, 0,
  77.     0, 0, 0, 0
  78. };
  79.  
  80. /* Function declarations */
  81. char *malloc(), *pidle(), *ptime(), *getstate(), *getnetloc();
  82. u_long cvt_to_unix_time();
  83. struct plist *makelist();
  84.  
  85. /* Globals */
  86. char *argv0;                /* Program name pointer */
  87. struct rlist *netlocs = 0;        /* List of remote locations */
  88. int doseconds = 0;            /* display seconds of idle time */
  89. int dofast = 0;                /* display locations by default */
  90.  
  91. extern int vmserrno;
  92.  
  93. #define SAVESTR(cp) strcpy(malloc(strlen(cp) + 1), cp)
  94.  
  95. main(argc, argv)
  96.     int argc;
  97.     char *argv[];
  98. {
  99.     register int i;
  100.     register char *cp;
  101.     register struct plist *pp;
  102.     int didany;
  103.     char *usage = "usage: %s [-fs] [[user]@host] ...\n";
  104.  
  105.     argv0 = argv[0];
  106.  
  107.     /* Handle arguments */
  108.     didany = 0;
  109.     for (i = 1; i < argc; i++) {
  110.         cp = argv[i];
  111.         if (netfinger(cp)) {
  112.             didany++;
  113.             continue;
  114.         }
  115.         if (*cp != '-') {
  116.             fprintf(stderr, usage, argv0);
  117.             exit(1);
  118.         }
  119.         for (cp++; *cp != '\0'; cp++)
  120.             switch (*cp) {
  121.  
  122.             case 'f':
  123.                 dofast++;
  124.                 break;
  125.             case 's':
  126.                 doseconds++;
  127.                 break;
  128.             default:
  129.                 fprintf(stderr, usage, argv0);
  130.                 exit(1);
  131.             }
  132.     }
  133.     if (didany)
  134.         exit(0);
  135.  
  136.     /* Get the stuff */
  137.     pp = makelist();
  138.  
  139.     /* Fill in the locations */
  140.     getlocs(pp);
  141.  
  142.     /* Fill in the real names */
  143.     getreal(pp);
  144.  
  145.     /* Output the data */
  146.     printf("Login        Name                 TTY  Idle When       Location\n");
  147.     while (pp) {
  148.         /*
  149.          *    Print out info about one user
  150.          */
  151.         printf("%-12.12s %-20.20s%c%4s %4s %9.9s",
  152.             pp->p_username,
  153.             pp->p_realname ? pp->p_realname : "",
  154.             pp->p_nomesg ? '*' : ' ',
  155.             pp->p_terminal,
  156.             pidle(pp->p_idletime),
  157.             pp->p_logintime ?
  158.             ptime(pp->p_logintime) : getstate(pp->p_state));
  159.         if (pp->p_location)
  160.             printf("  %s", pp->p_location);
  161.         putchar('\n');
  162.         pp = pp->p_next;
  163.     }
  164.     exit(0);
  165. }
  166.  
  167. /*
  168.  * Create the list of logged in users
  169.  */
  170. struct plist *
  171. makelist()
  172. {
  173.     register int i, j;
  174.     long *lp_tim;
  175.     u_long *lp_pid;
  176.     u_long *lp_net;
  177.     struct plist *p, *pp, *plast, pjunk;
  178.     long iosb[2];
  179.  
  180.     /* Get the idle time info */
  181.     vmserrno = getidle(&lp_tim, &lp_pid, &lp_net);
  182.     if ((vmserrno & 1) == 0) {
  183.         fprintf(stderr, "%s: ", argv0);
  184.         vmsperror("getidle()");
  185.         exit(1);
  186.     }
  187.  
  188.     /* Loop through the idle info and build the list */
  189.     bzero((char *)&pjunk, sizeof(struct plist));
  190.     for (i = 0; lp_pid[i]; i++) {
  191.         bterminal[0] = '\0';
  192.         vmserrno = sys$getjpiw(0, &lp_pid[i], 0, itmlst, iosb, 0, 0);
  193.         if (vmserrno & 1 || vmserrno == SS$_SUSPENDED)
  194.             vmserrno = iosb[0];
  195.         if (vmserrno == SS$_NONEXPR)
  196.             continue;
  197.         if ((vmserrno & 1) == 0 && vmserrno != SS$_SUSPENDED) {
  198.             fprintf(stderr, "%s: ", argv0);
  199.             vmsperror("sys$getjpiw()");
  200.             exit(1);
  201.         }
  202.         if (bterminal[0] == '\0')
  203.             continue;
  204.         p = (struct plist *) malloc(sizeof(struct plist));
  205.         bzero((char *)p, sizeof(struct plist));
  206.         busername[lusername] = '\0';
  207.         munch(busername);
  208.         (void) strcpy(p->p_username, busername);
  209.         if (lterminal > 1 && bterminal[lterminal-1] == ':')
  210.             lterminal--;
  211.         bterminal[lterminal] = '\0';
  212.         munch(bterminal);
  213.         (void) strcpy(p->p_terminal, bterminal);
  214.         if (vmserrno != SS$_SUSPENDED)
  215.             p->p_logintime = cvt_to_unix_time(blogintime);
  216.         else
  217.             p->p_logintime = 0;
  218.         p->p_state = bstate;
  219.         p->p_idletime = lp_tim[i];
  220.         p->p_pid = lp_pid[i];
  221.         p->p_nomesg = nomesg(bterminal);
  222.         if (p->p_net = lp_net[i])
  223.             p->p_location = getnetloc(p->p_net, p->p_terminal);
  224.  
  225.         /* Insert in proper order */
  226.         plast = &pjunk;
  227.         for (pp = plast->p_next; pp; pp = pp->p_next) {
  228.             if ((j = ttycmp(p->p_terminal, pp->p_terminal)) < 0) {
  229.                 /* Insert in front */
  230.                 p->p_next = plast->p_next;
  231.                 plast->p_next = p;
  232.                 p = 0;
  233.                 break;
  234.             } else if (j == 0 && p->p_pid == pp->p_pid) {
  235.                 /*
  236.                  * Managed to get some terminal twice.
  237.                  * This can happen if someone allocates
  238.                  * a terminal that isn't logged in...
  239.                  *
  240.                  * Keep one of the two entries. Keep the new
  241.                  * entry if it has a location (implying it's a
  242.                  * network entry) or has a non zero idle time.
  243.                  */
  244.                 if (p->p_location != 0 || p->p_idletime > 0) {
  245.                     pp->p_idletime = p->p_idletime;
  246.                     pp->p_net = p->p_net;
  247.                     pp->p_location = p->p_location;
  248.                 }
  249.                 p = 0;
  250.                 break;
  251.             }
  252.             plast = pp;
  253.         }
  254.         if (p)
  255.             plast->p_next = p;
  256.     }
  257.     return(pjunk.p_next);
  258. }
  259.  
  260. /*
  261.  * Pound a string to lowercase and lose trailing spaces
  262.  */
  263. static munch(str)
  264.     char *str;
  265. {
  266.     register char *cp;
  267.  
  268.     for (cp = str; *cp != ' ' && *cp != '\0' && *cp != '\n'; cp++)
  269.         if (isupper(*cp))
  270.             *cp = tolower(*cp);
  271.     *cp = '\0';
  272. }
  273.  
  274. /*
  275.  * Add locations to the list
  276.  */
  277. getlocs(p)
  278.     struct plist *p;
  279. {
  280.     int todo;
  281.     register struct plist *pp;
  282.     register char *cp;
  283.     char line[256];
  284.     FILE *f;
  285.  
  286.     /* If no locations file, no thing to do */
  287.     if ((f = fopen("/etc/locations","r")) == NULL)
  288.         return;
  289.  
  290.     /* Count number of entries to do */
  291.     todo = 0;
  292.     for (pp = p; pp; pp = pp->p_next)
  293.         if (pp->p_location == 0)
  294.             todo++;
  295.  
  296.     /* Read the locations file once, updating list as we go along */
  297.     while (todo > 0 && fgets(line, sizeof(line), f) != NULL) {
  298.         line[sizeof(line)-1] = '\0';
  299.         if ((cp = index(line, '\n')) != NULL)
  300.             *cp = '\0';
  301.         if ((cp = index(line, ',')) != NULL)
  302.             *cp++ = '\0';
  303.         for (pp = p; pp; pp = pp->p_next)
  304.             if (pp->p_location == 0 && strcmpn(pp->p_terminal,
  305.                 line, strlen(pp->p_terminal)) == 0) {
  306.                 pp->p_location = SAVESTR(cp);
  307.                 todo--;
  308.                 break;
  309.             }
  310.     }
  311.     (void) fclose(f);
  312.     return;
  313. }
  314.  
  315. /*
  316.  * Add real names to the list
  317.  */
  318. getreal(p)
  319.     struct plist *p;
  320. {
  321.     register struct plist *pp;
  322.     register struct passwd *pw;
  323.     register char *cp, *name;
  324.     int todo;
  325.  
  326.     /* Can't do much here without the password file */
  327.     if (setpwent() == 0)
  328.         return;
  329.  
  330.     /* Count number of entries */
  331.     todo = 0;
  332.     for (pp = p; pp; pp = pp->p_next)
  333.         todo++;
  334.  
  335.     /* Read the password file once, updating list as we go along */
  336.     while (todo > 0 && (pw = getpwent())) {
  337.         name = 0;
  338.         for (pp = p; pp; pp = pp->p_next)
  339.             if (strcmp(pp->p_username, pw->pw_name) == 0) {
  340.                 if (name == 0) {
  341.                     name = SAVESTR(pw->pw_gecos);
  342.                     if ((cp = index(name, ',')) != NULL)
  343.                         *cp = '\0';
  344.                 }
  345.                 pp->p_realname = name;
  346.                 todo--;
  347.             }
  348.     }
  349.     (void) endpwent();
  350.     return;
  351. }
  352.  
  353. /*
  354.  * Format idle time
  355.  */
  356. char *
  357. pidle(idle)
  358.     long idle;
  359. {
  360.     register long l;
  361.     static char idlebuf[16];
  362.  
  363.     if ((l = idle/60) == 0) {
  364.         if (idle > 0 && doseconds)
  365.             (void) sprintf(idlebuf, "%ds", idle);
  366.         else
  367.             idlebuf[0] = '\0';
  368.     } else if (l < 60)
  369.         (void) sprintf(idlebuf, "%d", l);
  370.     else if (l/60 < 10)
  371.         (void) sprintf(idlebuf, "%d:%02d", l/60, l%60);
  372.     else if ((l = l/60) < 24)
  373.         (void) sprintf(idlebuf, "%dh", l);
  374.     else
  375.         (void) sprintf(idlebuf, "%dd", l/24);
  376.     return(idlebuf);
  377. }
  378.  
  379. /*
  380.  * Format the time
  381.  */
  382. char *
  383. ptime(u)
  384.     u_long u;
  385. {
  386.     static char timebuf[32];
  387.     struct tm *tp;
  388.     static char days[][4] = {
  389.         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  390.     };
  391.  
  392.     if (u == 0)
  393.         return("<susp>");
  394.  
  395.     tp = localtime(&u);
  396.     (void) sprintf(timebuf,"%s %2d:%02d",
  397.         days[tp->tm_wday],
  398.         tp->tm_hour,
  399.         tp->tm_min);
  400.     return(timebuf);
  401. }
  402.  
  403. /*
  404.  * Determine if a terminal has broadcasts disabled
  405.  */
  406. nomesg(tty)
  407.     char *tty;
  408. {
  409.     struct dsc tdsc;
  410.     long iosb[2];
  411.  
  412.     tdsc.d_buf = tty;
  413.     tdsc.d_len = strlen(tdsc.d_buf);
  414.  
  415.     vmserrno = sys$getdviw(0, 0, &tdsc, dvilst, iosb, 0, 0, 0);
  416.     if (vmserrno & 1)
  417.         vmserrno = iosb[0];
  418.     if ((vmserrno & 1) == 0) {
  419.         fprintf(stderr, "%s: ", argv0);
  420.         vmsperror("sys$getdviw()");
  421.         exit(1);
  422.     }
  423.     return((bdevdepend & TT$M_NOBRDCST) != 0 &&
  424.            (bdevdepend2 & TT2$M_BRDCSTMBX) == 0);
  425. }
  426.  
  427. /*
  428.  * Determine the network location of a terminal
  429.  */
  430. char *
  431. getnetloc(n, tty)
  432.     u_long n;
  433.     char *tty;
  434. {
  435.     register struct rlist *rp;
  436.     struct hostent *hp;
  437.     char host[32], loc[256];
  438.     long node;
  439.  
  440.     /* First, check if we've already figured this one out */
  441.     for (rp = netlocs; rp; rp = rp->r_next)
  442.         if (n == rp->r_net)
  443.             return(rp->r_location);
  444.  
  445.     /* Figure this one out for the first time */
  446.     if (strcmpn(tty, "nty", 3) == 0 || strcmpn(tty, "nta", 3) == 0) {
  447.         if (dofast == 0 &&
  448.             (hp = gethostbyaddr(&n, sizeof(u_long), AF_INET)))
  449.             (void) strcpy(loc, hp->h_name);
  450.         else
  451.             (void) sprintf(loc, "%d.%d.%d.%d",
  452.                 n & 0xff,
  453.                 n >> 8 & 0xff,
  454.                 n >> 16 & 0xff,
  455.                 n >> 24 & 0xff);
  456.     } else {
  457.         host[0] = '\0';
  458.         if (((vmserrno = rmtinfo(n, &node, host)) & 1) == 0) {
  459.             fprintf(stderr, "%s: ", argv0);
  460.             vmsperror("rmtinfo()");
  461.             exit(1);
  462.         }
  463.         if (host[0] != '\0')
  464.             (void) strcpy(loc, host);
  465.         else
  466.             (void) sprintf(loc, "node %d", node);
  467.     }
  468.  
  469.     /* Add this one to our list */
  470.     rp = (struct rlist *) malloc(sizeof(struct rlist));
  471.     bzero((char *)rp, sizeof(struct rlist));
  472.     rp->r_net = n;
  473.     rp->r_location = SAVESTR(loc);
  474.     if (netlocs) {
  475.         rp->r_next = netlocs->r_next;
  476.         netlocs->r_next = rp;
  477.     } else
  478.         netlocs = rp;
  479.  
  480.     return(rp->r_location);
  481. }
  482.  
  483. char *
  484. getstate(state)
  485.     u_long state;
  486. {
  487.     static char buf[32];
  488.  
  489.     switch (state) {
  490.  
  491.     case SCH$C_CEF:
  492.         return("<cef>");
  493.     case SCH$C_COM:
  494.         return("<com>");
  495.     case SCH$C_COMO:
  496.         return("<como>");
  497.     case SCH$C_CUR:
  498.         return("<cur>");
  499.     case SCH$C_COLPG:
  500.         return("<colpg>");
  501.     case SCH$C_FPG:
  502.         return("<fpg>");
  503.     case SCH$C_HIB:
  504.         return("<hib>");
  505.     case SCH$C_HIBO:
  506.         return("<hibo>");
  507.     case SCH$C_LEF:
  508.         return("<lef>");
  509.     case SCH$C_LEFO:
  510.         return("<lefo>");
  511.     case SCH$C_MWAIT:
  512.         return("<mwait>");
  513.     case SCH$C_PFW:
  514.         return("<pfw>");
  515.     case SCH$C_SUSP:
  516.         return("<susp>");
  517.     case SCH$C_SUSPO:
  518.         return("<suspo>");
  519.     }
  520.     return(sprintf(buf, "<%d>", state));
  521. }
  522.  
  523. /*
  524.  *  Similar to strcmp() but handles trailing unit number part numerically.
  525.  */
  526. ttycmp(s1, s2)
  527.     register char *s1, *s2;
  528. {
  529.  
  530.     while (isalpha(*s1) && isalpha(*s2) && *s1 == *s2++)
  531.         if (*s1++=='\0')
  532.             return(0);
  533.     if (isdigit(*s1) && isdigit(*s2))
  534.         return(atoi(s1) - atoi(s2));
  535.     return(*s1 - *--s2);
  536. }
  537.  
  538. /*
  539.  * Finger a remote machine
  540.  */
  541. netfinger(name)
  542.     char *name;
  543. {
  544.     char *host;
  545.     struct hostent *hp;
  546.     struct servent *sp;
  547.     struct sockaddr_in sin;
  548.     int s;
  549.     register FILE *f;
  550.     register int c;
  551.     register int lastc;
  552.  
  553.     if (name == 0)
  554.         return (0);
  555.     if ((host = rindex(name, '@')) == 0)
  556.         return (0);
  557.     *host++ = '\0';
  558.     bzero((char *)&sin, sizeof (sin));
  559.     if ((sin.sin_addr.s_addr = inet_addr(host)) != -1)
  560.         sin.sin_family = AF_INET;
  561.     else if ((hp = gethostbyname(host)) != 0) {
  562.         sin.sin_family = hp->h_addrtype;
  563.         bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
  564.         host = hp->h_name;
  565.     } else {
  566.         printf("%s: unknown host\n", host);
  567.         return(1);
  568.     }
  569.     printf("[%s]", host);
  570.     if ((sp = getservbyname("finger", "tcp")) == 0) {
  571.         printf("tcp/finger: unknown service\n");
  572.         return (1);
  573.     }
  574.     sin.sin_port = sp->s_port;
  575.     s = socket(sin.sin_family, SOCK_STREAM, 0);
  576.     if (s < 0) {
  577.         (void) fflush(stdout);
  578.         perror("socket");
  579.         return (1);
  580.     }
  581.     if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
  582.         (void) fflush(stdout);
  583.         perror("connect");
  584.         (void) close(s);
  585.         return (1);
  586.     }
  587.     putchar('\n');
  588. #ifdef notdef
  589.     if (large)
  590.         write(s, "/W ", 3);
  591. #endif
  592.     write(s, name, strlen(name));
  593.     write(s, "\r\n", 2);
  594.     f = fdopen(s, "r");
  595.     while ((c = getc(f)) != EOF) {
  596.         switch(c) {
  597.         case 0210:
  598.         case 0211:
  599.         case 0212:
  600.         case 0214:
  601.             c -= 0200;
  602.             break;
  603.         case 0215:
  604.             c = '\n';
  605.             break;
  606.         }
  607.         lastc = c;
  608.         if (isprint(c) || isspace(c))
  609.             putchar(c);
  610.         else
  611.             putchar(c ^ 100);
  612.     }
  613.     if (lastc != '\n')
  614.         putchar('\n');
  615.     (void) fclose(f);
  616.     return (1);
  617. }
  618.  
  619. /*
  620.  * Convert a VMS time quadword to Unix format
  621.  */
  622. static u_long
  623. cvt_to_unix_time(time)
  624.     u_long time[2];
  625. {
  626.     u_long local[2];
  627.     int dummy;
  628.     static int January_1_1970[2] = {0x4bec0000,0x007c9567};
  629.  
  630.     local[0] = time[0]; local[1] = time[1];
  631.     _$Subtract_Quadword(January_1_1970, local);
  632.     if (!(_$Cache_Flags & _$GMT_VALID)) _$Get_GMT_Info();
  633.     return(_$EDIV(10000000, local, &dummy) + _$Seconds_From_GMT);
  634. }
  635.