home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / sps3 / part02 < prev    next >
Encoding:
Text File  |  1992-05-08  |  60.5 KB  |  2,189 lines

  1. Newsgroups: comp.sources.unix
  2. From: robert@olsen.ch (Robert Ward)
  3. Subject: v26i025: sps3 - show process status, Part02/03
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: robert@olsen.ch (Robert Ward)
  8. Posting-Number: Volume 26, Issue 25
  9. Archive-Name: sps3/part02
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 2 (of 3)."
  18. # Contents:  flagdecode.c getupage.c globals2.c initsymbols.c inittty.c
  19. #   main.c needed.c openfiles.c sps.h stream.c ttystatus.c
  20. # Wrapped by vixie@cognition.pa.dec.com on Sat May  9 22:30:50 1992
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'flagdecode.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'flagdecode.c'\"
  24. else
  25. echo shar: Extracting \"'flagdecode.c'\" \(5627 characters\)
  26. sed "s/^X//" >'flagdecode.c' <<'END_OF_FILE'
  27. X# ifndef lint
  28. static char SccsId[] =  "@(#)flagdecode.c    1.1\t10/1/88" ;
  29. X# endif
  30. X
  31. X# include       "sps.h"
  32. X# include       "flags.h"
  33. X
  34. X/* FLAGDECODE - Looks at the argument list and sets various internal switches */
  35. flagdecode ( argc, argv )
  36. X
  37. register int                    argc ;
  38. register char                   **argv ;
  39. X
  40. X{
  41. X    register char           *chp ;
  42. X    union flaglist          *plist ;
  43. X    union flaglist          *tlist ;
  44. X    union flaglist          *ulist ;
  45. X    static char             usage[] =
  46. X    "sps - Unknown option %s\nUsage - sps [ -dcefgijkoqrsvwyABFNPSTUWZ ][ process|tty|user ] ...\n";
  47. X    union flaglist          *getflgsp() ;
  48. X    extern struct flags     Flg ;
  49. X
  50. X    plist = tlist = ulist = (union flaglist*)0 ;
  51. X    for ( argv++ ; --argc ; argv++ )
  52. X    {
  53. X        chp = *argv ;
  54. X        while ( *chp )
  55. X            switch ( *chp++ )
  56. X            {
  57. X                case '-' :
  58. X                    /* Separation character */
  59. X                    continue ;
  60. X                case 'c' :
  61. X                case 'C' :
  62. X                    /* Print stored command, not args */
  63. X                    Flg.flg_c = 1 ;
  64. X                    continue ;
  65. X                case 'd' :
  66. X                case 'D' :
  67. X                    /* List disc orientated information */
  68. X                    Flg.flg_d = 1 ;
  69. X                    Flg.flg_v = 0 ;
  70. X                    continue ;
  71. X                case 'e' :
  72. X                case 'E' :
  73. X                    /* List environment strings */
  74. X                    Flg.flg_e = 1 ;
  75. X                    continue ;
  76. X                case 'f' :
  77. X                    /* List the father's process id */
  78. X                    Flg.flg_f = 1 ;
  79. X                    continue ;
  80. X                case 'g' :
  81. X                case 'G' :
  82. X                    /* List the process group id */
  83. X                    Flg.flg_g = 1 ;
  84. X                    continue ;
  85. X                case 'i' :
  86. X                case 'I' :
  87. X                    /* Initialise (super-user only) */
  88. X                    Flg.flg_i = 1 ;
  89. X                    continue ;
  90. X                case 'j' :
  91. X                case 'J' :
  92. X                    /* The next argument specifies the
  93. X                       name of the information file */
  94. X                    if ( argc <= 1 )
  95. X                        prexit(
  96. X          "sps - Name of an information file expected after `-j' flag\n" ) ;
  97. X                    argc-- ;
  98. X                    Flg.flg_j = *++argv ;
  99. X                    continue ;
  100. X                case 'k' :
  101. X                case 'K' :
  102. X                    /* Use a disc file such as /vmcore
  103. X                       rather than /dev/{k}mem for
  104. X                       accessing kernel data. The next
  105. X                       argument specifies the file name. */
  106. X                    if ( argc <= 1 )
  107. X                        prexit(
  108. X           "sps - Name of a memory dump file expected after `-k' flag\n" ) ;
  109. X                    argc-- ;
  110. X                    Flg.flg_k = *++argv ;
  111. X                    Flg.flg_o = 1 ;
  112. X                    continue ;
  113. X                case 'l' :
  114. X                case 'v' :
  115. X                case 'L' :
  116. X                case 'V' :
  117. X                    /* Verbose output */
  118. X                    Flg.flg_d = 0 ;
  119. X                    Flg.flg_v = 1 ;
  120. X                    continue ;
  121. X                case 'o' :
  122. X                case 'O' :
  123. X                    /* Avoid looking at the swap device */
  124. X                    Flg.flg_o = 1 ;
  125. X                    continue ;
  126. X                case 'q' :
  127. X                case 'Q' :
  128. X                    /* Show only the user time, not the
  129. X                       user + system times together. */
  130. X                    Flg.flg_q = 1 ;
  131. X                    continue ;
  132. X                case 'r' :
  133. X                case 'R' :
  134. X                    /* Repeat output every n seconds.
  135. X                       The next argument specifies n which
  136. X                       defaults to 5 if omitted. */
  137. X                    Flg.flg_r = 1 ;
  138. X                    if ( argc > 1 )
  139. X                    {
  140. X                        if ( **++argv >= '0'
  141. X                        && **argv <= '9' )
  142. X                        {
  143. X                            argc-- ;
  144. X                            Flg.flg_rdelay
  145. X                                   = atoi( *argv ) ;
  146. X                            continue ;
  147. X                        }
  148. X                        argv-- ;
  149. X                    }
  150. X                    Flg.flg_rdelay = 0 ;
  151. X                    continue ;
  152. X                case 's' :
  153. X                    /* Next argument specifies a symbol
  154. X                       file rather than the default
  155. X                       /vmunix. */
  156. X                    if ( argc <= 1 )
  157. X                        prexit(
  158. X            "sps - Name of a symbol file expected after `-s' flag\n" ) ;
  159. X                    argc-- ;
  160. X                    Flg.flg_s = *++argv ;
  161. X                    continue ;
  162. X                case 'w' :
  163. X                    /* Wide output, exceeding 79 columns */
  164. X                    Flg.flg_w = 1 ;
  165. X                    continue ;
  166. X                case 'y' :
  167. X                case 'Y' :
  168. X                    /* List current tty information */
  169. X                    Flg.flg_y = 1 ;
  170. X                    continue ;
  171. X                case 'a' :
  172. X                case 'A' :
  173. X                    /* List all processes */
  174. X                    Flg.flg_AZ = 1 ;
  175. X                    Flg.flg_A = 1 ;
  176. X                    continue ;
  177. X                case 'b' :
  178. X                case 'B' :
  179. X                    /* List only busy processes */
  180. X                    Flg.flg_AZ = 1 ;
  181. X                    Flg.flg_B = 1 ;
  182. X                    continue ;
  183. X                case 'F' :
  184. X                    /* List only foreground processes */
  185. X                    Flg.flg_AZ = 1 ;
  186. X                    Flg.flg_F = 1 ;
  187. X                    continue ;
  188. X                case 'n' :
  189. X                case 'N' :
  190. X                    /* No processes, just the summary line*/
  191. X                    Flg.flg_AZ = 1 ;
  192. X                    Flg.flg_N = 1 ;
  193. X                    continue ;
  194. X                case 'p' :
  195. X                case 'P' :
  196. X                    /* List only the given process ids */
  197. X                    Flg.flg_AZ = 1 ;
  198. X                    Flg.flg_P = 1 ;
  199. X                    if ( !plist )
  200. X                       plist=Flg.flg_Plist=getflgsp( argc );
  201. X                    while ( argc > 1 )
  202. X                    {
  203. X                        if ( **++argv == '-' )
  204. X                        {
  205. X                            --argv ;
  206. X                            break ;
  207. X                        }
  208. X                        --argc ;
  209. X                        plist->f_chp = *argv ;
  210. X                        (++plist)->f_chp = (char*)0 ;
  211. X                    }
  212. X                    continue ;
  213. X                case 'S' :
  214. X                    /* List only stopped processes */
  215. X                    Flg.flg_AZ = 1 ;
  216. X                    Flg.flg_S = 1 ;
  217. X                    continue ;
  218. X                case 't' :
  219. X                case 'T' :
  220. X                    /* List only processes attached to the
  221. X                       specified terminals */
  222. X                    Flg.flg_AZ = 1 ;
  223. X                    Flg.flg_T = 1 ;
  224. X                    if ( !tlist )
  225. X                       tlist=Flg.flg_Tlist=getflgsp( argc );
  226. X                    while ( argc > 1 )
  227. X                    {
  228. X                        if ( **++argv == '-' )
  229. X                        {
  230. X                            --argv ;
  231. X                            break ;
  232. X                        }
  233. X                        --argc ;
  234. X                        tlist->f_chp = *argv ;
  235. X                        (++tlist)->f_chp = (char*)0 ;
  236. X                    }
  237. X                    continue ;
  238. X                case 'u' :
  239. X                case 'U' :
  240. X                    /* List only processes belonging to the
  241. X                       specified users */
  242. X                    Flg.flg_AZ = 1 ;
  243. X                    Flg.flg_U = 1 ;
  244. X                    if ( !ulist )
  245. X                       ulist=Flg.flg_Ulist=getflgsp( argc );
  246. X                    while ( argc > 1 )
  247. X                    {
  248. X                        if ( **++argv == '-' )
  249. X                        {
  250. X                            --argv ;
  251. X                            break ;
  252. X                        }
  253. X                        --argc ;
  254. X                        ulist->f_chp = *argv ;
  255. X                        (++ulist)->f_chp = (char*)0 ;
  256. X                    }
  257. X                    continue ;
  258. X                case 'W' :
  259. X                    /* List only waiting processes */
  260. X                    Flg.flg_AZ = 1 ;
  261. X                    Flg.flg_W = 1 ;
  262. X                    continue ;
  263. X                case 'z' :
  264. X                case 'Z' :
  265. X                    /* List only zombie processes */
  266. X                    Flg.flg_AZ = 1 ;
  267. X                    Flg.flg_Z = 1 ;
  268. X                    continue ;
  269. X                default :
  270. X                    prexit( usage, *argv ) ;
  271. X                    /* NOTREACHED */
  272. X            }
  273. X    }
  274. X}
  275. END_OF_FILE
  276. if test 5627 -ne `wc -c <'flagdecode.c'`; then
  277.     echo shar: \"'flagdecode.c'\" unpacked with wrong size!
  278. fi
  279. # end of 'flagdecode.c'
  280. fi
  281. if test -f 'getupage.c' -a "${1}" != "-c" ; then 
  282.   echo shar: Will not clobber existing file \"'getupage.c'\"
  283. else
  284. echo shar: Extracting \"'getupage.c'\" \(4875 characters\)
  285. sed "s/^X//" >'getupage.c' <<'END_OF_FILE'
  286. X# ifndef lint
  287. static char SccsId[] =  "@(#)getupage.c    1.6\t12/4/91" ;
  288. X# endif
  289. X
  290. X# include       "sps.h"
  291. X# ifdef KVM
  292. X#  include      <kvm.h>
  293. X# else
  294. X#  include      <h/vm.h>
  295. X#  ifdef BSD42
  296. X#  include    <machine/pte.h>
  297. X#  else
  298. X#  include      <h/pte.h>
  299. X#  endif
  300. X# endif
  301. X# include       <stdio.h>
  302. X
  303. X/*
  304. X** GETUPAGE - Reads the upage for the specified process as well as sufficient
  305. X** page tables entries for reading the command arguments. The pte's are read
  306. X** into the argument `ptetbl'. The upage is read into the external variable
  307. X** `User'. This procedure returns 1 if the upage was successfully read.
  308. X*/
  309. X
  310. X# ifndef KVM
  311. X
  312. X# define        usrpt           (Info.i_usrpt)
  313. X
  314. getupage ( p, ptetbl )
  315. X
  316. register struct process         *p ;
  317. register struct pte             *ptetbl ;
  318. X
  319. X{
  320. X    register int            i ;
  321. X    register int            ncl ;
  322. X    struct pte              pte ;
  323. X
  324. X    extern struct info      Info ;
  325. X    extern union userstate  User ;
  326. X    extern int              Flmem, Flkmem, Flswap ;
  327. X
  328. X    /* If the process is not loaded, look for the upage on the swap device*/
  329. X# ifdef ULTRIX40
  330. X    if ( !(p->pr_p.p_sched & SLOAD) )
  331. X    {
  332. X        struct dmap        l_dmap ;
  333. X        int            ublkno ;
  334. X        int            swap ;
  335. X
  336. X        memseek( Flkmem, (long)p->pr_p.p_smap ) ;
  337. X        if ( read( Flkmem, (char*)&l_dmap, sizeof( struct dmap ) )
  338. X        != sizeof( struct dmap ) )
  339. X        {
  340. X            fprintf( stderr,
  341. X                "sps - Can't read data segment map of process %d\n",
  342. X                p->pr_p.p_pid ) ;
  343. X            return ( 0 ) ;
  344. X        }
  345. X        memseek( Flkmem, (long)l_dmap.dm_ptdaddr ) ;
  346. X        if ( read( Flkmem, (char*)&ublkno, sizeof( ublkno ) )
  347. X        != sizeof( ublkno ) )
  348. X        {
  349. X            fprintf( stderr,
  350. X                "sps - Can't read user block numer of process %d\n",
  351. X                p->pr_p.p_pid ) ;
  352. X            return ( 0 ) ;
  353. X        }
  354. X        swseek( (long)dtob( ublkno ) ) ;
  355. X# else ULTRIX40
  356. X    if ( !(p->pr_p.p_flag & SLOAD) )
  357. X    {                               
  358. X#  ifdef BSD42
  359. X        swseek( (long)dtob( p->pr_p.p_swaddr ) ) ;
  360. X#  else BSD42
  361. X        swseek( (long)ctob( p->pr_p.p_swaddr ) ) ;
  362. X#  endif BSD42
  363. X# endif ULTRIX40
  364. X# ifdef SUN
  365. X        if ( read( Flswap, (char*)&User.u_us, sizeof( union userstate ))
  366. X        != sizeof( union userstate ) )
  367. X# else SUN
  368. X        if ( read( Flswap, (char*)&User.u_us, sizeof( struct user ) )
  369. X        != sizeof( struct user ) )
  370. X# endif SUN
  371. X        {
  372. X            fprintf( stderr,
  373. X                "sps - Can't read upage of process %d\n",
  374. X                p->pr_p.p_pid ) ;
  375. X            return ( 0 ) ;
  376. X        }
  377. X        return ( 1 ) ;          
  378. X    }                               
  379. X    /* The process is loaded. Locate the process pte's by reading
  380. X       the pte of their base address from system virtual address space. */
  381. X# ifdef ULTRIX40
  382. X    /* This method of accessing the upage suffices on the DEC Station
  383. X       but only provides sufficient pte's to read the upage, leaving the
  384. X       command arguments inaccessible. */
  385. X    memseek( Flkmem, (long)p->pr_p.p_addr ) ;
  386. X    if ( read( Flkmem, (char*)ptetbl, (UPAGES+CLSIZE)*sizeof( struct pte ) )
  387. X    != (UPAGES+CLSIZE)*sizeof( struct pte ) )
  388. X    {
  389. X        fprintf( stderr, "sps - Can't read page table of process %d\n",
  390. X            p->pr_p.p_pid ) ;
  391. X        return ( 0 ) ;
  392. X    }
  393. X# else ULTRIX40
  394. X    memseek( Flkmem, (long)&Info.i_usrptmap[ btokmx(p->pr_p.p_p0br)
  395. X        + p->pr_p.p_szpt-1 ] ) ;
  396. X    if ( read( Flkmem, (char*)&pte, sizeof( struct pte ) )
  397. X    != sizeof( struct pte ) )
  398. X    {
  399. X        fprintf( stderr,
  400. X              "sps - Can't read indir pte for upage of process %d\n",
  401. X            p->pr_p.p_pid ) ;
  402. X        return ( 0 ) ;
  403. X    }                               
  404. X    /* Now read the process' pte's from physical memory. We need to access
  405. X       sufficient pte's for the upage and for the command arguments. */
  406. X    memseek( Flmem, (long)ctob( pte.pg_pfnum+1 )
  407. X        - (UPAGES+CLSIZE)*sizeof( struct pte ) ) ;
  408. X    if ( read( Flmem, (char*)ptetbl, (UPAGES+CLSIZE)*sizeof( struct pte ) )
  409. X    != (UPAGES+CLSIZE)*sizeof( struct pte ) )
  410. X    {
  411. X        fprintf( stderr, "sps - Can't read page table of process %d\n",
  412. X            p->pr_p.p_pid ) ;
  413. X        return ( 0 ) ;
  414. X    }
  415. X# endif ULTRIX40
  416. X    /* Now we can read the pages belonging to the upage.
  417. X       Here we read in an entire click at one go. */
  418. X    ncl = (sizeof( struct user ) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE) ;
  419. X    while ( --ncl >= 0 )            
  420. X    {                               
  421. X        i = ncl * CLSIZE ;
  422. X# ifdef ULTRIX40
  423. X        memseek( Flmem, (long)ctob( ptetbl[ i ].pg_pfnum ) ) ;
  424. X# else ULTRIX40
  425. X        memseek( Flmem, (long)ctob( ptetbl[ CLSIZE+i ].pg_pfnum ) ) ;
  426. X# endif ULTRIX40
  427. X        if ( read( Flmem, User.u_pg[i], CLSIZE*NBPG ) != CLSIZE*NBPG )
  428. X        {
  429. X            fprintf( stderr,
  430. X                "sps - Can't read page 0x%x of process %d\n",
  431. X                ptetbl[ CLSIZE+i ].pg_pfnum, p->pr_p.p_pid ) ;
  432. X            return ( 0 ) ;
  433. X        }
  434. X    }
  435. X    return ( 1 ) ;
  436. X}
  437. X
  438. X# else KVM
  439. X
  440. getupage ( p )
  441. X
  442. register struct process         *p ;
  443. X
  444. X{
  445. X        struct user            *upage ;
  446. X    extern union userstate  User ;
  447. X    extern kvm_t           *Flkvm ;
  448. X
  449. X    if (upage = kvm_getu( Flkvm, &p->pr_p ) )
  450. X    {
  451. X            bcopy( (char *)upage, User.u_pg[0], sizeof( struct user ) ) ;
  452. X        return ( 1 ) ;
  453. X    }
  454. X    fprintf( stderr, "sps - Can't read upage of process %d\n",
  455. X        p->pr_p.p_pid ) ;
  456. X    return ( 0 ) ;
  457. X}
  458. X
  459. X# endif KVM
  460. END_OF_FILE
  461. if test 4875 -ne `wc -c <'getupage.c'`; then
  462.     echo shar: \"'getupage.c'\" unpacked with wrong size!
  463. fi
  464. # end of 'getupage.c'
  465. fi
  466. if test -f 'globals2.c' -a "${1}" != "-c" ; then 
  467.   echo shar: Will not clobber existing file \"'globals2.c'\"
  468. else
  469. echo shar: Extracting \"'globals2.c'\" \(6920 characters\)
  470. sed "s/^X//" >'globals2.c' <<'END_OF_FILE'
  471. X# ifndef lint
  472. static char SccsId[] =  "@(#)globals2.c    1.2\t7/4/90" ;
  473. X# endif
  474. X
  475. X# include       "sps.h"
  476. X
  477. X/* Read Only variables, global to the code of sps ... */
  478. X
  479. X/* Null ttyline device ... */
  480. struct ttyline                  Notty = { "  " } ;
  481. X
  482. X/*
  483. X** The symbol table. For each address read from the kernel during
  484. X** initialisation, this table shows the following:
  485. X**      i.   the name of that symbol within the kernel ;
  486. X**      ii.  whether an extra indirection is needed through the kernel,
  487. X**           i.e. whether the value of that symbol should be obtained
  488. X**           rather than its address.
  489. X**      iii. where the obtained value/address is placed in the Info structure ;
  490. X**      iv.  whether the obtained value is associated with a reason for
  491. X**           a process wait state.
  492. X*/
  493. X/* The order of entries in this table is unimportant. */
  494. X
  495. extern struct info              Info ;
  496. X
  497. struct symbol   Symbollist[] =
  498. X{       
  499. X    /* Kernel addresses required in order to access process,
  500. X       tty and upage information. All these addresses should be
  501. X       located in the symbol file during initialisation. */
  502. X    { "_proc",      1,  (caddr_t*)&Info.i_proc0,    (char*)0        },
  503. X    { "_nproc",     1,  (caddr_t*)&Info.i_nproc,    (char*)0        },
  504. X# ifdef ULTRIX20
  505. X    { "_gnode",     1,  (caddr_t*)&Info.i_inode0,   (char*)0        },
  506. X    { "_ngnode",    1,  (caddr_t*)&Info.i_ninode,   (char*)0        },
  507. X# else
  508. X#  ifndef SUNOS41
  509. X    { "_inode",     1,  (caddr_t*)&Info.i_inode0,   (char*)0        },
  510. X#  endif SUNOS41
  511. X    { "_ninode",    1,  (caddr_t*)&Info.i_ninode,   (char*)0        },
  512. X# endif ULTRIX20
  513. X
  514. X# ifndef SUNOS40
  515. X    { "_text",      1,  (caddr_t*)&Info.i_text0,    (char*)0        },
  516. X    { "_ntext",     1,  (caddr_t*)&Info.i_ntext,    (char*)0        },
  517. X    { "_swbuf",     1,  (caddr_t*)&Info.i_swbuf0,   (char*)0        },
  518. X    { "_nswbuf",    1,  (caddr_t*)&Info.i_nswbuf,   (char*)0        },
  519. X    { "_buf",       1,  (caddr_t*)&Info.i_buf0,     (char*)0        },
  520. X    { "_nbuf",      1,  (caddr_t*)&Info.i_nbuf,     (char*)0        },
  521. X    { "_ecmx",      1,  (caddr_t*)&Info.i_ecmx,     (char*)0        },
  522. X    { "_Usrptmap",  0,  (caddr_t*)&Info.i_usrptmap, (char*)0        },
  523. X    { "_usrpt",     0,  (caddr_t*)&Info.i_usrpt,    (char*)0        },
  524. X#  ifdef ULTRIX40
  525. X    { "_swapfrag",    1,  (caddr_t*)&Info.i_swapfrag,    (char*)0    },
  526. X#  else ULTRIX40
  527. X    { "_dmmin",     1,  (caddr_t*)&Info.i_dmmin,    (char*)0        },
  528. X    { "_dmmax",     1,  (caddr_t*)&Info.i_dmmax,    (char*)0        },
  529. X#  endif ULTRIX40
  530. X# endif SUNOS40
  531. X
  532. X    { "_cdevsw",    0,  (caddr_t*)&Info.i_cdevsw,   (char*)0        },
  533. X# ifdef BSD42
  534. X#  ifdef NFS
  535. X#   ifndef NOQUOTA
  536. X    { "_dquot",     1,  (caddr_t*)&Info.i_quota0,   (char*)0        },
  537. X    { "_ndquot",    1,  (caddr_t*)&Info.i_nquota,   (char*)0        },
  538. X#   endif NOQUOTA
  539. X#  else NFS
  540. X    { "_quota",     1,  (caddr_t*)&Info.i_quota0,   (char*)0        },
  541. X    { "_nquota",    1,  (caddr_t*)&Info.i_nquota,   (char*)0        },
  542. X#  endif NFS
  543. X    { "_mbutl",     0,  (caddr_t*)&Info.i_mbutl,    (char*)0        },
  544. X# else BSD42
  545. X    { "_hz",        1,  (caddr_t*)&Info.i_hz,       (char*)0        },
  546. X# endif BSD42
  547. X
  548. X# ifdef CHAOS
  549. X    { "_Chconntab", 0,  &Info.i_Chconntab,          (char*)0        },
  550. X# endif CHAOS
  551. X
  552. X# ifdef SUNOS40
  553. X    { "_maxmem",    1,  (caddr_t*)&Info.i_ecmx,    (char*)0    },
  554. X    { "_segvn_ops",    0,  (caddr_t*)&Info.i_segvn_ops,(char*)0    },
  555. X    { "_pty_softc",    0,  (caddr_t*)&Info.i_ptybase,    (char*)0    },
  556. X    { "_npty",    1,  (caddr_t*)&Info.i_npty,    (char*)0    },
  557. X#  ifdef SUNOS41
  558. X    { "_strst",    0,  (caddr_t*)&Info.i_strst,    (char*)0    },
  559. X    { "_allstream",    1,  (caddr_t*)&Info.i_allstream, (char*)0    },
  560. X#  else SUNOS41
  561. X    { "_streams",    0,  (caddr_t*)&Info.i_streams,    (char*)0    },
  562. X    { "_streamsNSTREAMS", 1, (caddr_t*)&Info.i_streamsNSTREAMS ,(char*)0 },
  563. X#  endif SUNOS41
  564. X    { "_Sysbase",    1,  (caddr_t*)&Info.i_sysbase,    (char*)0    },
  565. X# endif SUNOS40
  566. X
  567. X    /* Kernel addresses associated with process wait states.
  568. X       It is not important if some of these addresses are unresolved
  569. X       at initialisation. */
  570. X# ifndef SUN
  571. X    { "_fltab",     0,  &Info.i_waitstate[0],       "floppy"        },
  572. X    { "_tu",        0,  &Info.i_waitstate[1],       "tu58"          },
  573. X    { "_lp_softc",  0,  &Info.i_waitstate[3],       "printr"        },
  574. X# endif SUN
  575. X    { "_bfreelist", 0,  &Info.i_waitstate[2],       "buffer"        },
  576. X    { "_lbolt",     0,  &Info.i_waitstate[4],       "lbolt"         },
  577. X    { "_runin",     0,  &Info.i_waitstate[5],       "runin"         },
  578. X    { "_runout",    0,  &Info.i_waitstate[6],       "runout"        },
  579. X    { "_ipc",       0,  &Info.i_waitstate[7],       "ptrace"        },
  580. X# ifdef SUNOS41
  581. X    { "_uunix",     0,  &Info.i_waitstate[8],       "pause"         },
  582. X# else SUNOS41
  583. X    { "_u",         0,  &Info.i_waitstate[8],       "pause"         },
  584. X# endif SUNOS41
  585. X    { "_freemem",   0,  &Info.i_waitstate[9],       "freemm"        },
  586. X    { "_kernelmap", 0,  &Info.i_waitstate[10],      "kermap"        },
  587. X    { "_cwaiting",  0,  &Info.i_waitstate[11],      "cwait"         },
  588. X# ifdef BSD42
  589. X    { "_selwait",   0,  &Info.i_waitstate[12],      "select"        },
  590. X# endif BSD42
  591. X# ifdef CHAOS
  592. X    { "_Chrfclist", 0,  &Info.i_waitstate[13],      "chrfc"         },
  593. X# endif CHAOS
  594. X# ifndef SUN
  595. X    { "_rhpbuf",    0,  &Info.i_waitstate[14],      "rhpbuf"        },
  596. X    { "_rhtbuf",    0,  &Info.i_waitstate[15],      "rhtbuf"        },
  597. X    { "_ridcbuf",   0,  &Info.i_waitstate[16],      "ridcbf"        },
  598. X    { "_rikbuf",    0,  &Info.i_waitstate[17],      "rikbuf"        },
  599. X    { "_rmtbuf",    0,  &Info.i_waitstate[18],      "rmtbuf"        },
  600. X    { "_rrkbuf",    0,  &Info.i_waitstate[19],      "rrkbuf"        },
  601. X    { "_rrlbuf",    0,  &Info.i_waitstate[20],      "rrlbuf"        },
  602. X    { "_rrxbuf",    0,  &Info.i_waitstate[21],      "rrxbuf"        },
  603. X    { "_rswbuf",    0,  &Info.i_waitstate[22],      "rswbuf"        },
  604. X    { "_rtmbuf",    0,  &Info.i_waitstate[23],      "rtmbuf"        },
  605. X    { "_rtsbuf",    0,  &Info.i_waitstate[24],      "rtsbuf"        },
  606. X    { "_rudbuf",    0,  &Info.i_waitstate[25],      "rudbuf"        },
  607. X    { "_rupbuf",    0,  &Info.i_waitstate[26],      "rupbuf"        },
  608. X    { "_rutbuf",    0,  &Info.i_waitstate[27],      "rutbuf"        },
  609. X    { "_rvabuf",    0,  &Info.i_waitstate[28],      "rvabuf"        },
  610. X    { "_rvpbuf",    0,  &Info.i_waitstate[29],      "rvpbuf"        },
  611. X    { "_chtbuf",    0,  &Info.i_waitstate[30],      "chtbuf"        },
  612. X    { "_cmtbuf",    0,  &Info.i_waitstate[31],      "cmtbuf"        },
  613. X    { "_ctmbuf",    0,  &Info.i_waitstate[32],      "ctmbuf"        },
  614. X    { "_ctsbuf",    0,  &Info.i_waitstate[33],      "ctsbuf"        },
  615. X    { "_cutbuf",    0,  &Info.i_waitstate[34],      "cutbuf"        },
  616. X#  ifdef NFS
  617. X    { "_async_bufhead", 0,  &Info.i_waitstate[35],  "async"        },
  618. X#  endif NFS
  619. X# else SUN
  620. X    { "_async_bufhead", 0,  &Info.i_waitstate[14],  "async"        },
  621. X    { "_desktops",    0,  &Info.i_waitstate[15],    "dtops"        },
  622. X# endif SUN
  623. X# ifdef ULTRIX20
  624. X    { "_async_bufhead", 0,  &Info.i_waitstate[35],  "async"        },
  625. X# endif ULTRIX20
  626. X    { (char*)0,     0,  (caddr_t*)0,                (char*)0        }
  627. X} ;
  628. END_OF_FILE
  629. if test 6920 -ne `wc -c <'globals2.c'`; then
  630.     echo shar: \"'globals2.c'\" unpacked with wrong size!
  631. fi
  632. # end of 'globals2.c'
  633. fi
  634. if test -f 'initsymbols.c' -a "${1}" != "-c" ; then 
  635.   echo shar: Will not clobber existing file \"'initsymbols.c'\"
  636. else
  637. echo shar: Extracting \"'initsymbols.c'\" \(3515 characters\)
  638. sed "s/^X//" >'initsymbols.c' <<'END_OF_FILE'
  639. X# ifndef lint
  640. static char SccsId[] =    "@(#)initsymbols.c    1.4\t8/6/90" ;
  641. X# endif lint
  642. X
  643. X# include       "sps.h"
  644. X# include       "flags.h"
  645. X# ifdef BSD42
  646. X#  include       <sys/file.h>
  647. X# endif BSD42
  648. X# ifdef KVM
  649. X#  include       <kvm.h>
  650. X# endif KVM
  651. X# include       <nlist.h>
  652. X# include       <stdio.h>
  653. X
  654. X/* INITSYMBOLS - Reads kmem values into the Info structure */
  655. X/*
  656. X** THIS CODE COPIES KMEM VALUES INTO THE INFO STRUCTURE ASSUMING THAT
  657. X** VALUES READ FROM THE KERNEL HAVE TYPE CADDR_T. THEREFORE, WE ARE
  658. X** MAKING THE DUBIOUS ASSUMPTION THAT INTS, POINTERS AND CADDR_T's
  659. X** HAVE IDENTICAL SIZES.
  660. X*/
  661. initsymbols ()
  662. X{
  663. X    register struct nlist   *np ;
  664. X    register struct symbol  *s ;
  665. X    register struct nlist   *np0 ;
  666. X    char                    *filesymbol ;
  667. X# ifdef KVM
  668. X    extern kvm_t           *Flkvm ;
  669. X# endif
  670. X    extern struct flags     Flg ;
  671. X    extern struct symbol    Symbollist[] ;
  672. X    extern struct info      Info ;
  673. X    char                    *getcore() ;
  674. X    char                    *strncpy() ;
  675. X
  676. X    filesymbol = Flg.flg_s ? Flg.flg_s : FILE_SYMBOL ;
  677. X    /* Find the length of the symbol table */
  678. X    for ( s = Symbollist ; s->s_kname ; s++ )
  679. X        ;
  680. X    /* Construct an nlist structure by copying names from the symbol table*/
  681. X    np0 = (struct nlist*)getcore( (s-Symbollist+1)*sizeof( struct nlist ) );
  682. X    for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
  683. X    {
  684. X# ifdef SUN386I
  685. X        /* Remove '_' prefix because 386i uses COFF format -
  686. X           Provided by Martin Reed <mr@ritd.co.uk> */
  687. X        np->n_name = &s->s_kname[1] ;       
  688. X# else SUN386I
  689. X                                     
  690. X        np->n_name = s->s_kname ; 
  691. X# endif SUN386I     
  692. X        np[1].n_name = (char*)0 ;       
  693. X        np->n_value = 0 ;
  694. X    }
  695. X# ifdef KVM
  696. X    if ( kvm_nlist( Flkvm, np0 ) == -1 )
  697. X    {
  698. X        fprintf( stderr, "sps - Can't read symbol file %s", filesymbol);
  699. X        sysperror() ;
  700. X    }
  701. X              
  702. X# else KVM
  703. X#  ifdef BSD42
  704. X    if ( access( filesymbol, R_OK ) < 0 )
  705. X#  else BSD42
  706. X    if ( access( filesymbol, 4 ) < 0 )
  707. X#  endif BSD42
  708. X    {
  709. X        fprintf( stderr, "sps - Can't open symbol file %s", filesymbol);
  710. X        sysperror() ;
  711. X    }
  712. X    /* Get kernel addresses */
  713. X    (void)nlist( filesymbol, np0 ) ;              
  714. X    if ( np0[0].n_value == -1 )
  715. X    {
  716. X        fprintf( stderr, "sps - Can't read symbol file %s", filesymbol);
  717. X        sysperror() ;
  718. X    }
  719. X# endif KVM
  720. X    for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
  721. X    {                                       
  722. X        if ( !np->n_value )             
  723. X        {
  724. X            fprintf( stderr, "sps - Can't find symbol %s in %s",
  725. X                np->n_name, filesymbol ) ;
  726. X            /* Assume this error to be unimportant if the address
  727. X               is only associated with a process wait state.
  728. X               This may happen if the system has been configured
  729. X               without a particular device. */
  730. X            fprintf( stderr, &Info.i_waitstate[ 0 ] <= s->s_info
  731. X                && s->s_info < &Info.i_waitstate[ NWAITSTATE ]
  732. X                ? " (error is not serious)\n"
  733. X                : " (ERROR MAY BE SERIOUS)\n" ) ;
  734. X            *s->s_info = (caddr_t)0 ;
  735. X            continue ;
  736. X        }
  737. X        /* If no indirection is required, just copy the obtained value
  738. X           into the `Info' structure. */
  739. X        if ( !s->s_indirect )           
  740. X        {                               
  741. X        /* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
  742. X            *s->s_info = (caddr_t)np->n_value ;
  743. X            continue ;              
  744. X        }                               
  745. X        /* Otherwise one level of indirection is required. Using the
  746. X           obtained address, look again in the kernel for the value */
  747. X        /* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
  748. X        (void)getkmem( (long)np->n_value, (char*)s->s_info,
  749. X            sizeof(caddr_t) ) ;
  750. X    }
  751. X    free( (char*)np0 ) ;
  752. X}
  753. END_OF_FILE
  754. if test 3515 -ne `wc -c <'initsymbols.c'`; then
  755.     echo shar: \"'initsymbols.c'\" unpacked with wrong size!
  756. fi
  757. # end of 'initsymbols.c'
  758. fi
  759. if test -f 'inittty.c' -a "${1}" != "-c" ; then 
  760.   echo shar: Will not clobber existing file \"'inittty.c'\"
  761. else
  762. echo shar: Extracting \"'inittty.c'\" \(3716 characters\)
  763. sed "s/^X//" >'inittty.c' <<'END_OF_FILE'
  764. X# ifndef lint
  765. static char SccsId[] =  "@(#)inittty.c    1.1\t10/1/88" ;
  766. X# endif
  767. X
  768. X# include       "sps.h"
  769. X# include       <h/conf.h>
  770. X# include       <h/ioctl.h>
  771. X# ifdef SUNOS40
  772. X# include       <h/stream.h>
  773. X# else
  774. X# include       <h/tty.h>
  775. X# endif
  776. X# include       <sys/stat.h>
  777. X# include       <stdio.h>
  778. X
  779. X/* INITTTY - Initialise the tty part of the info structure */
  780. inittty ()
  781. X{
  782. X    register struct ttyline *lp ;
  783. X# ifdef BSD42
  784. X    register struct direct  *dp ;
  785. X    DIR                     *dfd ;
  786. X# else
  787. X    struct direct           dir ;
  788. X    FILE                    *dfd ;
  789. X# endif
  790. X    struct stat             statbuf ;
  791. X    static char             filedev[] = FILE_DEV ;
  792. X    extern struct info      Info ;
  793. X# ifdef BSD42
  794. X    DIR                     *opendir() ;
  795. X    struct direct           *readdir() ;
  796. X# else
  797. X    FILE                    *fopen() ;
  798. X# endif
  799. X
  800. X    lp = Info.i_ttyline ;
  801. X# ifdef BSD42
  802. X    if ( !(dfd = opendir( filedev )) )
  803. X# else
  804. X    if ( !(dfd = fopen( filedev, "r" )) )
  805. X# endif
  806. X        prexit( "Can't open %s\n", filedev ) ;
  807. X    if ( chdir( filedev ) < 0 )
  808. X        prexit( "sps - Can't chdir to %s\n", filedev ) ;
  809. X# ifdef BSD42
  810. X    /* Read all entries in the device directory, looking for ttys */
  811. X    while ( dp = readdir( dfd ) )
  812. X    {       /* Skip entries that do not match "tty" or "console" */
  813. X        if ( strncmp( "tty", dp->d_name, 3 )
  814. X        &&   strcmp( "console", dp->d_name ) )
  815. X            continue ;
  816. X        /* Skip "tty" itself */
  817. X        if ( dp->d_namlen == 3 )
  818. X            continue ;
  819. X# ifdef CHAOS
  820. X        /* Skip chaos ttys ; they are accessed during ttystatus() */
  821. X        if ( dp->d_namelen > 3 &&
  822. X        dp->d_name[ sizeof( "tty" ) - 1 ] == 'C' )
  823. X            continue ;
  824. X# endif
  825. X        if ( lp >= &Info.i_ttyline[ MAXTTYS ] )
  826. X            prexit( "sps - Too many ttys in %s\n", filedev ) ;
  827. X        /* Copy the tty name into the information entry */
  828. X        if ( !strcmp( dp->d_name, "console" ) )
  829. X        {
  830. X            lp->l_name[0] = 'c' ;
  831. X            lp->l_name[1] = 'o' ;
  832. X        }
  833. X        else
  834. X        {
  835. X            lp->l_name[0] = dp->d_name[3] ;
  836. X            lp->l_name[1] = dp->d_name[4] ;
  837. X        }
  838. X        /* Ensure that this tty is actually a valid character device */
  839. X        if ( stat( dp->d_name, &statbuf ) < 0 )
  840. X            continue ;
  841. X# else
  842. X    /* Read all entries in the device directory, looking for ttys */
  843. X    while ( fread( (char*)&dir, sizeof( struct direct ), 1, dfd ) == 1 )
  844. X    {       /* Skip entries that do not match "tty" or "console" */
  845. X        if ( strncmp( "tty", dir.d_name, 3 )
  846. X        &&   strcmp( "console", dir.d_name ) )
  847. X            continue ;
  848. X        /* Skip "tty" itself */
  849. X        if ( dir.d_name[3] == '\0' )
  850. X            continue ;
  851. X# ifdef CHAOS
  852. X        /* Skip chaos ttys ; they are accessed during ttystatus() */
  853. X        if ( dir.d_name[ sizeof( "tty" ) - 1 ] == 'C' )
  854. X            continue ;
  855. X# endif
  856. X        if ( lp >= &Info.i_ttyline[ MAXTTYS ] )
  857. X            prexit( "sps - Too many ttys in %s\n", filedev ) ;
  858. X        /* Copy the tty name into the information entry */
  859. X        if ( !strcmp( dir.d_name, "console" ) )
  860. X        {
  861. X            lp->l_name[0] = 'c' ;
  862. X            lp->l_name[1] = 'o' ;
  863. X        }
  864. X        else
  865. X        {
  866. X            lp->l_name[0] = dir.d_name[3] ;
  867. X            lp->l_name[1] = dir.d_name[4] ;
  868. X        }
  869. X        /* Ensure that this tty is actually a valid character device */
  870. X        if ( stat( dir.d_name, &statbuf ) < 0 )
  871. X            continue ;
  872. X# endif
  873. X        if ( (statbuf.st_mode & S_IFMT) != S_IFCHR )
  874. X            continue ;
  875. X        /* Find the device # of the tty and the address of its
  876. X           associated struct tty in /dev/kmem. */
  877. X        lp->l_dev = statbuf.st_rdev ;
  878. X        if ( getkmem ( (long)&Info.i_cdevsw[ major( statbuf.st_rdev ) ]
  879. X# ifdef SUNOS40
  880. X            .d_str,
  881. X# else
  882. X            .d_ttys,
  883. X# endif
  884. X        (char*)&lp->l_addr, sizeof( lp->l_addr ) )
  885. X        != sizeof( lp->l_addr ) )
  886. X        {
  887. X            fprintf( stderr, "sps - Can't read struct tty for %s\n",
  888. X# ifdef BSD42
  889. X                dp->d_name ) ;
  890. X# else
  891. X                dir.d_name ) ;
  892. X# endif
  893. X            continue ;
  894. X        }
  895. X# ifndef SUNOS40
  896. X        lp->l_addr += (int)minor( statbuf.st_rdev ) ;
  897. X# endif
  898. X        lp++ ;
  899. X    }
  900. X# ifdef BSD42
  901. X    (void)closedir( dfd ) ;
  902. X# else
  903. X    (void)fclose( dfd ) ;
  904. X# endif
  905. X}
  906. END_OF_FILE
  907. if test 3716 -ne `wc -c <'inittty.c'`; then
  908.     echo shar: \"'inittty.c'\" unpacked with wrong size!
  909. fi
  910. # end of 'inittty.c'
  911. fi
  912. if test -f 'main.c' -a "${1}" != "-c" ; then 
  913.   echo shar: Will not clobber existing file \"'main.c'\"
  914. else
  915. echo shar: Extracting \"'main.c'\" \(4668 characters\)
  916. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  917. X# ifndef lint
  918. static char SccsId[] =  "@(#)main.c    1.3\t8/22/91" ;
  919. X# endif
  920. X
  921. X# include       "sps.h"
  922. X# include       "flags.h"
  923. X# ifdef KVM
  924. X# include       <kvm.h>
  925. X# include       <fcntl.h>
  926. X# endif KVM
  927. X# ifndef SUNOS40
  928. X# include       <h/text.h>
  929. X# endif
  930. X# include       <sys/stat.h>
  931. X# include       <stdio.h>
  932. X
  933. X
  934. X/* SPS - Show Process Status */
  935. X
  936. X
  937. X/* J. R. Ward - Hasler AG, Bern, Switzerland         - 24 May 1985 */
  938. X/*                                  - 26 Nov 1986 */
  939. X/* J. R. Ward - Olsen & Associates AG,
  940. X        Seefeldstrasse 233,
  941. X        CH-8008 Zuerich,
  942. X            Switzerland                 -  1 Oct 1988 */
  943. X/* J. R. Ward - Olsen & Associates AG             - 21 August 1991 */
  944. X
  945. X/* <robert@olsen.ch> or <uunet!chx400!olsen!robert> */
  946. X
  947. X/* NFS additions and SunOS4.0 support by Alexander Dupuy
  948. X   <dupuy@ncs.columbia.edu> and Charlie Kim <cck@cunixc.cc.columbia.edu>.
  949. X   Ultrix 2.x support by Rob Lehman at CUCCA.
  950. X   SunOS4.1 support by Sakari Jalovaara <sja@sirius.hut.fi>
  951. X   Ultrix 4.0 support by Stefano Diomedi <sdiomedi@tecsiel.it> */
  952. X
  953. X
  954. main ( argc,argv )
  955. X
  956. int                             argc ;
  957. char                            **argv ;
  958. X
  959. X{
  960. X    register struct process *plist ;
  961. X    register struct process *process ;
  962. X# ifndef SUNOS40
  963. X    register struct text    *text ;
  964. X# endif
  965. X    int                     flinfo ;
  966. X    char            *fileinfo, *filesymbol ;
  967. X    struct stat        sinfo, ssymbol ;
  968. X# ifdef WARNPASSWD
  969. X    struct stat        spasswd ;
  970. X# endif
  971. X    extern struct flags     Flg ;
  972. X    extern struct info      Info ;
  973. X# ifdef KVM
  974. X    extern kvm_t           *Flkvm ;
  975. X# else
  976. X    extern int              Flmem ;
  977. X    extern int              Flkmem ;
  978. X    extern int              Flswap ;
  979. X# endif
  980. X    char                    *getcore() ;
  981. X    struct process          *needed(), *mktree() ;
  982. X
  983. X    /* Renice as fast as possible for root only (Suggested by Jeff Mogul,
  984. X       gregorio!mogul) */
  985. X    if ( !getuid() )
  986. X        (void)nice( -40 ) ;
  987. X    /* Decode the flag arguments */
  988. X    flagdecode( argc, argv ) ;      
  989. X    /* Determine the terminal width */
  990. X    if ( !Flg.flg_w && !Flg.flg_N && !Flg.flg_i )
  991. X        termwidth() ;
  992. X    /* Open the cpu physical memory, kernel virtual memory and swap device*/
  993. X# ifdef KVM
  994. X    Flkvm = kvm_open( Flg.flg_s, Flg.flg_k, NULL, O_RDONLY, "sps" ) ;
  995. X    if ( !Flkvm )
  996. X        /* Error message already output */
  997. X        exit( 1 ) ;
  998. X# else
  999. X    if ( Flg.flg_k )
  1000. X    {
  1001. X        Flmem = openfile( Flg.flg_k ) ;
  1002. X        Flkmem = Flmem ;
  1003. X    }
  1004. X    else
  1005. X    {
  1006. X        Flmem = openfile( FILE_MEM ) ;
  1007. X        Flkmem = openfile( FILE_KMEM ) ;
  1008. X        if ( !Flg.flg_o )
  1009. X            Flswap = openfile( FILE_SWAP ) ;
  1010. X    }
  1011. X# endif
  1012. X    if ( Flg.flg_i )
  1013. X    {       /* -i flag for info file initialisation */
  1014. X        /* sps probably running setgid so patch security hole now */
  1015. X        (void)setgid( getgid() ) ;
  1016. X        initialise() ;          
  1017. X        exit( 0 ) ;
  1018. X    }
  1019. X    /* Check that the information file is newer than the symbol and
  1020. X       password files, suggested by gregorio!mogul */
  1021. X    fileinfo = Flg.flg_j ? Flg.flg_j : FILE_INFO ;
  1022. X    filesymbol = Flg.flg_s ? Flg.flg_s : FILE_SYMBOL ;
  1023. X    flinfo = openfile( fileinfo ) ;
  1024. X    (void)fstat( flinfo, &sinfo ) ;
  1025. X    if ( !stat( filesymbol, &ssymbol ) &&
  1026. X        sinfo.st_mtime < ssymbol.st_mtime )
  1027. X        fprintf( stderr,
  1028. X           "sps - WARNING: Info file `%s' is older than symbol file `%s'\n",
  1029. X            fileinfo, filesymbol ) ;
  1030. X# ifdef WARNPASSWD
  1031. X    if ( !stat( FILE_PASSWD, &spasswd ) &&
  1032. X        sinfo.st_mtime < spasswd.st_mtime )
  1033. X        fprintf( stderr,
  1034. X           "sps - WARNING: Info file `%s' is older than passwd file `%s'\n",
  1035. X            fileinfo, FILE_PASSWD ) ;
  1036. X# endif
  1037. X    /* Read the information file */
  1038. X    if ( read( flinfo, (char*)&Info, sizeof( struct info ) )
  1039. X    != sizeof( struct info ) )
  1040. X    {
  1041. X        fprintf( stderr, "sps - Can't read info file `%s'", fileinfo ) ;
  1042. X        sysperror() ;
  1043. X    }
  1044. X    (void)close( flinfo ) ;
  1045. X    /* Find current tty status */
  1046. X    ttystatus() ;                   
  1047. X    /* Now that we know the available ttys, decode the flags */
  1048. X    flagsetup() ;                   
  1049. X    process = (struct process*)getcore(Info.i_nproc*sizeof(struct process));
  1050. X# ifndef SUNOS40
  1051. X    text = (struct text*)getcore( Info.i_ntext * sizeof( struct text ) ) ;
  1052. X# endif
  1053. X    do
  1054. X    {       /* Read current process status */
  1055. X# ifdef SUNOS40
  1056. X        readstatus( process ) ;
  1057. X        /* Select those processes to be listed */
  1058. X        plist = needed( process ) ;
  1059. X# else
  1060. X        readstatus( process, text ) ;
  1061. X        /* Select those processes to be listed */
  1062. X        plist = needed( process, text ) ;
  1063. X# endif
  1064. X        /* Form a tree of listed processes */
  1065. X        plist = mktree( process, plist ) ;
  1066. X        if ( !Flg.flg_N )
  1067. X        {       /* Print the processes */
  1068. X            prheader() ;
  1069. X            printall( plist, 0 ) ;
  1070. X        }
  1071. X        prsummary() ;
  1072. X        (void)fflush( stdout ) ;
  1073. X        if ( Flg.flg_r )        
  1074. X        {       /* If repeating, again get tty status */
  1075. X            ttystatus() ;
  1076. X            if ( Flg.flg_rdelay )
  1077. X# ifdef BSD42
  1078. X                sleep( Flg.flg_rdelay ) ;
  1079. X# else
  1080. X                sleep( (int)Flg.flg_rdelay ) ;
  1081. X# endif
  1082. X        }
  1083. X    } while ( Flg.flg_r ) ;
  1084. X    exit( 0 ) ;
  1085. X}
  1086. END_OF_FILE
  1087. if test 4668 -ne `wc -c <'main.c'`; then
  1088.     echo shar: \"'main.c'\" unpacked with wrong size!
  1089. fi
  1090. # end of 'main.c'
  1091. fi
  1092. if test -f 'needed.c' -a "${1}" != "-c" ; then 
  1093.   echo shar: Will not clobber existing file \"'needed.c'\"
  1094. else
  1095. echo shar: Extracting \"'needed.c'\" \(5262 characters\)
  1096. sed "s/^X//" >'needed.c' <<'END_OF_FILE'
  1097. X# ifndef lint
  1098. static char SccsId[] =  "@(#)needed.c    1.4\t6/26/91" ;
  1099. X# endif
  1100. X
  1101. X# include       "sps.h"
  1102. X# include       "flags.h"
  1103. X# ifndef SUNOS40
  1104. X# include       <h/text.h>
  1105. X# endif
  1106. X# include       <stdio.h>
  1107. X
  1108. X/*
  1109. X** NEEDED - Determine which processes are needed for the printout
  1110. X** and add these to a list of needed processes.
  1111. X*/
  1112. X# ifdef SUNOS40
  1113. struct process  *needed ( process )
  1114. X
  1115. register struct process         *process ;
  1116. X
  1117. X# else
  1118. X
  1119. struct process  *needed ( process, text )
  1120. X
  1121. register struct process         *process ;
  1122. struct text                     *text ;
  1123. X
  1124. X# endif
  1125. X{
  1126. X    register struct process *p ;
  1127. X    register struct process *plist ;
  1128. X    struct process          *lastp ;
  1129. X    int                     uid ;
  1130. X    extern struct flags     Flg ;
  1131. X    extern union userstate  User ;
  1132. X    extern struct info      Info ;
  1133. X    extern struct ttyline   Notty ;
  1134. X    struct ttyline          *findtty() ;
  1135. X    char                    *getcmd() ;
  1136. X
  1137. X    plist = (struct process*)0 ;
  1138. X    lastp = &process[ Info.i_nproc ] ;
  1139. X    /* Normalise internal pointers from kernel addresses. For each kmem
  1140. X       address in the `proc' and `text' structures, we convert that
  1141. X       address for our own internal use. */
  1142. X    for ( p = process ; p < lastp ; p++ )
  1143. X    {                               
  1144. X        if ( !p->pr_p.p_stat )  
  1145. X            continue ;
  1146. X# ifndef SUNOS40
  1147. X        /* Normalise internal text pointers */
  1148. X        if ( p->pr_p.p_textp )
  1149. X            p->pr_p.p_textp = &text[p->pr_p.p_textp - Info.i_text0];
  1150. X# endif
  1151. X        /* Normalise internal linked list of processes */
  1152. X        p->pr_plink = p->pr_p.p_link ?
  1153. X            &process[ p->pr_p.p_link  - Info.i_proc0 ] :
  1154. X            (struct process*)0 ;
  1155. X        /* Normalise internal parent pointers */
  1156. X        p->pr_pptr = p->pr_p.p_pptr ?
  1157. X            &process[ p->pr_p.p_pptr - Info.i_proc0 ] :
  1158. X            (struct process*)0 ;
  1159. X        /* Check for valid parent pointers */
  1160. X        if ( !p->pr_pptr )
  1161. X        {
  1162. X            p->pr_pptr = process ;
  1163. X            continue ;
  1164. X        }
  1165. X        if ( p->pr_pptr < process || p->pr_pptr >= lastp )
  1166. X        {
  1167. X            fprintf( stderr, "sps - process %d has bad pptr\n",
  1168. X                p->pr_p.p_pid ) ;
  1169. X            p->pr_pptr = process ;
  1170. X        }
  1171. X    }
  1172. X    /* For each process, see if it is a candidate for selection.
  1173. X       If so, retrieve its command arguments and upage information. */
  1174. X    uid = getuid() ;
  1175. X    for ( p = process ; p < lastp ; p++ )
  1176. X    {                               
  1177. X        if ( !p->pr_p.p_stat )
  1178. X            continue ;
  1179. X        if ( p->pr_p.p_stat == SIDL )
  1180. X            continue ;
  1181. X        /* Count processes and sizes */
  1182. X        summarise( p ) ;
  1183. X        /* Select the given processes. Bear in mind that selection
  1184. X           of processes based on the `F' and `T' flags must be
  1185. X           postponed until the upage is accessed. */
  1186. X        if ( !Flg.flg_F && !Flg.flg_T && !selectproc( p, process, uid ))
  1187. X            continue ;
  1188. X        /* Try to find the process' command arguments. Accessing the
  1189. X           arguments also involves retrieving the upage. */
  1190. X        p->pr_cmd = getcmd( p ) ;
  1191. X        /* If the upage was found successfully, use this information */
  1192. X        if ( p->pr_upag )       
  1193. X        {
  1194. X# ifdef BSD42
  1195. X            p->pr_rself = User.u_us.u_ru ;
  1196. X            p->pr_rchild = User.u_us.u_cru ;
  1197. X# else
  1198. X            p->pr_vself = User.u_us.u_vm ;
  1199. X            p->pr_vchild = User.u_us.u_cvm ;
  1200. X# endif
  1201. X            p->pr_tty = findtty( p ) ;
  1202. X            p->pr_files = filecount( p ) ;
  1203. X        }
  1204. X        else
  1205. X            p->pr_tty = &Notty ;
  1206. X        /* Select on the basis of the `F' and `T' flags */
  1207. X        if ( Flg.flg_F          
  1208. X        && !(p->pr_p.p_pgrp && p->pr_p.p_pgrp == p->pr_tty->l_pgrp) )
  1209. X            continue ;
  1210. X        if ( Flg.flg_T && !selecttty( p ) )
  1211. X            continue ;
  1212. X        /* Arrive here with a selected process. Add this to the
  1213. X           linked list of needed processes. */
  1214. X        p->pr_plink = plist ;   
  1215. X        plist = p ;
  1216. X        p->pr_child = (struct process*)0 ;
  1217. X        p->pr_sibling = (struct process*)0 ;
  1218. X    }
  1219. X    return ( plist ) ;
  1220. X}
  1221. X
  1222. X/* SUMMARISE - Summarises the given process into the `Summary' structure */
  1223. X/*
  1224. X** SHOULD ACCOUNT HERE FOR THE SIZE OF LOADED PAGE TABLES, BUT WE DON'T REALLY
  1225. X** KNOW THEIR RESIDENT SIZES.
  1226. X*/
  1227. summarise ( p )
  1228. X
  1229. register struct process         *p ;
  1230. X
  1231. X{
  1232. X# ifndef SUNOS40
  1233. X    register struct text    *tp ;
  1234. X# endif
  1235. X    int                     busy ;
  1236. X    extern struct summary   Summary ;
  1237. X
  1238. X    Summary.sm_ntotal++ ;
  1239. X    if ( p->pr_p.p_stat == SZOMB )
  1240. X        return ;
  1241. X    /* Firstly, account for processes */
  1242. X# if defined(OLDSTATS) || !defined(SUNOS40)
  1243. X    Summary.sm_ktotal += p->pr_p.p_dsize + p->pr_p.p_ssize ;
  1244. X# else
  1245. X    seg_count( p ) ;        /* count up process pages */
  1246. X    
  1247. X    Summary.sm_ktotal += p->pr_private + p->pr_shared ;
  1248. X# endif
  1249. X    Summary.sm_kloaded += p->pr_p.p_rssize ;
  1250. X    Summary.sm_kswapped += p->pr_p.p_swrss ;
  1251. X# ifdef ULTRIX40
  1252. X    if ( p->pr_p.p_sched & SLOAD )
  1253. X# else
  1254. X    if ( p->pr_p.p_flag & SLOAD )
  1255. X# endif
  1256. X        Summary.sm_nloaded++ ;
  1257. X    else
  1258. X        Summary.sm_nswapped++ ;
  1259. X    busy = (p->pr_p.p_stat == SRUN) || (p->pr_p.p_stat==SSLEEP
  1260. X         && (p->pr_p.p_pri<PZERO && p->pr_p.p_pid > MSPID) ) ;
  1261. X# ifdef SUNOS40
  1262. X    /* Ignore the idle processes */
  1263. X    if ( p->pr_p.p_pid == 3 || p->pr_p.p_pid == 4 )
  1264. X        busy = 0 ;
  1265. X# endif SUNOS40
  1266. X    if ( busy )
  1267. X    {
  1268. X        Summary.sm_nbusy++ ;
  1269. X# if defined(OLDSTATS) || !defined(SUNOS40)
  1270. X        Summary.sm_kbusy += p->pr_p.p_dsize + p->pr_p.p_ssize ;
  1271. X# else
  1272. X        Summary.sm_kbusy += p->pr_private + p->pr_shared ;
  1273. X# endif
  1274. X    }
  1275. X# ifndef SUNOS40
  1276. X    /* Now account for their texts */
  1277. X    if ( !(tp = p->pr_p.p_textp) || !tp->x_count )
  1278. X        return ;                
  1279. X    Summary.sm_ktotal += tp->x_size ;
  1280. X    Summary.sm_kloaded += tp->x_rssize ;
  1281. X    Summary.sm_kswapped += tp->x_swrss ;
  1282. X    if ( busy )
  1283. X        Summary.sm_kbusy += tp->x_size ;
  1284. X    tp->x_count = 0 ;
  1285. X# endif
  1286. X}
  1287. END_OF_FILE
  1288. if test 5262 -ne `wc -c <'needed.c'`; then
  1289.     echo shar: \"'needed.c'\" unpacked with wrong size!
  1290. fi
  1291. # end of 'needed.c'
  1292. fi
  1293. if test -f 'openfiles.c' -a "${1}" != "-c" ; then 
  1294.   echo shar: Will not clobber existing file \"'openfiles.c'\"
  1295. else
  1296. echo shar: Extracting \"'openfiles.c'\" \(3718 characters\)
  1297. sed "s/^X//" >'openfiles.c' <<'END_OF_FILE'
  1298. X# ifndef lint
  1299. static char SccsId[] =  "@(#)openfiles.c    1.1\t10/1/88" ;
  1300. X# endif
  1301. X
  1302. X# include       <stdio.h>
  1303. X# include       "sps.h"
  1304. X# include       "flags.h"
  1305. X# include       <varargs.h>
  1306. X# ifdef KVM
  1307. X# include       <kvm.h>
  1308. X# endif
  1309. X
  1310. X/* Miscellaneous procedures */
  1311. X
  1312. X/* OPENFILE - Opens the named file */
  1313. openfile ( name )
  1314. X
  1315. char                            *name ;
  1316. X
  1317. X{
  1318. X    register int            fd ;
  1319. X
  1320. X    if ( (fd = open( name, 0 )) >= 0 )
  1321. X        return ( fd ) ;
  1322. X    fprintf( stderr, "sps - Can't open %s", name ) ;
  1323. X    sysperror() ;
  1324. X    /* NOTREACHED */
  1325. X}
  1326. X
  1327. X# ifdef KVM
  1328. X
  1329. getkmem ( addr, buf, bufsize )
  1330. X
  1331. long                            addr ;
  1332. char                            *buf ;
  1333. int                             bufsize ;
  1334. X{
  1335. X    extern kvm_t            *Flkvm ;
  1336. X
  1337. X    return( kvm_read( Flkvm, (long)addr, buf, bufsize ) ) ;
  1338. X}
  1339. X
  1340. X# else
  1341. X
  1342. getkmem ( addr, buf, bufsize )
  1343. X
  1344. long                            addr ;
  1345. char                            *buf ;
  1346. int                             bufsize ;
  1347. X{
  1348. X    extern int              Flkmem ;
  1349. X
  1350. X    memseek( Flkmem, (long)addr ) ;
  1351. X    return( read( Flkmem, buf, bufsize ) ) ;
  1352. X}
  1353. X
  1354. X/* MEMSEEK - Seek on a special file */
  1355. memseek ( fd, pos )
  1356. X
  1357. int                             fd ;
  1358. long                            pos ;
  1359. X
  1360. X{
  1361. X    extern int              errno ;
  1362. X    extern struct flags     Flg ;
  1363. X    long                    lseek() ;
  1364. X
  1365. X    errno = 0 ;
  1366. X    if ( Flg.flg_k )
  1367. X# ifdef SUN
  1368. X        pos &= KERNELBASE - 1 ;
  1369. X# else
  1370. X        pos &= 0x7fffffff ;
  1371. X# endif
  1372. X    (void)lseek( fd, pos, 0 ) ;
  1373. X    if ( errno )
  1374. X    {
  1375. X        fprintf( stderr, "sps - Seek failed" ) ;
  1376. X        sysperror() ;
  1377. X    }
  1378. X}
  1379. X
  1380. X/* SWSEEK - Seek on the swap device */
  1381. swseek ( pos )
  1382. X
  1383. long                            pos ;
  1384. X
  1385. X{
  1386. X    extern int              Flswap ;
  1387. X    extern int              errno ;
  1388. X    long                    lseek() ;
  1389. X
  1390. X    errno = 0 ;
  1391. X    (void)lseek( Flswap, pos, 0 ) ;
  1392. X    if ( errno )
  1393. X    {
  1394. X        fprintf( stderr, "sps - Seek failed" ) ;
  1395. X        sysperror() ;
  1396. X    }
  1397. X}
  1398. X
  1399. X# endif
  1400. X
  1401. X# ifdef lint
  1402. int                             errno ;
  1403. int                             sys_nerr ;
  1404. char                            *sys_errlist[] ;
  1405. X# endif
  1406. X
  1407. X/* SYSPERROR - Reports a system defined error msg and then exits gracefully */
  1408. sysperror ()
  1409. X{
  1410. X    extern int              errno ;
  1411. X    extern int              sys_nerr ;
  1412. X    extern char             *sys_errlist[] ;
  1413. X
  1414. X    if ( 0 < errno && errno < sys_nerr )
  1415. X        fprintf( stderr, " : %s", sys_errlist[errno] ) ;
  1416. X    (void)fputc( '\n', stderr ) ;
  1417. X    exit( 1 ) ;
  1418. X}
  1419. X
  1420. X/* STRSAVE - Store a string in core for later use. */
  1421. char    *strsave ( cp )
  1422. X
  1423. register char                   *cp ;
  1424. X
  1425. X{
  1426. X    register char           *chp ;
  1427. X    char                    *getcore(), *strcpy() ;
  1428. X
  1429. X    chp = getcore( strlen( cp ) + 1 ) ;
  1430. X    (void)strcpy( chp, cp ) ;
  1431. X    return ( chp ) ;
  1432. X}
  1433. X
  1434. X/* GETCORE - Allocate and return a pointer to the asked for amount of core */
  1435. char    *getcore ( size )
  1436. X
  1437. register int                    size ;
  1438. X
  1439. X{
  1440. X    register char           *chp ;
  1441. X    char                    *malloc() ;
  1442. X
  1443. X    if ( chp = malloc( (unsigned)size ) )
  1444. X        return ( chp ) ;
  1445. X    fprintf( stderr, "sps - Out of core" ) ;
  1446. X    sysperror() ;
  1447. X    /* NOTREACHED */
  1448. X}
  1449. X
  1450. union flaglist  *getflgsp ( argc )
  1451. X
  1452. register int                    argc ;
  1453. X
  1454. X{
  1455. X    char                    *getcore() ;
  1456. X
  1457. X    return ( (union flaglist*)getcore( sizeof( union flaglist )*argc ) ) ;
  1458. X}
  1459. X
  1460. X/* PREXIT - Print an error message and exit */
  1461. X/* VARARGS */
  1462. X/* ARGSUSED */
  1463. prexit ( va_alist )
  1464. X
  1465. va_dcl
  1466. X
  1467. X{
  1468. X    char                    *fmt ;
  1469. X    va_list                  args ;
  1470. X
  1471. X    va_start( args ) ;
  1472. X    fmt = va_arg( args, char * ) ;
  1473. X
  1474. X    vfprintf( stderr, fmt, args ) ;
  1475. X    exit( 1 ) ;
  1476. X}
  1477. X
  1478. X# ifndef VPRINTF
  1479. X
  1480. int vfprintf ( filep, fmt, args )
  1481. X
  1482. XFILE                            *filep ;
  1483. char                            *fmt ;
  1484. va_list                          args ;
  1485. X
  1486. X{
  1487. X    _doprnt( fmt, args, filep ) ;    
  1488. X    return( ferror( filep ) ? EOF : 0 ) ;
  1489. X}
  1490. X
  1491. X# endif
  1492. END_OF_FILE
  1493. if test 3718 -ne `wc -c <'openfiles.c'`; then
  1494.     echo shar: \"'openfiles.c'\" unpacked with wrong size!
  1495. fi
  1496. # end of 'openfiles.c'
  1497. fi
  1498. if test -f 'sps.h' -a "${1}" != "-c" ; then 
  1499.   echo shar: Will not clobber existing file \"'sps.h'\"
  1500. else
  1501. echo shar: Extracting \"'sps.h'\" \(7171 characters\)
  1502. sed "s/^X//" >'sps.h' <<'END_OF_FILE'
  1503. X# ifndef lint
  1504. static char SpsHId[] =  "@(#)sps.h    1.5\t8/22/91" ;
  1505. X# endif
  1506. X
  1507. X# ifdef SUNOS40
  1508. X#  define KERNEL
  1509. X# endif SUNOS40
  1510. X# include    <sys/param.h>
  1511. X# undef KERNEL
  1512. X# include    <sys/dir.h>
  1513. X# include    <sys/user.h>
  1514. X# include    <sys/proc.h>
  1515. X
  1516. X# ifdef SUNOS40
  1517. X#  ifndef BSD43
  1518. X#   define BSD43
  1519. X# endif BSD43
  1520. X# endif SUNOS40
  1521. X
  1522. X/*
  1523. X** Maximum # of users to be considered. (Because user names are stored
  1524. X** in a hash table, this should probably be at least double the number
  1525. X** of actual users defined in /etc/passwd or by the Yellow Pages.)
  1526. X*/
  1527. X# ifndef MAXUSERS
  1528. X# define    MAXUSERS    100
  1529. X# endif
  1530. X/* Maximum # ttys to be considered, plus 1 for the console ... */
  1531. X# ifndef MAXTTYS
  1532. X# define    MAXTTYS        193
  1533. X# endif
  1534. X
  1535. X
  1536. X/* Maximum user name length ... */
  1537. X# define    UNAMELEN    8
  1538. X/* Maximum process-id not to be considered busy ... */
  1539. X# define    MSPID        2
  1540. X/* # of wait states defined in the `struct info' ... */
  1541. X# ifdef NFS
  1542. X#  ifdef SUN
  1543. X#   define    NWAITSTATE    16
  1544. X#  else
  1545. X#   define    NWAITSTATE    36
  1546. X#  endif SUN
  1547. X# else NFS
  1548. X#  ifdef ULTRIX20
  1549. X#   define    NWAITSTATE    36
  1550. X#  else ULTRIX20
  1551. X#   define    NWAITSTATE    35
  1552. X#  endif ULTRIX20
  1553. X# endif NFS
  1554. X
  1555. X/* Convert clicks to kbytes ... */
  1556. X# ifndef PGSHIFT
  1557. X#  define    KBYTES( size )    ((size) << 1)
  1558. X# else PGSHIFT
  1559. X#  if PGSHIFT > 10
  1560. X#   define        KBYTES( size )  ((size) << (PGSHIFT - 10))
  1561. X#  else
  1562. X#   define    KBYTES( size )    ((size) >> (10 - PGSHIFT))
  1563. X#  endif
  1564. X# endif PGSHIFT
  1565. X
  1566. X/* Standard files to be examined ... */
  1567. X# ifndef FILE_MEM
  1568. X# define    FILE_MEM    "/dev/mem"    /* System physical memory */
  1569. X# endif
  1570. X# ifndef FILE_KMEM
  1571. X# define    FILE_KMEM    "/dev/kmem"    /* Kernel virtual memory */
  1572. X# endif
  1573. X# ifndef FILE_SWAP
  1574. X# define    FILE_SWAP    "/dev/drum"    /* Swap/paging device */
  1575. X# endif
  1576. X# ifndef FILE_DEV
  1577. X# define    FILE_DEV    "/dev"        /* Directory of tty entries */
  1578. X# endif
  1579. X# ifndef FILE_SYMBOL
  1580. X# define    FILE_SYMBOL    "/vmunix"    /* Symbol file for nlist() */
  1581. X# endif
  1582. X# ifndef FILE_INFO
  1583. X# define    FILE_INFO    "/tmp/.spsinfo"    /* Sps information file */
  1584. X# endif
  1585. X# ifndef FILE_PASSWD
  1586. X# define    FILE_PASSWD    "/etc/passwd"    /* User database */
  1587. X# endif
  1588. X
  1589. X
  1590. X/* Structure to hold necessary information concerning a tty ... */
  1591. struct ttyline
  1592. X{
  1593. X    char            l_name[2] ;    /* Tty character name */
  1594. X    unsigned short        l_pgrp ;    /* Tty process group */
  1595. X# ifdef SUNOS40
  1596. X    struct streamtab    *l_addr ;    /* Ptr to streamtab in kmem */
  1597. X    struct stdata        *l_stdata ;    /* Ptr to stdata at runtime */
  1598. X# else SUNOS40
  1599. X    struct tty        *l_addr ;    /* Ptr to tty struct in kmem */
  1600. X# endif SUNOS40
  1601. X    dev_t            l_dev ;        /* Tty device # */
  1602. X} ;
  1603. X
  1604. X/* Structure holding a single hash table entry ... */
  1605. struct hashtab
  1606. X{
  1607. X    short            h_uid ;        /* Uid of user entry */
  1608. X    char            h_uname[ UNAMELEN ] ; /* Corresponding name */
  1609. X} ;
  1610. X
  1611. X/*
  1612. X** Format of the standard information file maintained by sps.
  1613. X** This structure is filled in at initialisation time and then is read back
  1614. X** in whenever sps is invoked.
  1615. X** Note that the pointer variables in this structure refer to
  1616. X** kernel virtual addresses, not addresses within sps.
  1617. X** These variable are typed as such so that pointer arithmetic
  1618. X** on the kernel addresses will work correctly.
  1619. X*/
  1620. struct info
  1621. X{    /* Kernel values determining process, tty and upage info ... */
  1622. X    struct proc        *i_proc0 ;    /* address of process table */
  1623. X    int            i_nproc ;    /* length of process table */
  1624. X# ifndef SUNOS40
  1625. X    struct text        *i_text0 ;    /* address of text table */
  1626. X# endif SUNOS40
  1627. X    int            i_ntext ;    /* length of text table */
  1628. X# ifdef ULTRIX20
  1629. X    struct gnode        *i_inode0 ;    /* address of inode table */
  1630. X# else ULTRIX20
  1631. X    struct inode        *i_inode0 ;    /* address of inode table */
  1632. X# endif ULTRIX20
  1633. X    int            i_ninode ;    /* length of inode table */
  1634. X    int            i_ecmx ;    /* max physical memory address*/
  1635. X# ifndef SUNOS40
  1636. X    struct buf        *i_swbuf0 ;    /* address of swap buffers */
  1637. X    int            i_nswbuf ;    /* # swap buffers */
  1638. X    struct buf        *i_buf0 ;    /* address of i/o buffers */
  1639. X    int            i_nbuf ;    /* # i/o buffers */
  1640. X    struct pte        *i_usrptmap ;    /* page table map */
  1641. X    struct pte        *i_usrpt ;    /* page table map */
  1642. X# endif SUNOS40
  1643. X    struct cdevsw        *i_cdevsw ;    /* device switch to find ttys */
  1644. X# ifdef BSD42
  1645. X#  ifdef NFS
  1646. X    struct dquot        *i_quota0 ;    /* disc quota structures */
  1647. X#  else NFS
  1648. X    struct quota        *i_quota0 ;    /* disc quota structures */
  1649. X#  endif NFS
  1650. X    int            i_nquota ;    /* # quota structures */
  1651. X#  ifdef ULTRIX40
  1652. X    int            i_swapfrag ;    /* # swap blocks allocated */
  1653. X#  else
  1654. X    int            i_dmmin ;    /* The start of the disc map */
  1655. X    int            i_dmmax ;    /* The end of the disc map */
  1656. X#  endif ULTRIX40
  1657. X    struct mbuf        *i_mbutl ;    /* Start of mbuf area */
  1658. X# else BSD42
  1659. X    int            i_hz ;        /* Clock rate */
  1660. X# endif BSD42
  1661. X# ifdef CHAOS
  1662. X    caddr_t            i_Chconntab ;    /* Chaos connection table */
  1663. X# endif
  1664. X    /* Kernel addresses are associated with process wait states ... */
  1665. X    caddr_t            i_waitstate[ NWAITSTATE ] ;
  1666. X    /* User names, stored in a hash table ... */
  1667. X    struct hashtab        i_hnames[ MAXUSERS ] ;
  1668. X    /* Tty device info ... */
  1669. X    struct ttyline        i_ttyline[ MAXTTYS ] ;
  1670. X# ifdef SUNOS40
  1671. X    struct seg_ops        *i_segvn_ops ;    /* ptr to vnode segment ops */
  1672. X    struct pty        *i_ptybase ;
  1673. X    int            i_npty ;
  1674. X#  ifdef SUNOS41
  1675. X    struct strstat        *i_strst;
  1676. X    struct stdata        *i_allstream;
  1677. X#  else SUNOS41
  1678. X    struct stdata        *i_streams ;    /* streams list */
  1679. X    struct stdata        *i_streamsNSTREAMS ;
  1680. X#  endif SUNOS41
  1681. X    caddr_t            i_sysbase ;
  1682. X# endif SUNOS40
  1683. X} ;
  1684. X
  1685. X/*
  1686. X** The symbol structure cross-references values read from the kernel with
  1687. X** their place in the info structure, and if such a value is associated with
  1688. X** a process wait state or not.
  1689. X*/
  1690. struct symbol
  1691. X{
  1692. X    char            *s_kname ;    /* Kernel symbol name */
  1693. X    char            s_indirect ;    /* Value requires indirection */
  1694. X    caddr_t            *s_info ;    /* Corresponding info address */
  1695. X    char            *s_wait ;    /* Reason for wait, if any */
  1696. X} ;
  1697. X
  1698. X/* The `user' structure obtained from /dev/mem or /dev/swap ... */
  1699. union userstate
  1700. X{
  1701. X    struct user        u_us ;
  1702. X    char            u_pg[ UPAGES ][ NBPG ] ;
  1703. X} ;
  1704. X
  1705. X/* Information concerning each process filled from /dev/kmem ... */
  1706. struct process
  1707. X{
  1708. X    struct proc        pr_p ;        /* struct proc from /dev/kmem */
  1709. X    struct process        *pr_plink ;    /* Normalised ptrs from above */
  1710. X    struct process        *pr_sibling ;    /* Ptr to sibling process */
  1711. X    struct process        *pr_child ;    /* Ptr to child process */
  1712. X    struct process        *pr_pptr ;    /* Ptr to parent process */
  1713. X# ifdef BSD42
  1714. X    struct rusage        pr_rself ;    /* Read from upage for self */
  1715. X    struct rusage        pr_rchild ;    /* ... and the children */
  1716. X# else BSD42
  1717. X    struct vtimes        pr_vself ;    /* Read from upage for self */
  1718. X    struct vtimes        pr_vchild ;    /* ... and the children */
  1719. X# endif BSD42
  1720. X    int            pr_files ;    /* # open files */
  1721. X    struct ttyline        *pr_tty ;    /* Associated tty information */
  1722. X    char            *pr_cmd ;    /* Command args, from upage */
  1723. X    int            pr_upag:1 ;    /* Upage was obtained */
  1724. X    int            pr_csaved:1 ;    /* Cmd args saved by malloc() */
  1725. X# ifdef SUNOS40
  1726. X    unsigned        pr_private ;    /* private pages */
  1727. X    unsigned        pr_shared ;    /* shared pages */
  1728. X# endif SUNOS40
  1729. X} ;
  1730. X
  1731. X/* Structure to hold summarising information ... */
  1732. struct summary
  1733. X{
  1734. X    long            sm_ntotal ;    /* Total # processes */
  1735. X    long            sm_ktotal ;    /* Total virtual memory */
  1736. X    long            sm_nbusy ;    /* # busy processes */
  1737. X    long            sm_kbusy ;    /* Busy virtual memory */
  1738. X    long            sm_nloaded ;    /* # loaded processes */
  1739. X    long            sm_kloaded ;    /* Active resident memory */
  1740. X    long            sm_nswapped ;    /* # swapped processes */
  1741. X    long            sm_kswapped ;    /* Size totally swapped out */
  1742. X} ;
  1743. END_OF_FILE
  1744. if test 7171 -ne `wc -c <'sps.h'`; then
  1745.     echo shar: \"'sps.h'\" unpacked with wrong size!
  1746. fi
  1747. # end of 'sps.h'
  1748. fi
  1749. if test -f 'stream.c' -a "${1}" != "-c" ; then 
  1750.   echo shar: Will not clobber existing file \"'stream.c'\"
  1751. else
  1752. echo shar: Extracting \"'stream.c'\" \(5432 characters\)
  1753. sed "s/^X//" >'stream.c' <<'END_OF_FILE'
  1754. X# ifndef lint
  1755. static char SccsId[] =  "@(#)stream.c    1.3\t8/22/91" ;
  1756. X# endif
  1757. X
  1758. X# ifdef SUNOS40
  1759. X#  include        "sps.h"
  1760. X#  include        <h/stream.h>
  1761. X#  include        <h/vnode.h>
  1762. X#  ifdef SUNOS41
  1763. X#   include        <h/strstat.h>
  1764. X#  endif
  1765. X
  1766. static struct stdata    *pstreams ;
  1767. static struct stdata    *pstreamsNSTREAMS ;
  1768. X
  1769. init_streams_tab()
  1770. X{
  1771. X    int            len ;
  1772. X    extern struct info    Info ;
  1773. X    register struct stdata    *s ;
  1774. X    struct vnode        *v ;
  1775. X    char            *getcore() ;
  1776. X
  1777. X    if ( pstreams )
  1778. X    {
  1779. X        /* reinitializing */
  1780. X        for ( s = pstreams ; s <= pstreamsNSTREAMS ; s++ )
  1781. X            if ( s->sd_vnode != 0 )
  1782. X                free( (char*)s->sd_vnode ) ;
  1783. X        free( (char*)pstreams ) ;
  1784. X    }
  1785. X#  ifdef SUNOS41
  1786. X    /*
  1787. X     * In SunOS 4.1, the stream heads are in a linked list.  A
  1788. X     * `struct strstat' contains the number of active streams; the
  1789. X     * variable `allstream' points to an apparently random
  1790. X     * position in a doubly linked `struct stdata' chain.
  1791. X     *
  1792. X     * To find all streams we'll have to scan the chain forwards
  1793. X     * AND backwards from `allstream'.  `int going_forwards' below
  1794. X     * tells which direction we are currently going.  Weird.
  1795. X     *
  1796. X     */
  1797. X
  1798. X    {
  1799. X        struct strstat        strst ;
  1800. X        int            n ;
  1801. X        long            addr ;
  1802. X        struct stdata        *this_stream ;
  1803. X        int            going_forwards = 1 ;
  1804. X    
  1805. X        if ( getkmem ((long) Info.i_strst, (char *) &strst,
  1806. X            sizeof ( struct strstat )) != sizeof ( struct strstat ))
  1807. X            return 0 ;
  1808. X        len = strst.stream.use * sizeof( struct stdata ) ;
  1809. X        pstreams = (struct stdata *)getcore (len ) ;
  1810. X        addr = (long)Info.i_allstream ;
  1811. X        this_stream = pstreams ;
  1812. X        pstreamsNSTREAMS = pstreams - 1 ;
  1813. X        for (n = 0 ; n < strst.stream.use ; n++)
  1814. X        {
  1815. X            if ( getkmem ( addr, (char *) this_stream,
  1816. X                sizeof ( struct stdata ))
  1817. X                != sizeof ( struct stdata ))
  1818. X            {
  1819. X                /*
  1820. X                 * If we are following the `sd_next' chain we'll
  1821. X                 * have to start over from the stream pointed to
  1822. X                 * by Info.i_allstream and scan `sd_prev'
  1823. X                 * backwards.
  1824. X                 */
  1825. X                if ( going_forwards && n > 0 )
  1826. X                {
  1827. X                    going_forwards = 0 ;
  1828. X                    addr = (long) pstreams[0].sd_prev ;
  1829. X                    n--;
  1830. X                    continue ;
  1831. X                }
  1832. X                if ( pstreamsNSTREAMS < pstreams )
  1833. X                    return 0 ;
  1834. X                break ;
  1835. X            }
  1836. X            addr = going_forwards ? (long) this_stream->sd_next :
  1837. X                (long) this_stream->sd_prev ;
  1838. X            this_stream++ ;
  1839. X            pstreamsNSTREAMS++ ;
  1840. X        }
  1841. X    }
  1842. X#  else SUNOS41
  1843. X    len = ((Info.i_streamsNSTREAMS - Info.i_streams) + 1)
  1844. X        * sizeof( struct stdata ) ;
  1845. X    pstreams = (struct stdata *)getcore( len ) ;
  1846. X    pstreamsNSTREAMS = pstreams + (len / sizeof( struct stdata ) ) ;
  1847. X    if ( getkmem( (long)Info.i_streams, (char *)pstreams, len ) != len )
  1848. X        return( 0 ) ;
  1849. X#  endif SUNOS41
  1850. X
  1851. X    for ( s = pstreams ; s <= pstreamsNSTREAMS ; s++ )
  1852. X        if ( s->sd_vnode != 0 )
  1853. X        {
  1854. X            if ( ( v = (struct vnode*)getcore( sizeof( *v ) ) )
  1855. X            && getkmem( (long)s->sd_vnode, (char*)v, sizeof( *v ) )
  1856. X            == sizeof( *v ) )
  1857. X            {
  1858. X                s->sd_vnode = v ;
  1859. X                continue ;
  1860. X            }
  1861. X
  1862. X            s->sd_vnode = 0 ;
  1863. X        }
  1864. X    return( 1 ) ;
  1865. X}
  1866. X
  1867. X
  1868. X#  ifdef SUNOS41
  1869. struct sess *find_session ( addr )
  1870. X
  1871. struct sess            *addr ;
  1872. X
  1873. X{
  1874. X    /*
  1875. X     * SunOS 4.1 seems to store controlling tty's in a "struct
  1876. X     * sess" which is accessible as p->p_sessp.  Another layer
  1877. X     * of indirection to wade through...
  1878. X     *
  1879. X     * To make this a tiny bit faster, I'll store sessions in a
  1880. X     * linked list as I read them in with getkmem; subsequent
  1881. X     * calls to find_session() check the cache.
  1882. X     */
  1883. X
  1884. X    struct sps_sess {
  1885. X        struct sess        sess ;
  1886. X        struct sess        *addr ;
  1887. X        struct sps_sess        *next ;
  1888. X    };
  1889. X
  1890. X    static struct sps_sess        *sessions ; /* Cache of known sessions*/
  1891. X    register struct sps_sess    *s ;
  1892. X
  1893. X    /* Try to find the session in the cache */
  1894. X    for ( s = sessions ; s ; s = s->next )
  1895. X        if ( s->addr == addr )
  1896. X            return &s->sess ;
  1897. X    /* Not found; get it from kmem and put it in the cache */
  1898. X    s = (struct sps_sess *)getcore( sizeof ( struct sps_sess ) ) ;
  1899. X    if ( getkmem ((long) addr, (char *) &s->sess,
  1900. X            sizeof ( struct sess )) != sizeof ( struct sess ) )
  1901. X        return 0 ;
  1902. X    s->addr = addr ;
  1903. X    s->next = sessions ;
  1904. X    sessions = s ;
  1905. X    return &s->sess ;
  1906. X}
  1907. X#  endif SUNOS41
  1908. X
  1909. struct stdata *getstdata ( st, dev )
  1910. X
  1911. struct streamtab                *st ;
  1912. dev_t                            dev ;
  1913. X
  1914. X{
  1915. X    register struct stdata  *s ;
  1916. X
  1917. X    for ( s = pstreams ; s <= pstreamsNSTREAMS ; s++ )
  1918. X        if ( s->sd_strtab == st && s->sd_vnode
  1919. X        && s->sd_vnode->v_rdev == dev )
  1920. X            return( s ) ;
  1921. X    return( 0 ) ;
  1922. X}
  1923. X
  1924. X/* 1 if `w' is in the address range defined by `a1' and `a2' ... */
  1925. X# define        INRANGE( w, a1, a2 ) \
  1926. X            ( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )
  1927. X
  1928. char *gettty ( lp, w )
  1929. X
  1930. register struct ttyline         *lp ;
  1931. caddr_t                         w ;
  1932. X
  1933. X{
  1934. X    struct stdata           *s ;
  1935. X    struct queue            *q ;
  1936. X    struct queue            qq[2] ;
  1937. X    char                    *cp = 0 ;
  1938. X
  1939. X    if ( ( s = lp->l_stdata ) == 0 )
  1940. X        return( 0 ) ;
  1941. X
  1942. X    q = s->sd_wrq ;        /* get write queue (only queue_t in stdata) */
  1943. X    do
  1944. X    {
  1945. X        if ( INRANGE( w, RD( q ), q ) )
  1946. X        {            /* check read queue */
  1947. X            cp = "rtty??" ;
  1948. X            break ;
  1949. X        }
  1950. X        if ( INRANGE( w, q, WR ( q ) ) )
  1951. X        {            /* check write queue */
  1952. X            cp = "wtty??" ;
  1953. X            break ;
  1954. X        }
  1955. X        /* check queue private data structures - useful??? */
  1956. X        if ( getkmem( (long)RD( q ), (char*)qq, sizeof( qq ) )
  1957. X        != sizeof( qq ) )
  1958. X            break ;
  1959. X        if ( INRANGE( w, qq[0].q_ptr, qq[0].q_ptr + 1 ) )
  1960. X        {
  1961. X            cp = "r?ty??" ;
  1962. X        }
  1963. X        if ( INRANGE( w, qq[1].q_ptr, qq[1].q_ptr + 1 ) )
  1964. X        {
  1965. X            cp = "w?ty??" ;
  1966. X        }
  1967. X        q = qq[1].q_next ;
  1968. X    }
  1969. X    while ( q ) ;
  1970. X    if ( cp )
  1971. X    {
  1972. X        cp[4] = lp->l_name[0] ;
  1973. X        cp[5] = lp->l_name[1] ;
  1974. X        return( cp ) ;
  1975. X    }
  1976. X    return( 0 ) ;            /* chain down list? */
  1977. X}
  1978. X# endif SUNOS40
  1979. X
  1980. END_OF_FILE
  1981. if test 5432 -ne `wc -c <'stream.c'`; then
  1982.     echo shar: \"'stream.c'\" unpacked with wrong size!
  1983. fi
  1984. # end of 'stream.c'
  1985. fi
  1986. if test -f 'ttystatus.c' -a "${1}" != "-c" ; then 
  1987.   echo shar: Will not clobber existing file \"'ttystatus.c'\"
  1988. else
  1989. echo shar: Extracting \"'ttystatus.c'\" \(3826 characters\)
  1990. sed "s/^X//" >'ttystatus.c' <<'END_OF_FILE'
  1991. X# ifndef lint
  1992. static char SccsId[] =  "@(#)ttystatus.c    1.1\t10/1/88" ;
  1993. X# endif
  1994. X
  1995. X# include       "sps.h"
  1996. X# include       "flags.h"
  1997. X# include       <stdio.h>
  1998. X# include       <h/ioctl.h>
  1999. X# ifdef SUNOS40
  2000. X# include       <h/stream.h>
  2001. X# else
  2002. X# include       <h/tty.h>
  2003. X# endif
  2004. X# ifdef CHAOS
  2005. X# include       <chunix/chsys.h>
  2006. X# include       <chaos/chaos.h>
  2007. X# endif
  2008. X
  2009. X/*
  2010. X** TTYSTATUS - Reads the kernel memory for tty structures of active processes.
  2011. X** The addresses of the associated struct ttys of /dev/kmem are kept in the
  2012. X** info structure. Here we use those addresses to access the structures.
  2013. X** Actually, we are mostly interested just in the process group of each tty.
  2014. X*/
  2015. ttystatus ()
  2016. X{
  2017. X    register struct ttyline *lp ;
  2018. X# ifdef SUNOS40
  2019. X    struct stdata           *stdata ;
  2020. X    extern struct stdata    *getstdata() ;
  2021. X# else
  2022. X    struct tty              tty ;
  2023. X# endif
  2024. X    extern struct flags     Flg ;
  2025. X    extern struct info      Info ;
  2026. X# ifndef KVM
  2027. X    extern int              Flkmem ;
  2028. X# endif
  2029. X
  2030. X# ifdef SUNOS40
  2031. X    if ( !init_streams_tab() )
  2032. X        fprintf( stderr, "can't read streams table\n" ) ;
  2033. X# endif
  2034. X
  2035. X    if ( Flg.flg_y )
  2036. X# ifdef SUNOS40
  2037. X        printf( "Ty   Dev       Addr  Pgrp\n" ) ;
  2038. X# else
  2039. X        printf( "Ty   Dev       Addr Rawq Canq Outq  Pgrp\n" ) ;
  2040. X# endif
  2041. X    lp = Info.i_ttyline ;
  2042. X# ifdef CHAOS
  2043. X    while ( lp->l_name[0] && lp->l_name[0] != 'C' )
  2044. X# else
  2045. X    while ( lp->l_name[0] )
  2046. X# endif
  2047. X    {
  2048. X# ifdef SUNOS40 
  2049. X        if ( stdata = getstdata ( lp->l_addr, lp->l_dev ) )
  2050. X        {
  2051. X            lp->l_stdata = stdata ;
  2052. X            lp->l_pgrp = stdata->sd_pgrp ;
  2053. X            prstr( lp, stdata ) ;
  2054. X        }
  2055. X        else
  2056. X            lp->l_pgrp = 0 ;
  2057. X        lp++ ;
  2058. X# else
  2059. X        if ( getkmem( (long)lp->l_addr, (char*)&tty, sizeof( tty ) )
  2060. X        != sizeof( struct tty ) )
  2061. X        {
  2062. X            fprintf( stderr,
  2063. X                "sps - Can't read struct tty for tty%.2s\n",
  2064. X                lp->l_name ) ;
  2065. X            lp->l_pgrp = 0 ;
  2066. X            lp++ ;
  2067. X            continue ;
  2068. X        }
  2069. X        lp->l_pgrp = tty.t_pgrp ;
  2070. X        prtty( lp, &tty ) ;
  2071. X        lp++ ;
  2072. X# endif
  2073. X    }
  2074. X# ifdef CHAOS
  2075. X    chaosttys( lp ) ;               
  2076. X# endif
  2077. X}
  2078. X
  2079. X# ifdef SUNOS40
  2080. X
  2081. X/* PRSTR - Print out the stdata structure */
  2082. prstr ( lp, stdata )
  2083. X
  2084. register struct ttyline         *lp ;
  2085. register struct stdata          *stdata ;
  2086. X
  2087. X{
  2088. X    extern struct flags     Flg ;
  2089. X
  2090. X    if ( !Flg.flg_y )
  2091. X        return ;
  2092. X    printf( "%-2.2s %2d,%2d 0x%08x %5d\n",
  2093. X        lp->l_name,
  2094. X        major( lp->l_dev ),
  2095. X        minor( lp->l_dev ),
  2096. X        lp->l_addr,
  2097. X        stdata->sd_pgrp ) ;
  2098. X}
  2099. X
  2100. X# else
  2101. X
  2102. X/* PRTTY - Print out the tty structure */
  2103. prtty ( lp, tty )
  2104. X
  2105. register struct ttyline         *lp ;
  2106. register struct tty             *tty ;
  2107. X
  2108. X{
  2109. X    extern struct flags     Flg ;
  2110. X
  2111. X    if ( !Flg.flg_y )
  2112. X        return ;
  2113. X    printf( "%-2.2s %2d,%2d 0x%08x %4d %4d %4d %5d\n",
  2114. X        lp->l_name,
  2115. X        major( lp->l_dev ),
  2116. X        minor( lp->l_dev ),
  2117. X        lp->l_addr,
  2118. X        tty->t_rawq.c_cc,
  2119. X        tty->t_canq.c_cc,
  2120. X        tty->t_outq.c_cc,
  2121. X        tty->t_pgrp ) ;
  2122. X}
  2123. X
  2124. X# endif
  2125. X
  2126. X# ifdef CHAOS
  2127. X
  2128. X/* CHAOSTTYS - Finds ttys attached to the Chaos net */
  2129. chaosttys ( lp )
  2130. X
  2131. register struct ttyline         *lp ;
  2132. X
  2133. X{
  2134. X    register struct connection      **cnp ;
  2135. X    register int                    i ;
  2136. X    struct tty                      tty ;
  2137. X    struct connection               *conntab[CHNCONNS] ;
  2138. X    struct connection               conn ;
  2139. X    extern struct info              Info ;
  2140. X    extern int                      Flkmem ;
  2141. X
  2142. X    (void)getkmem( (long)Info.i_Chconntab, (char*)conntab,
  2143. X        sizeof( conntab ) ) ;
  2144. X    for ( i = 0, cnp = conntab ; cnp < &conntab[CHNCONNS] ; i++, cnp++ )
  2145. X    {
  2146. X        if ( !*cnp )
  2147. X            continue ;
  2148. X        (void)getkmem( (long)*cnp, (char*)&conn, sizeof( conn ) ) ;
  2149. X        if ( !(conn.cn_flags & CHTTY) )
  2150. X            continue ;
  2151. X        (void)getkmem( (long)conn.cn_ttyp, (char*)&tty, sizeof( tty ) ) ;
  2152. X        if ( lp >= &Info.i_ttyline[MAXTTYS] )
  2153. X            prexit( "sps - Too many chaos ttys\n" ) ;
  2154. X        lp->l_addr = conn.cn_ttyp ;
  2155. X        lp->l_pgrp = tty.t_pgrp ;
  2156. X        lp->l_dev = tty.t_dev ;
  2157. X        lp->l_name[0] = 'C' ;
  2158. X        lp->l_name[1] = i < 10 ? '0'+i : i-10 <= 'z'-'a' ? i-10+'a' :
  2159. X                i-10-('z'-'a')+'A' ;
  2160. X        prtty( lp, &tty ) ;
  2161. X        lp++ ;
  2162. X    }
  2163. X}
  2164. X
  2165. X# endif
  2166. END_OF_FILE
  2167. if test 3826 -ne `wc -c <'ttystatus.c'`; then
  2168.     echo shar: \"'ttystatus.c'\" unpacked with wrong size!
  2169. fi
  2170. # end of 'ttystatus.c'
  2171. fi
  2172. echo shar: End of archive 2 \(of 3\).
  2173. cp /dev/null ark2isdone
  2174. MISSING=""
  2175. for I in 1 2 3 ; do
  2176.     if test ! -f ark${I}isdone ; then
  2177.     MISSING="${MISSING} ${I}"
  2178.     fi
  2179. done
  2180. if test "${MISSING}" = "" ; then
  2181.     echo You have unpacked all 3 archives.
  2182.     rm -f ark[1-9]isdone
  2183. else
  2184.     echo You still need to unpack the following archives:
  2185.     echo "        " ${MISSING}
  2186. fi
  2187. ##  End of shell archive.
  2188. exit 0
  2189.