home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / finger / part06 / getcommand.c < prev   
Encoding:
C/C++ Source or Header  |  1992-04-03  |  14.6 KB  |  576 lines

  1. /*
  2.  * getcommand.c  -  return current command given a LUSER
  3.  *
  4.  * Copyright (C) 1986, 1990  Philip L. Budne
  5.  *
  6.  * This file is part of "Phil's Finger Program".
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 1, or (at your option)
  11.  * any later version.
  12.  *
  13.  */
  14.  
  15. # ifndef lint
  16. static char *rcsid = "$Id: getcommand.c,v 3.0 90/07/06 13:10:45 budd Rel $";
  17. # endif /* lint not defined */
  18.  
  19. # include "finger.h"
  20.  
  21. # ifndef Umax
  22. # include "ustruct.h"
  23. # else  /* Umax defined */
  24. # if Umax == 42
  25. # include <sys/signal.h>        /* for SIGxxx */
  26. # include <sys/pmdefs.h>        /* for SSTOP, procstates */
  27. # include <sys/time.h>            /* for statistics */
  28. # include <sys/types.h>            /* for dev_t */
  29. # include <sys/statistics.h>        /* for inq_stats */
  30. # include <sys/procstats.h>        /* for inq_stats */
  31. # endif /* Umax == 42 */
  32. # if Umax == 43
  33. # include <sys/signal.h>        /* for SIGxxx */
  34. # define KERNEL
  35. # include <sys/types.h>
  36. # undef KERNEL
  37. # include <sys/time.h>
  38. # include <sys/resource.h>
  39. # include <sys/proc.h>            /* Sxxx */
  40. # include <inq_stats/statistics.h>
  41. # include <inq_stats/procstats.h>
  42. # ifndef SSLEEP
  43. # define SSLEEP 1
  44. # endif /* SSLEEP not defined */
  45. # endif /* Umax == 43 */
  46. # endif /* Umax defined */
  47.  
  48. # include <stdio.h>
  49. # include "args.h"            /* before luser.h */
  50. # include "luser.h"
  51. # include "pr.h"
  52. # include "daemon.h"
  53. # define WAITSTATENAME waitstatename    /* for waitstate.h */
  54. # include "waitstate.h"
  55.  
  56. # ifdef Umax
  57. # include <sys/ioctl.h>            /* to get pgrp!!! */
  58. # define MAXP 100
  59. LOCAL struct pr prvec[ MAXP ];        /* per terminal process table */
  60. # else  /* Umax not defined */
  61. # include "kmem.h"
  62. extern FTYPE kmem;            /* from kmem.c */
  63. extern struct pr *readpr();        /* from readpr.c */
  64. extern waitstate_t waitstate();        /* from readpr.c */
  65.  
  66. LOCAL struct pr *prvec;            /* vector of processes */
  67. LOCAL int initialized;        /* true if have done readpr() */
  68. # endif /* Umax not defined */
  69.  
  70. # if Umax != 42
  71. LOCAL char *procstates[] = {
  72.     "?0", "SL",
  73. # ifdef SVR3_STATES
  74.  
  75.     "RU", "ZO", "ST", "ID", "ON", "SX",
  76. # ifdef UmaxV
  77.     "BS",
  78. # endif /* UmaxV defined */
  79.  
  80. # else  /* SVR3_STATES not defined */
  81.  
  82.     /* SVR2 and BSD */
  83.     "WA", "RU", "ID",
  84. # if Umax == 43
  85.     "ST", "EX", "EV",
  86. # else  /* not Umax == 43 */
  87.     "ZO", "ST",
  88. # ifdef AIX_RT
  89.     "?7", "?8", "?9", "SK",
  90. # endif /* AIX_RT defined */
  91. # endif /* not Umax == 43 */
  92.  
  93. # endif /* SVR3_STATES not defined */
  94.     "**" };
  95. # endif /* Umax != 42 */
  96.  
  97. # ifdef sun
  98. extern dev_t consdev;
  99. extern dev_t rconsdev;
  100. extern dev_t dev_console;
  101. # endif /* sun defined */
  102.  
  103. # ifndef PID_T
  104. # define PID_T short
  105. # endif /* PID_T not defined */
  106.  
  107. # ifndef PID_BITS
  108. # define PID_BITS 15            /* most Unices only go up to 30000 */
  109. # endif /* PID_BITS not defined */
  110.  
  111. LOCAL char *hidden[] = {
  112. # ifdef IN_DOT_SERVER
  113.     "in.comsat",
  114.     "in.syslog",
  115.     "in.talkd",
  116.     "in.rlogind",
  117.     "in.telnetd",
  118. # else  /* IN_DOT_SERVER not defined */
  119.     "comsat",
  120.     "syslogd",
  121.     "talkd",
  122.     "ntalkd",                /* 4.3 */
  123.     "rlogind",
  124.     "telnetd",
  125. # endif /* IN_DOT_SERVER not defined */
  126. # ifdef sun
  127.     "selection_svc",            /* SunView barfage */
  128. # endif /* sun defined */
  129. # ifdef HIDDEN_PROGRAMS
  130.     HIDDEN_PROGRAMS,
  131. # endif /* HIDDEN_PROGRAMS defined */
  132.     NULL
  133. };
  134.  
  135. LOCAL struct pr *getcommand2();
  136.  
  137. /*
  138.  *    given a luser, return pr struct for executing command.
  139.  *
  140.  *    getcommand is a jacket for getcommand2 which finds the
  141.  *    process.  we then trace back for process parent, and mark in
  142.  *    luser struct for potential use in printing ttyloc.
  143.  */
  144.  
  145. GLOBAL struct pr *getcommand( u )
  146. LUSER *u;
  147. {
  148.     struct pr *p2, *lastpr;
  149.     register struct pr *pr;
  150.     PID_T pp;
  151.  
  152.     u->u_command = u->u_daemonp = NULL;
  153.     u->u_daemon = NULL;
  154.  
  155.     if( (p2 = getcommand2( u )) == NULL )
  156.     return( NULL );
  157.     u->u_command = p2;
  158.  
  159.     /* only do this for lusers on ptys? *TODO* */
  160.     pp = p2->pr_ppid;
  161.     lastpr = NULL;
  162.     while( pp != INIT_PID && pp > 0 ) {
  163.     register struct daemon *dp;
  164.  
  165.     for( pr = prvec; pr->pr_stat != 0; pr++ ) /* search process table */
  166.         if( pr->pr_pid == pp )    /* for parent process pid */
  167.         break;
  168.  
  169.     if( pr->pr_pid != pp )        /* did not find parent? */
  170.         break;            /* (parent did not have a tty..) */
  171.  
  172.     lastpr = pr;            /* save most 'recent' ancestor */
  173.     /* here with parent, check for daemon-ness */
  174.     for( dp = daemons; dp->d_cmd != NULL; dp++ )
  175. /*        printf("%d %s %s\n", pp, pr->pr_cmd, dp->d_cmd );/**/
  176.         if( pr->pr_cmd[0] == dp->d_cmd[0] && /* quick test */
  177.            strcmp( pr->pr_cmd, dp->d_cmd ) == 0 ) {
  178.         u->u_daemon = dp;    /* save daemon type */
  179.         u->u_daemonp = pr;    /* save process for kicks */
  180.         return( p2 );        /* need goto to leave 2 loops */
  181.         } /* daemon match */
  182.     pp = pr->pr_ppid;        /* keep moving up process tree */
  183.     } /* while dp */
  184.  
  185.     /* catch things not in daemons[] */
  186.     /* (*) perhaps flush INIT_PID test? */
  187.     if( lastpr != NULL &&
  188.        pp == INIT_PID )            /* child of init (*) */
  189.     u->u_daemonp = lastpr;        /* save for possible display */
  190.     return( p2 );
  191. } /* getcommand */
  192.  
  193. /*
  194.  *    locate "current" process on a tty.
  195.  *    requires many silly heuristics.
  196.  */
  197.  
  198. LOCAL struct pr *getcommand2( u )
  199.     LUSER *u;
  200. {
  201.     SIGNED long weight, topweight;
  202.     struct pr *topweightpr;
  203.     register struct pr *pp;        /* process pointer */
  204.     register PID_T curpid;
  205.     char **progs;
  206.     PID_T tpg;                /* this tty's process group */
  207.     dev_t ttyd;                /* tty device */
  208.  
  209. # ifndef Umax
  210.     if( u->u_flags & U_BADTTY )
  211.     return( NULL );
  212.  
  213.     if( !initialized ) {
  214.     initialized = TRUE;
  215.     prvec = readpr();        /* read process table once. */
  216.     } /* not initialized */
  217.  
  218.     if( prvec == NULL )            /* have processes? */
  219.     return( NULL );
  220.  
  221.     if( ISBADFILE( kmem ) )        /* have kernel memory? */
  222.     return( NULL );
  223. # endif /* Umax not defined */
  224.  
  225.     tpg = -1;                /* terminal process group */
  226.     ttyd = u->u_ttydev;            /* get terminal device number */
  227.  
  228.     topweight = MINUS_INF;
  229.     topweightpr = NULL;
  230.  
  231. # ifdef sun
  232.     /*
  233.      * Sun console redirection (under SunOS 3.x and 4.0.3);
  234.      *
  235.      * values are major,minor
  236.      *                            consdev    rconsdev
  237.      * When the console device is the screen/kbd:    0,0(*)    0,0(*)
  238.      * When the console is serial port n:        12,n    12,n
  239.      * When the console is redirected to ptyN:        20,N    as above
  240.      *
  241.      * (*) under SunOS 4.0, 4.0.1 and 4.1 this is always 1,0
  242.      * but not under 4.0.3?!!
  243.      */
  244.  
  245. # if SunOS >= 400 && SunOS != 403
  246.     if( ttyd == dev_console )        /* utter crockery */
  247.     ttyd = makedev(1,0);        /* seems to work! */
  248. # endif /* SunOS >= 400 && SunOS != 403 */
  249.  
  250.     if( ttyd == dev_console &&        /* this is /dev/console */
  251.        consdev == rconsdev )        /* check if boot physical console */
  252.     ttyd = consdev;            /* is not screen, and not redirectd*/
  253. # endif /* sun defined */
  254.  
  255.  
  256. # ifdef Umax
  257.     ttyprocs( ttyd );            /* create array of processes on */
  258.                     /* this terminal */
  259. # endif /* Umax defined */
  260.  
  261. # ifdef DEBUGSW
  262.     if( sw_debug )
  263.     printf("ttyd=%#x\n", ttyd );
  264. # endif /* DEBUGSW defined */
  265.  
  266.     for( pp = prvec; pp->pr_stat != 0; pp++ ) {    /* for all processes */
  267.     if(
  268. # ifndef Umax
  269.        pp->pr_ttyp == NULL ||    /* no tty? */
  270. # endif /* Umax not defined */
  271.        ttyd != pp->pr_ttyd )    /* tty mismatch? */
  272.         continue;            /* yes, continue */
  273.  
  274. # define ONE 8                /* do fixed point fractions */
  275.     weight = 0;
  276.     curpid = pp->pr_pid;
  277.  
  278.     if( tpg == -1 )            /* try to get terminal */
  279.         tpg = gettpg( pp, u );    /*  process group */
  280.  
  281. # ifdef Umax
  282.     switch( pp->pr_stat ) {
  283.     case SRUN:
  284.         if( pp->pr_wchan == 0 )
  285.         weight += ONE;
  286.         break;
  287.     case SWAIT:
  288.         weight += ONE;        /* some semaphore */
  289.         break;
  290. # ifndef SEVENT
  291. # define SEVENT (SEXEC+1)        /* in proc.h but not pmdefs.h */
  292. # endif /* SEVENT not defined */
  293.     case SEVENT:            /* some event wait.. */
  294.         weight += ONE / 2;
  295.         break;
  296.     } /* switch */
  297. # else  /* Umax not defined */
  298.     switch( waitstate( pp ) ) {
  299.     case WS_TI:
  300.         weight += ONE * 4;
  301.         break;
  302.     case WS_TO:
  303.         weight += ONE * 2;
  304.         break;
  305.     case WS_TW:            /* random terminal wait */
  306.     case WS_SE:            /* select */
  307.         weight += ONE / 2;
  308.         break;
  309.     case WS_RU:            /* no wait */
  310.         if( pp->pr_stat == SRUN )    /* runnable? */
  311.         weight += ONE;
  312.         break;
  313.     default:
  314.         break;
  315.     } /* case */
  316. # endif /* Umax not defined */
  317.  
  318. /* sigh. give no special preference to leader (for things running under sh) */
  319. /*    if( curpid == tpg )        /* pid matches tty group? */
  320. /*        weight += ONE;        /* leader */
  321.  
  322. /* give bonus to children of leader? What about ..grandchildren? *WISH* */
  323. /* (pp->pr_ppid == tpg ) */
  324. /* other ways to benefit by looking up parents?? (done in getcommand()) */
  325.  
  326.     /* *WISH* perhaps consider p_pctcpu */
  327.  
  328.     if( pp->pr_pgrp == tpg )    /* process in process group? */
  329.         weight += ONE;
  330.  
  331.     if( pp->pr_stat == SSTOP )    /* stopped? */
  332.         weight -= ONE / 2;
  333.  
  334.     if( pp->pr_ppid == INIT_PID )    /* child of init? */
  335.         weight -= ONE / 2;
  336.  
  337.     if( pp->pr_pgrp == 0 )        /* no process group? */
  338.         weight -= ONE / 4;
  339.  
  340. # ifdef SLOAD
  341.     if( (pp->pr_flag & SLOAD) == 0 ) /* swapped? */
  342.         weight -= ONE / 4;
  343. # endif /* SLOAD defined */
  344.  
  345.     /* this is to catch programs started by sh with '&' */
  346.     if( pp->pr_intr == S_IGNORE && pp->pr_quit == S_IGNORE )
  347.         weight -= ONE / 4;
  348.  
  349.     if( pp->pr_hup == S_IGNORE )    /* process is nohup? */
  350.         weight -= ONE / 4;        /* was once 1/8th */
  351.  
  352.     /*
  353.      * penalize ugly stuff like "gamescontrol" which
  354.      * tend to have high pids.
  355.      */
  356.     for( progs = hidden; *progs != NULL; progs++ )
  357.         if( strcmp( pp->pr_cmd, *progs ) == 0 ) {
  358.         weight -= ONE;
  359.         break;
  360.         }
  361.  
  362.     pp->pr_weight = weight = (weight<<PID_BITS)/ONE + curpid;
  363.     if( weight > topweight ) {    /* beat previous winner */
  364.         topweight = weight;
  365.         topweightpr = pp;
  366.     } /* beat winner */
  367.  
  368. # ifdef DEBUGSW
  369.     if( sw_debug )
  370.         dumppr( pp );
  371. # endif /* DEBUGSW defined */
  372.  
  373.     } /* for pp */
  374.  
  375.     return( topweightpr );
  376. } /* getcommand2 */
  377.  
  378. # ifdef Umax
  379. LOCAL ttyprocs( dev )            /* get pr's for this terminal */
  380.     dev_t dev;
  381. {
  382.     struct stat_descr sd;
  383.     register int i;
  384.     register struct pr *pp;
  385.     register struct proc_detail *pd;
  386.     struct proc_detail dd[ MAXP ];
  387.  
  388.     sd.sd_next     = NULL;
  389.     sd.sd_objid    = dev;
  390.     sd.sd_subsys   = SUBSYS_PROC;
  391.     sd.sd_type     = PROCTYPE_DETAIL;
  392.     sd.sd_options  = PROC_DETAIL_TERM | PROC_DETAIL_GLEADER;
  393.     sd.sd_addr     = (char *) dd;    /* point to data region */
  394.     sd.sd_size     = sizeof( dd );    /* give size */
  395.     sd.sd_sizeused = 0;
  396.   
  397.     if( inq_stats(1, &sd) != 0 ) {
  398.     perror("inq_stats");
  399.     exit(1);
  400.     }
  401.  
  402. # define SZ sizeof( struct proc_detail )
  403.     pp = prvec;
  404.     pd = dd;
  405.     for( i = sd.sd_sizeused; i >= SZ; i -= SZ ) {
  406.     pp->pr_pid  = pd->pd_pid;
  407.     pp->pr_ppid = pd->pd_ppid;
  408.     pp->pr_pgrp = pd->pd_pgrp;
  409.     pp->pr_uid  = pd->pd_uid;
  410.     pp->pr_flag = pd->pd_flag;
  411.     pp->pr_stat = pd->pd_state;
  412.     pp->pr_ttyd = dev;
  413.     strncpy(pp->pr_cmd, pd->pd_command, sizeof( pp->pr_cmd ) );
  414. # define SIGFIG(pd,s) ( (pd->pd_sigignore & (1<<(s))) ? S_IGNORE : \
  415.                 (pd->pd_sigcatch  & (1<<(s))) ? S_CATCH  : S_DEFAULT )
  416.     pp->pr_hup  = SIGFIG(pd,SIGHUP);
  417.     pp->pr_intr = SIGFIG(pd,SIGINT);
  418.     pp->pr_quit = SIGFIG(pd,SIGQUIT);
  419. # undef SIGFIG
  420.     pp->pr_wchan = (caddr_t) pd->pd_sem; /* why not? */
  421.                     /* no way to figure out what */
  422.                     /* EVENT is what tho... */
  423.     pd++;
  424.     pp++;
  425.     } /* while i */
  426.     pp->pr_stat = 0;            /* mark end */
  427. } /* ttyprocs */
  428. # endif /* Umax defined */
  429.  
  430. GLOBAL void
  431. dumppr( pp )
  432.     register struct pr *pp;
  433. {
  434.     int st;
  435.     waitstate_t s;
  436.  
  437.     st = pp->pr_stat;
  438.     if( st < 0 || st > sizeof( procstates ) - 1 )
  439.     st = 0;
  440. # ifdef Umax
  441.     s = WS_SL;
  442. # else  /* Umax not defined */
  443.     s = waitstate( pp );
  444. # endif /* Umax not defined */
  445.     printf("%6dp %6dpp %6dpg %2s %2s %ci %cq %ch %5du %#8x %s %s %d\n",
  446.        pp->pr_pid,
  447.        pp->pr_ppid,
  448.        pp->pr_pgrp,
  449.        procstates[ st ],
  450. # if defined(SLOAD) && !defined(UmaxV)
  451.        ( (pp->pr_flag & SLOAD) ? "" : "SW" ),
  452. # else  /* not defined(SLOAD) && !defined(UmaxV) */
  453.        "",
  454. # endif /* not defined(SLOAD) && !defined(UmaxV) */
  455.        SIGNAME[ (int) pp->pr_intr ],
  456.        SIGNAME[ (int) pp->pr_quit ],
  457.        SIGNAME[ (int) pp->pr_hup  ],
  458.        pp->pr_uid,
  459.        pp->pr_ttyd,
  460. # if Umax == 42
  461.        "",                /* always bogus */
  462. # else  /* not Umax == 42 */
  463.        WAITSTATENAME[ (int)s ],
  464. # endif /* not Umax == 42 */
  465.        pp->pr_cmd,
  466.        pp->pr_weight
  467.        );
  468. } /* dumppr */
  469.  
  470. GLOBAL int gettpg( pp, u )
  471. register struct pr *pp;
  472. LUSER *u;
  473. {
  474.     short tpg;                /* MUST BE SHORT! (for SHORT_TTYP) */
  475. # ifdef Umax
  476.     static int checked = FALSE, notty = FALSE;
  477.     int f, w;
  478.     char devn[ 30 ];
  479.  
  480.     /* inq_stats does has no way to get terminal process group.  Newer
  481.      * releases have /dev/kmem, but rather than have to deal with kmem
  482.      * at all we open the tty (for write!) and do the ioctl!  if users
  483.      * do "mesg n" finger has to run suid root to ensure access (it is
  484.      * safe to do so)! (see BUGS in man page)
  485.      */
  486.     strcpy( devn, "/dev/" );
  487.     strcat( devn, u->u_line );
  488.  
  489.     if( !checked ) {            /* check if we have a tty */
  490.     if( (f = open( "/dev/tty", 1)) >= 0 )
  491.         close( f );            /* yes we do */
  492.     else
  493.         notty = TRUE;        /* we don't */
  494.     checked = TRUE;
  495.     }
  496.  
  497.     tpg = -2;
  498.     if( (f = open( devn, 1 )) >= 0 ) {    /* open for write!! */
  499.     if( ioctl( f, TIOCGPGRP, &w ) == 0 ) /* to get pgrp!!! */
  500.         tpg = w;
  501.     close( f );
  502.  
  503.     /* flush tty association -- so fingerd doesn't get attached!! */
  504.     if( notty && (f = open( "/dev/tty", 1)) >= 0 ) { /* if no tty */
  505.         ioctl( f, TIOCNOTTY, 0 );    /* flush assoc with one */
  506.         close( f );            /* we just opened */
  507.     }
  508.     }
  509. # else  /* Umax not defined */
  510. # ifndef AIX3
  511. # ifdef SHORT_TTYP
  512.     /* ttyp is pointer to (short) process group in stream structure! */
  513.     if( ! KMEMREAD( (long)pp->pr_ttyp, (char *)&tpg, sizeof(tpg)) )
  514.     tpg = -2;
  515. # else  /* SHORT_TTYP not defined */
  516.     /* read just process group from tty struct */
  517.     if( ! KMEMREAD( (long)&pp->pr_ttyp->t_pgrp, (char *)&tpg, sizeof(tpg)) )
  518.     tpg = -2;
  519. # endif /* SHORT_TTYP not defined */
  520. # endif /* AIX3 not defined */
  521. # endif /* Umax not defined */
  522. # ifdef DEBUGSW
  523.     if( sw_debug )
  524.         printf("tpg=%d\n", tpg );
  525. # endif /* DEBUGSW defined */
  526.     return( tpg );
  527. } /* gettpg */
  528.  
  529. GLOBAL void
  530. getstate( bp, pp )
  531.     char *bp;
  532.     struct pr *pp;
  533. {
  534.     waitstate_t s;
  535.     int st;
  536.  
  537.     st = pp->pr_stat;
  538.     if( st < 0 || st > sizeof( procstates ) - 1 )
  539.     st = 0;
  540.  
  541. # ifdef Umax
  542. # if Umax == 42
  543.     bp[0] = procstates[st][0];
  544.     bp[1] = procstates[st][1];
  545.     bp[2] = procstates[st][2];
  546.     bp[3] = procstates[st][3];
  547. # endif /* Umax == 42 */
  548. # else  /* Umax not defined */
  549.     if( st == SSLEEP ) {
  550.     s = waitstate( pp );
  551.     bp[0] = WAITSTATENAME[ (int)s ][0];
  552.     bp[1] = WAITSTATENAME[ (int)s ][1];
  553.     }
  554.     else {
  555.     bp[0] = procstates[st][0];
  556.     bp[1] = procstates[st][1];
  557.     }
  558.  
  559.     bp[2] = bp[3] = ' ';
  560. # if defined(SLOAD) && !defined(UmaxV)
  561.     if( (pp->pr_flag & SLOAD) == 0 ) {
  562.     bp[2] = 'S';
  563.     bp[3] = 'W';
  564.     }
  565. # endif /* defined(SLOAD) && !defined(UmaxV) */
  566. # endif /* Umax not defined */
  567.     bp[4] = EOS;
  568.  
  569. } /* getstate */
  570.  
  571. /*
  572.  * Local variables:
  573.  * comment-column: 40
  574.  * End:
  575.  */
  576.