home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / 3b1 / volume02 / pcmgr / part02 < prev    next >
Encoding:
Internet Message Format  |  1992-07-14  |  53.5 KB

  1. Path: comp-sources-3b1
  2. From: dave@galaxia.network23.com (David H. Brierley)
  3. Subject:  v02i018:  pcmgr: replacement status and window manager, Part02/03
  4. Newsgroups: comp.sources.3b1
  5. Approved: dave@galaxia.network23.com
  6. X-Checksum-Snefru: 0bb57f7f 37f4e3f1 f8e05b61 f6735f05
  7.  
  8. Submitted-by: dave@galaxia.network23.com (David H. Brierley)
  9. Posting-number: Volume 2, Issue 18
  10. Archive-name: pcmgr/part02
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 2 (of 3)."
  19. # Contents:  hotkey.c loadavgd.c subr.c windows.c
  20. # Wrapped by dave@galaxia on Tue Jul 14 21:15:48 1992
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'hotkey.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'hotkey.c'\"
  24. else
  25. echo shar: Extracting \"'hotkey.c'\" \(14255 characters\)
  26. sed "s/^X//" >'hotkey.c' <<'END_OF_FILE'
  27. X/************************************************************************
  28. X *
  29. X * Program:    pcmgr
  30. X * Module:    hotkey
  31. X *
  32. X * This module contains various routines related to processing the special
  33. X * function keys.
  34. X *
  35. X * Copyright 1990 David H. Brierley, All Rights Reserved
  36. X ************************************************************************/
  37. X
  38. X#include <stdio.h>
  39. X#include <sys/types.h>
  40. X#include <sys/font.h>
  41. X#include <sys/window.h>
  42. X#include <time.h>
  43. X#include <signal.h>
  44. X#include <string.h>
  45. X#include <status.h>
  46. X#include <utmp.h>
  47. X#include <pwd.h>
  48. X#include <sys/stat.h>
  49. X#include <nlist.h>
  50. X#include <fcntl.h>
  51. X#include <ctype.h>
  52. X#include <termio.h>
  53. X#include <malloc.h>
  54. X#include <setjmp.h>
  55. X#include <sys/wd.h>
  56. X#include <track.h>
  57. X#include <tam.h>
  58. X#include <menu.h>
  59. X#include <kcodes.h>
  60. X#include <errno.h>
  61. X#include <sys/sysinfo.h>
  62. X#include <sys/var.h>
  63. X#include <sys/syslocal.h>
  64. X#include <sys/file.h>
  65. X#include <sys/text.h>
  66. X#include <sys/tune.h>
  67. X#include <sys/user.h>
  68. X#include <sys/vmmac.h>
  69. X#include <sys/sysmacros.h>
  70. X
  71. X#include "config.h"
  72. X#include "pcmgr.h"
  73. X
  74. Xstatic char    *Sccs_Id = "@(#) hotkey.c: version 2.1 7/14/92 21:12:30";
  75. X
  76. Xstatic int      xloc = 0;
  77. Xstatic int      yloc = 0;
  78. X
  79. X/*
  80. X * Procedure: do_hotkey
  81. X *
  82. X * Create a window and execute a command within it.  The size of the window
  83. X * is defined by the key bindings file which also defines what command is
  84. X * to be run.
  85. X */
  86. Xvoid
  87. Xdo_hotkey (int code)
  88. X{
  89. X    int             wd;
  90. X    char           *argv[BUFSIZ / 2];
  91. X    char           *blank;
  92. X    char           *tname;
  93. X    int             argc;
  94. X    int             signo;
  95. X    int             temp;
  96. X    int             user_uid;
  97. X    int             user_gid;
  98. X    char            cmdbuf[BUFSIZ];
  99. X    char            keyfile[BUFSIZ];
  100. X    struct uwdata   uwdata;
  101. X    struct utdata   utdata;
  102. X    HotKey         *head;
  103. X    HotKey         *ptr;
  104. X    struct passwd  *pw;
  105. X    char           *ttyname (int);
  106. X
  107. X    /*
  108. X     * Figure out who the currently active user is.
  109. X     */
  110. X    if (get_user_id (&user_uid, &user_gid) == -1) {
  111. X    return;
  112. X    }
  113. X    if ((pw = getpwuid (user_uid)) == NULL) {
  114. X    return;
  115. X    }
  116. X
  117. X    /*
  118. X     * Read in the key bindings file and figure out which command to run
  119. X     */
  120. X    (void) sprintf (keyfile, "%s/.hotkey", pw -> pw_dir);
  121. X    head = read_keyfile (keyfile);
  122. X    for (ptr = head; ptr != NULL; ptr = ptr -> h_next) {
  123. X    if (ptr -> h_key == code) {
  124. X        break;
  125. X    }
  126. X    }
  127. X
  128. X    /*
  129. X     * If the key code specified in the argument was not listed in the key
  130. X     * bindings file then there is nothing for us to do.
  131. X     */
  132. X    if (ptr == NULL) {
  133. X    free_list (head);
  134. X    return;
  135. X    }
  136. X
  137. X    /*
  138. X     * Create a new window and size it and label it according to the
  139. X     * information read in from the key bindings file.
  140. X     */
  141. X    wd = open ("/dev/window", 2);
  142. X    if (wd == -1) {
  143. X    free_list (head);
  144. X    return;
  145. X    }
  146. X
  147. X    if (ioctl (wd, WIOCGETD, &uwdata) == -1) {
  148. X    (void) close (wd);
  149. X    free_list (head);
  150. X    return;
  151. X    }
  152. X
  153. X    uwdata.uw_height = ptr -> h_height * uwdata.uw_vs;
  154. X    uwdata.uw_width = ptr -> h_width * uwdata.uw_hs;
  155. X    if (yloc == 0) {
  156. X    yloc = uwdata.uw_vs;
  157. X    }
  158. X    uwdata.uw_x = xloc;
  159. X    uwdata.uw_y = yloc;
  160. X    xloc += (2 * uwdata.uw_hs);
  161. X    yloc += (2 * uwdata.uw_vs);
  162. X    if (xloc > (8 * uwdata.uw_hs)) {
  163. X    xloc = 0;
  164. X    yloc = 0;
  165. X    }
  166. X    if ((ptr -> h_height == 24) && (ptr -> h_width == 80)) {
  167. X    uwdata.uw_uflags = NBORDER;
  168. X    uwdata.uw_x = 0;
  169. X    uwdata.uw_y = uwdata.uw_vs;
  170. X    }
  171. X    else {
  172. X    uwdata.uw_uflags = BORDRESIZE;
  173. X    if (uwdata.uw_x + uwdata.uw_width > WINWIDTH - (3 * uwdata.uw_hs)) {
  174. X        temp = WINWIDTH - (3 * uwdata.uw_hs) - uwdata.uw_width;
  175. X        if (temp < 0) {
  176. X        temp = 0;
  177. X        }
  178. X        uwdata.uw_x = temp;
  179. X        uwdata.uw_width = WINWIDTH - (3 * uwdata.uw_hs) - uwdata.uw_x;
  180. X    }
  181. X    if (uwdata.uw_y + uwdata.uw_height > WINHEIGHT - (4 * uwdata.uw_vs)) {
  182. X        temp = WINHEIGHT - (4 * uwdata.uw_vs) - uwdata.uw_height;
  183. X        if (temp < uwdata.uw_vs) {
  184. X        temp = uwdata.uw_vs;
  185. X        }
  186. X        uwdata.uw_y = temp;
  187. X        uwdata.uw_height = WINHEIGHT - (4 * uwdata.uw_vs) - uwdata.uw_y;
  188. X    }
  189. X    }
  190. X
  191. X    if (ioctl (wd, WIOCSETD, &uwdata) == -1) {
  192. X    (void) close (wd);
  193. X    free_list (head);
  194. X    return;
  195. X    }
  196. X
  197. X    utdata.ut_num = WTXTLABEL;
  198. X    (void) strncpy (utdata.ut_text, ptr -> h_cmd, 40);
  199. X    (void) ioctl (wd, WIOCSETTEXT, &utdata);
  200. X
  201. X    utdata.ut_num = WTXTUSER;
  202. X    (void) strncpy (utdata.ut_text, ptr -> h_name, 40);
  203. X    (void) ioctl (wd, WIOCSETTEXT, &utdata);
  204. X
  205. X    /*
  206. X     * Break up the command line into words so that it can be used as an
  207. X     * argument to exec().
  208. X     */
  209. X    (void) strcpy (cmdbuf, ptr -> h_cmd);
  210. X    argc = 0;
  211. X    blank = cmdbuf;
  212. X
  213. X    while (blank != NULL) {
  214. X    argv[argc++] = blank;
  215. X    blank = strchr (blank, ' ');
  216. X    if (blank != NULL) {
  217. X        while (*blank == ' ') {
  218. X        *blank++ = '\0';
  219. X        }
  220. X    }
  221. X    }
  222. X    argv[argc] = NULL;
  223. X
  224. X    /*
  225. X     * Everything is all set up: time to fork!
  226. X     */
  227. X    if (fork () != 0) {
  228. X    (void) close (wd);
  229. X    free_list (head);
  230. X    return;
  231. X    }
  232. X
  233. X    /*
  234. X     * fork again so that the new process is not a direct child of the pcmgr
  235. X     * process.
  236. X     */
  237. X    if (fork () != 0) {
  238. X    _exit (0);
  239. X    }
  240. X
  241. X    /*
  242. X     * chdir to the users home directory so that they will know what
  243. X     * directory they are in when the program runs.  also set a few
  244. X     * basic env variables.
  245. X     */
  246. X    (void) chdir (pw -> pw_dir);
  247. X    setenv ("HOME", pw -> pw_dir);
  248. X    setenv ("LOGNAME", pw -> pw_name);
  249. X
  250. X    if (wd != 0) {
  251. X    (void) close (0);
  252. X    (void) dup (wd);
  253. X    }
  254. X    (void) close (1);
  255. X    (void) dup (0);
  256. X    (void) close (2);
  257. X    (void) dup (0);
  258. X    for (wd = 3; wd < _NFILE; ++wd) {
  259. X    (void) close (wd);
  260. X    }
  261. X
  262. X    /*
  263. X     * Set the ownership of the window device to the user
  264. X     */
  265. X    if ((tname = ttyname (0)) != NULL) {
  266. X    (void) chmod (tname, 0600);
  267. X    (void) chown (tname, user_uid, user_gid);
  268. X    }
  269. X    (void) setgid (user_gid);
  270. X    (void) setuid (user_uid);
  271. X    (void) setpgrp ();
  272. X    (void) ioctl (0, WIOCPGRP, NULL);
  273. X    for (signo = 1; signo < NSIG; ++signo) {
  274. X    (void) signal (signo, SIG_DFL);
  275. X    }
  276. X
  277. X    /*
  278. X     * First we try calling execvp using the argument array built above. This
  279. X     * allows commands to be specified in the binding file without requiring
  280. X     * that the full path name be specified.  If the execvp fails, try
  281. X     * calling execl to run the command using "sh -c".  If that fails there
  282. X     * is nothing else to try so just exit.
  283. X     */
  284. X    (void) execvp (argv[0], argv);
  285. X    (void) execl ("/bin/sh", "sh", "-c", ptr -> h_cmd, 0);
  286. X    _exit (0);
  287. X
  288. X}
  289. X
  290. X/*
  291. X * Procedure: read_keyfile
  292. X *
  293. X * Read in the specified key bindings file and return a pointer to
  294. X * a linked list containing hte information.
  295. X */
  296. XHotKey         *
  297. Xread_keyfile (char *filename)
  298. X{
  299. X    int             keynum;
  300. X    int             height;
  301. X    int             width;
  302. X    int             n;
  303. X    HotKey         *head;
  304. X    char            line[BUFSIZ];
  305. X    FILE           *fp;
  306. X    char           *cmd;
  307. X    char           *semi;
  308. X
  309. X    head = NULL;
  310. X    if ((fp = fopen (filename, "r")) == NULL) {
  311. X    return (head);
  312. X    }
  313. X
  314. X    while (fgets (line, BUFSIZ - 1, fp) != NULL) {
  315. X    cmd = line + strlen (line) - 1;
  316. X    *cmd = '\0';
  317. X    if ((cmd = strchr (line, ' ')) == NULL) {
  318. X        continue;
  319. X    }
  320. X    *cmd++ = '\0';
  321. X    while (*cmd == ' ') {
  322. X        ++cmd;
  323. X    }
  324. X    if ((semi = strchr (line, ';')) != NULL) {
  325. X        ++semi;
  326. X    }
  327. X    n = sscanf (line, "%d,%d,%d", &keynum, &height, &width);
  328. X    switch (n) {
  329. X    case 3:
  330. X        break;
  331. X    case 1:
  332. X        height = 12;
  333. X        width = 60;
  334. X        break;
  335. X    default:
  336. X        continue;
  337. X    }
  338. X    head = insert (head, keynum, height, width, cmd, semi);
  339. X    }
  340. X    (void) fclose (fp);
  341. X    return (head);
  342. X
  343. X}
  344. X
  345. X/*
  346. X * Procedure: free_list
  347. X *
  348. X * Recurse through the linked list, freeing each entry.
  349. X */
  350. Xvoid
  351. Xfree_list (HotKey * head)
  352. X{
  353. X    HotKey         *ptr;
  354. X    HotKey         *tmp;
  355. X
  356. X    ptr = head;
  357. X    while (ptr != NULL) {
  358. X    tmp = ptr;
  359. X    ptr = ptr -> h_next;
  360. X    (void) free (tmp);
  361. X    }
  362. X
  363. X}
  364. X
  365. X/*
  366. X * Procedure: insert
  367. X *
  368. X * This routine does the actual work of inserting the key bindings into
  369. X * the linked list.
  370. X */
  371. XHotKey         *
  372. Xinsert (HotKey *head, int key, int hgt, int width, char *cmd, char *cmd_name)
  373. X{
  374. X    HotKey         *ptr;
  375. X    HotKey         *old;
  376. X    char           *blank;
  377. X
  378. X    if (strlen (cmd) >= sizeof (ptr -> h_cmd)) {
  379. X    (void) fprintf (stderr,
  380. X            "Command string for key %d is too long, max = %d\n",
  381. X            key, sizeof (ptr -> h_cmd));
  382. X    exit (1);
  383. X    }
  384. X
  385. X    /*
  386. X     * first we look to see if this key exists already and delete it.
  387. X     */
  388. X    old = NULL;
  389. X    for (ptr = head; ptr != NULL; ptr = ptr -> h_next) {
  390. X    if (ptr -> h_key == key) {
  391. X        if (old != NULL) {
  392. X        old -> h_next = ptr -> h_next;
  393. X        }
  394. X        (void) free (ptr);
  395. X        break;
  396. X    }
  397. X    old = ptr;
  398. X    }
  399. X
  400. X    /*
  401. X     * next we find out where this entry belongs
  402. X     */
  403. X    old = NULL;
  404. X    for (ptr = head; ptr != NULL; ptr = ptr -> h_next) {
  405. X    if (ptr -> h_key > key)
  406. X        break;
  407. X    old = ptr;
  408. X    }
  409. X
  410. X    /*
  411. X     * allocate new entry
  412. X     */
  413. X    ptr = (HotKey *) malloc (sizeof (HotKey));
  414. X    if (ptr == NULL) {
  415. X    exit (1);
  416. X    }
  417. X
  418. X    /*
  419. X     * sanity check for window size
  420. X     */
  421. X    if (hgt > 24) {
  422. X    hgt = 24;
  423. X    }
  424. X    if (hgt < 6) {
  425. X    hgt = 6;
  426. X    }
  427. X    if (width > 80) {
  428. X    width = 80;
  429. X    }
  430. X    if (width < 20) {
  431. X    width = 20;
  432. X    }
  433. X
  434. X    /*
  435. X     * fill in the new entry
  436. X     */
  437. X    ptr -> h_key = key;
  438. X    ptr -> h_height = hgt;
  439. X    ptr -> h_width = width;
  440. X    (void) strcpy (ptr -> h_cmd, cmd);
  441. X
  442. X    /*
  443. X     * if no command name was specified use the first word of the command
  444. X     */
  445. X    if (cmd_name != NULL) {
  446. X    (void) strncpy (ptr -> h_name, cmd_name, H_NAME_MAX);
  447. X    }
  448. X    else {
  449. X    if ((blank = strchr (cmd, ' ')) != NULL) {
  450. X        *blank = '\0';
  451. X    }
  452. X    (void) strncpy (ptr -> h_name, cmd, H_NAME_MAX);
  453. X    if (blank != NULL) {
  454. X        *blank = ' ';
  455. X    }
  456. X    }
  457. X    ptr -> h_name[H_NAME_MAX] = '\0';
  458. X
  459. X    /*
  460. X     * set the links
  461. X     */
  462. X    ptr -> h_next = NULL;
  463. X    if (old != NULL) {
  464. X    if (old -> h_next != NULL) {
  465. X        ptr -> h_next = old -> h_next;
  466. X    }
  467. X    old -> h_next = ptr;
  468. X    }
  469. X    if (head == NULL) {
  470. X    head = ptr;
  471. X    }
  472. X    return (head);
  473. X
  474. X}
  475. X
  476. X/*
  477. X * Procedure: function_menu
  478. X *
  479. X * This procedure displays a list of all of the commands that are bound
  480. X * to the function keys and allows the user to select one of them.  Because
  481. X * this routine uses a dynamically sized list it is possible to have more
  482. X * choices in the list than there are actual function keys.  The extra
  483. X * entries are only accesible via this routine, they cannot be selected by
  484. X * pressing any of the special function keys.
  485. X */
  486. Xvoid
  487. Xfunction_menu (void)
  488. X{
  489. X    int             key_choice;
  490. X    int             n;
  491. X    menu_t          f_menu;
  492. X    mitem_t        *f_list;
  493. X    int             f_index;
  494. X    int             rc;
  495. X    char            keyfile[BUFSIZ];
  496. X    HotKey         *head;
  497. X    HotKey         *ptr;
  498. X    int             user_uid;
  499. X    int             user_gid;
  500. X    struct passwd  *pw;
  501. X    extern char    *calloc ();
  502. X
  503. X    /* find out who the active user is */
  504. X    if (get_user_id (&user_uid, &user_gid) == -1) {
  505. X    return;
  506. X    }
  507. X    if ((pw = getpwuid (user_uid)) == NULL) {
  508. X    return;
  509. X    }
  510. X
  511. X    /* fork to avoid possible deadlocks */
  512. X    if (fork () != 0) {
  513. X    return;
  514. X    }
  515. X
  516. X    /* read in the key binding file and create the menu list */
  517. X    (void) sprintf (keyfile, "%s/.hotkey", pw -> pw_dir);
  518. X    head = read_keyfile (keyfile);
  519. X    for (f_index = 0, ptr = head; ptr != NULL; ptr = ptr -> h_next) {
  520. X    ++f_index;
  521. X    }
  522. X    f_index += 4;
  523. X    f_list = (mitem_t *) calloc (f_index, sizeof (mitem_t));
  524. X    if (f_list == NULL) {
  525. X    _exit (1);
  526. X    }
  527. X
  528. X    keypad (0, 1);
  529. X    f_menu.m_label = "Functions";
  530. X    f_menu.m_title = NULL;
  531. X    f_menu.m_prompt = NULL;
  532. X    f_menu.m_rows = 0;
  533. X    f_menu.m_cols = 0;
  534. X    f_menu.m_iwidth = 0;
  535. X    f_menu.m_iheight = 0;
  536. X    f_menu.m_flags = M_USEWIN | M_SINGLE | M_NOMOVE | M_NOHELP | M_NORESIZE;
  537. X    f_menu.m_lbuf[0] = '\0';
  538. X    f_menu.m_items = f_list;
  539. X    f_menu.m_curi = f_list;
  540. X    f_index = 0;
  541. X
  542. X    for (ptr = head; ptr != NULL; ptr = ptr -> h_next) {
  543. X    f_list[f_index].mi_name = NULL;
  544. X    f_list[f_index].mi_flags = 0;
  545. X    f_list[f_index].mi_val = ptr -> h_key;
  546. X    f_list[f_index].mi_name = msave (ptr -> h_name);
  547. X    ++f_index;
  548. X    }
  549. X
  550. X    /* for completeness we add menu items for login, mail, and msgs */
  551. X    f_list[f_index].mi_flags = 0;
  552. X    f_list[f_index].mi_val = -1;
  553. X    f_list[f_index].mi_name = msave ("New Login Window");
  554. X    ++f_index;
  555. X    f_list[f_index].mi_flags = 0;
  556. X    f_list[f_index].mi_val = -2;
  557. X    f_list[f_index].mi_name = msave ("Read Mail");
  558. X    ++f_index;
  559. X    f_list[f_index].mi_flags = 0;
  560. X    f_list[f_index].mi_val = -3;
  561. X    f_list[f_index].mi_name = msave ("Display Messages");
  562. X    ++f_index;
  563. X
  564. X    f_list[f_index].mi_name = NULL;
  565. X    f_list[f_index].mi_flags = 0;
  566. X    f_list[f_index].mi_val = 0;
  567. X
  568. X    /* Create a window and initialize the menu interface */
  569. X    f_menu.m_win = wcreate (1, 49, 20, 30, 0);
  570. X    (void) menu (&f_menu, M_BEGIN);
  571. X
  572. X    /*
  573. X     * Accept input from the menu routines.  Recognize the Exit and Cancl
  574. X     * keys as cancelling the request.  If the return valud from the menu
  575. X     * routine is Enter and the m_selcnt field is set to one then the user
  576. X     * select one of the items and the m_curi pointer in the menu structure
  577. X     * will point to the item selected.
  578. X     */
  579. X    while (1) {
  580. X    rc = menu (&f_menu, M_INPUT);
  581. X    if ((rc == Exit) || (rc == Cancl)) {
  582. X        key_choice = 0;
  583. X        break;
  584. X    }
  585. X    if ((rc == Enter) && (f_menu.m_selcnt == 1)) {
  586. X        key_choice = f_menu.m_curi -> mi_val;
  587. X        break;
  588. X    }
  589. X    }
  590. X
  591. X    /* Terminate menu input and delete the window */
  592. X    menu (&f_menu, M_END);
  593. X    (void) wdelete (f_menu.m_win);
  594. X
  595. X    /*
  596. X     * release the storage used by the menu.  this is not really needed since
  597. X     * this process is about to be deleted anyway but this was here from a
  598. X     * previous version which did not do the fork so I decided to leave it
  599. X     * here for completeness.
  600. X     */
  601. X    free_list (head);
  602. X    for (n = 0; n < f_index; ++n) {
  603. X    if (f_list[n].mi_name != NULL) {
  604. X        (void) free (f_list[n].mi_name);
  605. X    }
  606. X    }
  607. X    (void) free (f_list);
  608. X
  609. X    switch (key_choice) {
  610. X    case -1:            /* login */
  611. X    make_login ();
  612. X    break;
  613. X    case -2:            /* mail */
  614. X    run_email ();
  615. X    break;
  616. X    case -3:            /* messages */
  617. X    show_msgs ();
  618. X    break;
  619. X    case 0:            /* Exit or Cancl */
  620. X    break;
  621. X    default:            /* normal menu item selected */
  622. X    do_hotkey (key_choice);
  623. X    }
  624. X
  625. X    /* since we forked up above we must exit instead of returning */
  626. X    _exit (0);
  627. X
  628. X}
  629. END_OF_FILE
  630. if test 14255 -ne `wc -c <'hotkey.c'`; then
  631.     echo shar: \"'hotkey.c'\" unpacked with wrong size!
  632. fi
  633. # end of 'hotkey.c'
  634. fi
  635. if test -f 'loadavgd.c' -a "${1}" != "-c" ; then 
  636.   echo shar: Will not clobber existing file \"'loadavgd.c'\"
  637. else
  638. echo shar: Extracting \"'loadavgd.c'\" \(10503 characters\)
  639. sed "s/^X//" >'loadavgd.c' <<'END_OF_FILE'
  640. X/*
  641. X * renamed loadavgd.c by Lenny Tropiano (lenny@icus.UUCP ICUS Software Systems)
  642. X *
  643. X *    ldavg.c -- compute load averages for System V
  644. X *    Phil Budne @ Boston U / DSG
  645. X *
  646. X *    Forges BSD 4.2 rwhod packets containing system load averages
  647. X *    (#ifdef RWHOD for this, else a shm segment is used, ftok("/unix", 'a'))
  648. X */
  649. X
  650. X# include <sys/types.h>            /* system types */
  651. X# include <sys/sysinfo.h>        /* sysinfo structure */
  652. X# include <sys/utsname.h>        /* for uname(2) */
  653. X# include <sys/stat.h>            /* for stat(2) */
  654. X# include <sys/param.h>            /* for HZ */
  655. X# include <stdio.h>
  656. X# include <nlist.h>
  657. X# include <time.h>
  658. X# include <math.h>
  659. X# include <utmp.h>
  660. X# include <fcntl.h>
  661. X#ifdef RWHOD
  662. X# include "rwhod.h"            /* (from BSD) */
  663. X#else  SHM
  664. X# include <sys/ipc.h>
  665. X# include <sys/shm.h>
  666. X#endif RWHOD
  667. X#ifdef UNIXPC
  668. X/*
  669. X * Open a window on the status line.  While SMGR owns columns 33-74, it doesn't
  670. X * seem to use columns 56-74, which by some strange chance is just enough for
  671. X * our window.
  672. X * (Whoops!  Can you say "icon"?  We use the spot reserved for the Phone
  673. X * Manager instead... your choice.  Compile with -DUNIXPC to get windows;
  674. X * the generic-System V code will work on the UNIX PC if you don't want them.)
  675. X */
  676. X# include <sys/window.h>
  677. X# include <status.h>
  678. X#endif UNIXPC
  679. X
  680. X/* # define DEBUG /**/
  681. X#ifdef RWHOD
  682. X# define UDP 1
  683. X# define DSK 1
  684. X# define PMUL 100
  685. X
  686. X# if UDP
  687. X# include "netdb.h"
  688. Xunsigned short port = 513;
  689. Xunsigned long ipaddr;
  690. X# endif
  691. X#endif RWHOD
  692. X
  693. Xextern struct utmp *getutent();
  694. X
  695. X# define UNIX "/unix"
  696. X# define KMEM "/dev/kmem"
  697. X
  698. Xstruct nlist nlsym[] = {
  699. X# define NL_SYSINFO 0
  700. X        { "sysinfo" },            /* 0 */
  701. X#ifdef RWHOD
  702. X# define NL_LBOLT 1
  703. X    { "lbolt" },            /* 1 */
  704. X#endif RWHOD
  705. X        { 0 }
  706. X};
  707. X
  708. X#ifdef RWHOD
  709. Xstruct whod proto;
  710. Xstruct utsname utsn;
  711. Xchar whopacket[100];
  712. X#else  SHM
  713. Xkey_t aven_key;
  714. Xint aven_shm;
  715. Xdouble *aven_seg;
  716. X#endif RWHOD
  717. Xint fd, memfd;
  718. X#ifdef UNIXPC
  719. Xstruct uwdata avenwin = {
  720. X    0,    0,    288,    12,    NBORDER,    0,    0,    0
  721. X};
  722. Xextern char *sys_errlist[];
  723. Xextern int errno;
  724. X#endif
  725. X
  726. Xchar *unixsys = UNIX;
  727. Xchar *kmem = KMEM;
  728. Xchar *argv0;
  729. X
  730. Xmain(argc, argv)
  731. Xint  argc;
  732. Xchar *argv[];
  733. X{
  734. X    switch (fork()) {
  735. X    case -1:
  736. X        perror("fork");
  737. X        exit(1);
  738. X    case 0:
  739. X        break;
  740. X    default:
  741. X        exit(0);
  742. X    }
  743. X    argv0 = argv[0];
  744. X#ifdef RWHOD
  745. X    uname(&utsn);            /* get system names */
  746. X#endif RWHOD
  747. X    setpgrp();            /* create own pgrp */
  748. X#ifdef UNIXPC
  749. X    if (freopen("/dev/window", "r+", stdout) == (FILE *) 0) {
  750. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Can't open load average window:\n%s", argv0, sys_errlist[errno]);
  751. X        exit(1);
  752. X    }
  753. X    ioctl(1, WIOCSETD, &avenwin);
  754. X    ioctl(0, WIOCSELECT);
  755. X    fclose(stdin);
  756. X    fclose(stderr);
  757. X#endif UNIXPC
  758. X    init_nlist();            /* get name values, open kmem */
  759. X    init_packet();            /* initialize packet prototype */
  760. X    doit();                /* never returns */
  761. X} /* main */
  762. X
  763. Xinit_nlist() {
  764. X    nlist(unixsys, nlsym);        /* get system values */
  765. X
  766. X        if(nlsym[NL_SYSINFO].n_value == 0) {
  767. X#ifdef UNIXPC
  768. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Cannot locate `sysinfo' structure", argv0);
  769. X#else
  770. X                fprintf(stderr, "%s: can't find sysinf structure\n", argv0);
  771. X#endif
  772. X                exit(1);
  773. X        } /* no value */
  774. X
  775. X    if ((memfd = open(kmem, O_RDONLY)) < 0) {
  776. X#ifdef UNIXPC
  777. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Cannot open kernel memory image:\n%s", argv0, sys_errlist[errno]);
  778. X#else
  779. X        fprintf(stderr, "%s: no mem\n", argv0);
  780. X#endif UNIXPC
  781. X        exit(1);
  782. X    } /* could not open kmem */
  783. X
  784. X} /* init_nlist */
  785. X
  786. X# define PERIOD 5            /* sample period (in seconds) */
  787. X# define INTERVAL1 60            /* average interval 1 (in seconds) */
  788. X# define INTERVAL2 (5*60)        /* average interval 2 (in seconds) */
  789. X# define INTERVAL3 (15*60)        /* average interval 3 (in seconds) */
  790. X# define PACKINTERVAL 30        /* interval for make_packet */
  791. X
  792. Xdoit() {
  793. X    struct sysinfo sinf;
  794. X    int packt = 0;
  795. X    long occ, que, nocc, nque, n, c;
  796. X    double avg1, avg2, avg3, new;
  797. X    double exp1, exp2, exp3;
  798. X
  799. X    exp1 = exp( - ((double) PERIOD) / INTERVAL1 );
  800. X    exp2 = exp( - ((double) PERIOD) / INTERVAL2 );
  801. X    exp3 = exp( - ((double) PERIOD) / INTERVAL3 );
  802. X
  803. X    getsysinf(&sinf);        /* prime the pump */
  804. X    occ = sinf.runocc;        /* number of samples */
  805. X    que = sinf.runque;        /* run queue summation */
  806. X
  807. X    avg1 = avg2 = avg3 = ((double) que) / occ;
  808. X
  809. X    for( ; ; ) {
  810. X        if( --packt < 0 ) {
  811. X#ifdef RWHOD
  812. X            make_packet((int) (avg1 * PMUL),
  813. X                    (int) (avg2 * PMUL),
  814. X                    (int) (avg3 * PMUL));
  815. X#else  SHM
  816. X            make_packet(avg1, avg2, avg3);
  817. X#endif RWHOD
  818. X            packt = PACKINTERVAL / PERIOD;
  819. X        } /* packet time */
  820. X
  821. X/*        printf("runque: %ld  runocc: %ld\n", que, occ ); /**/
  822. X
  823. X        sleep(PERIOD);
  824. X        getsysinf(&sinf);    /* get new info */
  825. X        nocc = sinf.runocc;
  826. X        nque = sinf.runque;
  827. X
  828. X        n = nocc - occ;        /* get number of times updated */
  829. X        if( n <= 0 ) continue;
  830. X        c = nque - que - n;    /* get number of runners w/o us */
  831. X        if( c < 0 ) c = 0;    /* mumble! */
  832. X
  833. X        new = ((double) c ) / n; /* new instantaneous avg */
  834. X
  835. X        /************************************************/
  836. X        /*   The following formula is used to achieve   */
  837. X        /*   exponential decay of old measurements:    */
  838. X        /*    avgN = avgN * expN  +  new * (1 - expN)    */
  839. X        /*                        */
  840. X        /*   However, the factorized forms below    */
  841. X        /*   require fewer floating point operations.    */
  842. X        /************************************************/
  843. X
  844. X        avg1 = ((avg1 - new) * exp1) + new;
  845. X        avg2 = ((avg2 - new) * exp2) + new;
  846. X        avg3 = ((avg3 - new) * exp3) + new;
  847. X
  848. X        occ = nocc;
  849. X        que = nque;
  850. X
  851. X    } /* for ever */
  852. X} /* doit */
  853. X
  854. Xgetsysinf(s)
  855. Xstruct sysinfo *s;
  856. X{
  857. X    l_lseek(memfd, (long)nlsym[NL_SYSINFO].n_value, 0);
  858. X    r_read(memfd, (char *)s, sizeof(struct sysinfo));
  859. X}
  860. X
  861. X/* lseek with error checking */
  862. Xl_lseek(fd, offset, whence)
  863. Xint fd, whence;
  864. Xlong    offset;
  865. X{
  866. X    if (lseek(fd, offset, whence) == -1) {
  867. X#ifdef UNIXPC
  868. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Error during seek in kernel memory image:\n%s", argv0, sys_errlist[errno]);
  869. X#else
  870. X        fprintf(stderr, "%s: error on lseek\n", argv0);
  871. X#endif UNIXPC
  872. X        exit(1);
  873. X    }
  874. X}
  875. X
  876. X/* read with error checking */
  877. Xr_read (fd, buf, nbytes)
  878. Xint    fd, nbytes;
  879. Xchar    *buf;
  880. X{
  881. X    if (read(fd, buf, nbytes) != nbytes) {
  882. X#ifdef UNIXPC
  883. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Error during read from kernel memory image:\n%s", argv0, sys_errlist[errno]);
  884. X#else
  885. X        fprintf(stderr, "%s: error on read\n", argv0);
  886. X#endif UNIXPC
  887. X        exit(1);
  888. X    }
  889. X}
  890. X
  891. Xinit_packet() {
  892. X#ifdef RWHOD
  893. X    time_t boothz;
  894. X# if UDP
  895. X    struct hostent *he;
  896. X
  897. X    he = gethostbyname( "localnet" );
  898. X    if( he == NULL || he->h_addr == 0 ) {
  899. X        fprintf(stderr, "no address: localnet\n");
  900. X        exit( 1 );
  901. X    }
  902. X    ipaddr = he->h_addr;
  903. X# endif
  904. X# if DSK
  905. X    sprintf(whopacket, "/usr/spool/rwho/whod.%s", utsn.nodename);
  906. X# endif
  907. X    memset(&proto, '\0', sizeof proto);    /* clear proto packet */
  908. X
  909. X    strncat(proto.wd_hostname, utsn.nodename, 9); /* at most 9, add null */
  910. X    proto.wd_vers = WHODVERSION;
  911. X    proto.wd_type = WHODTYPE_STATUS;
  912. X
  913. X    l_lseek(memfd, (long)nlsym[NL_LBOLT].n_value, 0);
  914. X    r_read(memfd, (char *)&boothz, sizeof( boothz ) );
  915. X    proto.wd_boottime = time(0) - (boothz / HZ);
  916. X#else  SHM
  917. X    if ((aven_key = ftok(UNIX, 'a')) == (key_t) -1) {
  918. X#ifdef UNIXPC
  919. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Can't find shared memory keyfile:\n%s: %s", argv0, UNIX, sys_errlist[errno]);
  920. X#else
  921. X        perror(UNIX);
  922. X#endif UNIXPC
  923. X        exit(1);
  924. X    }
  925. X    if ((aven_shm = shmget(aven_key, 3 * sizeof (double), IPC_CREAT|IPC_EXCL|0644)) < 0) {
  926. X#ifdef UNIXPC
  927. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Can't create shared memory segment:\n%s", argv0, sys_errlist[errno]);
  928. X#else
  929. X        perror("shmget");
  930. X#endif UNIXPC
  931. X        exit(1);
  932. X    }
  933. X    if ((int) (aven_seg = (double *) shmat(aven_shm, (char *) 0, 0)) == -1) {
  934. X#ifdef UNIXPC
  935. X        eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Can't attach shared memory segment:\n%s", argv0, sys_errlist[errno]);
  936. X#else
  937. X        perror("shmat");
  938. X#endif UNIXPC
  939. X        if (shmctl(aven_shm, IPC_RMID, (struct shmid_ds *) 0) < 0)
  940. X#ifdef UNIXPC
  941. X            eprintf(ST_OTHER, ST_DISPLAY, (char *) 0, "%s: Can't remove shared memory segment:\n%s", argv0, sys_errlist[errno]);
  942. X#else
  943. X            perror("shmctl(IPC_RMID)");
  944. X#endif UNIXPC
  945. X        exit(1);
  946. X    }
  947. X#endif RWHOD
  948. X    
  949. X} /* init_packet */
  950. X
  951. Xmake_packet(iavg1, iavg2, iavg3)
  952. X#ifdef RWHOD
  953. Xlong iavg1, iavg2, iavg3;
  954. X#else  SHM
  955. Xdouble iavg1, iavg2, iavg3;
  956. X#endif RWHOD
  957. X{
  958. X#ifdef RWHOD
  959. X    static struct whod packet;    /* local packet copy */
  960. X    register struct whoent *wep;    /* pointer to packet whoent */
  961. X    register struct utmp *utp;    /* return from getutent */
  962. X    int whof, cc;            /* output file, char count */
  963. X
  964. X    packet = proto;            /* copy proto packet */
  965. X    time(&packet.wd_sendtime);
  966. X    time(&packet.wd_recvtime);    /* forge this !! */
  967. X    packet.wd_loadav[0] = iavg1;
  968. X    packet.wd_loadav[1] = iavg2;
  969. X    packet.wd_loadav[2] = iavg3;
  970. X
  971. X    setutent();            /* open utmp file */
  972. X    wep = &packet.wd_we[0];        /* get pointer to first user in pkt */
  973. X
  974. X    while( (utp = getutent()) != NULL ) {
  975. X        if( (utp->ut_type == USER_PROCESS) && utp->ut_user[0]) {
  976. X        strncpy(wep->we_utmp.out_line, utp->ut_id, 4);
  977. X        wep->we_utmp.out_line[4] = '\0';
  978. X
  979. X        strncpy(wep->we_utmp.out_name, utp->ut_user, 8);
  980. X
  981. X        wep->we_utmp.out_time = utp->ut_time;
  982. X
  983. X        wep->we_idle = idletime(utp);
  984. X        wep++;            /* bump packet pointer */
  985. X        } /* user process */
  986. X    } /* while */
  987. X    endutent();
  988. X
  989. X# if DSK
  990. X    whof = creat(whopacket, 0644);    /* open packt file */
  991. X    if( whof >= 0 ) {
  992. X        cc = (char *)wep - (char *)&packet;
  993. X        if( write(whof, (char *)&packet, cc) != cc )
  994. X            perror("write failed");
  995. X        close(whof);
  996. X    } /* file opened */
  997. X    else perror(whopacket);
  998. X# endif
  999. X# if UDP
  1000. X    cc = (char *)wep - (char *)&packet;
  1001. X    udpsend( (char *)&packet, cc, ipaddr, port, port, 1);
  1002. X# endif
  1003. X# ifdef DEBUG
  1004. X    fprintf(stderr, "wrote packet (%d)\n", cc);
  1005. X    fflush(stderr);
  1006. X# endif
  1007. X#else  SHM
  1008. X    aven_seg[0] = iavg1;
  1009. X    aven_seg[1] = iavg2;
  1010. X    aven_seg[2] = iavg3;
  1011. X#ifdef UNIXPC
  1012. X    printf("\rLoad average: %4.2f %4.2f %4.2f", iavg1, iavg2, iavg3);
  1013. X    fflush(stdout);
  1014. X#endif UNIXPC
  1015. X#endif RWHOD
  1016. X} /* make_packet */
  1017. X
  1018. X#ifdef RWHOD
  1019. Xidletime(up)
  1020. Xstruct utmp *up;
  1021. X{
  1022. X    register int i;
  1023. X    register char *cp, *dp;
  1024. X    char ttyname[10];
  1025. X    struct stat buf;
  1026. X    time_t now;
  1027. X
  1028. X    cp = "/dev/";
  1029. X    dp = ttyname;
  1030. X    
  1031. X    while( *cp != '\0' )        /* copy "/dev/" */
  1032. X        *dp++ = *cp++;
  1033. X
  1034. X    cp = up->ut_line;            /* get line name */
  1035. X    if( *cp == 's' )            /* starts with an 's'? (sxtnnn) */
  1036. X        *dp++ = 'v';            /* insert a 'v' */
  1037. X
  1038. X    for( i = 0; i < 8; i++ )        /* copy line name */
  1039. X        if( (*dp++ = *cp++) == '\0' ) break;    /* or until null */
  1040. X
  1041. X    if( stat(ttyname, &buf) != 0 )    /* get file status */
  1042. X        return( 0 );
  1043. X
  1044. X    time(&now);                /* get current time */
  1045. X    i = now - buf.st_atime;        /* get differnce from last acces */
  1046. X    return( i );            /* return idle time */
  1047. X} /* idletime */
  1048. X#endif RWHOD
  1049. END_OF_FILE
  1050. if test 10503 -ne `wc -c <'loadavgd.c'`; then
  1051.     echo shar: \"'loadavgd.c'\" unpacked with wrong size!
  1052. fi
  1053. # end of 'loadavgd.c'
  1054. fi
  1055. if test -f 'subr.c' -a "${1}" != "-c" ; then 
  1056.   echo shar: Will not clobber existing file \"'subr.c'\"
  1057. else
  1058. echo shar: Extracting \"'subr.c'\" \(13685 characters\)
  1059. sed "s/^X//" >'subr.c' <<'END_OF_FILE'
  1060. X/*---------------------------------------------------------------------------
  1061. X *
  1062. X * Program: pcmgr
  1063. X * Module:  subr.c
  1064. X *
  1065. X * This module contains miscellaneous procedures used by the pcmgr program.
  1066. X *
  1067. X * Copyright 1992 David H. Brierley, All rights reserved.
  1068. X *-------------------------------------------------------------------------*/
  1069. X
  1070. X#include <stdio.h>
  1071. X#include <sys/types.h>
  1072. X#include <sys/font.h>
  1073. X#include <sys/window.h>
  1074. X#include <time.h>
  1075. X#include <signal.h>
  1076. X#include <string.h>
  1077. X#include <status.h>
  1078. X#include <utmp.h>
  1079. X#include <pwd.h>
  1080. X#include <sys/stat.h>
  1081. X#include <nlist.h>
  1082. X#include <fcntl.h>
  1083. X#include <ctype.h>
  1084. X#include <termio.h>
  1085. X#include <malloc.h>
  1086. X#include <setjmp.h>
  1087. X#include <sys/wd.h>
  1088. X#include <track.h>
  1089. X#include <tam.h>
  1090. X#include <menu.h>
  1091. X#include <kcodes.h>
  1092. X#include <errno.h>
  1093. X#include <sys/sysinfo.h>
  1094. X#include <sys/var.h>
  1095. X#include <sys/syslocal.h>
  1096. X#include <sys/file.h>
  1097. X#include <sys/text.h>
  1098. X#include <sys/tune.h>
  1099. X#include <sys/user.h>
  1100. X#include <sys/vmmac.h>
  1101. X#include <sys/sysmacros.h>
  1102. X
  1103. X#include "config.h"
  1104. X#include "pcmgr.h"
  1105. X
  1106. Xstatic char    *Sccs_Id = "@(#) subr.c: version 2.1 7/14/92 21:12:46";
  1107. X
  1108. X#ifdef    DEBUG
  1109. X#include <syslog.h>
  1110. X#endif
  1111. X
  1112. Xvoid
  1113. Xmake_login (void)
  1114. X{
  1115. X    int             pid;
  1116. X
  1117. X    pid = fork ();
  1118. X
  1119. X    /*
  1120. X     * If parent, or error, return
  1121. X     */
  1122. X    if (pid != 0) {
  1123. X    return;
  1124. X    }
  1125. X
  1126. X    /*
  1127. X     * fork again and have the parent exit.  this causes the child to be
  1128. X     * inherited by init.  we then exec the window program.
  1129. X     */
  1130. X    if ((pid = fork ()) != 0) {
  1131. X    _exit (0);
  1132. X    }
  1133. X
  1134. X    /*
  1135. X     * chdir to the root directory before doing the exec so that we can be
  1136. X     * sure of what directory we are in.
  1137. X     */
  1138. X    (void) chdir ("/");
  1139. X
  1140. X    /*
  1141. X     * set some env variables
  1142. X     */
  1143. X    setenv ("HOME", "/");
  1144. X    setenv ("LOGNAME", "nobody");
  1145. X
  1146. X    (void) execl (WINDOW_PROG, "window", 0);
  1147. X    _exit (1);
  1148. X
  1149. X}
  1150. X
  1151. Xvoid
  1152. Xcycle_window (int dir)
  1153. X{
  1154. X    int             wd;
  1155. X    int             winno;
  1156. X    int             orig_wd;
  1157. X    int             loop_count;
  1158. X    char            w_name[32];
  1159. X    struct utdata   utdata;
  1160. X
  1161. X    if ((wd = open ("/dev/window", 0)) == -1) {
  1162. X    return;
  1163. X    }
  1164. X    if ((winno = ioctl (wd, WIOCGCURR, NULL)) == -1) {
  1165. X    winno = 0;
  1166. X    }
  1167. X    (void) close (wd);
  1168. X    orig_wd = winno;
  1169. X    loop_count = 0;
  1170. X
  1171. X    while (1) {
  1172. X    winno += dir;
  1173. X    if (winno == orig_wd) {
  1174. X        if (++loop_count == 2) {
  1175. X        return;
  1176. X        }
  1177. X    }
  1178. X
  1179. X    /* Generate a window name and test for existence. */
  1180. X    (void) sprintf (w_name, "/dev/w%d", winno);
  1181. X    if ((wd = open (w_name, O_RDONLY)) != -1) {
  1182. X        utdata.ut_num = WTXTUSER;
  1183. X        if (ioctl (wd, WIOCGETTEXT, &utdata) == -1) {
  1184. X        (void) close (wd);
  1185. X        continue;
  1186. X        }
  1187. X        if (strcmp (utdata.ut_text, "Status Manager") == 0) {
  1188. X        (void) close (wd);
  1189. X        continue;
  1190. X        }
  1191. X        if (strcmp (utdata.ut_text, "Window Manager") == 0) {
  1192. X        (void) close (wd);
  1193. X        continue;
  1194. X        }
  1195. X        (void) ioctl (wd, WIOCSELECT, NULL);
  1196. X        (void) close (wd);
  1197. X        return;
  1198. X    }
  1199. X    else if (errno == ENOENT) {
  1200. X        winno = (dir == -1) ? MAX_WINDOW : MIN_WINDOW;
  1201. X    }
  1202. X    }
  1203. X}
  1204. X
  1205. Xstatic int      fd_error = -1;             /* /dev/error */
  1206. X
  1207. Xvoid
  1208. Xrd_dev_error (void)
  1209. X{
  1210. X    int             (*old_alarm) (int sig);
  1211. X    int             len;
  1212. X    static char     ebuffer[257];
  1213. X
  1214. X    if (fd_error == -1) {
  1215. X    fd_error = open (DEV_ERROR, O_RDONLY);
  1216. X    }
  1217. X    if (fd_error == -1) {
  1218. X    return;
  1219. X    }
  1220. X
  1221. X    old_alarm = signal (SIGALRM, trap_alarm);
  1222. X    (void) alarm (1);
  1223. X    len = read (fd_error, ebuffer, 256);
  1224. X    (void) alarm (0);
  1225. X    (void) signal (SIGALRM, old_alarm);
  1226. X    if (len <= 0) {
  1227. X    return;
  1228. X    }
  1229. X
  1230. X    ebuffer[len] = '\0';
  1231. X    write_to_log (*(long *) ebuffer, ebuffer + 4);
  1232. X    parse_ebuffer (ebuffer);
  1233. X
  1234. X    /*
  1235. X     * Recurse to see if there is more than one message pending.
  1236. X     */
  1237. X    rd_dev_error ();
  1238. X
  1239. X}
  1240. X
  1241. X/*
  1242. X * Routine: trap_alarm
  1243. X *
  1244. X * This routine is used to trap and effectively ignore an alarm signal.
  1245. X * The reason for using an actual signal trap instead of just using SIG_IGN
  1246. X * is so that the read() call will be terminated.
  1247. X */
  1248. Xvoid
  1249. Xtrap_alarm (int sig)
  1250. X{
  1251. X
  1252. X    (void) signal (sig, trap_alarm);
  1253. X    return;
  1254. X
  1255. X}
  1256. X
  1257. Xvoid
  1258. Xparse_ebuffer (char *buf)
  1259. X{
  1260. X    int             rc;
  1261. X    int             type;
  1262. X    int             action;
  1263. X    int             alarm_date = 0;
  1264. X    int             alarm_time = 0;
  1265. X    char           *user;
  1266. X    char           *text;
  1267. X
  1268. X    /*
  1269. X     * Does the message begin with a colon?
  1270. X     */
  1271. X    buf += 4;
  1272. X    if (*buf != ':') {
  1273. X    return;
  1274. X    }
  1275. X
  1276. X    /*
  1277. X     * And does it say x:x: ?
  1278. X     */
  1279. X    type = *++buf;
  1280. X    if (*++buf != ':') {
  1281. X    return;
  1282. X    }
  1283. X    action = *++buf;
  1284. X    if (*++buf != ':') {
  1285. X    return;
  1286. X    }
  1287. X
  1288. X    /*
  1289. X     * Only calendar, system, and popup messages are currently processed. All
  1290. X     * others are simply logged.
  1291. X     */
  1292. X    if ((type != 'C') && (type != 'S') && (type != 'P') && (type != 'D')) {
  1293. X    return;
  1294. X    }
  1295. X
  1296. X    /*
  1297. X     * If this is a LOG message it simply goes into the standard log file.
  1298. X     * Multiple log files are not supported.
  1299. X     */
  1300. X    if (action == 'L') {
  1301. X    return;
  1302. X    }
  1303. X
  1304. X    /*
  1305. X     * If we got this far then the user name and text are extracted and
  1306. X     * stored in a linked list for later display.
  1307. X     */
  1308. X    text = user = ++buf;
  1309. X    while (*text != ':') {
  1310. X    ++text;
  1311. X    }
  1312. X    *text = '\0';
  1313. X    text++;
  1314. X
  1315. X    /*
  1316. X     * If this is a calendar message, the date string is converted and stored
  1317. X     * in the structure
  1318. X     */
  1319. X    if ((type == 'C') && (action == 'E')) {
  1320. X    parse_cal_trigger (text, &alarm_date, &alarm_time);
  1321. X    }
  1322. X    insert_msg (type, action, alarm_date, alarm_time, user, text);
  1323. X    return;
  1324. X
  1325. X}
  1326. X
  1327. Xvoid
  1328. Xparse_cal_trigger (char *buf, int *adate, int *atime)
  1329. X{
  1330. X    int             year;
  1331. X    int             month;
  1332. X    int             day;
  1333. X    int             hour;
  1334. X    int             minute;
  1335. X    int             rc;
  1336. X
  1337. X    rc = sscanf (buf, "%*s %4d%2d%2d%2d%2d",
  1338. X         &year, &month, &day, &hour, &minute);
  1339. X
  1340. X    if (rc != 5) {
  1341. X    *atime = 2400;
  1342. X    *adate = 99991231;
  1343. X    }
  1344. X    else {
  1345. X    *atime = (hour * 100) + minute;
  1346. X    *adate = ((year - 1900) * 10000) + ((month - 1) * 100) + day;
  1347. X    }
  1348. X
  1349. X}
  1350. X
  1351. Xvoid
  1352. Xwrite_to_log (long pid, char *buf)
  1353. X{
  1354. X    time_t          clock;
  1355. X    static FILE    *logfp = NULL;
  1356. X    static char    *errfile_name = ERR_LOGFILE;
  1357. X
  1358. X    /*
  1359. X     * Is the log file open yet?
  1360. X     */
  1361. X    if (logfp == NULL) {
  1362. X    logfp = fopen (errfile_name, "a");
  1363. X    }
  1364. X    if (logfp == NULL) {
  1365. X    return;
  1366. X    }
  1367. X
  1368. X    /*
  1369. X     * Write the data out with a time stamp
  1370. X     */
  1371. X    (void) time (&clock);
  1372. X    (void) fprintf (logfp,
  1373. X            "%.24s: pid %5d: %s\n",
  1374. X            ctime (&clock), pid, buf);
  1375. X    (void) fflush (logfp);
  1376. X
  1377. X}
  1378. X
  1379. Xstatic struct emsg *msg_head = NULL;         /* head of message list */
  1380. X
  1381. Xvoid
  1382. Xinsert_msg (int type, int action, int adate, int atime, char *user, char *text)
  1383. X{
  1384. X    struct emsg    *ptr;
  1385. X    struct emsg    *old;
  1386. X    extern int      redraw_all;
  1387. X
  1388. X    for (ptr = msg_head; ptr != NULL; ptr = ptr -> mnext) {
  1389. X    old = ptr;
  1390. X    }
  1391. X
  1392. X    /*
  1393. X     * create a new node and add it to the end
  1394. X     */
  1395. X    ptr = (struct emsg *) malloc (sizeof (struct emsg));
  1396. X    if (ptr == NULL) {
  1397. X    return;
  1398. X    }
  1399. X
  1400. X    ptr -> mtype = type;
  1401. X    ptr -> mact = action;
  1402. X    ptr -> alrm_date = adate;
  1403. X    ptr -> alrm_time = atime;
  1404. X    ptr -> muser = msave (user);
  1405. X    ptr -> mtext = msave (text);
  1406. X    ptr -> mnext = NULL;
  1407. X    if (msg_head == NULL) {
  1408. X    msg_head = ptr;
  1409. X    }
  1410. X    else {
  1411. X    old -> mnext = ptr;
  1412. X    }
  1413. X    ++redraw_all;
  1414. X
  1415. X}
  1416. X
  1417. Xint
  1418. Xmsg_count (void)
  1419. X{
  1420. X    struct emsg    *ptr;
  1421. X    int             count = 0;
  1422. X    static int      uid;
  1423. X    static int      gid;
  1424. X    struct passwd  *pw;
  1425. X    char           *user = "";
  1426. X
  1427. X    if (get_user_id (&uid, &gid) != -1) {
  1428. X    if ((pw = getpwuid (uid)) != NULL) {
  1429. X        user = pw -> pw_name;
  1430. X    }
  1431. X    }
  1432. X
  1433. X    for (ptr = msg_head; ptr != NULL; ptr = ptr -> mnext) {
  1434. X    if ((ptr -> mtype == 'C') && (ptr -> mact == 'E')) {
  1435. X        continue;
  1436. X    }
  1437. X    if (ptr -> muser == NULL) {
  1438. X        count++;
  1439. X    }
  1440. X    else if (strcmp (ptr -> muser, user) == 0) {
  1441. X        count++;
  1442. X    }
  1443. X    }
  1444. X
  1445. X    return (count);
  1446. X
  1447. X}
  1448. X
  1449. Xvoid
  1450. Xshow_msgs (void)
  1451. X{
  1452. X    int             win;
  1453. X    int             wflags;
  1454. X    int             kflag;
  1455. X    struct emsg    *ptr;
  1456. X    struct emsg    *old;
  1457. X    struct emsg    *new;
  1458. X    int             in_key;
  1459. X    static int      uid;
  1460. X    static int      gid;
  1461. X    struct passwd  *pw;
  1462. X    char           *user = "";
  1463. X    extern int      redraw_all;
  1464. X
  1465. X    /*
  1466. X     * Set the window flags but dont create the window yet.  The window will
  1467. X     * be created further down once it is determined that there really is a
  1468. X     * message to be displayed.  I could call msg_count() to see if there are
  1469. X     * any messages but this way I only have to go through the message list
  1470. X     * once.
  1471. X     */
  1472. X    wflags = 0;            /* BORDER is the default, no other options */
  1473. X    win = -1;
  1474. X
  1475. X    if (get_user_id (&uid, &gid) != -1) {
  1476. X    if ((pw = getpwuid (uid)) != NULL) {
  1477. X        user = pw -> pw_name;
  1478. X    }
  1479. X    }
  1480. X
  1481. X    old = NULL;
  1482. X    for (ptr = msg_head; ptr != NULL; ptr = new) {
  1483. X    new = ptr -> mnext;
  1484. X    if ((ptr -> mtype == 'C') && (ptr -> mact == 'E')) {
  1485. X        old = ptr;
  1486. X        continue;
  1487. X    }
  1488. X    if ((ptr -> muser == NULL) || (strcmp (ptr -> muser, user) == 0)) {
  1489. X
  1490. X        /*
  1491. X         * If the display window has not been created yet, create it and
  1492. X         * set the keypad input mode.
  1493. X         */
  1494. X        if (win == -1) {
  1495. X        win = wcreate (2, 20, 10, 40, wflags);
  1496. X        if (win == -1) {
  1497. X            return;
  1498. X        }
  1499. X        keypad (win, 1);
  1500. X        }
  1501. X        wputs (win, "\033[2J");    /* clear */
  1502. X        wgoto (win, 0, 0);
  1503. X        wputs (win, "Message type = ");
  1504. X        switch (ptr -> mtype) {
  1505. X        case 'M':
  1506. X        wputs (win, "mail");
  1507. X        break;
  1508. X        case 'C':
  1509. X        wputs (win, "calendar");
  1510. X        break;
  1511. X        case 'O':
  1512. X        wputs (win, "miscellaneous");
  1513. X        break;
  1514. X        case 'S':
  1515. X        wputs (win, "system error");
  1516. X        break;
  1517. X        default:
  1518. X        wputs (win, "unknown");
  1519. X        break;
  1520. X        }
  1521. X        wgoto (win, 1, 0);
  1522. X        wputs (win, "Message action = ");
  1523. X        switch (ptr -> mact) {
  1524. X        case 'D':
  1525. X        wputs (win, "display");
  1526. X        break;
  1527. X        case 'E':
  1528. X        wputs (win, "execute");
  1529. X        break;
  1530. X        case 'N':
  1531. X        wputs (win, "notify");
  1532. X        break;
  1533. X        case 'C':
  1534. X        wputs (win, "confirm");
  1535. X        break;
  1536. X        default:
  1537. X        wputs (win, "display");
  1538. X        break;
  1539. X        }
  1540. X        wgoto (win, 3, 0);
  1541. X        if (ptr -> mtext != NULL) {
  1542. X        wputs (win, ptr -> mtext);
  1543. X        }
  1544. X        else {
  1545. X        wputs (win, "(message contains no text portion)");
  1546. X        }
  1547. X        wgoto (win, 9, 0);
  1548. X        wputs (win, "Press ENTER to continue");
  1549. X
  1550. X        /*
  1551. X         * Loop until the user presses Enter, Exit, or Cancl.  Enter
  1552. X         * means display the next message. Exit and Cancl cause the
  1553. X         * window to be deleted without removing any messages from the
  1554. X         * message list
  1555. X         */
  1556. X        kflag = 1;
  1557. X        while (kflag) {
  1558. X        in_key = wgetc (win);
  1559. X        switch (in_key) {
  1560. X        case Cancl:
  1561. X        case Exit:
  1562. X
  1563. X            /*
  1564. X             * Remove window and exit procedure without removing any
  1565. X             * more messages from the list.
  1566. X             */
  1567. X            wdelete (win);
  1568. X            return;
  1569. X            break;
  1570. X        case Enter:
  1571. X            if (old == NULL) {
  1572. X            msg_head = new;
  1573. X            }
  1574. X            else {
  1575. X            old -> mnext = new;
  1576. X            }
  1577. X            if (ptr -> muser != NULL) {
  1578. X            free (ptr -> muser);
  1579. X            }
  1580. X            if (ptr -> mtext != NULL) {
  1581. X            free (ptr -> mtext);
  1582. X            }
  1583. X            free (ptr);
  1584. X            ptr = old;
  1585. X            kflag = 0;
  1586. X            redraw_all++;
  1587. X            break;
  1588. X        }
  1589. X        }
  1590. X    }
  1591. X    old = ptr;
  1592. X    }
  1593. X
  1594. X    /*
  1595. X     * If we created a window then we must delete it.
  1596. X     */
  1597. X    if (win != -1) {
  1598. X    wdelete (win);
  1599. X    }
  1600. X
  1601. X}
  1602. X
  1603. Xvoid
  1604. Xcheck_alarms (void)
  1605. X{
  1606. X    struct emsg    *ptr;
  1607. X    struct emsg    *old;
  1608. X    struct emsg    *new;
  1609. X    static int      uid;
  1610. X    static int      gid;
  1611. X    int             flag;
  1612. X    struct passwd  *pw;
  1613. X    char           *user = "";
  1614. X    long            now;
  1615. X    long            discard;
  1616. X    int             cur_date;
  1617. X    int             cur_time;
  1618. X    int             toss_date;
  1619. X    int             toss_time;
  1620. X    struct tm      *tm;
  1621. X
  1622. X    if (get_user_id (&uid, &gid) != -1) {
  1623. X    if ((pw = getpwuid (uid)) != NULL) {
  1624. X        user = pw -> pw_name;
  1625. X    }
  1626. X    }
  1627. X
  1628. X    (void) time (&now);
  1629. X    tm = localtime (&now);
  1630. X    cur_date = (tm -> tm_year * 10000) + (tm -> tm_mon * 100) + tm -> tm_mday;
  1631. X    cur_time = (tm -> tm_hour * 100) + tm -> tm_min;
  1632. X
  1633. X    old = NULL;
  1634. X    flag = 0;
  1635. X    for (ptr = msg_head; ptr != NULL; ptr = new) {
  1636. X#ifdef    DEBUG
  1637. X    syslog (LOG_DEBUG, "check_alarm: type = %c, user = %s, text = %s",
  1638. X        ptr -> mtype, (ptr -> muser) ? ptr -> muser : "NULL",
  1639. X        ptr -> mtext);
  1640. X#endif
  1641. X    new = ptr -> mnext;
  1642. X    if ((ptr -> mtype != 'C') || (ptr -> mact != 'E')) {
  1643. X        old = ptr;
  1644. X        continue;
  1645. X    }
  1646. X    if ((ptr -> muser != NULL) && (strcmp (ptr -> muser, user) != 0)) {
  1647. X        old = ptr;
  1648. X        continue;
  1649. X    }
  1650. X#ifdef    DEBUG
  1651. X    syslog (LOG_DEBUG, "cdate=%d, ctime=%d, adate=%d, atime=%d",
  1652. X        cur_date, cur_time, ptr -> alrm_date, ptr -> alrm_time);
  1653. X#endif
  1654. X    if (cur_date < ptr -> alrm_date) {
  1655. X        old = ptr;
  1656. X        continue;
  1657. X    }
  1658. X    if (cur_time < ptr -> alrm_time) {
  1659. X        old = ptr;
  1660. X        continue;
  1661. X    }
  1662. X    if (flag == 0) {
  1663. X        discard = now - DISCARD_TIME;
  1664. X        tm = localtime (&discard);
  1665. X        toss_date = (tm -> tm_year * 10000)
  1666. X        + (tm -> tm_mon * 100) + tm -> tm_mday;
  1667. X        toss_time = (tm -> tm_hour * 100) + tm -> tm_min;
  1668. X#ifdef        DEBUG
  1669. X        syslog (LOG_DEBUG, "toss_date=%d, toss_time=%d",
  1670. X            toss_date, toss_time);
  1671. X#endif
  1672. X        if ((ptr -> alrm_date > toss_date) || (ptr -> alrm_date = toss_date && ptr -> alrm_time > toss_time)) {
  1673. X        run_calndr (ptr -> mtext);
  1674. X        flag++;
  1675. X        }
  1676. X    }
  1677. X    if (old == NULL) {
  1678. X        msg_head = new;
  1679. X    }
  1680. X    else {
  1681. X        old -> mnext = new;
  1682. X    }
  1683. X    if (ptr -> muser != NULL) {
  1684. X        free (ptr -> muser);
  1685. X    }
  1686. X    if (ptr -> mtext != NULL) {
  1687. X        free (ptr -> mtext);
  1688. X    }
  1689. X    free (ptr);
  1690. X    }
  1691. X
  1692. X    return;
  1693. X
  1694. X}
  1695. X
  1696. Xvoid
  1697. Xsetenv (name, value)
  1698. Xchar           *name;
  1699. Xchar           *value;
  1700. X{
  1701. X    auto char      *buf;
  1702. X
  1703. X    buf = malloc (strlen (name) + strlen (value) + 2);
  1704. X    if (buf == NULL) {
  1705. X    fprintf (stderr, "Unable to allocate dynamic memory for setenv\n");
  1706. X    exit (1);
  1707. X    }
  1708. X
  1709. X    (void) sprintf (buf, "%s=%s", name, value);
  1710. X    (void) putenv (buf);
  1711. X
  1712. X}
  1713. END_OF_FILE
  1714. if test 13685 -ne `wc -c <'subr.c'`; then
  1715.     echo shar: \"'subr.c'\" unpacked with wrong size!
  1716. fi
  1717. # end of 'subr.c'
  1718. fi
  1719. if test -f 'windows.c' -a "${1}" != "-c" ; then 
  1720.   echo shar: Will not clobber existing file \"'windows.c'\"
  1721. else
  1722. echo shar: Extracting \"'windows.c'\" \(11288 characters\)
  1723. sed "s/^X//" >'windows.c' <<'END_OF_FILE'
  1724. X/*---------------------------------------------------------------------------
  1725. X *
  1726. X * Program: pcmgr
  1727. X * Module:  windows.c
  1728. X *
  1729. X * This module contains routines that create various windows for
  1730. X * use by the pcmgr program and routines that help manage those
  1731. X * windows.
  1732. X *
  1733. X * Copyright 1992 David H. Brierley, All rights reserved.
  1734. X *-------------------------------------------------------------------------*/
  1735. X
  1736. X#include <stdio.h>
  1737. X#include <sys/types.h>
  1738. X#include <sys/font.h>
  1739. X#include <sys/window.h>
  1740. X#include <time.h>
  1741. X#include <signal.h>
  1742. X#include <string.h>
  1743. X#include <status.h>
  1744. X#include <utmp.h>
  1745. X#include <pwd.h>
  1746. X#include <sys/stat.h>
  1747. X#include <nlist.h>
  1748. X#include <fcntl.h>
  1749. X#include <ctype.h>
  1750. X#include <termio.h>
  1751. X#include <malloc.h>
  1752. X#include <setjmp.h>
  1753. X#include <sys/wd.h>
  1754. X#include <track.h>
  1755. X#include <tam.h>
  1756. X#include <menu.h>
  1757. X#include <kcodes.h>
  1758. X#include <errno.h>
  1759. X#include <sys/sysinfo.h>
  1760. X#include <sys/var.h>
  1761. X#include <sys/syslocal.h>
  1762. X#include <sys/file.h>
  1763. X#include <sys/text.h>
  1764. X#include <sys/tune.h>
  1765. X#include <sys/user.h>
  1766. X#include <sys/vmmac.h>
  1767. X#include <sys/sysmacros.h>
  1768. X
  1769. X#include "config.h"
  1770. X#include "pcmgr.h"
  1771. X
  1772. Xstatic char    *Sccs_Id = "@(#) windows.c: version 2.1 7/14/92 21:13:05";
  1773. X
  1774. X/*
  1775. X * Procedure: window_menu
  1776. X *
  1777. X * Display a list of all active windows on the system and allow the user
  1778. X * to select an entry from the list.
  1779. X */
  1780. Xvoid
  1781. Xwindow_menu (void)
  1782. X{
  1783. X    int             win;
  1784. X    int             w_current;
  1785. X    int             fd;
  1786. X    struct utdata   utdata;
  1787. X    char            win_name[16];
  1788. X    menu_t          w_menu;
  1789. X    mitem_t         w_list[17];
  1790. X    int             w_index;
  1791. X    int             rc;
  1792. X
  1793. X    /* fork to avoid possible deadlocks */
  1794. X    if (fork () != 0) {
  1795. X    return;
  1796. X    }
  1797. X
  1798. X    /*
  1799. X     * initialize the menu structure
  1800. X     */
  1801. X    keypad (0, 1);
  1802. X    w_menu.m_label = "Windows";
  1803. X    w_menu.m_title = "Window Menu";
  1804. X    w_menu.m_prompt = NULL;
  1805. X    w_menu.m_rows = 0;
  1806. X    w_menu.m_cols = 1;
  1807. X    w_menu.m_flags = M_USEWIN | M_SINGLE | M_NOMOVE | M_NOHELP | M_NORESIZE;
  1808. X    w_menu.m_lbuf[0] = '\0';
  1809. X    w_menu.m_items = w_list;
  1810. X    w_menu.m_curi = w_list;
  1811. X    w_index = 0;
  1812. X    w_current = ioctl (0, WIOCGCURR, NULL);
  1813. X
  1814. X    /*
  1815. X     * extract the names of all of the current windows and add them to
  1816. X     * the menu
  1817. X     */
  1818. X    for (win = 1; win <= 15; ++win) {
  1819. X    (void) sprintf (win_name, "/dev/w%d", win);
  1820. X    if ((fd = open (win_name, 0)) == -1) {
  1821. X        continue;
  1822. X    }
  1823. X    w_list[w_index].mi_name = NULL;
  1824. X    w_list[w_index].mi_flags = 0;
  1825. X    w_list[w_index].mi_val = win;
  1826. X    utdata.ut_num = WTXTUSER;
  1827. X    if (ioctl (fd, WIOCGETTEXT, &utdata) != -1) {
  1828. X        w_list[w_index].mi_name = msave (utdata.ut_text);
  1829. X    }
  1830. X    if (w_list[w_index].mi_name == NULL) {
  1831. X        utdata.ut_num = WTXTLABEL;
  1832. X        if (ioctl (fd, WIOCGETTEXT, &utdata) != -1) {
  1833. X        w_list[w_index].mi_name = msave (utdata.ut_text);
  1834. X        }
  1835. X    }
  1836. X    (void) close (fd);
  1837. X    if (w_list[w_index].mi_name == NULL) {
  1838. X        w_list[w_index].mi_name = msave ("Unknown Contents");
  1839. X    }
  1840. X    if (strcmp (w_list[w_index].mi_name, "Window Manager") == 0) {
  1841. X        (void) free (w_list[w_index].mi_name);
  1842. X        continue;
  1843. X    }
  1844. X    if (strcmp (w_list[w_index].mi_name, "Status Manager") == 0) {
  1845. X        (void) free (w_list[w_index].mi_name);
  1846. X        continue;
  1847. X    }
  1848. X    if (win == w_current) {
  1849. X        w_menu.m_curi = &w_list[w_index];
  1850. X    }
  1851. X    ++w_index;
  1852. X    }
  1853. X
  1854. X    w_list[w_index].mi_name = NULL;
  1855. X    w_list[w_index].mi_flags = 0;
  1856. X    w_list[w_index].mi_val = 0;
  1857. X
  1858. X    /*
  1859. X     * create a window to display the menu in and initialize
  1860. X     * the menu input routines
  1861. X     */
  1862. X    w_menu.m_win = wcreate (1, 50, 6, 25, 0);
  1863. X    (void) menu (&w_menu, M_BEGIN);
  1864. X
  1865. X    /*
  1866. X     * Accept input from the user
  1867. X     */
  1868. X    while (1) {
  1869. X    rc = menu (&w_menu, M_INPUT);
  1870. X    if ((rc == Exit) || (rc == Cancl)) {
  1871. X        win = -1;
  1872. X        break;
  1873. X    }
  1874. X    if ((rc == Enter) && (w_menu.m_selcnt == 1)) {
  1875. X        win = w_menu.m_curi -> mi_val;
  1876. X        break;
  1877. X    }
  1878. X    }
  1879. X
  1880. X    /*
  1881. X     * terminate the menu input routines and delete the menu window
  1882. X     */
  1883. X    menu (&w_menu, M_END);
  1884. X    (void) wdelete (w_menu.m_win);
  1885. X
  1886. X    /*
  1887. X     * cause the window designated by the user to be the currently
  1888. X     * selected window 
  1889. X     */
  1890. X    if (win != -1) {
  1891. X    (void) sprintf (win_name, "/dev/w%d", win);
  1892. X    if ((fd = open (win_name, 0)) != -1) {
  1893. X        (void) ioctl (fd, WIOCSELECT, NULL);
  1894. X        (void) close (fd);
  1895. X    }
  1896. X    }
  1897. X
  1898. X    /* clean up time */
  1899. X    for (win = 0; win < w_index; ++win) {
  1900. X    if (w_list[win].mi_name != NULL) {
  1901. X        (void) free (w_list[win].mi_name);
  1902. X    }
  1903. X    }
  1904. X
  1905. X    /* since we forked above we need to exit here instead of returning */
  1906. X    _exit (0);
  1907. X
  1908. X}
  1909. X
  1910. X/*
  1911. X * Procedure: msave
  1912. X *
  1913. X * Dynamically allocate storage for a character string and copy the
  1914. X * designated string into it.  Return the address of the new string.
  1915. X */
  1916. Xchar           *
  1917. Xmsave (char *str)
  1918. X{
  1919. X    unsigned int    length;
  1920. X    char           *new;
  1921. X
  1922. X    length = strlen (str) + 1;
  1923. X    if (length == 1) {
  1924. X    return (NULL);
  1925. X    }
  1926. X
  1927. X    if ((new = malloc (length)) == NULL) {
  1928. X    perror ("windows");
  1929. X    exit (1);
  1930. X    }
  1931. X
  1932. X    (void) strcpy (new, str);
  1933. X    return (new);
  1934. X
  1935. X}
  1936. X
  1937. X/*
  1938. X * Procedure: run_email
  1939. X *
  1940. X * Create a window and run the mail program in it.
  1941. X */
  1942. Xvoid
  1943. Xrun_email (void)
  1944. X{
  1945. X    static int      user_id;
  1946. X    static int      group_id;
  1947. X    struct uwdata   uwdata;
  1948. X    struct utdata   utdata;
  1949. X    struct passwd  *pw;
  1950. X    struct passwd  *getpwuid ();
  1951. X    int             fd;
  1952. X    int             n;
  1953. X
  1954. X    /*
  1955. X     * First we figure out who the active user is.  If there is no active
  1956. X     * user or if we cannot locate that user in the password file, no
  1957. X     * action is taken
  1958. X     */
  1959. X    if (get_user_id (&user_id, &group_id) == -1) {
  1960. X    return;
  1961. X    }
  1962. X
  1963. X    if ((pw = getpwuid (user_id)) == NULL) {
  1964. X    return;
  1965. X    }
  1966. X
  1967. X    /* fork to avoid possible deadlocks */
  1968. X    if (fork () != 0) {
  1969. X    return;
  1970. X    }
  1971. X
  1972. X    (void) setpgrp ();
  1973. X
  1974. X    /*
  1975. X     * create a full screen window to run the mail program in
  1976. X     */
  1977. X    fd = open ("/dev/window", 2);
  1978. X    if (fd == -1) {
  1979. X    _exit (1);
  1980. X    }
  1981. X
  1982. X    for (n = 0; n < _NFILE; ++n) {
  1983. X    if (n != fd) {
  1984. X        (void) close (n);
  1985. X    }
  1986. X    }
  1987. X
  1988. X    while (fd != 0) {
  1989. X    (void) close (0);
  1990. X    n = fcntl (fd, F_DUPFD, 0);
  1991. X    if (n != -1) {
  1992. X        (void) close (fd);
  1993. X        fd = n;
  1994. X    }
  1995. X    }
  1996. X    (void) dup (0);
  1997. X    (void) dup (0);
  1998. X    (void) ioctl (0, WIOCPGRP, NULL);
  1999. X
  2000. X    if (ioctl (0, WIOCGETD, &uwdata) == -1) {
  2001. X    _exit (1);
  2002. X    }
  2003. X
  2004. X    uwdata.uw_height = 24 * uwdata.uw_vs;
  2005. X    uwdata.uw_width = 80 * uwdata.uw_hs;
  2006. X    uwdata.uw_uflags = NBORDER;
  2007. X    uwdata.uw_x = 0;
  2008. X    uwdata.uw_y = uwdata.uw_vs;
  2009. X
  2010. X    if (ioctl (0, WIOCSETD, &uwdata) == -1) {
  2011. X    _exit (1);
  2012. X    }
  2013. X
  2014. X    /*
  2015. X     * Label the window so that everyone can tell what it is
  2016. X     */
  2017. X    utdata.ut_num = WTXTLABEL;
  2018. X    (void) strcpy (utdata.ut_text, "Mail Reader Program");
  2019. X    (void) ioctl (0, WIOCSETTEXT, &utdata);
  2020. X
  2021. X    /*
  2022. X     * chdir to the users home directory before attempting to run the mail
  2023. X     * program and set up some env variables.
  2024. X     */
  2025. X    (void) chdir (pw -> pw_dir);
  2026. X    setenv ("HOME", pw -> pw_dir);
  2027. X    setenv ("LOGNAME", pw -> pw_name);
  2028. X
  2029. X    /*
  2030. X     * Run the email program.  If the email program is not found then
  2031. X     * run the stock mail program.  This should probably be extended
  2032. X     * to allow a default mail program to be specified at compile time
  2033. X     * but the source for my implementation of email.c should be included
  2034. X     * with this package so why bother?
  2035. X     */
  2036. X    (void) setgid (group_id);
  2037. X    (void) setuid (user_id);
  2038. X    (void) execl ("/usr/bin/email", "email", "-i", "-u", pw -> pw_name);
  2039. X    (void) execl ("/bin/mail", "mail", "-u", pw -> pw_name);
  2040. X    _exit (1);
  2041. X
  2042. X}
  2043. X
  2044. X/*
  2045. X * Procedure: run_calndr
  2046. X *
  2047. X * Create a window and run the pcal program in it.
  2048. X */
  2049. Xvoid
  2050. Xrun_calndr (char *buf)
  2051. X{
  2052. X    static int      user_id;
  2053. X    static int      group_id;
  2054. X    char            alarm_time[16];
  2055. X    struct uwdata   uwdata;
  2056. X    struct utdata   utdata;
  2057. X    struct passwd  *pw;
  2058. X    struct passwd  *getpwuid ();
  2059. X    int             fd;
  2060. X    int             n;
  2061. X
  2062. X    /*
  2063. X     * First we figure out who the active user is.  If there is no active
  2064. X     * user or if we cannot locate that user in the password file, no
  2065. X     * action is taken
  2066. X     */
  2067. X    if (get_user_id (&user_id, &group_id) == -1) {
  2068. X    return;
  2069. X    }
  2070. X
  2071. X    if ((pw = getpwuid (user_id)) == NULL) {
  2072. X    return;
  2073. X    }
  2074. X
  2075. X    /* fork to avoid possible deadlocks */
  2076. X    if (fork () != 0) {
  2077. X    return;
  2078. X    }
  2079. X
  2080. X    (void) setpgrp ();
  2081. X
  2082. X    /*
  2083. X     * create a full screen window to run the pcal program in
  2084. X     */
  2085. X    fd = open ("/dev/window", 2);
  2086. X    if (fd == -1) {
  2087. X    _exit (1);
  2088. X    }
  2089. X
  2090. X    for (n = 0; n < _NFILE; ++n) {
  2091. X    if (n != fd) {
  2092. X        (void) close (n);
  2093. X    }
  2094. X    }
  2095. X
  2096. X    while (fd != 0) {
  2097. X    (void) close (0);
  2098. X    n = fcntl (fd, F_DUPFD, 0);
  2099. X    if (n != -1) {
  2100. X        (void) close (fd);
  2101. X        fd = n;
  2102. X    }
  2103. X    }
  2104. X    (void) dup (0);
  2105. X    (void) dup (0);
  2106. X    (void) ioctl (0, WIOCPGRP, NULL);
  2107. X
  2108. X    if (ioctl (0, WIOCGETD, &uwdata) == -1) {
  2109. X    _exit (1);
  2110. X    }
  2111. X
  2112. X    /*
  2113. X     * Make a relatively small window, pcal will resize it later.
  2114. X     */
  2115. X    uwdata.uw_height = 5 * uwdata.uw_vs;
  2116. X    uwdata.uw_width = 30 * uwdata.uw_hs;
  2117. X    uwdata.uw_uflags = 0;
  2118. X    uwdata.uw_x = 0;
  2119. X    uwdata.uw_y = uwdata.uw_vs;
  2120. X
  2121. X    if (ioctl (0, WIOCSETD, &uwdata) == -1) {
  2122. X    _exit (1);
  2123. X    }
  2124. X
  2125. X    /*
  2126. X     * Label the window so that everyone can tell what it is
  2127. X     */
  2128. X    utdata.ut_num = WTXTLABEL;
  2129. X    (void) strcpy (utdata.ut_text, "Personal Calendar Program");
  2130. X    (void) ioctl (0, WIOCSETTEXT, &utdata);
  2131. X
  2132. X    /*
  2133. X     * chdir to the users home directory before attempting to run
  2134. X     * the pcal program.  If this is not done then the users calendar
  2135. X     * file will not be accessible.
  2136. X     */
  2137. X    (void) chdir (pw -> pw_dir);
  2138. X    setenv ("HOME", pw -> pw_dir);
  2139. X    setenv ("LOGNAME", pw -> pw_name);
  2140. X
  2141. X    /*
  2142. X     * Run the pcal program.
  2143. X     */
  2144. X    (void) setgid (group_id);
  2145. X    (void) setuid (user_id);
  2146. X    if (buf == NULL) {
  2147. X    (void) execl ("/usr/bin/pcal", "pcal", NULL);
  2148. X    }
  2149. X    else {
  2150. X    if (sscanf (buf, "%*s %s", alarm_time) != 1) {
  2151. X        (void) strcpy (alarm_time, "");
  2152. X    }
  2153. X    (void) write (1, "\007", 1);
  2154. X    (void) execl ("/usr/bin/pcal", "pcal", "-a", alarm_time, NULL);
  2155. X    }
  2156. X    _exit (1);
  2157. X
  2158. X}
  2159. X
  2160. X/*
  2161. X * Procedure: do_sprint
  2162. X *
  2163. X * Run the sprint program to produce a screen dump.
  2164. X */
  2165. Xvoid
  2166. Xdo_sprint (void)
  2167. X{
  2168. X    int             fd;
  2169. X    int             n;
  2170. X    int             oldwd;
  2171. X    int             xd;
  2172. X    char            w_name[32];
  2173. X
  2174. X    /* fork to avoid possible deadlocks */
  2175. X    if (fork () != 0) {
  2176. X    return;
  2177. X    }
  2178. X
  2179. X    (void) setpgrp ();
  2180. X
  2181. X    /*
  2182. X     * create a window to run the sprint program in
  2183. X     */
  2184. X    fd = open ("/dev/window", 2);
  2185. X    if (fd == -1) {
  2186. X    _exit (1);
  2187. X    }
  2188. X
  2189. X    /*
  2190. X     * re-select the previously selected window, otherwise you get a screen
  2191. X     * dump of the newly created empty window.
  2192. X     */
  2193. X    oldwd = ioctl (fd, WIOCGPREV, NULL);
  2194. X    if (oldwd != -1) {
  2195. X    (void) sprintf (w_name, "/dev/w%d", oldwd);
  2196. X    if ((xd = open (w_name, 0)) != -1) {
  2197. X        (void) ioctl (xd, WIOCSELECT, NULL);
  2198. X        (void) close (xd);
  2199. X    }
  2200. X    }
  2201. X
  2202. X    for (n = 0; n < _NFILE; ++n) {
  2203. X    if (n != fd) {
  2204. X        (void) close (n);
  2205. X    }
  2206. X    }
  2207. X
  2208. X    while (fd != 0) {
  2209. X    (void) close (0);
  2210. X    n = fcntl (fd, F_DUPFD, 0);
  2211. X    if (n != -1) {
  2212. X        (void) close (fd);
  2213. X        fd = n;
  2214. X    }
  2215. X    }
  2216. X    (void) dup (0);
  2217. X    (void) dup (0);
  2218. X    (void) ioctl (0, WIOCPGRP, NULL);
  2219. X
  2220. X    /*
  2221. X     * Run the sprint program.
  2222. X     */
  2223. X    (void) sleep (4);    /* wait for screen to redraw */
  2224. X    (void) execl ("/usr/bin/sprint", "sprint", NULL);
  2225. X    _exit (1);
  2226. X
  2227. X}
  2228. END_OF_FILE
  2229. if test 11288 -ne `wc -c <'windows.c'`; then
  2230.     echo shar: \"'windows.c'\" unpacked with wrong size!
  2231. fi
  2232. # end of 'windows.c'
  2233. fi
  2234. echo shar: End of archive 2 \(of 3\).
  2235. cp /dev/null ark2isdone
  2236. MISSING=""
  2237. for I in 1 2 3 ; do
  2238.     if test ! -f ark${I}isdone ; then
  2239.     MISSING="${MISSING} ${I}"
  2240.     fi
  2241. done
  2242. if test "${MISSING}" = "" ; then
  2243.     echo You have unpacked all 3 archives.
  2244.     rm -f ark[1-9]isdone
  2245. else
  2246.     echo You still need to unpack the following archives:
  2247.     echo "        " ${MISSING}
  2248. fi
  2249. ##  End of shell archive.
  2250. exit 0
  2251. -- 
  2252. David H. Brierley
  2253. Home: dave@galaxia.network23.com; Work: dhb@quahog.ssd.ray.com
  2254. Send comp.sources.3b1 submissions to comp-sources-3b1@galaxia.network23.com
  2255. %% Can I be excused, my brain is full. **
  2256.