home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume3 / suntools / suntools.c < prev   
C/C++ Source or Header  |  1986-11-30  |  27KB  |  1,040 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)suntools.c 1.2 85/03/13 SMI";
  3. #endif
  4.  
  5. /*
  6. * Sun Microsystems, Inc.
  7. */
  8.  
  9. /*
  10. * Root window: Provides the background window for a screen.
  11. *    Put up environment manager menu.
  12. */
  13.  
  14. /*
  15.  
  16. Modified by Don Libes, National Bureau of Standards, 9/25/85
  17.  
  18. Added the following:
  19.  
  20. Menu selections via keyboard
  21. Su'd selections via shift key
  22. User-specifiable primary menu name
  23. User-specifiable root cursor
  24. Various keywords: EXIT_NOCONFIRM, VERSION, HELP, KEYS
  25.  
  26. */
  27.  
  28. #include <suntool/tool_hs.h>
  29. #include <sys/ioctl.h>
  30. #include <sys/dir.h>
  31. #include <sys/file.h>
  32. #include <sys/wait.h>
  33. #include <sys/resource.h>
  34. #include <sys/stat.h>
  35. #include <errno.h>
  36. #include <stdio.h>
  37. #include <pwd.h>
  38. #include <suntool/menu.h>
  39. #include <suntool/wmgr.h>
  40. #include <sundev/kbd.h>        /* SHIFTMASK - DEL */
  41. #include <ctype.h>
  42. #include <suntool/icon_load.h>    /* icon_load_mpr for user cursor - DEL */
  43.  
  44. extern int      errno;
  45.  
  46. extern char    *malloc (), *calloc (), *getenv (), *strcpy (), *strncat (), *strncpy ();
  47.  
  48. static int      rootfd = 0,
  49.                 rootnumber;
  50. static int      root_SIGCHLD,
  51.                 root_SIGWINCH;
  52. static struct screen    screen;
  53.  
  54. static struct pixwin   *pixwin;
  55.  
  56. #define    ROOTMENUITEMS    20
  57. #define    ROOTMENUFILE    "/usr/lib/rootmenu"
  58. #define ROOTMENUNAME    "Suntools"
  59.  
  60. struct menuitem root_items[ROOTMENUITEMS];
  61.  
  62. struct menuitemstrings {
  63.     char   *mis_prog;    /* program to call */
  64.     char   *mis_args;    /* args to program */
  65. }                       root_itemstrings[ROOTMENUITEMS];
  66.  
  67. char   *rootmenufile;
  68. char   *rootmenuname;        /* DEL */
  69.  
  70. struct menu     wmgr_rootmenubody,
  71.                *wmgr_rootmenu = &wmgr_rootmenubody;
  72. struct stat_rec {
  73.     char   *name;        /* Dynamically allocated menu file name */
  74.             time_t mftime;    /* Modified file time */
  75. };
  76. #define    MAX_MENUS    20
  77. static struct stat_rec  stat_array[MAX_MENUS];
  78. static int      menu_next;
  79.  
  80. #define    ROOTCOLOR_PATTERN    0
  81. #define    ROOTCOLOR_FOREGROUND    1
  82. #define    ROOTCOLOR_BACKGROUND    2
  83. static  rootcolor = ROOTCOLOR_PATTERN;
  84. /* Default cursor is a circle filled with stipple pattern. */
  85. /* When or-ed against another stipple pattern, it changes constantly. */
  86. /* Neat, huh?  - DEL */
  87. static short    cursor_image[CUR_MAXIMAGEWORDS] = {
  88.         0x0000,0x03E0,0x0E38,0x1224,0x288A,0x288A,0x6223,0x6223,
  89.         0x4889,0x4889,0x6223,0x2222,0x288A,0x188C,0x0E38,0x03E0 };
  90. mpr_static (cursor_pr, 8 * sizeof (cursor_image[0]),
  91.     sizeof (cursor_image) / sizeof (cursor_image[0]), 1,
  92.     cursor_image);
  93.  
  94. #define IS_ASCII_EVENT(x) (x>=ASCII_FIRST && x<=ASCII_LAST)
  95. #define KEY_BUFFER_LENGTH    30
  96. char    key_buffer[KEY_BUFFER_LENGTH] = "";
  97.                 /* keys coming directly to the root window */
  98. int     key_buffer_length = 0;
  99. #define KEYITEMS    50
  100. struct menuitem key_items[KEYITEMS];
  101. struct menuitemstrings  key_itemstrings[KEYITEMS];
  102. struct menu     keymenubody = {
  103.     0, 0, 0,
  104. };
  105.  
  106. struct pixfont *sysfont;
  107.  
  108. #define SU_LABEL        "su"
  109. int label_x, label_y;        /* where the label is on the screen */
  110. struct rect su_rect;
  111. struct pr_subregion su_bound;
  112. struct pixrect *oldpr;        /* save old screen image here while we */
  113.                 /* scribble the SU_LABEL on it */
  114.  
  115. int     wants_su = FALSE;    /* true if user has requested setuid(0) */
  116. int     oldruid, oldrgid;    /* save the originals here */
  117. struct passwd *pwd;
  118.  
  119. main (argc, argv)
  120. int     argc;
  121. char  **argv;
  122. {
  123.     char    name[WIN_NAMESIZE],
  124.             setupfile[MAXNAMLEN];
  125.     int     _root_sigchldcatcher (), _root_sigwinchcatcher ();
  126.     int     donosetup = 0,
  127.             printname = 0;
  128.     unsigned char   red[256],
  129.                     green[256],
  130.                     blue[256];
  131.     struct pixrect *fb_pixrect;
  132.     int     fullplanes = 255;
  133.  
  134.     /* 
  135.      * Parse cmd line.
  136.      */
  137.     setupfile[0] = NULL;
  138.     win_initscreenfromargv (&screen, argv);
  139.     if (argv) {
  140.         char  **args;
  141.  
  142.         for (args = ++argv; *args; args++) {
  143.             if ((strcmp (*args, "-s") == 0) && *(args + 1)) {
  144.                 (void) strcpy (setupfile, *(args + 1));
  145.                 args++;
  146.             }
  147.             else if (strcmp (*args, "-F") == 0)
  148.                 rootcolor = ROOTCOLOR_FOREGROUND;
  149.             else if (strcmp (*args, "-B") == 0)
  150.                 rootcolor = ROOTCOLOR_BACKGROUND;
  151.             else if (strcmp (*args, "-P") == 0)
  152.                 rootcolor = ROOTCOLOR_PATTERN;
  153.             else if (strcmp (*args, "-n") == 0)
  154.                 donosetup = 1;
  155.             else if (strcmp (*args, "-p") == 0)
  156.                 printname = 1;
  157.             else if (strcmp (*args, "-S") == 0)
  158.                 wants_su = 1;
  159.             else if (argc == 2 && *args[0] != '-')/* 
  160.                  * If only arg and not a flag then treat as
  161.                  * setupfile (backward compatibility with 1.0).
  162.                  */
  163.                 (void) strcpy (setupfile, *args);
  164.         }
  165.     }
  166.  
  167.     oldrgid = getgid ();
  168.     oldruid = getuid ();
  169.  
  170.     if (NULL == (pwd = getpwnam("root"))) {
  171.         fprintf(stderr,"couldn't find root in passwd file?\n");
  172.         exit(1);
  173.     }
  174.     if (*pwd->pw_passwd != '\0') {
  175.         if (wants_su) {
  176.             if (geteuid() != 0) {
  177.                 fprintf(stderr,"suntools must be setuid(0)\n");
  178.                 exit(1);
  179.             }
  180.             if (strcmp(pwd->pw_passwd,
  181.                     crypt(getpass("Password: "),
  182.                         pwd->pw_passwd))) {
  183.                 fprintf(stderr,"Sorry\n");
  184.                 exit(1);
  185.             }
  186.         } else disable_su();
  187.     }
  188.     wants_su = FALSE;
  189.  
  190.     /* 
  191.      * Initialize root menu from menu file.
  192.      */
  193.     if ((rootmenufile = getenv ("ROOTMENU")) == NULL)
  194.         rootmenufile = ROOTMENUFILE;
  195.     /* added changeable root menu name - DEL */
  196.     if ((rootmenuname = getenv ("ROOTMENUNAME")) == NULL)
  197.         rootmenuname = ROOTMENUNAME;
  198.     if (wmgr_getrootmenu (rootmenuname, wmgr_rootmenu, rootmenufile,
  199.                 root_items, root_itemstrings, ROOTMENUITEMS) <= 0) {
  200.         fprintf (stderr, "suntools: invalid root menu\n");
  201.         exit (1);
  202.     }
  203.     /* 
  204.      * Set up signal catchers.
  205.      */
  206.     (void) signal (SIGCHLD, _root_sigchldcatcher);
  207.     (void) signal (SIGWINCH, _root_sigwinchcatcher);
  208.     /* 
  209.      * Find out what colormap is so can restore later.
  210.      * Do now before call win_screennew which changes colormap.
  211.      */
  212.     if (screen.scr_fbname[0] == NULL)
  213.         strcpy (screen.scr_fbname, "/dev/fb");
  214.     if ((fb_pixrect = pr_open (screen.scr_fbname)) == (struct pixrect      *) 0) {
  215.         fprintf (stderr, "suntools: invalid frame buffer %s\n",
  216.             screen.scr_fbname);
  217.         exit (1);
  218.     }
  219.                                                                             pr_getcolormap (fb_pixrect, 0, 256, red, green, blue);
  220.     /* 
  221.      * Create root window
  222.      */
  223.     if ((rootfd = win_screennew (&screen)) == -1) {
  224.         perror ("suntools");
  225.         exit (1);
  226.     }
  227.     
  228.     init_cursor();
  229.  
  230.     if (rootcolor != ROOTCOLOR_PATTERN) {
  231.         struct cursor   cursor;
  232.  
  233.         cursor.cur_shape = &cursor_pr;
  234.         win_getcursor (rootfd, &cursor);
  235.         cursor.cur_function = PIX_SRC ^ PIX_DST;
  236.  
  237.         win_setcursor (rootfd, &cursor);
  238.     }
  239.     win_screenget (rootfd, &screen);
  240.     /* 
  241.      * Open pixwin.
  242.      */
  243.     if ((pixwin = pw_open (rootfd)) == 0) {
  244.         fprintf (stderr, "%s not available for window system usage\n",
  245.                 screen.scr_fbname);
  246.         perror ("suntools");
  247.         exit (1);
  248.     }
  249.     /* 
  250.      * Set up root's name in environment
  251.      */
  252.     win_fdtoname (rootfd, name);
  253.     rootnumber = win_nametonumber (name);
  254.     we_setparentwindow (name);
  255.     if (printname)
  256.         fprintf (stderr, "suntools window name is %s\n", name);
  257.     /* 
  258.      * Set up tool slot allocator
  259.      */
  260.     wmgr_setrectalloc (rootfd, 200, 40,
  261.             0, pixwin -> pw_pixrect -> pr_height - TOOL_ICONHEIGHT);
  262.     /* 
  263.      * Setup tty parameters for all terminal emulators that will start.
  264.      */
  265.     {
  266.         int     tty_fd;
  267.         tty_fd = open ("/dev/tty", O_RDWR, 0);
  268.         if (tty_fd < 0)
  269.             ttysw_saveparms (2);/* Try stderr */
  270.         else {
  271.             ttysw_saveparms (tty_fd);
  272.             (void) close (tty_fd);
  273.         }
  274.     }
  275.  
  276.     /*
  277.          * setup su hack - DEL
  278.      */
  279.  
  280.     /* find bounding box */
  281.     su_bound.pr = pixwin -> pw_pixrect;
  282.     su_bound.pos.x = 0;
  283.     su_bound.pos.y = 0;
  284.  
  285.     sysfont = pw_pfsysopen ();
  286.     pf_textbound (&su_bound, strlen (SU_LABEL), sysfont, SU_LABEL);
  287.     su_rect.r_width = su_bound.size.x;
  288.     su_rect.r_height = su_bound.size.y;
  289.  
  290.     /* create pixrect to save screen while scribbling on it */
  291.     oldpr = mem_create (su_bound.size.x, su_bound.size.y, 1);
  292.  
  293.     /* 
  294.      * Draw background.
  295.      */
  296.     _root_sigwinchhandler ();
  297.  
  298.     /* 
  299.      * Do initial window setup.
  300.      */
  301.     if (!donosetup)
  302.         _root_initialsetup (setupfile);
  303.  
  304.     /* 
  305.      * Do window management loop.
  306.      */
  307.     _root_winmgr ();
  308.     /* 
  309.      * Destroy screen sends SIGTERMs to all existing windows and
  310.      * wouldn't let any windows install themselves in the window tree.
  311.      * Calling process of win_screedestroy is spared SIGTERM.
  312.      */
  313.     win_screendestroy (rootfd);
  314.     /* 
  315.      * Lock screen before clear so don't clobber frame buffer while
  316.      * cursor moving.
  317.      */
  318.     pw_lock (pixwin, &screen.scr_rect);
  319.     /* 
  320.      * Enable writing to entire depth of frame buffer.
  321.      */
  322.     pr_putattributes (fb_pixrect, &fullplanes);
  323.     /* 
  324.      * Clear entire frame buffer.
  325.      */
  326.     pr_rop (fb_pixrect, screen.scr_rect.r_left, screen.scr_rect.r_top,
  327.             screen.scr_rect.r_width, screen.scr_rect.r_height, PIX_CLR, 0, 0, 0);
  328.     /* 
  329.      * Reset previous colormap.
  330.      */
  331.     pr_putcolormap (fb_pixrect, 0, 256, red, green, blue);
  332.     /* 
  333.      * Unlock screen.
  334.      */
  335.     pw_unlock (pixwin);
  336.     exit (0);
  337. }
  338.  
  339. _root_winmgr () {
  340.     struct inputmask        im;
  341.     struct inputevent       event;
  342.     struct menuitem *mi;
  343.     extern struct menuitem *menu_display ();
  344.     int     keyexit = 0,
  345.             exit;
  346.  
  347.     /* 
  348.      * Set up input mask so can do menu stuff
  349.      */
  350.     input_imnull (&im);
  351.     im.im_flags |= IM_NEGEVENT;
  352.     im.im_flags |= IM_ASCII;
  353.     win_setinputcodebit (&im, SELECT_BUT);
  354.     win_setinputcodebit (&im, MENU_BUT);
  355.     /* by enabling LOC_MOVE, we can discard the input buffer when the */
  356.     /* mouse moves. */
  357.     win_setinputcodebit (&im, LOC_MOVE);
  358.     win_setinputmask (rootfd, &im, (struct inputmask *) 0, WIN_NULLLINK);
  359.     /* 
  360.      * Read and invoke menu items
  361.      */
  362.     for (;;) {
  363.         int     ibits,
  364.                 nfds;
  365.  
  366.         /* 
  367.          * Use select (to see if have input) so will return on
  368.          * SIGWINCH or SIGCHLD.
  369.          */
  370.         ibits = 1 << rootfd;
  371.         do {
  372.             if (root_SIGCHLD)
  373.                 _root_sigchldhandler ();
  374.             if (root_SIGWINCH)
  375.                 _root_sigwinchhandler ();
  376.         } while (root_SIGCHLD || root_SIGWINCH);
  377.         nfds = select (8 * sizeof (ibits), &ibits, (int *) 0, (int *) 0,
  378.                 (struct timeval *) 0);
  379.         if (nfds == -1) {
  380.             if (errno == EINTR)/* 
  381.                  * Go around again so that signals can be
  382.                  * handled.  ibits may be non-zero but should
  383.                  * be ignored in this case and they will be
  384.                  * selected again.
  385.                  */
  386.                 continue;
  387.             else {
  388.                 perror ("suntools");
  389.                 break;
  390.             }
  391.         }
  392.         if (ibits & (1 << rootfd)) {
  393.             /* 
  394.              * Read will not block.
  395.              */
  396.             if (input_readevent (rootfd, &event) < 0) {
  397.                 if (errno != EWOULDBLOCK) {
  398.                     perror ("suntools");
  399.                     break;
  400.                 }
  401.             }
  402.         }
  403.         else
  404.             continue;
  405.  
  406.         if (win_inputnegevent (&event))
  407.             continue;
  408.  
  409.         if (IS_ASCII_EVENT (event.ie_code)) {
  410.             int     i;
  411.  
  412.             /* add to key input buffer */
  413.             if (isupper (event.ie_code)) {
  414.                 event.ie_code = tolower (event.ie_code);
  415.                 wants_su = TRUE;
  416.             }
  417.             key_buffer[key_buffer_length] = event.ie_code;
  418.             key_buffer_length += (key_buffer_length > KEY_BUFFER_LENGTH ? 0 : 1);
  419.             key_buffer[key_buffer_length] = '\0';
  420.             for (i = 0; i < keymenubody.m_itemcount; i++) {
  421.                 if (strcmp (keymenubody.m_items[i].mi_imagedata,
  422.                             key_buffer) == 0)
  423.                     break;
  424.             }
  425.             if (i >= keymenubody.m_itemcount)
  426.                 continue;/* not found */
  427.  
  428.             exit = wmgr_handlerootmenuitem ((struct menu   *) NULL /* not used! */ ,
  429.                                                                &keymenubody.m_items[i], rootfd) == -1;
  430.             if (exit)
  431.                 break;/* exit suntools */
  432.             /* zap buffer now that we have used it */
  433.             /* for now this occurs simply by falling through */
  434.         }
  435.         key_buffer_length = 0;
  436.         key_buffer[0] = '\0';
  437.         wants_su = FALSE;
  438.  
  439.         if (event.ie_code != MENU_BUT)
  440.             continue;
  441.  
  442.         if (wants_su = (event.ie_shiftmask & SHIFTMASK)) {
  443.             struct pr_prpos textpos;
  444.  
  445.             /* move to the left by its width, so its right flush 
  446.             */
  447.             /* against the menu */
  448.             su_rect.r_left = event.ie_locx - su_bound.size.x;
  449.             /* origin for text is from the bottom, so subtract its
  450.                /* its height */
  451.             su_rect.r_top = event.ie_locy - sysfont -> pf_defaultsize.y;
  452.             /* ignore going off the screen, since clipping is
  453.                enabled */
  454.  
  455.             pw_lock (pixwin, &su_rect);
  456.             /* save whats lying on the screen */
  457.             pr_rop (oldpr, 0, 0, su_rect.r_width, su_rect.r_height,
  458.                     PIX_SRC, pixwin -> pw_pixrect,
  459.                     su_rect.r_left, su_rect.r_top);
  460.             textpos.pr = pixwin -> pw_pixrect;
  461.             textpos.pos.x = su_rect.r_left;
  462.             textpos.pos.y = su_rect.r_top
  463.                 - /* distance to baseline */ sysfont -> pf_char['a'].pc_home.y;
  464.             /* textpos is a structure passed by value!?! - DEL */
  465.             pf_text (textpos, PIX_SRC, sysfont, SU_LABEL);
  466.             pw_unlock (pixwin);
  467.         }
  468.  
  469.         /* 
  470.          * Do menus
  471.          */
  472.         if (wmgr_getrootmenu (rootmenuname, wmgr_rootmenu, rootmenufile,
  473.                     root_items, root_itemstrings, ROOTMENUITEMS) <= 0) {
  474.             fprintf (stderr, "suntools: invalid root menu\n");
  475.             continue;
  476.         }
  477.         for (;;) {
  478.             struct inputevent       tevent;
  479.  
  480.             exit = 0;
  481.             tevent = event;
  482.             mi = menu_display (&wmgr_rootmenu, &event, rootfd);
  483.             if (mi)
  484.                 exit = wmgr_handlerootmenuitem (wmgr_rootmenu, mi, rootfd) == -1;
  485.             if (event.ie_code == MS_LEFT && !exit) {
  486.                 event = tevent;
  487.                 /*         
  488.                    win_setmouseposition(rootfd, event.ie_locx,
  489.                    event.ie_locy); */
  490.             }
  491.             else {
  492.                 break;
  493.             }
  494.         }
  495.         if (exit)
  496.             break;    /* exit suntools */
  497.         if (wants_su) {
  498.             /* restore what was lying on screen */
  499.             pw_lock (pixwin, &su_rect);
  500.             pr_rop (pixwin -> pw_pixrect,
  501.                     su_rect.r_left, su_rect.r_top,
  502.                     su_rect.r_width, su_rect.r_height,
  503.                     PIX_SRC, oldpr, 0, 0);
  504.             pw_unlock (pixwin);
  505.             wants_su = FALSE;
  506.         }
  507.     }
  508. }
  509.  
  510. _root_sigchldhandler () {
  511.     union wait status;
  512.  
  513.     root_SIGCHLD = 0;
  514.     while (wait3 (&status, WNOHANG, (struct rusage *) 0) > 0) {
  515.     }
  516. }
  517.  
  518. _root_sigwinchhandler()
  519. {
  520.     root_SIGWINCH = 0;
  521.     pw_damaged (pixwin);
  522.     switch (rootcolor) {
  523.     case ROOTCOLOR_PATTERN: 
  524.         pw_replrop(pixwin,
  525.             screen.scr_rect.r_left, screen.scr_rect.r_top,
  526.             screen.scr_rect.r_width, screen.scr_rect.r_height,
  527.             PIX_SRC, tool_bkgrd, 0, 0);
  528.         break;
  529.     default: 
  530.         pw_writebackground(pixwin,
  531.             screen.scr_rect.r_left, screen.scr_rect.r_top,
  532.             screen.scr_rect.r_width, screen.scr_rect.r_height,
  533.             (rootcolor == ROOTCOLOR_BACKGROUND)?PIX_CLR:PIX_SET);
  534.     }
  535.  
  536.     pw_donedamaged (pixwin);
  537.     return;
  538. }
  539.  
  540. static
  541.         _root_sigchldcatcher () {
  542.             root_SIGCHLD = 1;
  543. }
  544.  
  545. static
  546.         _root_sigwinchcatcher () {
  547.             root_SIGWINCH = 1;
  548. }
  549.  
  550. char   *
  551.         _get_home_dir () {
  552.     extern char    *getlogin ();
  553.     extern struct passwd   *getpwnam (), *getpwuid ();
  554.     struct passwd  *passwdent;
  555.     char   *home_dir = getenv ("HOME"), *loginname;
  556.  
  557.     if (home_dir != NULL)
  558.         return (home_dir);
  559.     loginname = getlogin ();
  560.     if (loginname == NULL) {
  561.         passwdent = getpwuid (getuid ());
  562.     }
  563.     else {
  564.         passwdent = getpwnam (loginname);
  565.     }
  566.     if (passwdent == NULL) {
  567.         fprintf(stderr,
  568.             "suntools: couldn't find user in password file.\n");
  569.         return (NULL);
  570.     }
  571.     if (passwdent -> pw_dir == NULL) {
  572.         fprintf (stderr,
  573.             "suntools: no home directory in password file.\n");
  574.         return (NULL);
  575.     }
  576.     return (passwdent -> pw_dir);
  577. }
  578.  
  579. #define    ROOT_ARGBUFSIZE        1000
  580. #define    ROOT_SETUPFILE        "/.suntools"
  581. #define    ROOT_MAXTOOLDELAY    10
  582.  
  583. _root_initialsetup (requestedfilename)
  584. char   *requestedfilename;
  585. {
  586.     register        i;
  587.     FILE * file;
  588.     char    filename[MAXNAMLEN],
  589.             programname[MAXNAMLEN],
  590.             otherargs[ROOT_ARGBUFSIZE];
  591.     struct rect     rectnormal,
  592.                     recticonic;
  593.     int     iconic,
  594.             topchild,
  595.             bottomchild,
  596.             seconds,
  597.             j;
  598.     char    line[200];
  599.  
  600.     if (requestedfilename[0] == NULL) {
  601.         char   *home_dir = _get_home_dir ();
  602.         if (home_dir == NULL)
  603.             return;
  604.         (void) strcpy (filename, home_dir);
  605.         (void) strncat (filename, ROOT_SETUPFILE, sizeof (filename) - 1 -
  606.                 strlen (filename) - strlen (ROOT_SETUPFILE));
  607.     }
  608.     else
  609.         (void) strncpy (filename, requestedfilename, sizeof (filename) - 1);
  610.     if ((file = fopen (filename, "r")) == 0) {
  611.         if (requestedfilename[0] == NULL)
  612.                 /* 
  613.                  * No message if was trying to open default.
  614.                  */
  615.             return;
  616.         fprintf (stderr, "suntools: couldn't open %s\n", filename);
  617.         return;
  618.     }
  619.     while (fgets (line, sizeof (line), file)) {
  620.         if (line[0] == '#')
  621.             continue;
  622.         otherargs[0] = '\0';
  623.         programname[0] = '\0';
  624.         i = sscanf (line, "%s%hd%hd%hd%hd%hd%hd%hd%hd%hD%[^\n]\n",
  625.                 programname,
  626.                 &rectnormal.r_left, &rectnormal.r_top,
  627.                 &rectnormal.r_width, &rectnormal.r_height,
  628.                 &recticonic.r_left, &recticonic.r_top,
  629.                 &recticonic.r_width, &recticonic.r_height,
  630.                 &iconic, otherargs);
  631.         if (i == EOF)
  632.             break;
  633.         if (i < 10 || i > 11) {
  634.             /* 
  635.              * Just get progname and args.
  636.              */
  637.             otherargs[0] = '\0';
  638.             programname[0] = '\0';
  639.             j = sscanf (line, "%s%[^\n]\n", programname, otherargs);
  640.             if (j > 0) {
  641.                 iconic = 0;
  642.                 rect_construct (&recticonic, WMGR_SETPOS, WMGR_SETPOS,
  643.                         WMGR_SETPOS, WMGR_SETPOS);
  644.                 rect_construct (&rectnormal, WMGR_SETPOS, WMGR_SETPOS,
  645.                         WMGR_SETPOS, WMGR_SETPOS);
  646.             }
  647.             else {
  648.                 fprintf (stderr,
  649.                         "suntools: in file=%s fscanf gave %D, correct format is:\n",
  650.                         filename, i);
  651.                 fprintf (stderr,
  652.                         "program open-left open-top open-width open-height close-left close-top close-width close-height iconicflag [args] <newline>\n OR\nprogram [args] <newline>\n");
  653.                 continue;
  654.             }
  655.         }
  656.         /* 
  657.          * Handle WMGR_SETPOS requests.
  658.          */
  659.         wmgr_figuretoolrect (rootfd, &rectnormal);
  660.         wmgr_figureiconrect (rootfd, &recticonic);
  661.         /* 
  662.          * Remember who top and bottom children windows are for use when
  663.          * trying to determine when tool is installed.
  664.          */
  665.         topchild = win_getlink (rootfd, WL_TOPCHILD);
  666.         bottomchild = win_getlink (rootfd, WL_BOTTOMCHILD);
  667.         /* 
  668.          * Fork tool.
  669.          */
  670.         /* 
  671.          (void) wmgr_forktool (programname, otherargs,
  672.          &rectnormal, &recticonic, iconic);
  673.          */
  674.  
  675.         del_forktool (programname, otherargs, &rectnormal, &recticonic, iconic);
  676.         /* 
  677.          * Give tool chance to intall self in tree before starting next.
  678.          */
  679.         for (seconds = 0; seconds < ROOT_MAXTOOLDELAY; seconds++) {
  680.             sleep (1);
  681.             if (topchild != win_getlink (rootfd, WL_TOPCHILD) ||
  682.                     bottomchild != win_getlink (rootfd, WL_BOTTOMCHILD))
  683.                 break;
  684.         }
  685.     }
  686.     (void) fclose (file);
  687. }
  688.  
  689. int
  690.         wmgr_rootmenuschanged (menu)
  691. struct menu    *menu;
  692. {
  693.     struct stat     statb;
  694.     int     sa_count;
  695.  
  696.     /* Whenever existing menu going up, stat menu files */
  697.     for (sa_count = 0; sa_count < menu_next; sa_count++) {
  698.         if (stat (stat_array[sa_count].name, &statb) < 0) {
  699.             if (errno == ENOENT)
  700.                 return (1);
  701.             fprintf (stderr, "suntools: ");
  702.             perror (stat_array[sa_count].name);
  703.             return (-1);
  704.         }
  705.         if (statb.st_mtime > stat_array[sa_count].mftime)
  706.             return (1);
  707.     }
  708.     return (0);
  709. }
  710.  
  711. wmgr_freerootmenus (menu)
  712. struct menu    *menu;
  713. {
  714.     int     sa_count = 0;
  715.     struct menu    *next = menu -> m_next,
  716.                    *nnext;
  717.  
  718.     while (next) {
  719.         nnext = next -> m_next;
  720.         if (next -> m_items) {
  721.             free (next -> m_items -> mi_data);
  722.                 /* free string storage */
  723.             free (next -> m_items);/* item storage */
  724.         }
  725.         free (next);    /* menu storage */
  726.         next = nnext;
  727.     }
  728.     while (sa_count < menu_next) {
  729.         free (stat_array[sa_count].name);/* file name */
  730.         stat_array[sa_count].name = NULL;
  731.         stat_array[sa_count].mftime = 0;
  732.         sa_count++;
  733.     }
  734.     menu_next = 0;
  735. }
  736.  
  737. wmgr_getrootmenu (mn, menu, mf, mi, mis, maxitems)
  738. char   *mn,
  739.        *mf;
  740. struct menu    *menu;
  741. struct menuitem *mi;
  742. struct menuitemstrings *mis;
  743. int     maxitems;
  744. {
  745.     FILE * f;
  746.     int     lineno;
  747.     char    line[256];
  748.     char    tag[256],    /* was 32 - DEL */
  749.             prog[256],
  750.             args[256];
  751.     char   *savestr ();
  752.     struct stat     statb;
  753.     struct menu    *menunext = wmgr_rootmenu;
  754.     int     nitems = 0;
  755.     static  time_t mftime = 0;
  756.     static char    *nqformat = "%[^ \t\n]%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n";
  757.     static char    *qformat = "\"%[^\"]\"%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n";
  758.  
  759.     if (menu == wmgr_rootmenu && menu_next != 0) {
  760.         if (wmgr_rootmenuschanged (wmgr_rootmenu) != 0)
  761.             wmgr_freerootmenus (wmgr_rootmenu);
  762.         else
  763.             return menu -> m_itemcount;
  764.     }
  765.     if (menu_next >= MAX_MENUS - 1) {
  766.         fprintf (stderr,
  767.                 "suntools: max number of menus is %D\n", MAX_MENUS);
  768.         return - 1;
  769.     }
  770.     if ((f = fopen (mf, "r")) == NULL) {
  771.         fprintf (stderr, "suntools: can't open menu file %s\n", mf);
  772.         return - 1;
  773.     }
  774.     if (stat (mf, &statb) < 0) {
  775.         fprintf (stderr, "suntools: ");
  776.         perror (mf);
  777.         return - 1;
  778.     }
  779.     stat_array[menu_next].mftime = statb.st_mtime;
  780.     stat_array[menu_next].name = savestr (mf);
  781.     ++menu_next;
  782.     menu -> m_imagetype = MENU_IMAGESTRING;
  783.     menu -> m_imagedata = mn;
  784.     menu -> m_items = mi;
  785.     for (nitems = 0, lineno = 1; nitems < maxitems &&
  786.             fgets (line, sizeof (line), f); lineno++) {
  787.         if (line[0] == '#')
  788.             continue;
  789.         args[0] = '\0';
  790.         if (sscanf (line, line[0] == '"' ? qformat : nqformat,
  791.                     tag, prog, args) < 2) {
  792.             fprintf (stderr,
  793.                     "suntools: format error in %s: line %d\n",
  794.                     mf, lineno);
  795.             mftime = 0;/* complain every time */
  796.             continue;
  797.         }
  798.         if (strcmp (prog, "KEYS") == 0) {
  799.             /* check for calling only from root menu...bah! */
  800.             if (wmgr_getrootmenu ("keys" /* menu name */ ,
  801.                         &keymenubody, /* key file name */ args,
  802.                         &key_items[0], &key_itemstrings[0],
  803.                         KEYITEMS) <= 0) {
  804.                 fprintf (stderr, "suntools: bad key menu %s\n", args);
  805.                 continue;
  806.             }
  807.             /* do not link this menu in with others!!! */
  808.             /* it will not be displayed! */
  809.         }
  810.         else if (strcmp (prog, "MENU") == 0) {
  811.             struct menu    *m;
  812.             char   *mi,
  813.                    *ms;
  814.             if (menu != wmgr_rootmenu) {
  815.                 fprintf (stderr,
  816.                         "suntools: MENU command illegal in secondary menu file %s: line %d\n",
  817.                         mf, lineno);
  818.                 continue;
  819.             }
  820.             if (wmgr_getrootmenu (
  821.                         savestr (tag),/* menu name */
  822.                         m = (struct menu       *)
  823.                                             calloc (1, sizeof (struct menu)), args,
  824.                      /* file name */                                        mi = calloc (ROOTMENUITEMS, sizeof (struct menuitem))  ,
  825.                                                                                                                                     ms = calloc (ROOTMENUITEMS, sizeof (struct menuitemstrings))   ,
  826.                                                                                                                                                                                                     ROOTMENUITEMS) <= 0) {
  827.                 fprintf (stderr,
  828.                     "suntools: invalid secondary menu %s\n", args);
  829.                 free (m);
  830.                 free (mi), free (ms);
  831.                 continue;
  832.             }
  833.             else {
  834.                                                                                                                                                                                                 menunext -> m_next = m;
  835.                 menunext = m;
  836.             }
  837.         }
  838.         else {
  839.             if (mi -> mi_imagedata)
  840.                 free ((char *) mi -> mi_imagedata);
  841.             mi -> mi_imagetype = MENU_IMAGESTRING;
  842.             mi -> mi_imagedata = (caddr_t) savestr (tag);
  843.             mi -> mi_data = (caddr_t) mis;
  844.             if (mis -> mis_prog)
  845.                 free (mis -> mis_prog);
  846.             if (mis -> mis_args)
  847.                 free (mis -> mis_args);
  848.             mis -> mis_prog = savestr (prog);
  849.             if (args[0] == '\0')
  850.                 mis -> mis_args = (char *) NULL;
  851.             else
  852.                 mis -> mis_args = savestr (args);
  853.             mi++;
  854.             mis++;
  855.             nitems++;
  856.         }
  857.     }
  858.     fclose (f);
  859.     return menu -> m_itemcount = nitems;
  860. }
  861.  
  862. char   *
  863.         savestr (s)
  864. register char  *s;
  865. {
  866.     register char  *p;
  867.  
  868.     if ((p = malloc (strlen (s) + 1)) == NULL) {
  869.         if (rootfd)
  870.             win_screendestroy (rootfd);
  871.         fprintf (stderr, "suntools: out of memory for menu strings\n");
  872.         exit (1);
  873.     }
  874.     strcpy (p, s);
  875.     return (p);
  876. }
  877.  
  878. wmgr_handlerootmenuitem (menu, mi, rootfd)
  879. struct menu    *menu;
  880. struct menuitem *mi;
  881. int     rootfd;
  882. {
  883.     int     returncode = 0;
  884.     struct rect     recticon,
  885.                     rectnormal;
  886.     struct menuitemstrings *mis;
  887.  
  888.     /* 
  889.      * Get next default tool positions
  890.      */
  891.     rect_construct (&recticon, WMGR_SETPOS, WMGR_SETPOS,
  892.             WMGR_SETPOS, WMGR_SETPOS);
  893.     rectnormal = recticon;
  894.     mis = (struct menuitemstrings  *) mi -> mi_data;
  895.     if (strcmp (mis -> mis_prog, "EXIT_NOCONFIRM") == 0) {
  896.         returncode = -1;
  897.     }
  898.     else if (strcmp (mis -> mis_prog, "EXIT") == 0) {
  899.         returncode = wmgr_confirm (rootfd,
  900.                 "Press the left mouse button to confirm Exit.  \
  901. To cancel, press the right mouse button now.");
  902.     }
  903.     else if (strcmp (mis -> mis_prog, "REFRESH") == 0) {
  904.         wmgr_refreshwindow (rootfd);
  905.     }
  906.     else if (strcmp (mis -> mis_prog, "HELP") == 0) {
  907.         wmgr_confirm (rootfd, "Right mouse down displays menus.  \
  908. Right mouse up selects.  \
  909. Left mouse down selects without losing menus.  \
  910. Holding shift key down before right mouse enables superuser.  \
  911. Press any key to remove this garbage.");
  912.     }
  913.     else if (strcmp (mis -> mis_prog, "VERSION") == 0) {
  914.         wmgr_confirm(rootfd,"suntools 1.2.4 (9/26/85) by Don Libes \
  915. at NBS (nbs-amrf!libes).  Based on suntools 1.2 (3/13/85) by unknown \
  916. at SMI.  Press any key to remove this garbage.");
  917.     }
  918.     else {
  919.         wmgr_figureiconrect (rootfd, &recticon);
  920.         wmgr_figuretoolrect (rootfd, &rectnormal);
  921.         del_forktool (mis -> mis_prog, mis -> mis_args,
  922.                 &rectnormal, &recticon, 0 /* not iconic */ );
  923.     }
  924.     return (returncode);
  925. }
  926.  
  927. enable_su () {
  928.     if (setuid (0)) perror ("setuid(0)");
  929.     setgid (1);
  930. }
  931.  
  932. disable_su () {
  933.     setgid (oldrgid);
  934.     if (setuid (oldruid)) perror ("setuid(oldruid)");
  935. }
  936.  
  937. del_forktool (program, args, open_rect, closed_rect, iconic)
  938. char   *program, *args;
  939. struct rect     open_rect, closed_rect;
  940. int     iconic;
  941. {
  942.     if (0 == fork ()) {    /* child */
  943.         char    buffer[5000];/* space for program name and args */
  944.         /* if doesn't have rectnormal, add it */
  945.         /* if doesn't have recticon, add it */
  946.         /* if it doesn't have iconic, add it if iconic */
  947.         if (wants_su && (geteuid() == 0))
  948.             enable_su ();
  949.         else
  950.             disable_su ();
  951.         if (args)
  952.             sprintf (buffer, "%s %s", program, args);
  953.         else
  954.             strcpy (buffer, program);
  955.  
  956.         /*
  957.            now exec the program.  Only problem is we have the
  958.            prog name and args in a character string.  We have
  959.            to tokenize them in order to call exec or exec sh
  960.            and have that do it for us.  But that will create
  961.            two processes for every one.
  962.         */
  963.         /* execl ("/bin/sh", "sh", "-c", buffer, 0);*/
  964.         del_exec(buffer);
  965.         _exit (127);
  966.     }
  967. }
  968.  
  969. #define end_token if (in_token) {        \
  970.     /* terminate current token */    *cp = '\0';        \
  971.     /* advance to next token */    args[++argi] = cp = ++s;\
  972.     /* not sure if there is anything valid here, so */ in_token = FALSE; }\
  973.     else s++;
  974.  
  975. /* exec a program and args that are all stored as one string */
  976. del_exec(s)
  977. char *s;
  978. {
  979.     char *args[50];
  980.     char *cp;
  981.     int argi = 0;
  982.     int quoting = FALSE;
  983.     int in_token = FALSE;    /* TRUE if we are reading a token */
  984.  
  985.     args[0] = cp = s;
  986.     while (*s) {
  987.         if (quoting) {
  988.             if (*s == '\\' && *(s+1) == '"') { /* quoted quote */
  989.                 s++;    /* get past " */
  990.                 *cp++ = *s++;
  991.             } else     if (*s == '\"') { /* close quote */
  992.                 end_token
  993.                 quoting = FALSE;
  994.             } else *cp++ = *s++; /* suck up anything */
  995.         } else if (*s == '\"') { /* open quote */
  996.             in_token = TRUE;
  997.             quoting = TRUE;
  998.             s++;
  999.         } else if (isspace(*s)) {
  1000.             end_token
  1001.         } else {
  1002.             *cp++ = *s++;
  1003.             in_token = TRUE;
  1004.         }
  1005.     }
  1006.     end_token
  1007.     args[argi] = (char *) 0; /* terminate argv */
  1008.     execvp(args[0],args);
  1009. }
  1010.  
  1011. /* allow user to set cursor attributes - DEL */
  1012. init_cursor()
  1013. {
  1014.     struct cursor cursor;
  1015.     char *cursorfile, *x_hot, *y_hot, *cursor_rop;    /* environment parms */
  1016.  
  1017.     cursor.cur_shape = &cursor_pr;
  1018.  
  1019.     /* default cursor is a weird looking dot */
  1020.     cursor.cur_xhot = 8;
  1021.     cursor.cur_yhot = 8;
  1022.     cursor.cur_function = PIX_SRC | PIX_DST;
  1023.     win_setcursor(rootfd,&cursor);
  1024.  
  1025.     /* win_getcursor(rootfd, &cursor); */
  1026.     if (cursorfile = getenv("ROOT_CURSOR")) {
  1027.         char errmsg[1000];
  1028.  
  1029.         if (cursor.cur_shape = icon_load_mpr(cursorfile,errmsg)) {
  1030.             if (x_hot = getenv("ROOT_CURSOR_HOTSPOT_X"))
  1031.                 cursor.cur_xhot = atoi(x_hot);
  1032.             if (y_hot = getenv("ROOT_CURSOR_HOTSPOT_Y"))
  1033.                 cursor.cur_yhot = atoi(y_hot);
  1034.             if (cursor_rop = getenv("ROOT_CURSOR_ROP"))
  1035.                 cursor.cur_function = atoi(cursor_rop);
  1036.             win_setcursor(rootfd,&cursor);
  1037.         } else printf(errmsg);
  1038.     }
  1039. }
  1040.