source: trunk/athena/bin/dash/dash.c @ 12537

Revision 12537, 41.7 KB checked in by danw, 25 years ago (diff)
from mwhitson: don't assume sizeof(int) == sizeof(void *)
Line 
1/*
2 * $Id: dash.c,v 1.3 1999-02-22 18:21:33 danw Exp $
3 *
4 * Copyright 1990, 1991 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#if  (!defined(lint))  &&  (!defined(SABER))
12static char *rcsid =
13"$Id: dash.c,v 1.3 1999-02-22 18:21:33 danw Exp $";
14#endif
15
16#include "mit-copyright.h"
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <ctype.h>
21#include <errno.h>
22#include <signal.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <sys/wait.h>
26#include <sys/time.h>
27#include <sys/resource.h>
28#include <sys/param.h>
29#include <fcntl.h>
30#include <athdir.h>
31#include <X11/Xlib.h>
32#include <X11/Xutil.h>
33#include <X11/Xatom.h>
34#include <X11/Xmu/WinUtil.h>
35#include <Jets/Jets.h>
36#include <Jets/Window.h>
37#include <Jets/Button.h>
38#include <Jets/Label.h>
39#include <Jets/Menu.h>
40#include <Jets/DClock.h>
41#include <Jets/AClock.h>
42#include <Jets/Form.h>
43#include <Jets/Tree.h>
44/* #include <StripChart.h> */
45/* #include <List.h> */
46#include <Jets/warn.h>
47#include "dash.h"
48
49
50extern int DEBUG;
51
52#define LOADST "/usr/athena/lib/gnuemacs/etc/loadst"
53
54#define DASH "Dash"
55#define DASH_NOP (char)0x00
56#define DASH_DEBUG (char)0x01
57#define DASH_KILL (char)0x02
58#define DASH_CREATE (char)0x03
59#define DASH_DESTROY (char)0x04
60#define DASH_MAP (char)0x05
61#define DASH_UNMAP (char)0x06
62#define DASH_CREATEORMAP (char)0x07
63#define DASH_RESTART (char)0x08
64
65Atom dashAtom, nameAtom;
66#define DASH_ATOM "_ATHENA_DASH"
67
68
69
70Jet root;
71/*
72 * These definitions are needed by the tree jet
73 */
74JetClass *jetClasses[] =
75{ &treeJetClass, &windowJetClass, &buttonJetClass, &labelJetClass,
76    &menuJetClass, &dClockJetClass,
77    &aClockJetClass, &formJetClass,
78    /* &stripChartJetClass, */
79    /* &listJetClass, */};
80
81int numJetClasses = XjNumber(jetClasses);
82
83static XrmOptionDescRec opTable[] = {
84{"+rv",         "*reverseVideo", XrmoptionNoArg,        (caddr_t) "off"},
85{"-background", "*background",  XrmoptionSepArg,        (caddr_t) NULL},
86{"-bd",         "*borderColor", XrmoptionSepArg,        (caddr_t) NULL},
87{"-bg",         "*background",  XrmoptionSepArg,        (caddr_t) NULL},
88{"-bordercolor","*borderColor", XrmoptionSepArg,        (caddr_t) NULL},
89{"-borderwidth",".borderWidth", XrmoptionSepArg,        (caddr_t) NULL},
90{"-bw",         ".borderWidth", XrmoptionSepArg,        (caddr_t) NULL},
91{"-display",    ".display",     XrmoptionSepArg,        (caddr_t) NULL},
92{"-fg",         "*foreground",  XrmoptionSepArg,        (caddr_t) NULL},
93{"-fn",         "*font",        XrmoptionSepArg,        (caddr_t) NULL},
94{"-font",       "*font",        XrmoptionSepArg,        (caddr_t) NULL},
95{"-foreground", "*foreground",  XrmoptionSepArg,        (caddr_t) NULL},
96{"-geometry",   "*menuTree.window.geometry",    XrmoptionSepArg,
97   (caddr_t) NULL},
98{"-reverse",    "*reverseVideo", XrmoptionNoArg,        (caddr_t) "on"},
99{"-rv",         "*reverseVideo", XrmoptionNoArg,        (caddr_t) "on"},
100{"+rude",       "*rude",        XrmoptionNoArg,         (caddr_t) "off"},
101{"-rude",       "*rude",        XrmoptionNoArg,         (caddr_t) "on"},
102{"+verify",     "*verify",      XrmoptionNoArg,         (caddr_t) "off"},
103{"-verify",     "*verify",      XrmoptionNoArg,         (caddr_t) "on"},
104{"-xrm",        NULL,           XrmoptionResArg,        (caddr_t) NULL},
105{"-name",       ".name",        XrmoptionSepArg,        (caddr_t) NULL},
106{"-appdefs",    ".appDefs",     XrmoptionSepArg,        (caddr_t) NULL},
107{"-f",          ".appDefs",     XrmoptionSepArg,        (caddr_t) NULL},
108{"-userdefs",   ".userDefs",    XrmoptionSepArg,        (caddr_t) NULL},
109{"-menus",      "*Menu.file",   XrmoptionSepArg,        (caddr_t) NULL},
110{"-send",       ".send",        XrmoptionNoArg,         (caddr_t) "true"},
111{"-kill",       ".kill",        XrmoptionNoArg,         (caddr_t) "true"},
112{"-run",        ".run",         XrmoptionNoArg,         (caddr_t) "true"},
113{"-restart",    ".restart",     XrmoptionNoArg,         (caddr_t) "true"},
114{"-debug",      ".debug",       XrmoptionNoArg,         (caddr_t) "true"},
115{"-nofork",     ".nofork",      XrmoptionNoArg,         (caddr_t) "true"},
116{"-nosession",  "*showCommand", XrmoptionNoArg,         (caddr_t) "false"},
117#ifdef HAVE_KRB4
118{"-nochecktickets",  ".checkTickets",  XrmoptionNoArg,  (caddr_t) "false"},
119#endif /* HAVE_KRB4 */
120};
121
122MyResources parms;
123
124#define offset(field) XjOffset(MyResourcesPtr,field)
125
126static XjResource appResources[] =
127{
128  { "verify", "Verify", XjRBoolean, sizeof(Boolean),
129      offset(verifyOn), XjRBoolean, (caddr_t) True },
130  { "notify", "Notify", XjRBoolean, sizeof(Boolean),
131      offset(notifyOn), XjRBoolean, (caddr_t) True },
132  { "startString", "StartString", XjRString, sizeof(char *),
133      offset(startString), XjRString, (caddr_t) NULL },
134  { "run", "Run", XjRBoolean, sizeof(Boolean),
135      offset(run), XjRBoolean, (caddr_t) False },
136  { "send", "Send", XjRBoolean, sizeof(Boolean),
137      offset(send), XjRBoolean, (caddr_t) False },
138  { "kill", "Kill", XjRBoolean, sizeof(Boolean),
139      offset(kill), XjRBoolean, (caddr_t) False },
140  { "restart", "Restart", XjRBoolean, sizeof(Boolean),
141      offset(restart), XjRBoolean, (caddr_t) False },
142  { "debug", "Debug", XjRBoolean, sizeof(Boolean),
143      offset(debug), XjRBoolean, (caddr_t) False },
144  { "nofork", "Nofork", XjRBoolean, sizeof(Boolean),
145      offset(nofork), XjRBoolean, (caddr_t) False },
146#ifdef HAVE_KRB4
147  { "checkTickets", "CheckTickets", XjRBoolean, sizeof(Boolean),
148      offset(checkTickets), XjRBoolean, (caddr_t) True },
149#endif /* HAVE_KRB4 */
150};
151
152#undef offset
153
154
155/*
156 *  setenv() doesn't exist on some systems...  it's putenv instead.
157 *  So, we write our own setenv routine, and use it instead.
158 *
159 *  Arguments:  (same as setenv in BSD Unix)
160 *      char *name;     name of environment variable to set or change.
161 *      char *value;    value to set or change environment variable to.
162 *      int overwrite;  if non-zero, force variable to value.
163 *                      if zero, and variable does not exist, add variable
164 *                              to environment.
165 *                      else, do nothing.
166 *
167 *  Returns:   (same as setenv in bsd Unix)
168 *      -1              if unsuccessful (unable to malloc enough space for
169 *                              an expanded environment).
170 *      0               otherwise.
171 *
172 */
173static int psetenv(name, value, overwrite)
174     char *name, *value;
175     int overwrite;
176{
177  char *string;
178
179  if ((overwrite) ||
180      ( (char *) getenv(name) == NULL))
181    {
182      string = (char *) malloc((strlen(name) + strlen(value) + 2)
183                               * sizeof(char));
184                                        /* add 1 for the null and 1 for "=" */
185      if (string == NULL)
186        return(-1);
187      strcpy(string, name);
188      strcat(string, "=");
189      strcat(string, value);
190      if (! putenv(string) )
191        return(-1);
192    }
193  return(0);
194}
195
196
197/*
198 * Set utilities
199 */
200
201typedef struct _Set
202{
203  struct _Set *next;
204  char *name;
205} Set;
206
207Set *setCache[100];
208int cacheSize = 0;
209
210/*
211 * Single level expansion of name
212 */
213Set *expandName(name)
214     char *name;
215{
216  char *type;
217  XrmValue value;
218  Set *tmp, *list;
219  char *start, *end, *more;
220  char n[50], c[50];
221  int i;
222
223  if (!strcasecmp("NULL", name))
224    return NULL;
225
226  for (i = 0; i < cacheSize; i++)
227    if (!strcmp(name, setCache[i]->name))
228      return setCache[i]->next;
229
230  sprintf(n, "%s.set.%s", programName, name);
231  sprintf(c, "%s.Set.%s", programClass, name);
232
233  if (XrmGetResource(rdb, n, c, &type, &value))
234    start = (char *)(value.addr);
235  else
236    {
237      char errtext[100];
238
239      sprintf(errtext, "no set %s exists", name);
240      XjWarning(errtext);
241      return NULL;
242    }
243
244  list = (Set *)XjMalloc((unsigned) sizeof(Set));
245  list->name = XjNewString(name);
246  list->next = NULL;
247
248  while (isspace(*start)) start++;
249  while (*start != '\0')
250    {
251      end = start;
252      while (!isspace(*end) && *end != '\0') end++;
253      more = end;
254      if (*end != '\0') more++;
255      *end = '\0';
256
257      tmp = (Set *)XjMalloc((unsigned) sizeof(Set));
258      tmp->name = start;
259      tmp->next = list->next;
260      list->next = tmp;
261         
262      start = more;
263    }
264
265  setCache[cacheSize++] = list;
266  return list->next;
267}
268
269Set *resolveName(name, list)
270     char *name;
271     Set *list;
272{
273  Set *e, *tmp;
274
275  e = expandName(name);
276  while (e != NULL)
277    {
278      if (*(e->name) == '_')
279        {
280          tmp = (Set *)XjMalloc((unsigned) sizeof(Set));
281          tmp->name = e->name + 1;
282          tmp->next = list;
283          list = tmp;
284        }
285      else
286        list = resolveName(e->name, list);
287      e = e->next;
288    }
289
290  return list;
291}
292
293void freeSet(set)
294     Set *set;
295{
296  Set *back;
297
298  while (set)
299    {
300      back = set;
301      set = set->next;
302      XjFree((char *) back);
303    }
304}
305
306/*
307 * Tree callbacks...
308 */
309
310int printTree(fromJet, what, data)
311     Jet fromJet;
312     char *what;
313     caddr_t data;
314{
315  Jet j;
316
317  for (j = root->core.child; j != NULL; j = j->core.sibling)
318    fprintf(stdout, "%s\n", j->core.name);
319  return 0;
320}
321
322int mapTree(fromJet, what, data)
323     Jet fromJet;
324     char *what;
325     caddr_t data;
326{
327  Jet w;
328
329  w = XjFindJet(what, root);
330
331  if (w != NULL)
332    {
333      w = w->core.child;
334      while (w)
335        {
336          MapWindow(w, True);
337          w = w->core.sibling;
338        }
339      return 0;
340    }
341  else
342    {
343      char errtext[100];
344
345      sprintf(errtext, "couldn't find %s to map it", what);
346      XjWarning(errtext);
347      return 1;
348    }
349}
350
351int mapSet(fromJet, what, data)
352     Jet fromJet;
353     char *what;
354     caddr_t data;
355{
356  Set *set, *ptr;
357
358  set = resolveName(what, NULL);
359  if (set)
360    {
361      for (ptr = set; ptr != NULL; ptr = ptr->next)
362        (void)mapTree(fromJet, ptr->name, data);
363      freeSet(set);
364    }
365  return 0;
366}
367
368int unmapTree(fromJet, what, data)
369     Jet fromJet;
370     char *what;
371     caddr_t data;
372{
373  Jet w;
374
375  w = XjFindJet(what, root);
376
377  if (w != NULL)
378    {
379      w = w->core.child;
380      while (w)
381        {
382          UnmapWindow(w);
383          w = w->core.sibling;
384        }
385      return 0;
386    }
387  else
388    {
389      char errtext[100];
390
391      sprintf(errtext, "couldn't find %s to unmap it", what);
392      XjWarning(errtext);
393      return 1;
394    }
395}
396
397int unmapSet(fromJet, what, data)
398     Jet fromJet;
399     char *what;
400     caddr_t data;
401{
402  Set *set, *ptr;
403
404  set = resolveName(what, NULL);
405  if (set)
406    {
407      for (ptr = set; ptr != NULL; ptr = ptr->next)
408        (void)unmapTree(fromJet, ptr->name, data);
409      freeSet(set);
410    }
411  return 0;
412}
413
414int createTree(fromJet, what, data)
415     Jet fromJet;
416     char *what;
417     caddr_t data;
418{
419  if (NULL == XjFindJet(what, root))
420    XjRealizeJet(XjVaCreateJet(what, treeJetClass, root, NULL, NULL));
421  return 0;
422}
423
424int createSet(fromJet, what, data)
425     Jet fromJet;
426     char *what;
427     caddr_t data;
428{
429  Set *set, *ptr;
430
431  set = resolveName(what, NULL);
432  if (set)
433    {
434      for (ptr = set; ptr != NULL; ptr = ptr->next)
435        (void)createTree(fromJet, ptr->name, data);
436      freeSet(set);
437    }
438  return 0;
439}
440
441int createMapTree(fromJet, what, data)
442     Jet fromJet;
443     char *what;
444     caddr_t data;
445{
446  if (NULL == XjFindJet(what, root))
447    XjRealizeJet(XjVaCreateJet(what, treeJetClass, root, NULL, NULL));
448  else
449    mapTree(fromJet, what, data);
450
451  return 0;
452}
453
454int createMapSet(fromJet, what, data)
455     Jet fromJet;
456     char *what;
457     caddr_t data;
458{
459  Set *set, *ptr;
460
461  set = resolveName(what, NULL);
462  if (set)
463    {
464      for (ptr = set; ptr != NULL; ptr = ptr->next)
465        (void)createMapTree(fromJet, ptr->name, data);
466      freeSet(set);
467    }
468  return 0;
469}
470
471int destroyTree(fromJet, what, data)
472     Jet fromJet;
473     char *what;
474     caddr_t data;
475{
476  Jet w;
477
478  w = XjFindJet(what, root);
479  if (w != NULL)
480    {
481      XjDestroyJet(w);
482      return 0;
483    }
484  else
485    {
486      char errtext[100];
487
488      sprintf(errtext, "couldn't find %s to destroy it", what);
489      XjWarning(errtext);
490      return 1;
491    }
492}
493
494int destroySet(fromJet, what, data)
495     Jet fromJet;
496     char *what;
497     caddr_t data;
498{
499  Set *set, *ptr;
500
501  set = resolveName(what, NULL);
502  if (set)
503    {
504      for (ptr = set; ptr != NULL; ptr = ptr->next)
505        (void)destroyTree(fromJet, ptr->name, data);
506      freeSet(set);
507    }
508  return 0;
509}
510
511int warpTree(fromJet, what, data)
512     Jet fromJet;
513     char *what;
514     caddr_t data;
515{
516  Jet w;
517
518  w = XjFindJet(what, root);
519
520  if (w != NULL)
521    {
522      w = w->core.child;
523      if (w != NULL)
524        XWarpPointer(w->core.display,
525                     None,
526                     w->core.window,
527                     0, 0, 0, 0,
528                     w->core.width / 2,
529                     w->core.height / 2);
530      return 0;
531    }
532  else
533    {
534      char errtext[100];
535
536      sprintf(errtext, "couldn't find %s to warp there", what);
537      XjWarning(errtext);
538      return 1;
539    }
540}
541
542int warpSet(fromJet, what, data)
543     Jet fromJet;
544     char *what;
545     caddr_t data;
546{
547  Set *set;
548
549  set = resolveName(what, NULL);
550  if (set)
551    {
552      (void)warpTree(fromJet, set->name, data);
553      freeSet(set);
554    }
555  return 0;
556}
557
558/*
559 * Exec related callbacks
560 */
561int sh(fromJet, what, data)
562     Jet fromJet;
563     char *what;
564     caddr_t data;
565{
566  if (127 == system(what))
567    {
568      XjWarning("couldn't execute shell");
569      return 1;
570    }
571  return 0;
572}
573
574/*
575 * Translate the string "what," expanding %M, %S, etc, and place
576 * it into the string "where."
577 */
578void expand(what, where)
579     char *what, *where;
580{
581  static int initialized = 0;
582  static char sys[20], bin[20], sysdir[50], bindir[50], home[100];
583  char *start, *wherestart, *tmp, **found;
584  struct stat bdir;
585
586  if (initialized == 0)
587    {
588      initialized++;
589
590      tmp = getenv("HOME");
591      if (tmp != NULL)
592        strncpy(home, tmp, sizeof(home)/sizeof(char));
593      else
594        sprintf(home, "nohome");
595
596      tmp = getenv("ATHENA_SYS");
597      if (tmp != NULL)
598        strncpy(sys, tmp, sizeof(sys)/sizeof(char));
599      else
600        sprintf(sys, "@sys");
601
602      tmp = getenv("HOSTTYPE");
603      if (tmp != NULL)
604        strncpy(bin, tmp, sizeof(bin)/sizeof(char));
605      else
606        strcpy(bin, HOSTTYPE);
607
608      sprintf(sysdir, "arch/%s/bin", sys);
609      sprintf(bindir, "%sbin", bin);
610    }
611
612  while (isspace(*what)) what++;
613  start = what;
614  wherestart = where;
615
616  while (*what != '\0')
617    {
618      while (*what != '\0' && *what != '%' && *what != '~')
619        *where++ = *what++;
620
621      if (*what == '~' && what == start)
622        {
623          strncpy(where, home, strlen(home));
624          where += strlen(home);
625          what++;
626        }
627      else
628        if (*what == '%')
629          {
630            what++;
631            switch(*what)
632              {
633              case '%':
634                *where++ = '%';
635                what++;
636                break;
637              case 'M':
638                strncpy(where, bin, strlen(bin));
639                where += strlen(bin);
640                what++;
641                break;
642              case 'S':
643                strncpy(where, sys, strlen(sys));
644                where += strlen(sys);
645                what++;
646                break;
647              case 'B':
648                /* Make tmp point to the beginning of the path we're
649                 * looking for binary directories under, and null
650                 * terminate it.
651                 */
652                tmp = where;
653                if (where != wherestart)
654                  {
655                    tmp--;
656                    while (*tmp != ' ' && tmp > wherestart)
657                      tmp--;
658                    if (*tmp == ' ') tmp++;
659                  }
660                *where = '\0';
661
662                /* Let athdir do the work... */
663                found = athdir_get_paths(tmp, "bin",
664                                         NULL, NULL, NULL, NULL, 0);
665                if (found)
666                  {
667                    /* Replace partially constructed path ending with
668                     * %B with the path athdir returned.
669                     */
670                    strcpy(tmp, *found);
671                    where = tmp + strlen(*found);
672                    athdir_free_paths(found);
673                  }
674                else
675                  {
676                    /* If we found nothing to substitute, don't. */
677                    strcpy(where, "%B");
678                    where += 2;
679                  }
680
681                what++;
682                break;
683              default:
684                *where++ = '%';
685                what++;
686              }
687          }
688    }
689  *where = '\0';
690}
691
692static char *cwd = NULL; /* working directory for exec'ed programs */
693static char *subject = NULL;
694static char buf[MAXPATHLEN];
695static char addpath[MAXPATHLEN];
696
697int setup(fromJet, what, data)
698caddr_t fromJet;
699char *what;
700caddr_t data;
701{
702  subject = what;
703  return 0;
704}
705
706int cd(fromJet, what, data)
707caddr_t fromJet;
708char *what;
709caddr_t data;
710{
711  cwd = what;
712  return 0;
713}
714
715void setupEnvironment()
716{
717  char *path, *space;
718
719  if (displayName != NULL)
720    psetenv("DISPLAY", displayName, True);
721
722  if (cwd != NULL)
723    {
724      expand(cwd, buf);
725      if (-1 == chdir(buf))
726        {
727          char errtext[100];
728
729          sprintf(errtext, "cd to %s failed with error %d",
730                  cwd, errno);
731          XjWarning(errtext);
732        }
733    }
734
735  if (subject != NULL)
736    psetenv("SUBJECT", subject, True);
737
738  if (*addpath != '\0')
739    {
740      path = (char *) getenv("PATH");
741      if (path == NULL)
742        {
743          space = XjMalloc((unsigned) MAXPATHLEN);
744          space[0] = '\0';
745        }
746      else
747        {
748          space = XjMalloc((unsigned) (MAXPATHLEN + strlen(path)));
749          strcpy(space, path);
750          strcat(space, ":");
751        }
752
753      strcat(addpath, "/%B");
754      expand(addpath, &space[strlen(space)]);
755      psetenv("PATH", space, True);
756    }
757}
758
759
760int add(fromJet, what, data)
761     Jet fromJet;
762     char *what;
763     caddr_t data;
764{
765  int err;
766  FILE *a;
767  int l;
768  sigset_t set, oset;
769  char line1[100], line2[100];
770
771  line2[0] = '\0';
772  sprintf(addpath, "attach -p %s", what);
773  (void) sigemptyset(&set);
774  (void) sigaddset(&set, SIGCHLD);
775  (void) sigprocmask(SIG_BLOCK, &set, &oset);
776  if (NULL != (a = popen(addpath, "r")))
777    {
778      fgets(addpath, MAXPATHLEN, a);
779      err = pclose(a);
780      (void) sigprocmask(SIG_SETMASK, &oset, NULL);
781
782      if (err != 0)
783        sprintf(line2, "Attach failed with error %d", err/256);
784      else
785        {
786          l = strlen(addpath);
787          if (l > 0)
788            if (addpath[l - 1] == '\n')
789              addpath[l - 1] = '\0';
790          return 0;
791        }
792    }
793  (void) sigprocmask(SIG_SETMASK, &oset, NULL);
794  sprintf(line1, "Could not attach %s", what);
795  XjUserWarning(root, NULL, True, line1, line2);
796
797  return 1;
798}
799
800int attach(fromJet, what, data)
801     Jet fromJet;
802     char *what;
803     caddr_t data;
804{
805  int err;
806
807  err = add(fromJet, what, data);
808  addpath[0] = '\0';
809
810  return err;
811}
812
813typedef struct _Child
814{
815  struct _Child *next;
816  int pid;
817  char *title;
818} Child;
819
820static Child *firstChild = NULL;
821
822
823/*
824 * Avoid zombies
825 */
826void checkChildren(sig)
827     int sig;
828{
829  Boolean found;
830  Child *ch, **last;
831  int child, status;
832
833  while ((child = waitpid(-1, &status, WNOHANG)) > 0)
834    {
835      found = False;
836      last = &firstChild;
837      for (ch = firstChild;
838           ch != NULL && !found;
839           last = &ch->next, ch = ch->next)
840        if (ch->pid == child)
841          {
842            found = True;
843            *last = ch->next;
844
845            if (WIFEXITED(status) && WEXITSTATUS(status))
846              {
847                char line1[100];
848
849                sprintf(line1, "%s exited with status %d",
850                        ch->title, WEXITSTATUS(status));
851                XjUserWarning(root, NULL, True, line1, "");
852              }
853            if (WIFSIGNALED(status) && WTERMSIG(status))
854              {
855                char line1[100], line2[100];
856
857                sprintf(line1, "%s exited with signal %d",
858                        ch->title, WTERMSIG(status));
859                if (WCOREDUMP(status))
860                  strcpy(line2, "(core dumped!)");
861                else
862                  line2[0] = '\0';
863                XjUserWarning(root, NULL, True, line1, line2);
864              }
865
866            XjFree((char *) ch);
867          }
868    }
869}
870
871char *NAME; /* oh no! a global variable! */
872
873
874input(fd, name)
875     int fd;
876     char *name;
877{
878  char buf[MAXPATHLEN];
879  char buf2[MAXPATHLEN + 7]; /* add some in for the length of errno */
880  int n;
881
882  if (read(fd, buf2, MAXPATHLEN + 7))
883    {
884      char line1[100], line2[100];
885
886      sscanf(buf2, "%s %d", buf, &n);
887      sprintf(line1, "Could not start %s:", name);
888      sprintf(line2, "%s: %s", buf, strerror(n));
889      XjUserWarning(root, NULL, True, line1, line2);
890    }
891  XjReadCallback((XjCallbackProc)NULL, fd, &fd);
892  close(fd);
893}
894
895
896int exec(info, what, data)
897     MenuInfo *info;
898     char *what;
899     caddr_t data;
900{
901  int pid;
902  char *ptr;
903  int argc = 0;
904  char *argv[100];
905  Child *ch;
906  char *name;
907  int fd[2];
908  int pipes;
909  int num_fds;
910
911
912  if (info != NULL &&           /* exec through menu item */
913      info->null == NULL)
914    name = info->menu->title;
915  else
916    if (NAME != NULL)           /* exec through verify, because verify */
917      {                         /* can't pass the menuinfo structure */
918        name = NAME;            /* it got, since the menus may have */
919        NAME = NULL;            /* rearranged by now. There _is_ a better */
920      }                         /* solution, but if I had time to do it, you */
921  else                          /* wouldn't be reading this! */
922    name = what;                /* exec through non-menu item */
923
924  if ((pipes = pipe(fd)))
925    {
926      char line1[100], line2[100];
927
928      sprintf(line1, "Could not set up pipe:  %s", strerror(errno));
929      sprintf(line2, "There will be no warning if `%s' can't be started.",
930              name);
931      XjUserWarning(root, NULL, True, line1, line2);
932    }
933  pipes = !pipes;
934
935  pid = fork();                 /* vfork will block indefinitely... :-( */
936
937  if (pid == -1)
938    {
939      char line1[100], line2[100];
940
941      sprintf(line1, "Could not start %s:", name);
942      sprintf(line2, "Fork - %s", strerror(errno));
943      XjUserWarning(root, NULL, True, line1, line2);
944      if (pipes)
945        {
946          close(fd[0]);
947          close(fd[1]);
948        }
949      return 1;
950    }
951
952  if (pid != 0)                 /* We're in the parent... */
953    {
954      addpath[0] = '\0';
955      cwd = NULL;
956      subject = NULL;
957
958      ch = (Child *)XjMalloc((unsigned) sizeof(Child));
959      ch->pid = pid;
960      ch->title = name;
961      ch->next = firstChild;
962      firstChild = ch;
963
964      if (pipes)
965        {
966          close(fd[1]);         /* Parent reads on fd[0] */
967          XjReadCallback((XjCallbackProc)input, fd[0], name);
968        }
969      return 0;
970    }
971
972  setupEnvironment();
973
974  expand(what, buf);
975  ptr = buf;
976
977  while (*ptr != '\0')
978    {
979      while (isspace(*ptr))
980        ptr++;
981
982      argv[argc++] = ptr;
983
984      while (!isspace(*ptr) && *ptr != '\0')
985        ptr++;
986
987      if (*ptr != '\0')
988        {
989          *ptr = '\0';
990          ptr++;
991        }
992
993    }
994
995  argv[argc] = NULL;
996
997  for (num_fds = 3; num_fds < getdtablesize(); num_fds++)
998    fcntl(num_fds, F_SETFD, 1);
999
1000  if (-1 == execvp(argv[0], argv))
1001    {
1002      char buf2[MAXPATHLEN + 7]; /* add some in for the length of errno */
1003      int n;
1004
1005      /* Child writes on the wall with crayon...  just kidding - fd[1] */
1006      if (pipes)
1007        {
1008          sprintf(buf2, "%s %d", buf, errno);
1009          n = strlen(buf2);
1010          if (write(fd[1], buf2, n) == n)
1011            _exit(0);
1012        }
1013      _exit(42);
1014    }
1015  return 42;                    /* never reached, but makes saber happy... */
1016}
1017
1018int restart(info, what, data)
1019     MenuInfo *info;
1020     char *what;
1021     caddr_t data;
1022{
1023  char *ptr;
1024  int argc = 0;
1025  char *argv[100];
1026  char line1[100], line2[100];
1027
1028  setupEnvironment();
1029
1030  if (what != NULL &&
1031      *what != '\0')
1032    {
1033      expand(what, buf);
1034      ptr = buf;
1035
1036      while (*ptr != '\0')
1037        {
1038          while (isspace(*ptr))
1039            ptr++;
1040
1041          argv[argc++] = ptr;
1042
1043          while (!isspace(*ptr) && *ptr != '\0')
1044            ptr++;
1045
1046          if (*ptr != '\0')
1047            {
1048              *ptr = '\0';
1049              ptr++;
1050            }
1051        }
1052      execvp(argv[0], argv);
1053    }
1054  else
1055    execvp(global_argv[0], global_argv);
1056
1057  sprintf(line1, "Attempt to restart failed with error %d", errno);
1058  sprintf(line2, "%s: %s", global_argv[0], strerror(errno));
1059  XjUserWarning(root, NULL, True, line1, line2);
1060  return 1;
1061}
1062
1063int addMenus(info, file, data)
1064     MenuInfo *info;
1065     char *file;
1066     caddr_t data;
1067{
1068  if (info->null != NULL) /* we weren't called by menu code */
1069    return 1;
1070
1071  return loadNewMenus(info->menubar, file);
1072}
1073
1074/*
1075 * Danger Will Robinson!
1076 * This mechanism makes it possible for callbacks to
1077 * be called after the calling jet has already been
1078 * destroyed. Ain't that special?
1079 */
1080typedef struct _vstruct {
1081  Jet top;
1082  Jet yes;
1083  XjCallback me;
1084  Menu *menu;
1085  char *string;
1086  char *title;
1087} Verify;
1088
1089int yesorno(who, v, data)
1090     Jet who;
1091     Verify *v;
1092     caddr_t data;
1093{
1094  XUnmapWindow(v->top->core.display, XjWindow(v->top));
1095  XFlush(v->top->core.display);
1096
1097  if (v->yes == who)
1098    {
1099      NAME = v->title;
1100      XjCallCallbacks((caddr_t) who, v->menu->activateProc, NULL);
1101    }
1102
1103  XjDestroyJet(v->top);
1104  XjFree(v->string);
1105  XjFree((char *) v);
1106  return 0;
1107}
1108
1109int verify(info, foo, data)
1110     MenuInfo *info;
1111     int foo;
1112     caddr_t data;
1113{
1114  Verify *v;
1115  Jet lqtop, lqform, logo, lqlabel, lqybutton, lqnbutton,
1116  lqnwindow, lqywindow, lqylabel, lqnlabel;
1117
1118  if (info->null != NULL) /* we weren't called by menu code */
1119    return 1;
1120
1121  if (!parms.verifyOn)
1122    {
1123      XjCallCallbacks((caddr_t) info, info->menu->activateProc, NULL);
1124      return 0;
1125    }
1126
1127  v = (Verify *)XjMalloc((unsigned) sizeof(Verify));
1128
1129  v->me.next = NULL;
1130  v->me.argType = argPtr;
1131  v->me.passPtr = v;
1132  v->me.proc = yesorno;
1133  v->menu = info->menu;
1134
1135  lqtop =  XjVaCreateJet("lqWindow", windowJetClass, root, NULL, NULL);
1136  lqform = XjVaCreateJet("lqForm", formJetClass, lqtop, NULL, NULL);
1137
1138  /* in this structure because that widget may need it forever, long
1139     after it's off the stack and we have returned */
1140  v->title = info->menu->title;
1141  v->string = XjMalloc((unsigned) (strlen(info->menu->title) + 1
1142                                   + strlen(parms.startString)));
1143  sprintf(v->string, parms.startString, info->menu->title);
1144
1145  logo = XjVaCreateJet("dashLogo", labelJetClass, lqform,
1146                       NULL, NULL);
1147  lqlabel = XjVaCreateJet("lqLabel", labelJetClass, lqform,
1148                          XjNlabel, v->string, NULL, NULL);
1149  lqywindow = XjVaCreateJet("lqYWindow", windowJetClass, lqform, NULL, NULL);
1150  lqnwindow = XjVaCreateJet("lqNWindow", windowJetClass, lqform, NULL, NULL);
1151  lqybutton = XjVaCreateJet("lqYButton", buttonJetClass, lqywindow,
1152                            XjNactivateProc, &(v->me), NULL, NULL);
1153  lqnbutton = XjVaCreateJet("lqNButton", buttonJetClass, lqnwindow,
1154                            XjNactivateProc, &(v->me), NULL, NULL);
1155  lqylabel = XjVaCreateJet("lqYLabel", labelJetClass, lqybutton, NULL, NULL);
1156  lqnlabel = XjVaCreateJet("lqNLabel", labelJetClass, lqnbutton, NULL, NULL);
1157
1158  v->top = lqtop;
1159  v->yes = lqybutton;
1160
1161  XjRealizeJet(lqtop);
1162  return 0;
1163}
1164
1165
1166int toggleVerify(info, otherName, data)
1167MenuInfo *info;
1168char *otherName;
1169caddr_t data;
1170{
1171  static int initialized = 0;
1172  static char *onName, *offName;
1173
1174  if (info->null != NULL) /* we weren't called by menu code */
1175    return 1;
1176
1177  if (initialized == 0)
1178    {
1179      char *ptr = otherName;
1180
1181      initialized = 1;
1182
1183                                /* Deal with star BS... */
1184      if (ptr[0] == ' '  &&  ptr[1] == ' '  &&  ptr[2] == ' ')
1185        ptr += 3;
1186      if (ptr[0] == '*'  &&  ptr[1] == ' ')
1187        ptr += 2;
1188                                /* Rip this code out in a future */
1189                                /* release... */
1190
1191      if (parms.verifyOn)
1192        {
1193          onName = info->menu->title;
1194          offName = ptr;
1195        }
1196      else
1197        {
1198          onName = ptr;
1199          offName = info->menu->title;
1200        }
1201    }
1202
1203  if (parms.verifyOn)
1204    info->menu->title = offName;
1205  else
1206    info->menu->title = onName;
1207
1208  parms.verifyOn = !parms.verifyOn;
1209
1210  computeMenuSize(info->menubar, info->menu);
1211  computeMenuSize(info->menubar, info->menu->parent); /* bug */
1212  return 0;
1213}
1214
1215int toggleHelp(info, otherName, data)
1216MenuInfo *info;
1217char *otherName;
1218caddr_t data;
1219{
1220  static int initialized = 0;
1221  static char *onName, *offName;
1222  XjSize size;
1223
1224  if (info->null != NULL) /* we weren't called by menu code */
1225    return 1;
1226
1227  if (initialized == 0)
1228    {
1229      char *ptr = otherName;
1230
1231      initialized = 1;
1232
1233                                /* Deal with star BS... */
1234      if (ptr[0] == ' '  &&  ptr[1] == ' '  &&  ptr[2] == ' ')
1235        ptr += 3;
1236      if (ptr[0] == '*'  &&  ptr[1] == ' ')
1237        ptr += 2;
1238                                /* Rip this code out in a future */
1239                                /* release... */
1240
1241      if (info->menubar->menu.showHelp == 1)
1242        {
1243          onName = info->menu->title;
1244          offName = ptr;
1245        }
1246      else
1247        {
1248          onName = ptr;
1249          offName = info->menu->title;
1250        }
1251    }
1252
1253  if (info->menubar->menu.showHelp == 1)
1254    info->menu->title = offName;
1255  else
1256    info->menu->title = onName;
1257
1258  info->menubar->menu.showHelp = !info->menubar->menu.showHelp;
1259
1260  computeAllMenuSizes(info->menubar, info->menubar->menu.rootMenu);
1261  computeRootMenuSize(info->menubar, &size);
1262  return 0;
1263}
1264
1265int quit(fromJet, what, data)
1266caddr_t fromJet;
1267int what;
1268caddr_t data;
1269{
1270  XjExit(what);
1271  return 0;                             /* For linting... */
1272}
1273
1274int debug(fromJet, what, data)
1275caddr_t fromJet;
1276char *what;
1277caddr_t data;
1278{
1279  fprintf(stdout, "malloced %d\n", malloced);
1280  return 0;
1281}
1282
1283int usage(fromJet, what, data)
1284caddr_t fromJet;
1285char *what;
1286caddr_t data;
1287{
1288  XjUsage(what);
1289  return 0;
1290}
1291
1292int printMenu(info, what, data)
1293     MenuInfo *info;
1294     char *what;
1295     caddr_t data;
1296{
1297  if (info->null != NULL)               /* we weren't called by menu code */
1298    return 1;
1299
1300  PrintMenu(info->menubar); /* call only from a menu item. :-) */
1301  return 0;
1302}
1303
1304/* when the menu works without being overrideRedirect, this should
1305   be made ICCCM compliant. */
1306int lowerMenu(info, what, data)
1307     MenuInfo *info;
1308     char *what;
1309     caddr_t data;
1310{
1311#ifndef sgi
1312  if (info->null != NULL)
1313    return 1;
1314
1315  XLowerWindow(info->menubar->core.display,
1316               info->menubar->core.window);
1317  return 0;
1318#else
1319  /* HACK HACK HACK
1320   * If fam is running with icons on the background, it puts a window
1321   * up in front of the root window but behind everything else,
1322   * override redirect, but the full size of the screen. The code in
1323   * the other half of this ifdef pushes dash behind that window
1324   * where you can't see it. This is clearly not satisfactory.
1325   */
1326  Window rooter, parent, *list;
1327  WindowJet menuWindow;
1328  int i;
1329  unsigned int num;
1330  XWindowAttributes win;
1331  XWindowChanges config;
1332
1333  if (info->null != NULL)
1334    return 1;
1335
1336  /*
1337   * If the menu bar is not override redirect, we're ok.
1338   * If XQueryTree fails, just lower ourselves.
1339   */
1340  menuWindow = (WindowJet)info->menubar->core.parent;
1341  if (menuWindow->window.overrideRedirect == False ||
1342      !XQueryTree(root->core.display, root->core.window,
1343                  &rooter, &parent, &list, &num))
1344    {
1345      XLowerWindow(info->menubar->core.display,
1346                   info->menubar->core.window);
1347      return 0;
1348    }
1349
1350  /*
1351   * Start examining the children of the root from back to font.
1352   */
1353  for (i = 0; i < num; i++)
1354    {
1355      /* Ignore ourselves. */
1356      if (list[i] == info->menubar->core.window)
1357        continue;
1358
1359      if (XGetWindowAttributes(root->core.display, list[i], &win))
1360        {
1361          /* Is this the fam window? A fine heuristic. It's override
1362             redirect, we can see it, and it takes up the whole
1363             screen. */
1364          if (win.override_redirect == True &&
1365              win.map_state == IsViewable &&
1366              win.x == 0 && win.y == 0 &&
1367              win.width == root->core.width &&
1368              win.height == root->core.height)
1369            break;
1370
1371          /* Is this a normal viewable window? Then we're safe putting
1372             ourselves behind it. (Or, in front of the window behind
1373             it.) This catches the case where fam isn't actually
1374             running. */
1375          if (win.override_redirect == False &&
1376              win.map_state == IsViewable)
1377            {
1378              if (i > 0)
1379                i--; /* bug; we should probably really change
1380                        to Below, below, for this case */
1381              break;
1382            }
1383        }
1384
1385      /* We didn't find the fam window or any viewable windows at all.
1386         So we simply lower ourselves to the bottom. We could probably
1387         just as well do nothing at all. */
1388      if (i == num)
1389        {
1390          XLowerWindow(info->menubar->core.display,
1391                       info->menubar->core.window);
1392          XFree(list);
1393          return 0;
1394        }
1395    }
1396
1397  config.sibling = list[i];
1398  config.stack_mode = Above;
1399  XConfigureWindow(root->core.display, info->menubar->core.window,
1400                   CWSibling | CWStackMode, &config);
1401
1402  XFree(list);
1403  return 0;
1404#endif
1405}
1406
1407int logout(fromJet, what, data)
1408caddr_t fromJet;
1409char *what;
1410caddr_t data;
1411{
1412  char *pid_string;
1413  int pid_int;
1414
1415  if (pid_string = (char *) getenv("XSESSION"))
1416    if (pid_int = atoi(pid_string))
1417      if (!kill(pid_int, SIGHUP))
1418        return 0;
1419
1420  NAME = "logout";
1421  /*return exec(NULL, "/usr/athena/end_session", NULL);*/
1422  return exec(NULL, "end_session", NULL);
1423}
1424
1425fatal(display)
1426     Display *display;
1427{
1428  XjExit(-1);
1429}
1430
1431static int (*def_handler)();
1432
1433static int handler(display, error)
1434     Display *display;
1435     XErrorEvent *error;
1436{
1437  if (error->error_code == BadWindow  ||  error->error_code == BadAtom)
1438    return 0;
1439
1440  def_handler(display, error);
1441  return 0;                     /* it'll never get this far anyway... */
1442}
1443
1444
1445
1446Window findDASH(display)
1447     Display *display;
1448{
1449  char *atom_name;
1450  Atom actual_type;
1451  int actual_format;
1452  unsigned long nitems;
1453  unsigned long bytes_after;
1454  Window *prop;
1455  unsigned char *name;
1456/*  unsigned char *prop; */
1457  int status;
1458
1459#ifdef TIME_STARTUP
1460  struct timeval start, end;
1461
1462  gettimeofday(&start, NULL);
1463  printf("findDASH: - %d.%d + \n", start.tv_sec, start.tv_usec);
1464#endif
1465
1466  atom_name = (char *) XjMalloc(strlen(programName) + strlen(DASH_ATOM)
1467                                + 2);
1468  sprintf(atom_name, "%s_%s", DASH_ATOM, programName);
1469  nameAtom = XInternAtom(display, atom_name, False);
1470  XjFree(atom_name);
1471
1472  status = XGetWindowProperty(display, RootWindow(display, 0),
1473                              nameAtom, 0, 1,
1474                              False, AnyPropertyType, &actual_type,
1475                              &actual_format, &nitems, &bytes_after,
1476                              (unsigned char **) &prop);
1477  if (status==BadWindow)
1478    XjFatalError("rootWindow does not exist!");
1479  if (status!=Success)
1480    return (Window) NULL;
1481  if (! prop)
1482    return (Window) NULL;
1483
1484  def_handler = XSetErrorHandler(handler);
1485  status = XGetWindowProperty(display, *prop,
1486                              dashAtom, 0, 1,
1487                              False, AnyPropertyType, &actual_type,
1488                              &actual_format, &nitems, &bytes_after,
1489                              &name);
1490  (void) XSetErrorHandler(def_handler);
1491
1492  if (status==BadWindow)
1493    {
1494      XjFatalError("rootWindow does not exist!");
1495    }
1496  if (status!=Success)
1497    {
1498      return (Window) NULL;
1499    }
1500
1501#ifdef TIME_STARTUP
1502          gettimeofday(&end, NULL);
1503          printf("findDASH: %d.%d = %d.%06.6d\n", end.tv_sec, end.tv_usec,
1504                 (end.tv_usec > start.tv_usec)
1505                 ? end.tv_sec - start.tv_sec
1506                 : end.tv_sec - start.tv_sec - 1,
1507                 (end.tv_usec > start.tv_usec)
1508                 ? end.tv_usec - start.tv_usec
1509                 : end.tv_usec + 1000000 - start.tv_usec );
1510#endif
1511 
1512  if (!strcmp((char *)name, programName))
1513    {
1514      XjFree(name);
1515      return *prop;
1516    }
1517
1518  XjFree(name);
1519  return (Window) NULL;
1520}
1521
1522
1523
1524Status sendEvent(display, window, opcode, data)
1525     Display *display;
1526     Window window;
1527     char opcode;
1528     char *data;
1529{
1530  Status s;
1531  XEvent e;
1532
1533  e.xclient.type = ClientMessage;
1534  e.xclient.window = window;
1535  e.xclient.message_type = dashAtom;
1536  e.xclient.format = 8;
1537  memset(e.xclient.data.b, 0, sizeof(e.xclient.data.b));
1538  e.xclient.data.b[0] = opcode;
1539  if (data)
1540    strcpy(&e.xclient.data.b[1], data);
1541
1542  if (s = XSendEvent(display, window, False, NoEventMask, &e))
1543    XFlush(display);
1544
1545  return s;
1546}
1547
1548int delete(fromJet, what, data)
1549     Jet fromJet;
1550     char *what;
1551     caddr_t data;
1552{
1553  XjDestroyJet(fromJet);
1554  return 0;
1555}
1556
1557int deleteParent(fromJet, what, data)
1558     Jet fromJet;
1559     char *what;
1560     caddr_t data;
1561{
1562  XjDestroyJet(XjParent(fromJet));
1563  return 0;
1564}
1565
1566int message(info, zilch, data)
1567     WindowInfo *info;
1568     char *zilch;
1569     caddr_t data;
1570{
1571  char errtext[100];
1572  info->event->xclient.data.b[19] = '\0'; /* just in case */
1573
1574  if (info->event->xclient.message_type == dashAtom)
1575    switch(info->event->xclient.data.b[0])
1576      {
1577      case DASH_NOP:
1578        break;
1579      case DASH_DEBUG:
1580        DEBUG = !DEBUG;
1581        printTree(NULL, NULL, NULL);
1582        break;
1583      case DASH_KILL:
1584        XjExit(0);
1585        break;
1586      case DASH_CREATE:
1587        createSet(NULL, &info->event->xclient.data.b[1], NULL);
1588        break;
1589      case DASH_DESTROY:
1590        destroySet(NULL, &info->event->xclient.data.b[1], NULL);
1591        break;
1592      case DASH_MAP:
1593        mapSet(NULL, &info->event->xclient.data.b[1], NULL);
1594        break;
1595      case DASH_UNMAP:
1596        unmapSet(NULL, &info->event->xclient.data.b[1], NULL);
1597        break;
1598      case DASH_CREATEORMAP:
1599        createMapSet(NULL, &info->event->xclient.data.b[1], NULL);
1600        break;
1601      case DASH_RESTART:
1602        restart(NULL, NULL, NULL);
1603        break;
1604      default:
1605        sprintf(errtext, "unknown ClientMessage opcode: %d\n",
1606                (int)info->event->xclient.data.b[0]);
1607        break;
1608      }
1609  else
1610    {
1611      sprintf(errtext, "unrecognized ClientMessage: %d\n",
1612              info->event->xclient.message_type);
1613      XjWarning(errtext);
1614      return 1;
1615    }
1616
1617  return 0;
1618}
1619
1620/*
1621struct loadInfo {
1622  FILE *f;
1623  StripChartJet who;
1624};
1625
1626void getLoad(fd, info)
1627     int fd;
1628     struct loadInfo *info;
1629{
1630  char s[40];
1631  int l1, l2, l3;
1632
1633  fscanf(info->f, "%s %d.%d[%d]\n", s, &l1, &l2, &l3);
1634  XjStripChartData(info->who, 100*l1+l2);
1635}
1636
1637int load(init, foo, data)
1638     StripChartInit *init;
1639     int foo;
1640     caddr_t data;
1641{
1642  FILE *loadFile;
1643  char command[80];
1644  struct loadInfo *info;
1645
1646  sprintf(command, "%s %d", LOADST, init->interval/1000);
1647  loadFile = popen(command, "r");
1648  info = (struct loadInfo *)XjMalloc(sizeof(struct loadInfo));
1649  info->who = init->j;
1650  info->f = loadFile;
1651
1652  XjReadCallback((XjCallbackProc)getLoad, fileno(loadFile), info);
1653  return 0;
1654}
1655
1656int cpu(where)
1657     int *where;
1658{
1659  double l;
1660
1661  getcpu(NULL, NULL, &l);
1662  *where = (int)(l * 100.0);
1663  return 0;
1664}
1665
1666int pstat(where)
1667     int *where;
1668{
1669  FILE *ps;
1670  static int Pused, Ptext, Pfree, Pwasted, Pmissing;
1671  static int Pnum[6], Psize[6];
1672  static struct timeval last = { 0, 0 };
1673  struct timeval now;
1674
1675  gettimeofday(&now, NULL);
1676  if (now.tv_sec - last.tv_sec > 60)
1677    {
1678      last = now;
1679
1680      ps = popen("/etc/pstat -s", "r");
1681
1682      fscanf(ps, "%dk used (%dk text), %dk free, %dk wasted, %dk missing\n",
1683             &Pused, &Ptext, &Pfree, &Pwasted, &Pmissing);
1684      fscanf(ps, "avail: %d*%dk %d*%dk %d*%dk %d*%dk %d*%dk %d*%dk\n",
1685             &Pnum[0], &Psize[0], &Pnum[1], &Psize[1], &Pnum[2], &Psize[2],
1686             &Pnum[3], &Psize[3], &Pnum[4], &Psize[4], &Pnum[5], &Psize[5]);
1687
1688      pclose(ps);
1689    }
1690
1691  *where = 100 * Pused / (Pused + Pfree + Pwasted + Pmissing);
1692
1693  return 0;
1694}
1695*/
1696
1697
1698int std_out(fromJet, what, data)
1699     Jet fromJet;
1700     char *what;
1701     caddr_t data;
1702{
1703  printf(what);
1704  fflush(stdout);
1705  return 0;                             /* For linting... */
1706}
1707
1708int std_err(fromJet, what, data)
1709     Jet fromJet;
1710     char *what;
1711     caddr_t data;
1712{
1713  fprintf(stderr, what);
1714  fflush(stderr);
1715  return 0;                             /* For linting... */
1716}
1717
1718
1719XjCallbackRec callbacks[] =
1720{
1721  /* tree operations */
1722  { "createTree", createTree },
1723  { "createMapTree", createMapTree },
1724  { "destroyTree", destroyTree },
1725  { "warpTree", warpTree },
1726  { "mapTree", mapTree },
1727  { "unmapTree", unmapTree },
1728  { "printTree", printTree },
1729  /* set operations */
1730  { "createSet", createSet },
1731  { "createMapSet", createMapSet },
1732  { "destroySet", destroySet },
1733  { "warpSet", warpSet },
1734  { "mapSet", mapSet },
1735  { "unmapSet", unmapSet },
1736  /* misc */
1737  { "quit", quit },
1738  { "exec", exec },
1739  { "sh", sh },
1740  { "toggleHelp", toggleHelp },
1741  { "toggleVerify", toggleVerify },
1742  { "debug", debug },
1743  { "usage", usage },
1744  { "logout", logout },
1745  { "delete", delete },
1746  { "deleteParent", deleteParent },
1747  { "printMenu", printMenu },
1748  { "lowerMenu", lowerMenu },
1749  { "cd", cd },
1750  { "attach", attach },
1751  { "add", add },
1752  { "setup", setup },
1753  { "addMenus", addMenus },
1754  { "verify", verify },
1755  { "restart", restart },
1756  { "message", message },
1757  { "stdout", std_out },
1758  { "stderr", std_err },
1759/*
1760  { "load", load },
1761  { "cpu", cpu },
1762  { "pstat", pstat },
1763*/
1764};
1765
1766main(argc, argv)
1767int argc;
1768char **argv;
1769{
1770  Display *display;
1771  char *home;
1772  char userFile[100];
1773  Window handle = (Window) NULL;
1774  int cd[50];
1775  Set *tmp, *list;
1776  char *nameOptions[50];
1777  int i, numOptions = 0;
1778  int count, sign = 1;
1779  Status e;
1780  Jet handlejet;
1781  struct sigaction act;
1782  sigemptyset(&act.sa_mask);
1783  act.sa_flags = 0;
1784
1785  expand("~/.dashrc", userFile); /* Also guarantees expand() is initialized
1786                                    in this process, not multiple times in
1787                                    children. */
1788
1789  (void)XSetIOErrorHandler(fatal);
1790
1791  root = XjCreateRoot(&argc, argv, DASH, userFile,
1792                      opTable, XjNumber(opTable));
1793
1794  XjLoadFromResources(NULL,
1795                      NULL,
1796                      programClass,
1797                      programName,
1798                      appResources,
1799                      XjNumber(appResources),
1800                      (caddr_t) &parms);
1801  display = root->core.display;
1802
1803  dashAtom = XInternAtom(display, DASH_ATOM, False);
1804
1805  /*
1806   * Parse special creation options out of command line.
1807   */
1808  argv++;
1809  while (*argv)
1810    {
1811      if (!strcmp(*argv, "-show"))
1812        sign = 1;
1813      else
1814        {
1815          if (!strcmp(*argv, "-hide"))
1816            sign = 0;
1817          else
1818            {
1819              if (**argv == '+' || **argv == '-')
1820                {
1821                  cd[numOptions] = (**argv) == '+' ? 0 : 1;
1822                  nameOptions[numOptions++] = *argv + 1;
1823                }
1824              else
1825                {
1826                  cd[numOptions] = sign;
1827                  nameOptions[numOptions++] = *argv;
1828                }
1829            }
1830        }
1831      argv++;
1832    }
1833
1834  if (numOptions == 0)
1835    {
1836      nameOptions[0] = "default";
1837      cd[0] = 1;
1838      numOptions = 1;
1839    }
1840
1841  if (!parms.run) /* don't get a handle if we don't care */
1842    handle = findDASH(display);
1843
1844  if (!handle && (parms.send || parms.kill))
1845    {
1846      /* try harder... */
1847      count = 3;
1848      while (!handle && count)
1849        {
1850          sleep(10);
1851          handle = findDASH(display);
1852          count--;
1853        }
1854
1855      if (!handle)
1856        {
1857          char errtext[100];
1858
1859          sprintf(errtext, "couldn't find a running %s", programName);
1860          XjWarning(errtext);
1861          XjExit(1);
1862        }
1863    }
1864
1865  /*
1866   * -kill
1867   */
1868  if (handle && parms.kill)
1869    {
1870      if (sendEvent(display, handle, DASH_KILL, NULL))
1871        XjExit(0);
1872      else
1873        XjFatalError("sendEvent failed");
1874    }
1875
1876  /*
1877   * -restart
1878   */
1879  if (handle && parms.restart)
1880    {
1881      if (sendEvent(display, handle, DASH_RESTART, NULL))
1882        XjExit(0);
1883      else
1884        XjFatalError("sendEvent failed");
1885    }
1886
1887  /*
1888   * -debug
1889   */
1890  if (handle && parms.debug)
1891    {
1892      if (sendEvent(display, handle, DASH_DEBUG, NULL))
1893        XjExit(0);
1894      else
1895        XjFatalError("sendEvent failed");
1896    }
1897
1898  /*
1899   * Either -send, or a dash exists and not -run
1900   */
1901  if (handle)
1902    {
1903      for (i = 0; i < numOptions; i++)
1904        {
1905          if (cd[i] == 0)
1906            e = sendEvent(display, handle, DASH_UNMAP, nameOptions[i]);
1907          else
1908            e = sendEvent(display, handle, DASH_CREATEORMAP, nameOptions[i]);
1909          if (!e)
1910            XjFatalError("sendEvent failed");
1911        }
1912      XjExit(0);
1913    }
1914
1915  /*
1916   * Now we deal with the rest of the command line args...
1917   */
1918  if (!parms.nofork)
1919    {
1920      switch (fork())
1921        {
1922        case 0:                 /* child */
1923          break;
1924        case -1:                /* error */
1925          perror ("Can't fork");
1926          XjExit(-1);
1927        default:                /* parent */
1928          XjExit(0);
1929        }
1930    }
1931
1932  if (parms.startString == NULL)
1933    parms.startString = "Start %s?";
1934
1935  DEBUG = parms.debug;
1936
1937  XjRegisterCallbacks(callbacks, XjNumber(callbacks));
1938
1939  for (i = 0; i < numOptions; i++)
1940    {
1941      tmp = resolveName(nameOptions[i], NULL);
1942      if (cd[i] == 1)
1943        for (list = tmp; list != NULL; list = list->next)
1944          (void)XjVaCreateJet(list->name, treeJetClass, root, NULL, NULL);
1945      freeSet(tmp);
1946    }
1947
1948  XjRealizeJet(root);
1949  /*
1950   * Okay, so there is no handle...  we'll create one and install the
1951   * property on the root.
1952   */
1953  handlejet = XjVaCreateJet("handleWindow", windowJetClass, root,
1954                            XjNoverrideRedirect, True,
1955                            XjNmapped, False,
1956                            XjNx, -100,
1957                            XjNy, -100,
1958                            XjNwidth, 1,
1959                            XjNheight, 1,
1960                            XjNtitle, DASH_ATOM,
1961                            NULL, NULL);
1962  XjRealizeJet(handlejet);
1963  handle = XjWindow(handlejet);
1964  XChangeProperty(display, handle, dashAtom,
1965                  XA_STRING, 8, PropModeReplace,
1966                  (unsigned char *) programName, strlen(programName));
1967  XChangeProperty(display, RootWindow(display, 0), nameAtom,
1968                  XA_WINDOW, 32, PropModeReplace,
1969                  (unsigned char *) &handle, 1);
1970  XFlush(display);
1971
1972
1973
1974   act.sa_handler= (void (*)())checkChildren;
1975   (void) sigaction(SIGCHLD, &act, NULL);
1976
1977#ifdef HAVE_KRB4
1978  if (parms.checkTickets)
1979    checkTkts(0,0);
1980#endif /* HAVE_KRB4 */
1981
1982  XjEventLoop(root);
1983}
Note: See TracBrowser for help on using the repository browser.