Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: Improved version of Sun's window manager (suntools) for 2.0 Message-ID: <1330@panda.UUCP> Date: 22 Jan 86 14:57:06 GMT Sender: jpn@panda.UUCP Lines: 1258 Approved: jpn@panda.UUCP Mod.sources: Volume 3, Issue 91 Submitted by: seismo!nbs-amrf!libes (Don Libes) #!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # README # suntools.c # This archive created: Sun Nov 24 20:10:54 1985 export PATH; PATH=/bin:$PATH if test -f 'Makefile' then echo shar: over-writing existing file "'Makefile'" fi cat << \SHAR_EOF > 'Makefile' DESTDIR=/usr/local/bin CFLAGS= -O LDFLAGS= -O LIBS= -lsuntool -lsunwindow -lpixrect suntools: suntools.o cc ${LDFLAGS} -o suntools suntools.o ${LIBS} chmod 4755 suntools mv suntools $(DESTDIR) shar: suntools.c README Makefile suntools.o: /usr/include/suntool/tool_hs.h /usr/include/sys/ioctl.h suntools.o: /usr/include/sys/dir.h /usr/include/sys/file.h suntools.o: /usr/include/sys/wait.h /usr/include/sys/resource.h suntools.o: /usr/include/sys/stat.h /usr/include/errno.h /usr/include/stdio.h suntools.o: /usr/include/pwd.h /usr/include/suntool/menu.h suntools.o: /usr/include/suntool/wmgr.h SHAR_EOF chmod +x 'Makefile' if test -f 'README' then echo shar: over-writing existing file "'README'" fi cat << \SHAR_EOF > 'README' This file describes additions by nbs-amrf!libes to Sun's suntools program (version 1.2) that was distributed with 2.0. BRIEF DESCRIPTION Menu selections are allowed from the keyboard. Tools may be run setuid(0) by pressing the shift key down while the menus are brought up. The user may specify the primary menu name. The user may specify the shape, and rasterop used by the root cursor. The one incompatibility introduced is that the 9 numerical fields in the .suntools files are now ignored. However, these are of dubious value anyway since they are incomplete, contradictory and their effect can be achieved by using the -W tool arguments. LONG DESCRIPTION Unified key mechanism Menu entries may be invoked from the keyboard, by creating a "key" menu (using KEYS instead of MENU in the rootmenu). To invoke a menu item off the key menu, simply type the tag associated with the menu. Keystrokes are stored in a key stroke buffer until a key menu tag is matched or the mouse is moved. For example, my root menu looks as follows: "big shell (b)" /usr/bin/shelltool -Ww 80 -Wh 56 -Wp 506 0 -Wn -WL "big shell" "console (c)" /usr/bin/shelltool -C -Ww 50 -Wh 12 -Wp 0 0 -Wn -WL "console" -Wt /usr/lib/fonts/fixedwidthfonts/sail.r.6 "debugger (d)" /usr/bin/dbxtool "graphics (g)" /usr/bin/gfxtool "rlogin" MENU /usr2/libes/environ/rloginmenu "fun and games" MENU /usr2/libes/environ/toolmenu "Coke Classic" KEYS /usr2/libes/environ/keymenu Note, that the key menu file is not displayed in the stack of menus, hence the tag is simply a place-holder. Since key associations are not displayed, people typically include the same entries in other (visible) menus with the key tags in parens (ala Macintosh). My key menu is as follows: b /usr/bin/shelltool -Ww 80 -Wh 56 -Wp 502 0 -Wn -WL "big csh" c /usr/bin/shelltool -C -Ww 50 -Wh 12 -Wp 0 0 -Wn -WL "console" -Wt /usr/lib/fonts/fixedwidthfonts/sail.r.6 d /usr/bin/dbxtool s /usr/bin/shelltool "g" /usr/bin/gfxtool "r" REFRESH EXIT_NOCONFIRM "?" HELP = VERSION v /usr/bin/shelltool -Wl "vex" -WL "" -WI /usr/local/icon/vax.icon rlogin nbs-amrf k /usr/bin/shelltool -Wl "Kanamid at your service. May I take your order?" -WL "" -WI /usr/local/icon/kanamid.icon rlogin kanamid Notice that multiple keystroke tags are available. They should be quoted if containing blanks or other whitespace. New keywords The menu above also demonstrates several other keywords that are available. EXIT_NOCONFIRM is like EXIT, but it does not confirm that you want to exit. HELP puts up a help box for suntools. VERSION prints out the current version of suntools. New environment variables Several environment variables were added for more flexibility. ROOTMENUNAME is a string that is used as the name of the primary menu. As distributed from Sun (and by default in this version), it is "Suntools". ROOT_CURSOR is a cursor that is used as the root menu cursor. Since this cursor isn't used to point to anything, it seemed odd to use an arrow. A much more interesting cursor is the default in this version. ROOT_CURSOR_ROP is the rasterop function associated with the cursor. This should be an integer. For example, the default raster-op in this version of suntools is 28, which corresponds to or-ing the source and destination. The raster-op used in the original suntools was 24 (source). For more information, see . ROOT_CURSOR_HOTSPOT_X sets the cursor hotspot in the x axis. ROOT_CURSOR_HOTSPOT_Y sets the cursor hotspot in the y axis. The default for both of these is 8 - the middle of the cursor. Superuser shortcut This feature is enabled for anyone who can supply the root password when starting suntools, or everyone if there is no root password (as at our installation, believe it or not). If there is a root password, and suntools is started with the -S flag, the user is prompted for the root password. If it is correct, the running suntools will have the superuser shortcut enabled. When the shortcut is enabled, the user may invoke tools with setuid(0) by pressing the shift key down before bringing up the menus (or typing a key to the root window). If the mouse is used to raise the menus, a little "su" appears to the left of the menu. Besides being a tremendous convenience, this squeezes the tool and su processes down into one. We use it a lot as follows - while sitting at a client, one key stroke brings up an su'd window on the server. .suntools files While the tools understand how to interpret arguments based on the -Wxxxx conventions, suntools provides another way of passing arguments in the suntools startup file. That is, there are several reserved fields available for window position information and whether the window should be open or closed in the suntools startup file. The second method has two drawbacks. First, it is incomplete. Second, it can contradict arguments from the first method. Since I didn't want to waste my time figuring out how to 1) convert the .suntools parameters into tool-style parameters, 2) resolve contradictions between the two parameter passing techniques and 3) I did not have the source, I decided to disallow (actually ignore) the second method of passing arguments. Thus if you provide information via the 9 numerical parameters, it will be ignored. You should use the -W style of tool parameter passing. While this means you may have to modify your .suntools file, the end result is much more consistent. (Although no less easy to read, since strings like -Wp are not very intuitive either.) So for example, if you had a line in your .suntools file like: shelltool 0 72 -1 728 -1 -1 -1 -1 emacs $HOME/sked -Wn You should convert it to shelltool emacs $HOME/sked -Wp 0 72 -WP 4 4 -Wn (or even better, use -Ww and -Wh since they do not depend on the font size.) Please send comments, enhancements, bug reports and fixes to: Don Libes Met. Bldg, Rm B229 National Bureau of Standards Gaithersburg, MD 20899 (301) 921-2461 seismo!nbs-amrf!libes SHAR_EOF chmod +x 'README' if test -f 'suntools.c' then echo shar: over-writing existing file "'suntools.c'" fi cat << \SHAR_EOF > 'suntools.c' #ifndef lint static char sccsid[] = "@(#)suntools.c 1.2 85/03/13 SMI"; #endif /* * Sun Microsystems, Inc. */ /* * Root window: Provides the background window for a screen. * Put up environment manager menu. */ /* Modified by Don Libes, National Bureau of Standards, 9/25/85 Added the following: Menu selections via keyboard Su'd selections via shift key User-specifiable primary menu name User-specifiable root cursor Various keywords: EXIT_NOCONFIRM, VERSION, HELP, KEYS */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* SHIFTMASK - DEL */ #include #include /* icon_load_mpr for user cursor - DEL */ extern int errno; extern char *malloc (), *calloc (), *getenv (), *strcpy (), *strncat (), *strncpy (); static int rootfd = 0, rootnumber; static int root_SIGCHLD, root_SIGWINCH; static struct screen screen; static struct pixwin *pixwin; #define ROOTMENUITEMS 20 #define ROOTMENUFILE "/usr/lib/rootmenu" #define ROOTMENUNAME "Suntools" struct menuitem root_items[ROOTMENUITEMS]; struct menuitemstrings { char *mis_prog; /* program to call */ char *mis_args; /* args to program */ } root_itemstrings[ROOTMENUITEMS]; char *rootmenufile; char *rootmenuname; /* DEL */ struct menu wmgr_rootmenubody, *wmgr_rootmenu = &wmgr_rootmenubody; struct stat_rec { char *name; /* Dynamically allocated menu file name */ time_t mftime; /* Modified file time */ }; #define MAX_MENUS 20 static struct stat_rec stat_array[MAX_MENUS]; static int menu_next; #define ROOTCOLOR_PATTERN 0 #define ROOTCOLOR_FOREGROUND 1 #define ROOTCOLOR_BACKGROUND 2 static rootcolor = ROOTCOLOR_PATTERN; /* Default cursor is a circle filled with stipple pattern. */ /* When or-ed against another stipple pattern, it changes constantly. */ /* Neat, huh? - DEL */ static short cursor_image[CUR_MAXIMAGEWORDS] = { 0x0000,0x03E0,0x0E38,0x1224,0x288A,0x288A,0x6223,0x6223, 0x4889,0x4889,0x6223,0x2222,0x288A,0x188C,0x0E38,0x03E0 }; mpr_static (cursor_pr, 8 * sizeof (cursor_image[0]), sizeof (cursor_image) / sizeof (cursor_image[0]), 1, cursor_image); #define IS_ASCII_EVENT(x) (x>=ASCII_FIRST && x<=ASCII_LAST) #define KEY_BUFFER_LENGTH 30 char key_buffer[KEY_BUFFER_LENGTH] = ""; /* keys coming directly to the root window */ int key_buffer_length = 0; #define KEYITEMS 50 struct menuitem key_items[KEYITEMS]; struct menuitemstrings key_itemstrings[KEYITEMS]; struct menu keymenubody = { 0, 0, 0, }; struct pixfont *sysfont; #define SU_LABEL "su" int label_x, label_y; /* where the label is on the screen */ struct rect su_rect; struct pr_subregion su_bound; struct pixrect *oldpr; /* save old screen image here while we */ /* scribble the SU_LABEL on it */ int wants_su = FALSE; /* true if user has requested setuid(0) */ int oldruid, oldrgid; /* save the originals here */ struct passwd *pwd; main (argc, argv) int argc; char **argv; { char name[WIN_NAMESIZE], setupfile[MAXNAMLEN]; int _root_sigchldcatcher (), _root_sigwinchcatcher (); int donosetup = 0, printname = 0; unsigned char red[256], green[256], blue[256]; struct pixrect *fb_pixrect; int fullplanes = 255; /* * Parse cmd line. */ setupfile[0] = NULL; win_initscreenfromargv (&screen, argv); if (argv) { char **args; for (args = ++argv; *args; args++) { if ((strcmp (*args, "-s") == 0) && *(args + 1)) { (void) strcpy (setupfile, *(args + 1)); args++; } else if (strcmp (*args, "-F") == 0) rootcolor = ROOTCOLOR_FOREGROUND; else if (strcmp (*args, "-B") == 0) rootcolor = ROOTCOLOR_BACKGROUND; else if (strcmp (*args, "-P") == 0) rootcolor = ROOTCOLOR_PATTERN; else if (strcmp (*args, "-n") == 0) donosetup = 1; else if (strcmp (*args, "-p") == 0) printname = 1; else if (strcmp (*args, "-S") == 0) wants_su = 1; else if (argc == 2 && *args[0] != '-')/* * If only arg and not a flag then treat as * setupfile (backward compatibility with 1.0). */ (void) strcpy (setupfile, *args); } } oldrgid = getgid (); oldruid = getuid (); if (NULL == (pwd = getpwnam("root"))) { fprintf(stderr,"couldn't find root in passwd file?\n"); exit(1); } if (*pwd->pw_passwd != '\0') { if (wants_su) { if (geteuid() != 0) { fprintf(stderr,"suntools must be setuid(0)\n"); exit(1); } if (strcmp(pwd->pw_passwd, crypt(getpass("Password: "), pwd->pw_passwd))) { fprintf(stderr,"Sorry\n"); exit(1); } } else disable_su(); } wants_su = FALSE; /* * Initialize root menu from menu file. */ if ((rootmenufile = getenv ("ROOTMENU")) == NULL) rootmenufile = ROOTMENUFILE; /* added changeable root menu name - DEL */ if ((rootmenuname = getenv ("ROOTMENUNAME")) == NULL) rootmenuname = ROOTMENUNAME; if (wmgr_getrootmenu (rootmenuname, wmgr_rootmenu, rootmenufile, root_items, root_itemstrings, ROOTMENUITEMS) <= 0) { fprintf (stderr, "suntools: invalid root menu\n"); exit (1); } /* * Set up signal catchers. */ (void) signal (SIGCHLD, _root_sigchldcatcher); (void) signal (SIGWINCH, _root_sigwinchcatcher); /* * Find out what colormap is so can restore later. * Do now before call win_screennew which changes colormap. */ if (screen.scr_fbname[0] == NULL) strcpy (screen.scr_fbname, "/dev/fb"); if ((fb_pixrect = pr_open (screen.scr_fbname)) == (struct pixrect *) 0) { fprintf (stderr, "suntools: invalid frame buffer %s\n", screen.scr_fbname); exit (1); } pr_getcolormap (fb_pixrect, 0, 256, red, green, blue); /* * Create root window */ if ((rootfd = win_screennew (&screen)) == -1) { perror ("suntools"); exit (1); } init_cursor(); if (rootcolor != ROOTCOLOR_PATTERN) { struct cursor cursor; cursor.cur_shape = &cursor_pr; win_getcursor (rootfd, &cursor); cursor.cur_function = PIX_SRC ^ PIX_DST; win_setcursor (rootfd, &cursor); } win_screenget (rootfd, &screen); /* * Open pixwin. */ if ((pixwin = pw_open (rootfd)) == 0) { fprintf (stderr, "%s not available for window system usage\n", screen.scr_fbname); perror ("suntools"); exit (1); } /* * Set up root's name in environment */ win_fdtoname (rootfd, name); rootnumber = win_nametonumber (name); we_setparentwindow (name); if (printname) fprintf (stderr, "suntools window name is %s\n", name); /* * Set up tool slot allocator */ wmgr_setrectalloc (rootfd, 200, 40, 0, pixwin -> pw_pixrect -> pr_height - TOOL_ICONHEIGHT); /* * Setup tty parameters for all terminal emulators that will start. */ { int tty_fd; tty_fd = open ("/dev/tty", O_RDWR, 0); if (tty_fd < 0) ttysw_saveparms (2);/* Try stderr */ else { ttysw_saveparms (tty_fd); (void) close (tty_fd); } } /* * setup su hack - DEL */ /* find bounding box */ su_bound.pr = pixwin -> pw_pixrect; su_bound.pos.x = 0; su_bound.pos.y = 0; sysfont = pw_pfsysopen (); pf_textbound (&su_bound, strlen (SU_LABEL), sysfont, SU_LABEL); su_rect.r_width = su_bound.size.x; su_rect.r_height = su_bound.size.y; /* create pixrect to save screen while scribbling on it */ oldpr = mem_create (su_bound.size.x, su_bound.size.y, 1); /* * Draw background. */ _root_sigwinchhandler (); /* * Do initial window setup. */ if (!donosetup) _root_initialsetup (setupfile); /* * Do window management loop. */ _root_winmgr (); /* * Destroy screen sends SIGTERMs to all existing windows and * wouldn't let any windows install themselves in the window tree. * Calling process of win_screedestroy is spared SIGTERM. */ win_screendestroy (rootfd); /* * Lock screen before clear so don't clobber frame buffer while * cursor moving. */ pw_lock (pixwin, &screen.scr_rect); /* * Enable writing to entire depth of frame buffer. */ pr_putattributes (fb_pixrect, &fullplanes); /* * Clear entire frame buffer. */ pr_rop (fb_pixrect, screen.scr_rect.r_left, screen.scr_rect.r_top, screen.scr_rect.r_width, screen.scr_rect.r_height, PIX_CLR, 0, 0, 0); /* * Reset previous colormap. */ pr_putcolormap (fb_pixrect, 0, 256, red, green, blue); /* * Unlock screen. */ pw_unlock (pixwin); exit (0); } _root_winmgr () { struct inputmask im; struct inputevent event; struct menuitem *mi; extern struct menuitem *menu_display (); int keyexit = 0, exit; /* * Set up input mask so can do menu stuff */ input_imnull (&im); im.im_flags |= IM_NEGEVENT; im.im_flags |= IM_ASCII; win_setinputcodebit (&im, SELECT_BUT); win_setinputcodebit (&im, MENU_BUT); /* by enabling LOC_MOVE, we can discard the input buffer when the */ /* mouse moves. */ win_setinputcodebit (&im, LOC_MOVE); win_setinputmask (rootfd, &im, (struct inputmask *) 0, WIN_NULLLINK); /* * Read and invoke menu items */ for (;;) { int ibits, nfds; /* * Use select (to see if have input) so will return on * SIGWINCH or SIGCHLD. */ ibits = 1 << rootfd; do { if (root_SIGCHLD) _root_sigchldhandler (); if (root_SIGWINCH) _root_sigwinchhandler (); } while (root_SIGCHLD || root_SIGWINCH); nfds = select (8 * sizeof (ibits), &ibits, (int *) 0, (int *) 0, (struct timeval *) 0); if (nfds == -1) { if (errno == EINTR)/* * Go around again so that signals can be * handled. ibits may be non-zero but should * be ignored in this case and they will be * selected again. */ continue; else { perror ("suntools"); break; } } if (ibits & (1 << rootfd)) { /* * Read will not block. */ if (input_readevent (rootfd, &event) < 0) { if (errno != EWOULDBLOCK) { perror ("suntools"); break; } } } else continue; if (win_inputnegevent (&event)) continue; if (IS_ASCII_EVENT (event.ie_code)) { int i; /* add to key input buffer */ if (isupper (event.ie_code)) { event.ie_code = tolower (event.ie_code); wants_su = TRUE; } key_buffer[key_buffer_length] = event.ie_code; key_buffer_length += (key_buffer_length > KEY_BUFFER_LENGTH ? 0 : 1); key_buffer[key_buffer_length] = '\0'; for (i = 0; i < keymenubody.m_itemcount; i++) { if (strcmp (keymenubody.m_items[i].mi_imagedata, key_buffer) == 0) break; } if (i >= keymenubody.m_itemcount) continue;/* not found */ exit = wmgr_handlerootmenuitem ((struct menu *) NULL /* not used! */ , &keymenubody.m_items[i], rootfd) == -1; if (exit) break;/* exit suntools */ /* zap buffer now that we have used it */ /* for now this occurs simply by falling through */ } key_buffer_length = 0; key_buffer[0] = '\0'; wants_su = FALSE; if (event.ie_code != MENU_BUT) continue; if (wants_su = (event.ie_shiftmask & SHIFTMASK)) { struct pr_prpos textpos; /* move to the left by its width, so its right flush */ /* against the menu */ su_rect.r_left = event.ie_locx - su_bound.size.x; /* origin for text is from the bottom, so subtract its /* its height */ su_rect.r_top = event.ie_locy - sysfont -> pf_defaultsize.y; /* ignore going off the screen, since clipping is enabled */ pw_lock (pixwin, &su_rect); /* save whats lying on the screen */ pr_rop (oldpr, 0, 0, su_rect.r_width, su_rect.r_height, PIX_SRC, pixwin -> pw_pixrect, su_rect.r_left, su_rect.r_top); textpos.pr = pixwin -> pw_pixrect; textpos.pos.x = su_rect.r_left; textpos.pos.y = su_rect.r_top - /* distance to baseline */ sysfont -> pf_char['a'].pc_home.y; /* textpos is a structure passed by value!?! - DEL */ pf_text (textpos, PIX_SRC, sysfont, SU_LABEL); pw_unlock (pixwin); } /* * Do menus */ if (wmgr_getrootmenu (rootmenuname, wmgr_rootmenu, rootmenufile, root_items, root_itemstrings, ROOTMENUITEMS) <= 0) { fprintf (stderr, "suntools: invalid root menu\n"); continue; } for (;;) { struct inputevent tevent; exit = 0; tevent = event; mi = menu_display (&wmgr_rootmenu, &event, rootfd); if (mi) exit = wmgr_handlerootmenuitem (wmgr_rootmenu, mi, rootfd) == -1; if (event.ie_code == MS_LEFT && !exit) { event = tevent; /* win_setmouseposition(rootfd, event.ie_locx, event.ie_locy); */ } else { break; } } if (exit) break; /* exit suntools */ if (wants_su) { /* restore what was lying on screen */ pw_lock (pixwin, &su_rect); pr_rop (pixwin -> pw_pixrect, su_rect.r_left, su_rect.r_top, su_rect.r_width, su_rect.r_height, PIX_SRC, oldpr, 0, 0); pw_unlock (pixwin); wants_su = FALSE; } } } _root_sigchldhandler () { union wait status; root_SIGCHLD = 0; while (wait3 (&status, WNOHANG, (struct rusage *) 0) > 0) { } } _root_sigwinchhandler() { root_SIGWINCH = 0; pw_damaged (pixwin); switch (rootcolor) { case ROOTCOLOR_PATTERN: pw_replrop(pixwin, screen.scr_rect.r_left, screen.scr_rect.r_top, screen.scr_rect.r_width, screen.scr_rect.r_height, PIX_SRC, tool_bkgrd, 0, 0); break; default: pw_writebackground(pixwin, screen.scr_rect.r_left, screen.scr_rect.r_top, screen.scr_rect.r_width, screen.scr_rect.r_height, (rootcolor == ROOTCOLOR_BACKGROUND)?PIX_CLR:PIX_SET); } pw_donedamaged (pixwin); return; } static _root_sigchldcatcher () { root_SIGCHLD = 1; } static _root_sigwinchcatcher () { root_SIGWINCH = 1; } char * _get_home_dir () { extern char *getlogin (); extern struct passwd *getpwnam (), *getpwuid (); struct passwd *passwdent; char *home_dir = getenv ("HOME"), *loginname; if (home_dir != NULL) return (home_dir); loginname = getlogin (); if (loginname == NULL) { passwdent = getpwuid (getuid ()); } else { passwdent = getpwnam (loginname); } if (passwdent == NULL) { fprintf(stderr, "suntools: couldn't find user in password file.\n"); return (NULL); } if (passwdent -> pw_dir == NULL) { fprintf (stderr, "suntools: no home directory in password file.\n"); return (NULL); } return (passwdent -> pw_dir); } #define ROOT_ARGBUFSIZE 1000 #define ROOT_SETUPFILE "/.suntools" #define ROOT_MAXTOOLDELAY 10 _root_initialsetup (requestedfilename) char *requestedfilename; { register i; FILE * file; char filename[MAXNAMLEN], programname[MAXNAMLEN], otherargs[ROOT_ARGBUFSIZE]; struct rect rectnormal, recticonic; int iconic, topchild, bottomchild, seconds, j; char line[200]; if (requestedfilename[0] == NULL) { char *home_dir = _get_home_dir (); if (home_dir == NULL) return; (void) strcpy (filename, home_dir); (void) strncat (filename, ROOT_SETUPFILE, sizeof (filename) - 1 - strlen (filename) - strlen (ROOT_SETUPFILE)); } else (void) strncpy (filename, requestedfilename, sizeof (filename) - 1); if ((file = fopen (filename, "r")) == 0) { if (requestedfilename[0] == NULL) /* * No message if was trying to open default. */ return; fprintf (stderr, "suntools: couldn't open %s\n", filename); return; } while (fgets (line, sizeof (line), file)) { if (line[0] == '#') continue; otherargs[0] = '\0'; programname[0] = '\0'; i = sscanf (line, "%s%hd%hd%hd%hd%hd%hd%hd%hd%hD%[^\n]\n", programname, &rectnormal.r_left, &rectnormal.r_top, &rectnormal.r_width, &rectnormal.r_height, &recticonic.r_left, &recticonic.r_top, &recticonic.r_width, &recticonic.r_height, &iconic, otherargs); if (i == EOF) break; if (i < 10 || i > 11) { /* * Just get progname and args. */ otherargs[0] = '\0'; programname[0] = '\0'; j = sscanf (line, "%s%[^\n]\n", programname, otherargs); if (j > 0) { iconic = 0; rect_construct (&recticonic, WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS); rect_construct (&rectnormal, WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS); } else { fprintf (stderr, "suntools: in file=%s fscanf gave %D, correct format is:\n", filename, i); fprintf (stderr, "program open-left open-top open-width open-height close-left close-top close-width close-height iconicflag [args] \n OR\nprogram [args] \n"); continue; } } /* * Handle WMGR_SETPOS requests. */ wmgr_figuretoolrect (rootfd, &rectnormal); wmgr_figureiconrect (rootfd, &recticonic); /* * Remember who top and bottom children windows are for use when * trying to determine when tool is installed. */ topchild = win_getlink (rootfd, WL_TOPCHILD); bottomchild = win_getlink (rootfd, WL_BOTTOMCHILD); /* * Fork tool. */ /* (void) wmgr_forktool (programname, otherargs, &rectnormal, &recticonic, iconic); */ del_forktool (programname, otherargs, &rectnormal, &recticonic, iconic); /* * Give tool chance to intall self in tree before starting next. */ for (seconds = 0; seconds < ROOT_MAXTOOLDELAY; seconds++) { sleep (1); if (topchild != win_getlink (rootfd, WL_TOPCHILD) || bottomchild != win_getlink (rootfd, WL_BOTTOMCHILD)) break; } } (void) fclose (file); } int wmgr_rootmenuschanged (menu) struct menu *menu; { struct stat statb; int sa_count; /* Whenever existing menu going up, stat menu files */ for (sa_count = 0; sa_count < menu_next; sa_count++) { if (stat (stat_array[sa_count].name, &statb) < 0) { if (errno == ENOENT) return (1); fprintf (stderr, "suntools: "); perror (stat_array[sa_count].name); return (-1); } if (statb.st_mtime > stat_array[sa_count].mftime) return (1); } return (0); } wmgr_freerootmenus (menu) struct menu *menu; { int sa_count = 0; struct menu *next = menu -> m_next, *nnext; while (next) { nnext = next -> m_next; if (next -> m_items) { free (next -> m_items -> mi_data); /* free string storage */ free (next -> m_items);/* item storage */ } free (next); /* menu storage */ next = nnext; } while (sa_count < menu_next) { free (stat_array[sa_count].name);/* file name */ stat_array[sa_count].name = NULL; stat_array[sa_count].mftime = 0; sa_count++; } menu_next = 0; } wmgr_getrootmenu (mn, menu, mf, mi, mis, maxitems) char *mn, *mf; struct menu *menu; struct menuitem *mi; struct menuitemstrings *mis; int maxitems; { FILE * f; int lineno; char line[256]; char tag[256], /* was 32 - DEL */ prog[256], args[256]; char *savestr (); struct stat statb; struct menu *menunext = wmgr_rootmenu; int nitems = 0; static time_t mftime = 0; static char *nqformat = "%[^ \t\n]%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n"; static char *qformat = "\"%[^\"]\"%*[ \t]%[^ \t\n]%*[ \t]%[^\n]\n"; if (menu == wmgr_rootmenu && menu_next != 0) { if (wmgr_rootmenuschanged (wmgr_rootmenu) != 0) wmgr_freerootmenus (wmgr_rootmenu); else return menu -> m_itemcount; } if (menu_next >= MAX_MENUS - 1) { fprintf (stderr, "suntools: max number of menus is %D\n", MAX_MENUS); return - 1; } if ((f = fopen (mf, "r")) == NULL) { fprintf (stderr, "suntools: can't open menu file %s\n", mf); return - 1; } if (stat (mf, &statb) < 0) { fprintf (stderr, "suntools: "); perror (mf); return - 1; } stat_array[menu_next].mftime = statb.st_mtime; stat_array[menu_next].name = savestr (mf); ++menu_next; menu -> m_imagetype = MENU_IMAGESTRING; menu -> m_imagedata = mn; menu -> m_items = mi; for (nitems = 0, lineno = 1; nitems < maxitems && fgets (line, sizeof (line), f); lineno++) { if (line[0] == '#') continue; args[0] = '\0'; if (sscanf (line, line[0] == '"' ? qformat : nqformat, tag, prog, args) < 2) { fprintf (stderr, "suntools: format error in %s: line %d\n", mf, lineno); mftime = 0;/* complain every time */ continue; } if (strcmp (prog, "KEYS") == 0) { /* check for calling only from root menu...bah! */ if (wmgr_getrootmenu ("keys" /* menu name */ , &keymenubody, /* key file name */ args, &key_items[0], &key_itemstrings[0], KEYITEMS) <= 0) { fprintf (stderr, "suntools: bad key menu %s\n", args); continue; } /* do not link this menu in with others!!! */ /* it will not be displayed! */ } else if (strcmp (prog, "MENU") == 0) { struct menu *m; char *mi, *ms; if (menu != wmgr_rootmenu) { fprintf (stderr, "suntools: MENU command illegal in secondary menu file %s: line %d\n", mf, lineno); continue; } if (wmgr_getrootmenu ( savestr (tag),/* menu name */ m = (struct menu *) calloc (1, sizeof (struct menu)), args, /* file name */ mi = calloc (ROOTMENUITEMS, sizeof (struct menuitem)) , ms = calloc (ROOTMENUITEMS, sizeof (struct menuitemstrings)) , ROOTMENUITEMS) <= 0) { fprintf (stderr, "suntools: invalid secondary menu %s\n", args); free (m); free (mi), free (ms); continue; } else { menunext -> m_next = m; menunext = m; } } else { if (mi -> mi_imagedata) free ((char *) mi -> mi_imagedata); mi -> mi_imagetype = MENU_IMAGESTRING; mi -> mi_imagedata = (caddr_t) savestr (tag); mi -> mi_data = (caddr_t) mis; if (mis -> mis_prog) free (mis -> mis_prog); if (mis -> mis_args) free (mis -> mis_args); mis -> mis_prog = savestr (prog); if (args[0] == '\0') mis -> mis_args = (char *) NULL; else mis -> mis_args = savestr (args); mi++; mis++; nitems++; } } fclose (f); return menu -> m_itemcount = nitems; } char * savestr (s) register char *s; { register char *p; if ((p = malloc (strlen (s) + 1)) == NULL) { if (rootfd) win_screendestroy (rootfd); fprintf (stderr, "suntools: out of memory for menu strings\n"); exit (1); } strcpy (p, s); return (p); } wmgr_handlerootmenuitem (menu, mi, rootfd) struct menu *menu; struct menuitem *mi; int rootfd; { int returncode = 0; struct rect recticon, rectnormal; struct menuitemstrings *mis; /* * Get next default tool positions */ rect_construct (&recticon, WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS, WMGR_SETPOS); rectnormal = recticon; mis = (struct menuitemstrings *) mi -> mi_data; if (strcmp (mis -> mis_prog, "EXIT_NOCONFIRM") == 0) { returncode = -1; } else if (strcmp (mis -> mis_prog, "EXIT") == 0) { returncode = wmgr_confirm (rootfd, "Press the left mouse button to confirm Exit. \ To cancel, press the right mouse button now."); } else if (strcmp (mis -> mis_prog, "REFRESH") == 0) { wmgr_refreshwindow (rootfd); } else if (strcmp (mis -> mis_prog, "HELP") == 0) { wmgr_confirm (rootfd, "Right mouse down displays menus. \ Right mouse up selects. \ Left mouse down selects without losing menus. \ Holding shift key down before right mouse enables superuser. \ Press any key to remove this garbage."); } else if (strcmp (mis -> mis_prog, "VERSION") == 0) { wmgr_confirm(rootfd,"suntools 1.2.4 (9/26/85) by Don Libes \ at NBS (nbs-amrf!libes). Based on suntools 1.2 (3/13/85) by unknown \ at SMI. Press any key to remove this garbage."); } else { wmgr_figureiconrect (rootfd, &recticon); wmgr_figuretoolrect (rootfd, &rectnormal); del_forktool (mis -> mis_prog, mis -> mis_args, &rectnormal, &recticon, 0 /* not iconic */ ); } return (returncode); } enable_su () { if (setuid (0)) perror ("setuid(0)"); setgid (1); } disable_su () { setgid (oldrgid); if (setuid (oldruid)) perror ("setuid(oldruid)"); } del_forktool (program, args, open_rect, closed_rect, iconic) char *program, *args; struct rect open_rect, closed_rect; int iconic; { if (0 == fork ()) { /* child */ char buffer[5000];/* space for program name and args */ /* if doesn't have rectnormal, add it */ /* if doesn't have recticon, add it */ /* if it doesn't have iconic, add it if iconic */ if (wants_su && (geteuid() == 0)) enable_su (); else disable_su (); if (args) sprintf (buffer, "%s %s", program, args); else strcpy (buffer, program); /* now exec the program. Only problem is we have the prog name and args in a character string. We have to tokenize them in order to call exec or exec sh and have that do it for us. But that will create two processes for every one. */ /* execl ("/bin/sh", "sh", "-c", buffer, 0);*/ del_exec(buffer); _exit (127); } } #define end_token if (in_token) { \ /* terminate current token */ *cp = '\0'; \ /* advance to next token */ args[++argi] = cp = ++s;\ /* not sure if there is anything valid here, so */ in_token = FALSE; }\ else s++; /* exec a program and args that are all stored as one string */ del_exec(s) char *s; { char *args[50]; char *cp; int argi = 0; int quoting = FALSE; int in_token = FALSE; /* TRUE if we are reading a token */ args[0] = cp = s; while (*s) { if (quoting) { if (*s == '\\' && *(s+1) == '"') { /* quoted quote */ s++; /* get past " */ *cp++ = *s++; } else if (*s == '\"') { /* close quote */ end_token quoting = FALSE; } else *cp++ = *s++; /* suck up anything */ } else if (*s == '\"') { /* open quote */ in_token = TRUE; quoting = TRUE; s++; } else if (isspace(*s)) { end_token } else { *cp++ = *s++; in_token = TRUE; } } end_token args[argi] = (char *) 0; /* terminate argv */ execvp(args[0],args); } /* allow user to set cursor attributes - DEL */ init_cursor() { struct cursor cursor; char *cursorfile, *x_hot, *y_hot, *cursor_rop; /* environment parms */ cursor.cur_shape = &cursor_pr; /* default cursor is a weird looking dot */ cursor.cur_xhot = 8; cursor.cur_yhot = 8; cursor.cur_function = PIX_SRC | PIX_DST; win_setcursor(rootfd,&cursor); /* win_getcursor(rootfd, &cursor); */ if (cursorfile = getenv("ROOT_CURSOR")) { char errmsg[1000]; if (cursor.cur_shape = icon_load_mpr(cursorfile,errmsg)) { if (x_hot = getenv("ROOT_CURSOR_HOTSPOT_X")) cursor.cur_xhot = atoi(x_hot); if (y_hot = getenv("ROOT_CURSOR_HOTSPOT_Y")) cursor.cur_yhot = atoi(y_hot); if (cursor_rop = getenv("ROOT_CURSOR_ROP")) cursor.cur_function = atoi(cursor_rop); win_setcursor(rootfd,&cursor); } else printf(errmsg); } } SHAR_EOF chmod +x 'suntools.c' # End of shell archive exit 0