home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume13 / budpak < prev    next >
Encoding:
Text File  |  1988-09-11  |  40.6 KB  |  1,748 lines

  1. Subject:  v13i077:  Utilities to monitor usage on system
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Steven Grimm <koreth@ssyx.UCSC.EDU>
  7. Posting-number: Volume 13, Issue 77
  8. Archive-name: budpak
  9.  
  10. The "buddy system."
  11.  
  12. This is a collection of utilities for monitoring other users on the system.
  13. It runs on 4.3BSD on a VAX, and 4.2BSD on a Sun 3/160 and an ISI Optimum V.
  14. I have no idea whether it works (or even compiles) on SysV or not.
  15.  
  16. +New! Improved! Now 100% Artificial-+-+-----------------------------------+
  17. |#   #  @@@  ****  &&&&& $$$$$ %   %| |Steven Grimm                       |
  18. |#  #  @   @ *   * &       $   %   %+-+ ARPA: koreth@ssyx.ucsc.edu        |
  19. |###   @   @ ****  &&&&    $   %%%%%| | UUCP: ...!ucbvax!ucscc!ssyx!koreth|
  20. |#  #  @   @ * *   &       $   %   %+-+     ______________________________|
  21. |#   #  @@@  *  ** &&&&&   $   %   %| |     |"Let's see what's out there."|
  22. +-----with NutraSour(TM)!  No natural colors or preservatives!------------+
  23.  
  24.  
  25. ------------ (chop here) ------------
  26. # This is a shell archive.  Remove anything before this line
  27. # then unpack it by saving it in a file and typing "sh file"
  28. # (Files unpacked will be owned by you and have default permissions).
  29. # This archive contains the following files:
  30. #    ./MANIFEST
  31. #    ./Makefile
  32. #    ./aliases
  33. #    ./budpak.1
  34. #    ./buds.1
  35. #    ./buds.c
  36. #    ./cbuds.1
  37. #    ./cbuds.c
  38. #    ./mbuds.1
  39. #    ./mbuds.c
  40. #    ./monitor.1
  41. #    ./monitor.c
  42. #    ./rbuds.1
  43. #    ./rbuds.c
  44. #    ./wbuds.1
  45. #    ./wbuds.c
  46. #
  47. if `test ! -s ./MANIFEST`
  48. then
  49. echo "writing ./MANIFEST"
  50. cat > ./MANIFEST << '\Rogue\Monster\'
  51. This shar should contain the following files:
  52.  
  53. Makefile    - A makefile for BudPak.
  54. budpak.1
  55. buds.1
  56. cbuds.1
  57. mbuds.1
  58. monitor.1
  59. rbuds.1
  60. wbuds.1        - Documentation for the BudPak utilities.  Use [nt]roff -man.
  61. buds.c
  62. cbuds.c
  63. mbuds.c
  64. monitor.c
  65. rbuds.c
  66. wbuds.c        - BudPak source code.
  67. aliases        - Aliases for setting "single" and "horny" flags (see buds.6)
  68.  
  69. Read budpak.1 for an overview of the utilities provided.
  70. \Rogue\Monster\
  71. else
  72.   echo "will not over write ./MANIFEST"
  73. fi
  74. if `test ! -s ./Makefile`
  75. then
  76. echo "writing ./Makefile"
  77. cat > ./Makefile << '\Rogue\Monster\'
  78. #
  79. # BUDPAK 1.0
  80. #
  81. # Written by Jon Luini    (niteowl@ssyx.ucsc.edu)
  82. #                          ...!uunet!ucbvax!ucscc!ssyx!niteowl
  83. #        and Steven Grimm (koreth@ssyx.ucsc.edu)
  84. #                          ...!uunet!ucbvax!ucscc!ssyx!koreth
  85. #
  86. CFLAGS=        -g
  87. BINDIR=     /usr/local
  88. BINARIES=    buds cbuds mbuds monitor rbuds wbuds
  89.  
  90. BudPak: $(BINARIES)
  91. buds :  buds.c
  92.     cc $(CFLAGS)  buds.c -o  buds
  93. cbuds: cbuds.c
  94.     cc $(CFLAGS) cbuds.c -o cbuds
  95. mbuds: mbuds.c
  96.     cc $(CFLAGS) mbuds.c -o mbuds
  97. monitor: monitor.c
  98.     cc $(CFLAGS) monitor.c -o monitor
  99. rbuds: rbuds.c
  100.     cc $(CFLAGS) rbuds.c -o rbuds
  101. wbuds: wbuds.c
  102.     cc $(CFLAGS) wbuds.c -o wbuds
  103. \Rogue\Monster\
  104. else
  105.   echo "will not over write ./Makefile"
  106. fi
  107. if `test ! -s ./aliases`
  108. then
  109. echo "writing ./aliases"
  110. cat > ./aliases << '\Rogue\Monster\'
  111. alias single chmod g+x \`tty\`
  112. alias horny chmod o+x \`tty\`
  113. \Rogue\Monster\
  114. else
  115.   echo "will not over write ./aliases"
  116. fi
  117. if `test ! -s ./budpak.1`
  118. then
  119. echo "writing ./budpak.1"
  120. cat > ./budpak.1 << '\Rogue\Monster\'
  121. .TH BUDPAK 1 BUDPAK
  122. .UC 4
  123. .SH NAME
  124. buds, wbuds, mbuds, monitor, rbuds, cbuds \- The Buddy System
  125. .SH SYNOPSIS
  126. .B buds
  127. [
  128. .I options
  129. ]
  130. .PP
  131. .B wbuds
  132. .PP
  133. .B mbuds
  134. [ user1 user2 user3 ... ]
  135. .PP
  136. .B monitor
  137. [
  138. .I options
  139. ] [ user1 user2 user3 ... ]
  140. .PP
  141. .B rbuds
  142. .PP
  143. .B cbuds
  144. .SH DESCRIPTION
  145. .I BudPak
  146. is a collection of silly utilities to monitor the activities of other users on
  147. the system.  It consists of six programs of varying uselessness:
  148. .PP
  149. .TP
  150. .I buds
  151. This is the program that started it all.  It was suggested by Mark Axelrod
  152. (deckard@ucscb.ucsc.edu), who was displeased with the
  153. .I whom
  154. utility's inability to handle large alternate usernames (our
  155. .I whom
  156. reads in a file called
  157. .B .whom
  158. in the user's home directory, so that short real names can be substituted for
  159. account names).
  160. .I buds
  161. and its friends allow tremendous (well, 37 characters) aliases.  The
  162. .I buds
  163. program itself simply lists the people who are online and in a file called
  164. .B .buddy
  165. in the your home directory.
  166. .TP
  167. .I wbuds
  168. This command looks at your buddies and tells you what they're up to.
  169. .TP
  170. .I mbuds
  171. .I mbuds
  172. checks /usr/spool/mail and tells you which buddies have mail, and how much
  173. of it they have.
  174. .TP
  175. .I monitor
  176. This is perhaps the most interesting program of the bunch, which isn't saying
  177. a whole lot.  It constantly monitors /etc/utmp and tells you when buddies log
  178. on or off.
  179. .TP
  180. .I rbuds
  181. .I rbuds
  182. is a handy utility that allows several aliases to be kept for each buddy.
  183. It randomly selects aliases from a file called
  184. .B .rbuds
  185. in your home directory.
  186. .TP
  187. .I cbuds
  188. This is a silly hack that was necessary when we wrote
  189. .I rbuds\fR.
  190. It converts a
  191. .B .buddy
  192. file to a
  193. .B .rbuds
  194. file, so that you don't have to retype the whole thing.  If you use
  195. .B .rbuds
  196. from the start, you'll never need to use
  197. .I cbuds.
  198. .PP
  199. .PP
  200. The \fB.buddy\fR file in your home directory contains a list of account
  201. names and a \fIbuddy alias\fR for each name.  A buddy alias can be up
  202. to 37 characters, and is typically a user's real name, or a nickname or
  203. some other information.  The format of the \fB.buddy\fR file is simply
  204. <account> <space> <alias> <newline> for each buddy.  For instance:
  205. .PP
  206. .PP
  207.   root Mister SuperUser
  208.   zooker Donuts!  Feed me donuts!
  209.   harris David Harris, accountant at large
  210. .PP
  211. .PP
  212. Other utilities can affect your \fB.buddy\fR file; see rbuds(1) for
  213. the most useful one.
  214. .SH "SEE ALSO"
  215. buds(1), wbuds(1), mbuds(1), monitor(1), rbuds(1), cbuds(1)
  216. .SH AUTHORS
  217. Jon Luini, niteowl@ssyx.ucsc.edu (\fIbuds\fR and the original \fImonitor\fR)
  218. .PP
  219. Steven Grimm, koreth@ssyx.ucsc.edu (everything else)
  220. .SH BUGS
  221. .I BudPak
  222. is far too simple to have any bugs.
  223.  
  224. \Rogue\Monster\
  225. else
  226.   echo "will not over write ./budpak.1"
  227. fi
  228. if `test ! -s ./buds.1`
  229. then
  230. echo "writing ./buds.1"
  231. cat > ./buds.1 << '\Rogue\Monster\'
  232. .TH BUDS 1 BUDPAK
  233. .UC 4
  234. .SH NAME
  235. buds \- list of other users
  236. .SH SYNOPSIS
  237. .B buds
  238. [
  239. .I options
  240. ]
  241. .SH DESCRIPTION
  242. .I buds
  243. tells you who's online at the moment, and prints some statistics about
  244. them.  Foremost is the \fIbuddy alias\fR, which is a long (up to 37 characters)
  245. string containing a user's real name, nickname, or other information.
  246. See budpak(1) for more information.  A typical line of \fIbuds\fR output
  247. is:
  248. .PP
  249. .PP
  250. Mister SuperUser      wb 13 hs p3 (root)  0:47 [ucbvax]
  251. .PP
  252. .PP
  253. "Mister SuperUser" is the buddy alias for "root" (whose real username is
  254. in the third to last column of the listing).  "w" and "b" indicates that
  255. he's writable (see mesg(1)) and biffable (see biff(1)).  He has been idle
  256. for 13 minutes.  "h" is the "horny" flag -- it indicates that root wants it,
  257. and wants it bad.  "s" means that he's single ("h" without "s" can mean
  258. trouble, so watch it!)  "p3" is the name of the tty that root is on; in this
  259. example, it's rlogin port 3.  0:47 is the amount of time he's been
  260. logged on.  The last field only appears when the user is logged in from a
  261. remote host, and contains the name of the remote host (ucbvax, in this
  262. example.)
  263. .SH OPTIONS
  264. .TP
  265. .I \-w
  266. Only lists writable users.
  267. .TP
  268. .I \-b
  269. Only lists biffable users.
  270. .TP
  271. .I \-i
  272. Only lists users who have been idle for one minute or more.
  273. .TP
  274. .I \-h
  275. Only lists horny users.
  276. .TP
  277. .I \-s
  278. Only lists single users.
  279. .TP
  280. .I \-d
  281. Doesn't substitute buddy aliases for usernames.  This flag is actually pretty
  282. useless, since real usernames are printed anyway.
  283. .TP
  284. .I \-a
  285. List all users who are online, whether they're in \fB.buddy\fR or not.
  286. .TP
  287. .I \-S
  288. Doesn't print the load average at the end of the buddy listing.  The load average
  289. is only printed on systems which support the rwho(1C) service.
  290. .SH AUTHOR
  291. Jon Luini, niteowl@ssyx.ucsc.edu
  292. .SH FILES
  293. .TP
  294. /etc/utmp
  295. .TP
  296. $HOME/.buddy \-
  297. Buddy alias file.
  298. .SH "SEE ALSO"
  299. monitor(1), rbuds(1), budpak(1)
  300.  
  301. \Rogue\Monster\
  302. else
  303.   echo "will not over write ./buds.1"
  304. fi
  305. if `test ! -s ./buds.c`
  306. then
  307. echo "writing ./buds.c"
  308. cat > ./buds.c << '\Rogue\Monster\'
  309. /**
  310. *** buds.c --> the ORIGINAL (completely rewritten) budpak utility
  311. ***   this (and all) versions 
  312. ***   by Jon Luini, niteowl@ssyx.ucsc.edu
  313. ***
  314. ***   A couple of modifications by Steven Grimm, koreth@ssyx.ucsc.edu
  315. ***
  316. *** 1:32:11 A.M.  Saturday, November 14th 1987
  317. **/
  318.  
  319. #include <stdio.h>
  320. #include <utmp.h>
  321. #include <sys/types.h>
  322. #include <sys/stat.h>
  323. #include <sys/time.h>
  324.  
  325. /*
  326. ** Comment out the following #define statement if your machine isn't listed
  327. ** in its own /etc/rwhod section.  The /etc/rwhod section is used for a fast
  328. ** load average estimate.
  329. */
  330. #define RWHOD
  331.  
  332. /*
  333. ** The following define is a prefix that will be removed from the remote
  334. ** hostnames of people who are rlogged-in.  For instance, at UCSC we have
  335. ** machines called "ucsca", "ucscb", "ucscc", and so on.  Our prefix is
  336. ** "ucsc", so that the aforementioned machine names will show up as "a",
  337. ** "b", and "c", respectively, in the remote host part of the buddy listing.
  338. ** If you don't want a prefix, set it to something silly like "zzzzzzzzz"
  339. ** that will never occur.
  340. */
  341. #define PREFIX      "ucsc"
  342.  
  343. #define TRUE             1
  344. #define FALSE            0
  345. #define UTMP   "/etc/utmp"    /* the location of utmp                       */
  346. #define MAX_USERS       80    /* Maximum number of users possible           */
  347.  
  348. #define IDLE           002    /* is user idle for longer than 60 seconds?   */
  349. #define RITABLE        020    /* Is each user's tty ritable?                */
  350. #define BIFF          0100    /* User have biff set?                        */
  351. #define SINGLE        0010    /* User have single set?                      */
  352. #define HORNY         0001    /* User have HoRnY set?                       */
  353. #define C_IDLE     0000001    /* list only if user is idle                  */
  354. #define C_RITEABLE 0000010    /* list only if writeable                     */
  355. #define C_BIFF     0000100    /* list only if biffable                      */
  356. #define C_SINGLE   0001000    /* list only if user is single                */
  357. #define C_HORNY    0010000    /* list only if HoRnY                         */
  358. #define DONT_SUB   0100000    /* Don't substitute the login with the alias  */
  359. #define LIST_ALL  01000000    /* List all users, not just buddies           */
  360.  
  361. struct BUD {
  362.     char login[8];        /* login name           */
  363.     char alias[50];        /* alias of login       */
  364.     char line[8];        /* tty name             */
  365.     char host[16];        /* host name, if remote */
  366.     long time;        /* time on              */
  367.     int  idle;        /* time idle            */
  368.     int  buddy;        /* is the user a buddy? */
  369.     unsigned long perm;    /* perm of the buds tty */
  370. } buddy[MAX_USERS];
  371.  
  372. char *month[] = {
  373.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  374.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 
  375. };
  376.  
  377. char *space(),            /* function for printing spaces            */
  378.      *lentime(),        /* funtion to print time buddy has been on */
  379.      hostname[10];        /* the hostname of this machine            */
  380. unsigned long mode;        /* the mode of the command line params     */
  381. int num_usrs = 0,        /* total number of users online            */
  382.     num_buds = 0,        /* total number of buddies online          */
  383.     compare(),            /* algorithm used for qsort                */
  384.     shortf;            /* flag to tell buds to be in short mode   */
  385.  
  386. main(argc, argv)
  387. int argc;
  388. char **argv;
  389. {
  390.     int bflag = FALSE;
  391.  
  392.     while (*argv) {
  393.         if (**argv == '-') {
  394.             ++*argv;
  395.             while (**argv) {
  396.                 switch (**argv) {
  397.                     case 'w': mode |= C_RITEABLE; break;
  398.                     case 'b': mode |= C_BIFF; break;
  399.                     case 'i': mode |= C_IDLE; break;
  400.                     case 'h': mode |= C_HORNY; break;
  401.                     case 's': mode |= C_SINGLE; break;
  402.                     case 'd': mode |= DONT_SUB; break;
  403.                     case 'a': mode |= LIST_ALL; break;
  404.                     case 'S': shortf = TRUE; break;
  405.                     default : printf("'%c': bad flag\n",
  406.                             **argv); bflag = TRUE;
  407.                 }
  408.                 ++*argv;
  409.             }
  410.         }
  411.         ++argv;
  412.     }
  413.  
  414.     if (bflag) {    /** print usage screen **/
  415.         puts("Usage: buds [-wbihsdaS]");
  416.         puts("\tw \tlist only writeable users");
  417.         puts("\tb \tlist only biffable users");
  418.         puts("\ti \tlist only idle users");
  419.         puts("\th \tlist only horny users");
  420.         puts("\ts \tlist only single users");
  421.         puts("\td \tdon't substitute buddy aliases");
  422.         puts("\ta \tlist all users on");
  423. #ifdef RWHOD
  424.         puts("\tS \trun buds in Short mode.. dont print the load (faster)");
  425. #endif
  426.         exit(-1);
  427.     }
  428.  
  429.     init();
  430.     get_usrs();
  431.     if (!(mode & DONT_SUB)) get_buds();
  432.     qsort((char *) &buddy[0], num_usrs, sizeof(struct BUD), compare);
  433.     print_out();
  434. }
  435.  
  436. compare(name1, name2)        /** the compare function for qsort **/
  437. struct BUD *name1, *name2; {
  438.     return(strncmp(name1->alias, name2->alias, 40));
  439. }
  440.  
  441. init() {      /** zero the buddy struct array **/
  442.     register int i;
  443.  
  444.     for (i = 0; i < MAX_USERS; i++) 
  445.         bzero(&buddy[i], sizeof(buddy[i]));
  446. }
  447.  
  448. get_usrs() { /** get the user online in putthem in buddy struct array **/
  449.     struct utmp butane;
  450.     int fd, i = 0;
  451.  
  452.     if ((fd = open(UTMP, 0)) == -1) {
  453.         perror("reading users");
  454.         exit(-1);
  455.     }
  456.  
  457.     while (read(fd, &butane, sizeof(struct utmp))) {
  458.         if (butane.ut_name[0]) {
  459.             strncpy(buddy[i].login, butane.ut_name, 8);
  460.             strncpy(buddy[i].alias, butane.ut_name, 8);
  461.             strncpy(buddy[i].line, butane.ut_line, 8);
  462.             strcpy(buddy[i].host, butane.ut_host);
  463.             buddy[i].time = butane.ut_time;
  464.             status(&buddy[i]);
  465.             i++;
  466.         }
  467.     }
  468.     num_usrs = i;
  469.     close(fd);
  470. }
  471.  
  472. status(buddy)       /** get the ttystatus of each buddy **/
  473. struct BUD *buddy;
  474. {
  475.     struct stat sbuf;
  476.     char tty[14];
  477.     long now;
  478.  
  479.     sprintf(tty, "/dev/%s", buddy->line);
  480.     if (stat(tty, &sbuf) == -1) {
  481.         perror("getting tty status");
  482.         buddy->perm = 0;
  483.         return(-1);
  484.     }
  485.     time(&now);
  486.     buddy->perm = 0;
  487.     if ((now - sbuf.st_atime) >= 60) {
  488.         buddy->perm |= IDLE;
  489.         buddy->idle = now - sbuf.st_atime;
  490.     }
  491.     if (sbuf.st_mode & RITABLE) buddy->perm |= RITABLE;
  492.     if (sbuf.st_mode & BIFF) buddy->perm |= BIFF;
  493.     if (sbuf.st_mode & HORNY) buddy->perm |= HORNY;
  494.     if (sbuf.st_mode & SINGLE) buddy->perm |= SINGLE;
  495. }
  496.  
  497. int get_buds() {  /** check the ~/.buddy for valid buddies **/
  498.     FILE *fp;
  499.     char budpath[100], login[8], alias[40];
  500.     register int i;
  501.  
  502.     sprintf(budpath, "%s/.buddy", getenv("HOME"));
  503.     if ((fp = fopen(budpath, "r")) == NULL) {
  504.         perror("getting buddies");
  505.         return(-1);
  506.     }
  507.     while (!feof(fp)) {
  508.         fscanf(fp, "%s %[^\n]\n", login, alias);
  509.         for (i = 0; i < num_usrs; i++) 
  510.             if (!strcmp(buddy[i].login, login)) {
  511.                 strncpy(buddy[i].alias, alias, 40);
  512.                 buddy[i].buddy = TRUE;
  513.             }
  514.     }
  515.     return(1);
  516. }
  517.  
  518. print_out() {  /** print the final output to the screen **/
  519.     struct tm *t;
  520.     char idle[2], buf[14], host[20];
  521.     register int i;
  522.     long now;
  523.     int valid[MAX_USERS], lav[2];
  524.  
  525.     num_buds = 0;
  526.     gethostname(buf, 14);
  527.     strncpy(hostname, buf, 5);
  528.     hostname[5] = '\0';
  529.  
  530.     /** check to see whether buddy should be printed **/
  531.     for (i = 0; i < num_usrs; i++) { 
  532.         valid[i] = TRUE;
  533.         if (mode & LIST_ALL)
  534.             valid[i] = TRUE; else 
  535.             if (!buddy[i].buddy && (!(mode & DONT_SUB))) 
  536.                 valid[i] = FALSE; 
  537.             else valid[i] = TRUE;
  538.         if (mode & C_RITEABLE) 
  539.             if (!(buddy[i].perm & RITABLE)) valid[i] = FALSE;
  540.         if (mode & C_BIFF) 
  541.             if (!(buddy[i].perm & BIFF)) valid[i] = FALSE;
  542.         if (mode & C_IDLE) 
  543.             if (!(buddy[i].perm & IDLE)) valid[i] = FALSE;
  544.         if (mode & C_HORNY)
  545.             if (!(buddy[i].perm & HORNY)) valid[i] = FALSE;
  546.         if (mode & C_SINGLE)
  547.             if (!(buddy[i].perm & SINGLE)) valid[i] = FALSE;
  548.         if (valid[i] && buddy[i].buddy) num_buds++;
  549.     }
  550.  
  551.     time(&now);
  552.     t = localtime(&now);
  553.  
  554.     if (!shortf)
  555.         printf("%d buddies out of %d users on %s : %s %d at %d:%02d%s\n",
  556.             num_buds, num_usrs, hostname, month[t->tm_mon], t->tm_mday,
  557.             t->tm_hour > 12 ? t->tm_hour-12 : t->tm_hour == 0 ? 12 : t->tm_hour,
  558.             t->tm_min, t->tm_hour > 11 ? "pm" : "am");
  559.  
  560.     puts("===================================================================");
  561.     for (i = 0; i < num_usrs; i++) {
  562.         if (buddy[i].line[strlen(buddy[i].line)-2] == 'p')
  563.             sprintf(host, "[%s]", !strncmp(buddy[i].host, PREFIX, sizeof(PREFIX)-1) ?
  564.         buddy[i].host+sizeof(PREFIX)-1 : buddy[i].host);
  565.         else strcpy(host, "");
  566.  
  567.         if (valid[i]) {
  568.             if (buddy[i].idle >= 60) sprintf(idle, "%02d", buddy[i].idle / 60);
  569.             else strcpy(idle, "--");
  570.             printf("%-40.40s %c%c %s %c%c %2.2s (%s)%s%s %s\n", 
  571.                 buddy[i].alias, 
  572.                 buddy[i].perm & RITABLE ? 'w' : '-',
  573.                 buddy[i].perm & BIFF    ? 'b' : '-',
  574.                 idle,
  575.                 buddy[i].perm & HORNY   ? 'h' : '-',
  576.                 buddy[i].perm & SINGLE  ? 's' : '-',
  577.                 strcmp(buddy[i].line, "console") ? &buddy[i].line[3] : "co",
  578.                 buddy[i].login, space(7-strlen(buddy[i].login)),
  579.                 lentime(now - buddy[i].time),
  580.                 host);
  581.         }
  582.     }
  583. #ifdef RWHOD
  584.     if (!shortf) {
  585.         load(lav);
  586.         printf("================== Load: %2.2f %2.2f %2.2f ===========================\n",
  587.             lav[0]/100.0, lav[1]/100.0, lav[2]/100.0);
  588.     } else
  589. #endif    /* RWHOD */
  590.         puts("===================================================================");
  591. }
  592.  
  593. char *space(len)  /** returns a blank string of length 'len' **/
  594. int len;
  595. {
  596.     register int i;
  597.     static char tmp[100];
  598.  
  599.     strcpy(tmp, "");
  600.     for (i = 0; i < len; i++) strcat(tmp, " ");
  601.     return(tmp);
  602. }
  603.  
  604. char *lentime (time)  /** returns the time on in readable format **/
  605. long  time;
  606. {
  607.      static char    buffer[32],        /* A buffer for formatted time         */
  608.             *s;            /* A pointer to the formatted time   */
  609.      int        minutes,        /* Number of minutes past the hour   */
  610.             hours;            /* The number of hours past midnight */
  611.  
  612.      hours = time / 3600;
  613.      minutes =  (time % 3600) / 60;
  614.      s = &buffer[31];
  615.      *s-- = '\0';
  616.      *s-- = minutes % 10 + '0';
  617.      *s-- = minutes / 10 + '0';
  618.      if (hours > 23)
  619.      {
  620.         hours %= 24;
  621.         *s-- = '?';
  622.      } 
  623.      else
  624.         *s-- = ':';
  625.      *s-- = hours % 10 + '0';
  626.      *s =  (hours >= 10) ? hours / 10 + '0' : ' ';
  627.      return(s);
  628. }
  629.  
  630. #ifdef RWHOD
  631. #include <protocols/rwhod.h>
  632.  
  633. load(load_buf)
  634. int *load_buf;
  635. {
  636.     struct whod wbuf;
  637.     char whod_path[80];
  638.     int fd;
  639.  
  640.     sprintf(whod_path, "/usr/spool/rwho/whod\.%s", hostname);
  641.     if ((fd = open(whod_path, 0)) == -1) {
  642.         perror("getting load");
  643.         load_buf[0] = 0;
  644.         load_buf[1] = 0;
  645.         load_buf[2] = 0;
  646.         return(-1);
  647.     }
  648.     read(fd, (char *) &wbuf, sizeof(struct whod));
  649.     load_buf[0] = wbuf.wd_loadav[0];
  650.     load_buf[1] = wbuf.wd_loadav[1];
  651.     load_buf[2] = wbuf.wd_loadav[2];
  652.     close(fd);
  653. }
  654.  
  655. #endif    /* RWHOD */
  656. \Rogue\Monster\
  657. else
  658.   echo "will not over write ./buds.c"
  659. fi
  660. if `test ! -s ./cbuds.1`
  661. then
  662. echo "writing ./cbuds.1"
  663. cat > ./cbuds.1 << '\Rogue\Monster\'
  664. .TH CBUDS 1 BUDPAK
  665. .UC 4
  666. .SH NAME
  667. cbuds \- Convert a .buddy file to a .rbuds file.
  668. .SH SYNOPSIS
  669. .B cbuds
  670. .SH DESCRIPTION
  671. .I Cbuds
  672. reads in a
  673. .B .buddy
  674. file (from the user's home directory) and creates a
  675. .B .rbuds
  676. file (also in the user's home directory).  See rbuds(1) for more information
  677. about the format of the .rbuds file.
  678. .SH AUTHOR
  679. Steven Grimm, koreth@ssyx.ucsc.edu
  680. .SH "SEE ALSO"
  681. rbuds(1)
  682. \Rogue\Monster\
  683. else
  684.   echo "will not over write ./cbuds.1"
  685. fi
  686. if `test ! -s ./cbuds.c`
  687. then
  688. echo "writing ./cbuds.c"
  689. cat > ./cbuds.c << '\Rogue\Monster\'
  690. #include <stdio.h>
  691. #include <ctype.h>
  692.  
  693. char *getenv();
  694.  
  695. main()
  696. {
  697.     FILE *bud, *rbud;
  698.     char f1[99], f2[99];
  699.  
  700.     strcpy(f1, getenv("HOME"));
  701.     strcpy(f2, f1);
  702.     strcat(f1, "/.buddy");
  703.     strcat(f2, "/.rbuds");
  704.  
  705.     if ((bud = fopen(f1, "r")) == NULL)
  706.     {
  707.         printf("Couldn't open %s for read.\n", f1);
  708.         exit(-1);
  709.     }
  710.     if (access(f2, 0) == 0)
  711.     {
  712.         char x;
  713.         printf("%s already exists.  Overwrite? ", f2);
  714.         fflush(stdout);
  715.         x = getchar();
  716.         if (toupper(x) != 'Y')
  717.         {
  718.             fclose(bud);
  719.             exit(-1);
  720.         }
  721.     }
  722.     if ((rbud = fopen(f2, "w+")) == NULL)
  723.     {
  724.         printf("Couldn't open %s for write.\n", f2);
  725.         exit(-1);
  726.     }
  727.  
  728.     while (! feof(bud))
  729.     {
  730.         char login[8], budname[99];
  731.         fscanf(bud, "%s %[^\n]\n", login, budname);
  732.         fprintf(rbud, "*%s\n%s\n", login, budname);
  733.     }
  734.     fclose(bud);
  735.     fclose(rbud);
  736. }
  737.  
  738. \Rogue\Monster\
  739. else
  740.   echo "will not over write ./cbuds.c"
  741. fi
  742. if `test ! -s ./mbuds.1`
  743. then
  744. echo "writing ./mbuds.1"
  745. cat > ./mbuds.1 << '\Rogue\Monster\'
  746. .TH MBUDS 1 BUDPAK
  747. .UC 4
  748. .SH NAME
  749. mbuds \- Check buddies for mail
  750. .SH SYNOPSIS
  751. .B mbuds
  752. [
  753. .I user1
  754. .I user2
  755. .I user3
  756. \&... ]
  757. .SH DESCRIPTION
  758. .I Mbuds
  759. scans the file \fB.buddy\fR in the user's home directory (see budpak(1))
  760. and checks the users
  761. listed therein for mail.  If there are some users whose mailboxes (which
  762. are assumed to be located in /usr/spool/mail) aren't empty, their names,
  763. their aliases in the .buddy file, and the length of their mailbox files
  764. are printed.
  765. .PP
  766. If login names are specified,
  767. .I mbuds
  768. scans those users' mailboxes and lists them (using the above format) whether
  769. they have mail or not.
  770. .SH AUTHOR
  771. Steven Grimm, koreth@ssyx.ucsc.edu
  772. .SH "SEE ALSO"
  773. buds(1), wbuds(1), monitor(1), rbuds(1), budpak(1)
  774. \Rogue\Monster\
  775. else
  776.   echo "will not over write ./mbuds.1"
  777. fi
  778. if `test ! -s ./mbuds.c`
  779. then
  780. echo "writing ./mbuds.c"
  781. cat > ./mbuds.c << '\Rogue\Monster\'
  782. #include <stdio.h>
  783. #include <sys/types.h>
  784. #include <sys/stat.h>
  785.  
  786. char *getlogin(), *getenv(), *malloc();
  787.  
  788. /*
  789. ** MBUDS - Check for buddies' mail
  790. **
  791. ** Usage: mbuds [login1 login2 login3...]
  792. **
  793. ** If no logins are specified, mbuds prints everyone in the user's .buddy
  794. ** file who has mail.  Otherwise, only the specified logins are selected
  795. ** from the .buddy file, and are printed whether they have mail or not.
  796. */
  797.  
  798. struct bud {
  799.     char login[8];
  800.     char name[40];
  801.     struct bud *next;
  802. };
  803.  
  804. struct bud *start;
  805.  
  806. /* Read in a .buddy file and make a linked list out of it. */
  807. readbuds()
  808. {
  809.     struct bud *end;
  810.     FILE *fp;
  811.     char budfile[80];
  812.     strcpy(budfile, getenv("HOME"));
  813.     strcat(budfile, "/.buddy");
  814.     if ((fp=fopen(budfile, "r"))==NULL)
  815.     {
  816.         printf("No .buddy file.\n");
  817.         return 0;
  818.     }
  819.     start = end = (struct bud *)NULL;
  820.     while (! feof(fp))
  821.     {
  822.         struct bud *newnode;
  823.         newnode = (struct bud *)malloc(sizeof(struct bud));
  824.         newnode->login[0] = 0;
  825.         newnode->next = (struct bud *)NULL;
  826.         fscanf(fp, "%s %39[^\n]\n", newnode->login, newnode->name);
  827.         if (strlen(newnode->login))
  828.         {
  829.             if (end)
  830.                 end->next = newnode;
  831.             else
  832.                 start = newnode;
  833.             end = newnode;
  834.         }
  835.     }
  836.     return 1;
  837. }
  838.  
  839. /* Scan the linked list for entries that aren't in the command line arguments
  840.    and chop them out. */
  841. scanlist(argc, argv)
  842. int argc;
  843. char **argv;
  844. {
  845.     struct bud *now, *then, *temp;
  846.     if (argc < 2)
  847.         return;
  848.     argv++;
  849.     argc--;
  850.     then = (struct bud *)NULL;
  851.     now = start;
  852.     while (now)
  853.     {
  854.         int i;
  855.         for (i = 0; i < argc; ++i)
  856.             if (! strcmp(argv[i], now->login))
  857.                 break;
  858.         if (i >= argc)        /* Loop finished = name not found */
  859.         {
  860.             if (then)
  861.             {
  862.                 temp = now;
  863.                 then->next = now->next;
  864.                 now = now->next;
  865.                 free(temp);
  866.             }
  867.             else
  868.             {
  869.                 temp = now;
  870.                 start = now->next;
  871.                 now = start;
  872.                 free(temp);
  873.             }
  874.         }
  875.         else
  876.         {
  877.             then = now;
  878.             now = now->next;
  879.             argv[i] = argv[argc];    /* Trim the list so it's */
  880.             argc--;            /* faster to search */
  881.         }
  882.     }
  883. }
  884.  
  885. checkmail(bud)
  886. struct bud *bud;
  887. {
  888.     struct stat buf;
  889.     if (stat(bud->login, &buf) < 0)
  890.         return 0;
  891.     return (int)buf.st_size;
  892. }
  893.  
  894. main(argc, argv)
  895. int argc;
  896. char **argv;
  897. {
  898.     struct bud *now;
  899.     int maillen;
  900.     chdir("/usr/spool/mail");
  901.     if (! readbuds())
  902.         exit(-1);
  903.     scanlist(argc, argv);
  904.     now = start;
  905.     while (now)
  906.     {
  907.         maillen = checkmail(now);
  908.         if (argc > 1 || maillen)
  909.         {
  910.             printf("%7s %-40s %6d bytes\n", now->login,
  911.                 now->name, maillen);
  912.         }
  913.         now = now->next;
  914.     }
  915. }
  916.  
  917. \Rogue\Monster\
  918. else
  919.   echo "will not over write ./mbuds.c"
  920. fi
  921. if `test ! -s ./monitor.1`
  922. then
  923. echo "writing ./monitor.1"
  924. cat > ./monitor.1 << '\Rogue\Monster\'
  925. .TH MONITOR 1 BUDPAK
  926. .UC 4
  927. .SH NAME
  928. monitor \- Notify about logins and logouts
  929. .SH SYNOPSIS
  930. .B monitor
  931. [
  932. .I options
  933. ] [ user1 user2 user3 ... ]
  934. .SH DESCRIPTION
  935. .I Monitor
  936. is a utility that notifies the user when certain other people log on and off.
  937. Pass the usernames of the people to monitor on the command line.  When one of
  938. the monitored people logs on, a short message is printed containing his
  939. username and alias in the user's
  940. .B .buddy
  941. file (see budpak(1)), if he has an alias there.  If the \-o option
  942. (see below) is used, a short message is also printed when one of the
  943. monitored users logs off.  The messages can be changed using the \-m option.
  944. .SH OPTIONS
  945. .TP
  946. .I \-o
  947. Users specified after the \-o option are monitored for both logins and
  948. logouts.  Only logins are monitored for users specified before the \-o
  949. option.
  950. .TP
  951. .I \-c
  952. The \-c option prevents the program from printing its messages when "cbreak"
  953. mode is on.  Cbreak is active in programs such as vi, which can easily be
  954. messed up by messages appearing at random on the screen.  The messages are
  955. printed as soon as cbreak mode is deactivated (e.g., when you leave vi).
  956. .TP
  957. .I \-n
  958. The \-n option prevents \fImonitor\fR from printing users' real account
  959. names if there are aliases in the \fB.buddy\fR file.
  960. .TP
  961. .I \-N
  962. The \-N option prevents \fImonitor\fR from printing aliases from a \fB.buddy\fR
  963. file.
  964. .TP
  965. .I \-q
  966. The \-q (quiet) option suppresses \fImonitor\fR's startup message.
  967. .TP
  968. .I \-b
  969. The \-b flag stops \fImonitor\fR from beeping when it prints messages.
  970. .TP
  971. .I \-t
  972. The \-t flag causes \fImonitor\fR to print the name of the tty a monitoree
  973. is on, as well as his name.
  974. .TP
  975. .I \-d
  976. The \-d option causes \fImonitor\fR to terminate when any of the specified
  977. users logs on.  This is useful if you're waiting for someone, and don't
  978. want to have to search for \fImonitor\fR's PID to kill it.
  979. .TP
  980. .I \-m
  981. The \-m option takes login names from a file called
  982. .B .monitor
  983. in the user's home directory, rather than from the command line.  The format of
  984. the
  985. .B .monitor
  986. file is as follows:  The first line is a message that's printed out when one
  987. of the users logs on (with a "%s" where the login name and/or buddy alias is
  988. to be placed).  The second line is the logout message (again, with a "%s"
  989. where the username should go).  The following lines are the login names that
  990. the user wants to watch for logins only (i.e., logouts aren't printed).  Then,
  991. optionally, a line containing only a pound sign ("#") character can be followed
  992. by the login names of users to monitor for both logins and logouts.  Note that
  993. it's possible to have the login/logout messages, then a pound sign and a list
  994. of users; that will monitor both logins and logouts of everyone listed in the
  995. .B .monitor
  996. file.  A
  997. .B .monitor
  998. file might look like:
  999.  
  1000.     Wow!  %s is here!
  1001.     Drat.  There goes %s.
  1002.     jones
  1003.     martin
  1004.     #
  1005.     root
  1006.     zooker
  1007.     harris
  1008.  
  1009. .SH AUTHOR
  1010. Steven Grimm, koreth@ssyx.ucsc.edu
  1011. .SH FILES
  1012. .TP
  1013. /etc/utmp
  1014. .TP
  1015. $HOME/.monitor \-
  1016. The file of login names to monitor, and the alert strings for logins and
  1017. logouts.
  1018. .TP
  1019. $HOME/.buddy \-
  1020. Buddy alias file.
  1021. .SH "SEE ALSO"
  1022. buds(1), rbuds(1), budpak(1)
  1023. .SH BUGS
  1024. .I Monitor
  1025. doesn't allow different login and logout messages for individual buddies.
  1026.  
  1027.  
  1028.  
  1029. \Rogue\Monster\
  1030. else
  1031.   echo "will not over write ./monitor.1"
  1032. fi
  1033. if `test ! -s ./monitor.c`
  1034. then
  1035. echo "writing ./monitor.c"
  1036. cat > ./monitor.c << '\Rogue\Monster\'
  1037. #include <stdio.h>
  1038. #include <sys/types.h>
  1039. #include <sys/stat.h>
  1040. #include <utmp.h>
  1041. #include <signal.h>
  1042. #include <sgtty.h>
  1043.  
  1044. /*
  1045. ** MONITOR - Watch people log on and off
  1046. **
  1047. ** Original program by    Jon Luini
  1048. **            niteowl@ssyx.ucsc.edu
  1049. ** This version by    Steven Grimm
  1050. **            koreth@ssyx.ucsc.edu
  1051. **
  1052. ** Operation:
  1053. **
  1054. **   Monitor scans the file /etc/utmp and checks each entry to see if its
  1055. ** tty is in the binary tree of ttys belonging to buddies (actually, the
  1056. ** tree is a structure with lots of information about the buddy).  If the
  1057. ** tty is used by a buddy, Monitor compares the login names of the buddy and
  1058. ** the person using the tty.  If they're not equal, the buddy who used to
  1059. ** be on the tty has logged off and a message to that effect may be printed.
  1060. ** The buddy is deleted from the tty tree and added to the second tree,
  1061. ** the buddy tree.  If the tty isn't in the tty tree, the login name of the
  1062. ** buddy is searched for in the second binary tree, which is sorted by login
  1063. ** names.  If the name is found, the buddy is added to the tty tree and a
  1064. ** logon message is printed out.
  1065. **   The /etc/utmp file isn't scanned if it hasn't been modified since the
  1066. ** last time Monitor passed through it.
  1067. */
  1068.  
  1069. #define UTMP    "/etc/utmp"
  1070. #define WAIT    15        /* Seconds between status checks */
  1071.  
  1072. char *ttyname(), *getenv(), *rindex();
  1073.  
  1074. struct buddy {
  1075.     char tty[8];        /* Tty name */
  1076.     char login[8];        /* Login name */
  1077.     char budname[40];    /* .buddy file name, if any */
  1078.     int  logoff;        /* Flag: Monitor logoffs? */
  1079.     struct buddy *lchild,    /* Binary search tree pointers */
  1080.              *rchild,
  1081.              *parent;
  1082. };
  1083.  
  1084. struct buddy *buddy, *tty;
  1085.  
  1086. char    logonmsg[80],        /* Gets printed when someone logs on */
  1087.     logoffmsg[80],        /* Gets printed when someone logs off */
  1088.     whichtty[8],        /* Which tty this was started on */
  1089.     login[8];        /* Name of the user who started this */
  1090.  
  1091. int    check_off = 0,        /* Flag: Check logoffs */
  1092.     die = 0,        /* Flag: Die when someone comes on */
  1093.     quiet = 0,        /* Flag: Start quietly */
  1094.     nobeep = 0,        /* Flag: Don't beep */
  1095.     noreal = 0,        /* Flag: Don't print account names */
  1096.     nofake = 0,        /* Flag: Don't print buddy aliases */
  1097.     dotty = 0,        /* Flag: Print a user's tty */
  1098.     cblock = 0;        /* Flag: Don't interrupt cbreak */
  1099.  
  1100. /* Search for a buddy.  Pass a 0 in "type" to search for a login name, or a
  1101.    1 to search for a tty. */
  1102. struct buddy *bst_search(tree, key, type)
  1103. struct buddy *tree;
  1104. char *key;
  1105. int type;
  1106. {
  1107.     int comp;
  1108.     while (tree)
  1109.     {
  1110.         if (type)
  1111.         {
  1112.             if (! (comp=strcmp(key, tree->tty)))
  1113.                 return tree;
  1114.         }
  1115.         else
  1116.             if (! (comp=strcmp(key, tree->login)))
  1117.                 return tree;
  1118.         if (comp < 0)
  1119.             tree = tree->lchild;
  1120.         else
  1121.             tree = tree->rchild;
  1122.     }
  1123.     return tree;
  1124. }
  1125.  
  1126. /* Add a node to a tree (the node can have children).  Pass the tree type,
  1127.    as in bst_search above. */
  1128. bst_add(tree, node, type)
  1129. struct buddy *tree, *node;
  1130. int type;
  1131. {
  1132.     int comp;
  1133.     if (! node)
  1134.         return 1;
  1135.     while (tree)
  1136.     {
  1137.         if (type)
  1138.         {
  1139.             if (! (comp=strcmp(node->tty, tree->tty)))
  1140.                 return 0;
  1141.         }
  1142.         else
  1143.             if (! (comp=strcmp(node->login, tree->login)))
  1144.                 return 0;
  1145.         if (comp < 0)
  1146.         {
  1147.             if (tree->lchild)
  1148.                 tree = tree->lchild;
  1149.             else
  1150.             {
  1151.                 tree->lchild = node;
  1152.                 node->parent = tree;
  1153.                 break;
  1154.             }
  1155.         }
  1156.         else
  1157.         {
  1158.             if (tree->rchild)
  1159.                 tree = tree->rchild;
  1160.             else
  1161.             {
  1162.                 tree->rchild = node;
  1163.                 node->parent = tree;
  1164.                 break;
  1165.             }
  1166.         }
  1167.     }
  1168.     if (tree)
  1169.         return 1;
  1170.     else
  1171.         return 0;        /* This should never happen */
  1172. }
  1173.  
  1174. /* Delete a node from a tree.  Returns the node that has taken the deleted
  1175.    node's place in the tree. */
  1176. struct buddy *bst_delete(node, type)
  1177. struct buddy *node;
  1178. int type;
  1179. {
  1180.     if (node->parent)
  1181.     {
  1182.         if (node == node->parent->lchild)
  1183.         {
  1184.             node->parent->lchild = node->rchild;
  1185.             if (node->rchild)
  1186.                 node->rchild->parent = node->parent;
  1187.             if (node->lchild)
  1188.                 bst_add(node->parent, node->lchild, type);
  1189.             return node->rchild;
  1190.         }
  1191.         else if (node == node->parent->rchild)
  1192.         {
  1193.             node->parent->rchild = node->lchild;
  1194.             if (node->lchild)
  1195.                 node->lchild->parent = node->parent;
  1196.             if (node->rchild)
  1197.                 bst_add(node->parent, node->rchild, type);
  1198.             return node->lchild;
  1199.         }
  1200.         else
  1201.             fprintf(stderr, "\r\nBinary tree error!\r\n");
  1202.     }
  1203.     else if (node->lchild)
  1204.     {
  1205.         node->lchild->parent = 0;
  1206.         if (node->rchild)
  1207.             bst_add(node->lchild, node->rchild, type);
  1208.         return node->lchild;
  1209.     }
  1210.     else if (node->rchild)
  1211.     {
  1212.         node->rchild->parent = 0;
  1213.         if (node->lchild)
  1214.             bst_add(node->rchild, node->lchild, type);
  1215.         return node->rchild;
  1216.     }
  1217.     else
  1218.         return (struct buddy *)0;
  1219. }
  1220.  
  1221. /* Handle one entry from the utmp file. */
  1222. doutmp(entry)
  1223. struct utmp *entry;
  1224. {
  1225.     struct buddy *bud, *newbud;
  1226.     if (tty)    /* Only check logoffs if there are buddies on */
  1227.     {
  1228.         bud = bst_search(tty, entry->ut_line, 1);
  1229.         if (bud)
  1230.         {
  1231.             if (strcmp(bud->login, entry->ut_name))
  1232.             {
  1233.                 if (bud->logoff)
  1234.                     domsg(logoffmsg, bud);
  1235.                 newbud = bst_delete(bud);
  1236.                 if (bud == tty)
  1237.                     tty = newbud;
  1238.                 free(bud);
  1239.             }
  1240.             return;
  1241.         }
  1242.     }
  1243.     if (buddy)
  1244.     {
  1245.         bud = bst_search(buddy, entry->ut_name, 0);
  1246.         if (bud)
  1247.         {
  1248.             newbud = (struct buddy *) malloc(sizeof(struct buddy));
  1249.             *newbud = *bud;
  1250.             strcpy(newbud->tty, entry->ut_line);
  1251.             newbud->parent =
  1252.             newbud->lchild =
  1253.             newbud->rchild = (struct buddy *) 0;
  1254.             if (tty)
  1255.                 bst_add(tty, newbud, 1);
  1256.             else
  1257.                 tty = newbud;
  1258.             domsg(logonmsg, newbud);
  1259.             if (die)
  1260.                 exit(0);
  1261.         }
  1262.     }
  1263. }
  1264.  
  1265. /* Process the utmp file.  Returns 0 if the user has logged off. */
  1266. process()
  1267. {
  1268.     int    hand, status=1;
  1269.     struct utmp entry;
  1270.     hand = open(UTMP, 0);
  1271.     while (read(hand, &entry, sizeof(entry)) > 0)
  1272.     {
  1273.         if (! strcmp(entry.ut_line, whichtty))
  1274.             if (strcmp(entry.ut_name, login))
  1275.                 status = 0;
  1276.         doutmp(&entry);
  1277.     }
  1278.     close(hand);
  1279.     return status;
  1280. }
  1281.  
  1282. /* Print the logoff message for a buddy. */
  1283. domsg(message, bud)
  1284. char *message;
  1285. struct buddy *bud;
  1286. {
  1287.     char budname[60], text[256];
  1288.     if ((! bud->budname[0]) || nofake)
  1289.         strcpy(budname, bud->login);
  1290.     else if (bud->budname[0] && !noreal)
  1291.         sprintf(budname, "%s (%s)", bud->budname, bud->login);
  1292.     else if (bud->budname[0])
  1293.         sprintf(budname, "%s", bud->budname);
  1294.     if (dotty)
  1295.     {
  1296.         strcat(budname, " on ");
  1297.         strcat(budname, bud->tty);
  1298.     }
  1299.     sprintf(text, message, budname);
  1300.     fprintf(stderr, "\r\n%s\r\n", text);
  1301.     if (! nobeep)
  1302.         putc(7, stderr);
  1303. }
  1304.  
  1305. /* Read in the .buddy file and assign aliases to the buddies in the buddy
  1306.    tree. */
  1307. readbuddy()
  1308. {
  1309.     char fname[256], login[8], budname[40];
  1310.     struct buddy *bud;
  1311.     FILE *fp;
  1312.     strcpy(fname, getenv("HOME"));
  1313.     strcat(fname, "/.buddy");
  1314.     if (!(fp = fopen(fname, "r")))
  1315.         return 1;
  1316.     while (! feof(fp))
  1317.     {
  1318.         fscanf(fp, "%s %[^\n]\n", login, budname);
  1319.         bud = bst_search(buddy, login, 0);
  1320.         if (bud)
  1321.             strcpy(bud->budname, budname);
  1322.     }
  1323.     fclose(fp);
  1324. }
  1325.  
  1326. /* Initialize the login and whichtty variables. */
  1327. initvars()
  1328. {
  1329.     char ttypath[256], *ri;
  1330.     strcpy(login, getenv("USER"));
  1331.     strcpy(ttypath, ttyname(2));
  1332.     ri = rindex(ttypath, '/');
  1333.     if (! ri)
  1334.         ri = ttypath;
  1335.     else
  1336.         ++ri;
  1337.     strcpy(whichtty, ri);
  1338.     buddy = tty = (struct buddy *)0;
  1339. }
  1340.  
  1341. /* Add a user to the buddy tree. */
  1342. adduser(name)
  1343. char *name;
  1344. {
  1345.     struct buddy *newbud;
  1346.     newbud = (struct buddy *) malloc(sizeof(struct buddy));
  1347.     newbud->parent =
  1348.     newbud->lchild =
  1349.     newbud->rchild = (struct buddy *) 0;
  1350.     newbud->tty[0] = newbud->budname[0] = 0;
  1351.     newbud->logoff = check_off;
  1352.     strcpy(newbud->login, name);
  1353.     if (buddy)
  1354.         bst_add(buddy, newbud, 0);
  1355.     else
  1356.         buddy = newbud;
  1357. }
  1358.  
  1359. /* Read in a .monitor file. */
  1360. readmonitor()
  1361. {
  1362.     FILE *fp;
  1363.     char fname[256], user[80];
  1364.     strcpy(fname, getenv("HOME"));
  1365.     strcat(fname, "/.monitor");
  1366.     if (!(fp=fopen(fname, "r")))
  1367.     {
  1368.         printf("Monitor: Error opening %s.\n", fname);
  1369.         return 0;
  1370.     }
  1371.     fscanf(fp, "%[^\n]\n%[^\n]\n", logonmsg, logoffmsg);
  1372.     while (! feof(fp))
  1373.     {
  1374.         fscanf(fp, "%s\n", user);
  1375.         if (strcmp(user, "#"))
  1376.             adduser(user);
  1377.         else
  1378.             check_off = 1;
  1379.     }
  1380.     fclose(fp);
  1381.     return 1;
  1382. }
  1383.  
  1384. /* Check the last modify date of a file. */
  1385. long lastmod(file)
  1386. char *file;
  1387. {
  1388.     struct stat buf;
  1389.     stat(file, &buf);
  1390.     return buf.st_mtime;
  1391. }
  1392.  
  1393. /* Check the tty for cbreak mode. */
  1394. cbreak()
  1395. {
  1396.     struct sgttyb tty;
  1397.     gtty(0, &tty);
  1398.     return tty.sg_flags & CBREAK;
  1399. }
  1400.  
  1401. /* Main program. */
  1402. main(argc, argv)
  1403. int argc;
  1404. char **argv;
  1405. {
  1406.     long lastutmp, lu;
  1407.     initvars();
  1408.     strcpy(logonmsg, "%s has logged on.");
  1409.     strcpy(logoffmsg, "%s has logged off.");
  1410.     while (*++argv)
  1411.     {
  1412.         if (argv[0][0] == '-')
  1413.             switch (argv[0][1])
  1414.             {
  1415.                 case 'o':
  1416.                     check_off = 1;
  1417.                     break;
  1418.                 case 'm':
  1419.                     readmonitor();
  1420.                     break;
  1421.                 case 'c':
  1422.                     cblock = 1;
  1423.                     break;
  1424.                 case 'd':
  1425.                     die = 1;
  1426.                     break;
  1427.                 case 'q':
  1428.                     quiet = 1;
  1429.                     break;
  1430.                 case 'n':
  1431.                     noreal = 1;
  1432.                     break;
  1433.                 case 'N':
  1434.                     nofake = 1;
  1435.                     break;
  1436.                 case 'b':
  1437.                     nobeep = 1;
  1438.                     break;
  1439.                 case 't':
  1440.                     dotty = 1;
  1441.                     break;
  1442.                 default:
  1443.                     printf("%c: unknown flag\n",
  1444.                         argv[0][1]);
  1445.                     break;
  1446.             }
  1447.         else
  1448.             adduser(argv[0]);
  1449.     }
  1450.     if (! quiet)
  1451.         printf("Monitor: running on %s.\n", whichtty);
  1452.     if (fork())        /* Shove myself in the background */
  1453.         exit(0);
  1454.     signal(SIGHUP, SIG_IGN);    /* Ignore some signals so that */
  1455.     signal(SIGINT, SIG_IGN);    /* w won't think we're the user's */
  1456.     signal(SIGQUIT, SIG_IGN);    /* current process. */
  1457.     if (! buddy)
  1458.     {
  1459.         printf("Monitor: No users selected (using default)\n");
  1460.         adduser("root");
  1461.         strcpy(buddy->budname, "God");
  1462.     }
  1463.     readbuddy();
  1464.     lastutmp = 0;
  1465.     while (1)
  1466.     {
  1467.         if ((!cblock)||(!cbreak()))
  1468.         {
  1469.             lu = lastmod(UTMP);
  1470.             if (lu != lastutmp)
  1471.             {
  1472.                 lastutmp = lu;
  1473.                 if (! process())
  1474.                     exit(0);
  1475.             }
  1476.         }
  1477.         sleep(WAIT);
  1478.     }
  1479. }
  1480.  
  1481.  
  1482.  
  1483. \Rogue\Monster\
  1484. else
  1485.   echo "will not over write ./monitor.c"
  1486. fi
  1487. if `test ! -s ./rbuds.1`
  1488. then
  1489. echo "writing ./rbuds.1"
  1490. cat > ./rbuds.1 << '\Rogue\Monster\'
  1491. .TH RBUDS 1 BUDPAK
  1492. .UC 4
  1493. .SH NAME
  1494. rbuds \- Construct a random .buddy file
  1495. .SH SYNOPSIS
  1496. .B rbuds
  1497. [
  1498. .I \-b
  1499. ]
  1500. .SH DESCRIPTION
  1501. .I Rbuds
  1502. allows users to keep lists of aliases for buddies on the system, and select
  1503. random names from those lists to put in a .buddy file.  The input to
  1504. .I rbuds
  1505. is the file
  1506. .B .rbuds
  1507. in the user's home directory, which contains data in the following format:
  1508. .PP
  1509.  *login1
  1510.  Buddy Alias 1 for login 1
  1511.  Buddy Alias 2 for login 1
  1512.  Buddy Alias 3 for login 1
  1513.  *login2
  1514.  Buddy Alias for login 2
  1515.  *login3
  1516.  Buddy Alias 1 for login 3
  1517.  Buddy Alias 2 for login 3
  1518.     .
  1519.     .
  1520.     .
  1521. .PP
  1522. Up to 128 aliases per buddy are allowed.  When
  1523. .I rbuds
  1524. is run, it reads in all the buddy aliases for a login name and selects a
  1525. random one to output to the
  1526. .B .buddy
  1527. file in the user's home directory.
  1528. .SH OPTIONS
  1529. .TP
  1530. .I \-b
  1531. The \-b option causes
  1532. .I rbuds
  1533. to put itself in the background as soon as it begins executing.  This is
  1534. primarily intended for users with large .rbuds files who want to put the
  1535. .I rbuds
  1536. command in their .login files without having to wait longer to log in.
  1537. .SH AUTHOR
  1538. Steven Grimm, koreth@ssyx.ucsc.edu
  1539. .SH FILES
  1540. $HOME/.buddy \- The output
  1541. .br
  1542. $HOME/.rbuds \- The input
  1543. .SH "SEE ALSO"
  1544. buds(1), mbuds(1), wbuds(1), monitor(1), budpak(1), cbuds(1)
  1545. .SH BUGS
  1546. Buddy aliases can't begin with asterisks.
  1547.  
  1548. \Rogue\Monster\
  1549. else
  1550.   echo "will not over write ./rbuds.1"
  1551. fi
  1552. if `test ! -s ./rbuds.c`
  1553. then
  1554. echo "writing ./rbuds.c"
  1555. cat > ./rbuds.c << '\Rogue\Monster\'
  1556. #include <stdio.h>
  1557.  
  1558. /*
  1559. ** RBUDS - make a .buddy file from a .rbuds file.
  1560. **
  1561. ** .rbuds is in the format
  1562. **
  1563. ** *login1
  1564. ** Buddy Alias 0
  1565. ** *login2
  1566. ** Buddy Alias 1
  1567. ** Buddy Alias 2
  1568. ** Buddy Alias 3
  1569. **
  1570. ** Buddy aliases can't begin with asterisks.  Up to 128 choices per login
  1571. ** name are allowed.
  1572. **
  1573. ** If the -b option is used, rbuds puts itself in the background.
  1574. */
  1575.  
  1576. char *getenv();
  1577.  
  1578. char oldlogin[8], curlogin[8];
  1579. char budnames[40][128];
  1580. FILE *rbuds, *buddy;
  1581.  
  1582. /* Read in the names for a person and return an index into budnames[]
  1583.    corresponding to the name that'll be used. */
  1584. getname()
  1585. {
  1586.     int i=0;
  1587.     budnames[i][0] = ' ';
  1588.     while (! feof(rbuds))
  1589.     {
  1590.         fscanf(rbuds, "%[^\n]\n", budnames[i]);
  1591.         if (budnames[i][0] == '*')
  1592.             break;
  1593.         i++;
  1594.     }
  1595.     if (budnames[i][0] == '*')
  1596.         strcpy(curlogin, budnames[i]+1);
  1597.     return (random() % i);
  1598. }
  1599.  
  1600. main(argc, argv)
  1601. char **argv;
  1602. {
  1603.     char fname[128], bname[128];
  1604.     if (argc == 2 && !strcmp(argv[1], "-b"))
  1605.         if (fork())
  1606.             exit(0);
  1607.     srandom(getpid());
  1608.     strcpy(fname, getenv("HOME"));
  1609.     strcpy(bname, fname);
  1610.     strcat(fname, "/.rbuds");
  1611.     strcat(bname, "/.buddy");
  1612.     if (! (rbuds = fopen(fname, "r")))
  1613.     {
  1614.         fprintf(stderr, "rbuds: No .rbuds file!\n");
  1615.         exit(-1);
  1616.     }
  1617.     if (! (buddy = fopen(bname, "w+")))
  1618.     {
  1619.         fprintf(stderr, "rbuds: Couldn't open .buddy!\n");
  1620.         exit(-1);
  1621.     }
  1622.     fscanf(rbuds, "*%s\n", curlogin);
  1623.     while (! feof(rbuds))
  1624.     {
  1625.         strcpy(oldlogin, curlogin);
  1626.         fprintf(buddy, "%s %s\n", oldlogin, budnames[getname()]);
  1627.     }
  1628.     fclose(buddy);
  1629.     fclose(rbuds);
  1630. }
  1631.  
  1632. \Rogue\Monster\
  1633. else
  1634.   echo "will not over write ./rbuds.c"
  1635. fi
  1636. if `test ! -s ./wbuds.1`
  1637. then
  1638. echo "writing ./wbuds.1"
  1639. cat > ./wbuds.1 << '\Rogue\Monster\'
  1640. .TH WBUDS 1 BUDPAK
  1641. .UC 4
  1642. .SH NAME
  1643. wbuds \- See what buddies are doing
  1644. .SH SYNOPSIS
  1645. .B wbuds
  1646. .SH DESCRIPTION
  1647. .I Wbuds
  1648. executes the "w" command, but only selects those users who are in the caller's
  1649. ".buddy" file.  It replaces the statistics reported by "w" with the aliases
  1650. in the .buddy file.
  1651. .SH AUTHOR
  1652. Steven Grimm, koreth@ssyx.ucsc.edu
  1653. .SH FILES
  1654. /usr/ucb/w - the "w" command
  1655. .SH "SEE ALSO"
  1656. w(1), buds(1), budpak(1)
  1657. .SH BUGS
  1658. .I Wbuds
  1659. assumes that the output of /usr/ucb/w is in a specific format.
  1660. .PP
  1661. .I Wbuds
  1662. doesn't support the -s option to /usr/ucb/w, and can't restrict its
  1663. output to certain users.
  1664.  
  1665. \Rogue\Monster\
  1666. else
  1667.   echo "will not over write ./wbuds.1"
  1668. fi
  1669. if `test ! -s ./wbuds.c`
  1670. then
  1671. echo "writing ./wbuds.c"
  1672. cat > ./wbuds.c << '\Rogue\Monster\'
  1673. #include <stdio.h>
  1674.  
  1675. /*
  1676. ** wbuds
  1677. **
  1678. ** Tells you what everyone in your .buddy file is doing.
  1679. */
  1680.  
  1681. #define W "/usr/ucb/w"
  1682.  
  1683. extern char *getenv();
  1684. extern FILE *popen();
  1685.  
  1686. main()
  1687. {
  1688.     FILE *buddy, *w;
  1689.     char budfile[128], budname[16], buddud[128];
  1690.     char buds[128][16], rbuds[128][60];
  1691.     int  numbuds=0, i;
  1692.     strcpy(budfile, getenv("HOME"));
  1693.     strcat(budfile, "/.buddy");
  1694.     if ((buddy = fopen(budfile, "r")) == NULL)
  1695.     {
  1696.         printf("No .buddy file!\n");
  1697.         exit(-1);
  1698.     }
  1699.     while (! feof(buddy))
  1700.     {
  1701.         budname[0] = 0;
  1702.         fscanf(buddy, "%s", budname);
  1703.         if (! budname[0])
  1704.             continue;
  1705.         fscanf(buddy, "%[^\n]", buddud);
  1706.         getc(buddy);
  1707.         buddud[38] = 0;
  1708.         while (buddud[0] == 10)        /* Strip tabs. */
  1709.             strcpy(buddud, buddud+1);
  1710.         strcpy(rbuds[numbuds], buddud);
  1711.         strcpy(buds[numbuds++], budname);
  1712.     }
  1713.     fclose(buddy);
  1714.     if ((w = popen(W, "r")) == NULL)
  1715.     {
  1716.         printf("%s isn't working.\n", W);
  1717.         exit(-1);
  1718.     }
  1719.     fscanf(w, "%[^\n]", buddud);    /* Get the load, etc. */
  1720.     getc(w);
  1721.     printf("%s\n", buddud);
  1722.     printf("%-8s%-39s%s\n", "Login", "Name", "What");
  1723.     fscanf(w, "%[^\n]", buddud);    /* Get the column headers. */
  1724.     getc(w);
  1725.     while (! feof(w))
  1726.     {
  1727.         buddud[0]=0;
  1728.         fscanf(w, "%[^\n]", buddud);
  1729.         buddud[8]=0;
  1730.         while (buddud[strlen(buddud)-1] == ' ')
  1731.             buddud[strlen(buddud)-1]=0;
  1732.         getc(w);
  1733.         for (i=0; i<numbuds; ++i)
  1734.             if (! strcmp(buddud, buds[i]))
  1735.                 printf("%-7s%-40s%s\n", buddud, rbuds[i], &buddud[47]);
  1736.     }
  1737.     pclose(w);
  1738. }
  1739. \Rogue\Monster\
  1740. else
  1741.   echo "will not over write ./wbuds.c"
  1742. fi
  1743. echo "Finished archive 1 of 1"
  1744. # if you want to concatenate archives, remove anything after this line
  1745. exit
  1746.  
  1747.  
  1748.