4 #include <Wc/WcCreate.h>
5 #include <X11/StringDefs.h>
6 #include <X11/Xaw/Text.h>
10 #include <moira_site.h>
13 extern void AriRegisterAthena();
16 typedef struct _ClusterResources {
20 static XrmOptionDescRec options[] = {
21 {"-server", "*moiraServer", XrmoptionSepArg, NULL},
24 #define Offset(field) (XtOffset(ClusterResources *, field))
26 static XtResource my_resources[] = {
27 {"moiraServer", XtCString, XtRString, sizeof(String),
28 Offset(server), XtRImmediate, "" },
34 void localErrorHandler(), mr_x_input(), inputDone(), Help(), popup_error_hook();
35 void getClusters(), getClusterMachine();
36 void selectClusters(), selectClusterMachine(), selectClusterData();
37 void deselectClusters(), clearClusters();
38 void getMachines(), getMachineCluster();
39 void selectMachines(), selectMachineCluster();
40 void deselectMachines(), clearMachines(), getMachineTypes();
41 void selectMachineType(), selectMachineSubnet(), getClusterServer();
42 void addMachineCluster(), removeMachineCluster(), removeMachineAllCluster();
43 void selectAllCluster(), selectAllMachine();
44 void saveCluster(), saveMachine();
46 XtActionsRec actions[] = {
47 { "inputDone", inputDone },
50 XtActionsRec callbacks[] = {
52 { "getClusters", getClusters },
53 { "getClusterMachine", getClusterMachine },
54 { "selectClusters", selectClusters },
55 { "selectClusterData", selectClusterData },
56 { "selectAllCluster", selectAllCluster },
57 { "selectClusterMachine", selectClusterMachine },
58 { "deselectClusters", deselectClusters },
59 { "clearClusters", clearClusters },
60 { "getClusterServer", getClusterServer },
61 { "getMachines", getMachines },
62 { "getMachineCluster", getMachineCluster },
63 { "selectMachines", selectMachines },
64 { "selectAllMachine", selectAllMachine },
65 { "selectMachineCluster", selectMachineCluster },
66 { "deselectMachines", deselectMachines },
67 { "clearMachines", clearMachines },
68 { "getMachineTypes", getMachineTypes },
69 { "selectMachineType", selectMachineType },
70 { "selectMachineSubnet", selectMachineSubnet },
71 { "addMachineCluster", addMachineCluster },
72 { "removeMachineCluster", removeMachineCluster },
73 { "removeMachineAllCluster", removeMachineAllCluster },
74 { "saveCluster", saveCluster },
75 { "saveMachine", saveMachine },
78 char *moira_help = "Moira is the Athena configuration management system.";
81 "This program allows you to manipulate machine/cluster mappings. To\n\
82 create or delete machines or clusters, use one of the other moira\n\
85 You can fetch from the database clusters and machines, which will be\n\
86 listed in the two scrolling windows. They may be fetched by name\n\
87 (wildcards are allowed), machine<->cluster mappings, or fileservers\n\
90 The machines and clusters you are going to change must be selected.\n\
91 You can do this by mousing on them or using operations similar ton\n\
92 those that fetched them from the database. Then you can use the\n\
93 commands in the Mappings menu.";
94 char *author_help = "Written by Mark Rosenstein <mar@MIT.EDU>, MIT Project Athena.";
95 char *unknown_help = "Sorry, help is not available on that topic.";
100 typedef struct _mattr {
105 Widget appShell, clist, mlist;
106 ClusterResources resources;
109 char *clusters[256], *machines[1000];
110 mattr machattr[1000];
111 int nclusters = 0, nmachines = 0;
112 int suppress_updates = 0;
124 /* setenv("XFILESEARCHPATH", "/afs/athena/system/moira/lib/%N", 1); */
125 setenv("XFILESEARCHPATH", "/afs/athena/astaff/project/moiradev/src/clients/cluster/%N", 1);
126 if ((program_name = rindex(argv[0], '/')) == NULL)
127 program_name = argv[0];
130 program_name = strsave(program_name);
133 * Intialize Toolkit creating the application shell, and get
134 * application resources.
136 appShell = XtInitialize("cluster", "Cluster",
137 options, XtNumber(options),
139 app = XtWidgetToApplicationContext(appShell);
140 XtAppSetErrorHandler(app, localErrorHandler);
141 dpy = XtDisplay(appShell);
142 XtAppAddActions(app, actions, XtNumber(actions));
143 XtGetApplicationResources(appShell, (caddr_t) &resources,
144 my_resources, XtNumber(my_resources),
146 for (i = 0; i < sizeof(callbacks)/sizeof(XtActionsRec); i++)
147 WcRegisterCallback(app, callbacks[i].string, callbacks[i].proc, NULL);
148 /* Register all Motif widget classes */
149 AriRegisterAthena(app);
151 status = mr_connect(resources.server);
153 com_err(program_name, status, " connecting to server");
157 status = mr_motd(&motd);
159 com_err(program_name, status, " connecting to server");
163 fprintf(stderr, "The Moira server is currently unavailable:\n%s\n",
169 status = mr_auth("cluster");
170 if (status == MR_USER_AUTH) {
172 com_err(program_name, status, "\nPress [RETURN] to continue");
175 com_err(program_name, status, "; authorization failed - may need to run kinit");
179 /* Create widget tree below toplevel shell using Xrm database */
180 WcWidgetCreation(appShell);
181 clist = WcFullNameToWidget(appShell, "*clusterlist");
182 XawMListChange(clist, clusters, 0, 0, False);
183 mlist = WcFullNameToWidget(appShell, "*machinelist");
184 XawMListChange(mlist, machines, 0, 0, False);
186 * Realize the widget tree, finish up initializing,
187 * and enter the main application loop
189 XtRealizeWidget(appShell);
190 mr_set_alternate_input(ConnectionNumber(dpy), mr_x_input);
191 set_com_err_hook(popup_error_hook);
196 int collect(argc, argv, sq)
199 struct save_queue *sq;
204 argv_copy = (char **)malloc((argc + 1) * sizeof (char *));
205 for (i = 0; i < argc; i++)
206 argv_copy[i] = strsave(argv[i]);
209 sq_save_data(sq, (char *)argv_copy);
214 void deselectClusters()
216 XawMListReturnStruct *ret;
219 ret = XawMListShowCurrent(clist, &count);
220 for (count--; count >= 0; count--)
221 XawMListUnhighlight(clist, ret[count].list_index);
231 XawMListChange(clist, clusters, 0, 0, False);
238 XawMListReturnStruct *ret;
239 int count, i, j, new, status;
240 char *argv[3], **nargv, buf[BUFSIZ], buf1[BUFSIZ];
241 struct save_queue *sq;
243 /* Get cluster data and assemble line */
247 status = MoiraQuery("get_cluster_data", 2, argv, collect, sq);
249 com_err(program_name, status, " while fetching cluster data");
250 if (status == MR_SUCCESS) {
251 sq_get_data(sq, &nargv);
252 sprintf(buf, "%-16s %s %s", clu, nargv[1], nargv[2]);
254 while (sq_get_data(sq, &nargv)) {
255 sprintf(buf1, "%s; %s %s", buf, nargv[1], nargv[2]);
263 /* find out where in sorted list new item will go */
264 for (new = 0; new < nclusters; new++) {
265 if ((i = strmcmp(clusters[new], clu)) > 0)
269 clusters[new] = strsave(buf);
274 /* unselect everything in list */
275 ret = XawMListShowCurrent(clist, &count);
276 for (i = 0; i < count; i++)
277 XawMListUnhighlight(clist, ret[i].list_index);
279 /* insert new item */
280 for (i = nclusters; i > new; i--)
281 clusters[i + 1] = clusters[i];
283 clusters[new] = strsave(buf);
285 if (suppress_updates)
288 XawMListChange(clist, clusters, nclusters, 0, True);
290 /* re-highlight (possibly moved) items */
291 for (i = 0; i < count; i++)
292 for (j = 0; j < nclusters; j++)
293 if (!strmcmp(ret[i].string, clusters[j]))
294 XawMListHighlight(clist, j);
299 void selectCluster(clu)
305 for (i = 0; i < nclusters; i++)
306 if (!strmcmp(clusters[i], clu)) {
307 XawMListHighlight(clist, i);
315 char clu[64], **argv, *p;
316 struct save_queue *sq;
320 PromptUser("Cluster name:", clu, sizeof(clu));
322 status = MoiraQuery("get_cluster", 1, &p, collect, sq);
324 com_err(program_name, status, " while fetching clusters");
326 suppress_updates = 1;
327 while (sq_get_data(sq, &argv)) {
328 addCluster(strsave(argv[0]));
332 if (suppress_updates > 1)
333 XawMListChange(clist, clusters, nclusters, 0, True);
334 suppress_updates = 0;
337 void selectClusters()
339 char clu[64], **argv, *p;
340 struct save_queue *sq;
344 PromptUser("Cluster name:", clu, sizeof(clu));
346 status = MoiraQuery("get_cluster", 1, &p, collect, sq);
348 com_err(program_name, status, " while fetching clusters");
350 suppress_updates = 1;
351 while (sq_get_data(sq, &argv)) {
352 selectCluster(strsave(argv[0]));
356 if (suppress_updates > 1)
357 XawMListChange(clist, clusters, nclusters, 0, True);
358 suppress_updates = 0;
361 void getClusterMachine()
363 char mach[64], **argv, *qargv[2];
364 struct save_queue *sq;
368 PromptUser("Machine name:", mach, sizeof(mach));
369 qargv[0] = canonicalize_hostname(strsave(mach));
371 status = MoiraQuery("get_machine_to_cluster_map", 2, qargv, collect, sq);
373 com_err(program_name, status, " while fetching clusters");
376 suppress_updates = 1;
377 while (sq_get_data(sq, &argv)) {
378 addCluster(strsave(argv[1]));
382 if (suppress_updates > 1)
383 XawMListChange(clist, clusters, nclusters, 0, True);
384 suppress_updates = 0;
388 void selectClusterMachine()
390 char mach[64], **argv, *qargv[2];
391 struct save_queue *sq;
395 PromptUser("Machine name:", mach, sizeof(mach));
396 qargv[0] = canonicalize_hostname(strsave(mach));
398 status = MoiraQuery("get_machine_to_cluster_map", 2, qargv, collect, sq);
400 com_err(program_name, status, " while fetching clusters");
403 suppress_updates = 1;
404 while (sq_get_data(sq, &argv)) {
405 selectCluster(strsave(argv[1]));
409 if (suppress_updates > 1)
410 XawMListChange(clist, clusters, nclusters, 0, True);
411 suppress_updates = 0;
415 void getClusterServer()
417 char buf[64], *mach, **argv, *qargs[3];
418 struct save_queue *fsq, *cluq, *sq;
422 PromptUser("Server name:", buf, sizeof(buf));
423 mach = canonicalize_hostname(strsave(buf));
424 status = MoiraQuery("get_filesys_by_machine", 1, &mach, collect, fsq);
426 com_err(program_name, status, " while fetching filesystems");
433 status = MoiraQuery("get_cluster_data", 2, qargs, collect, cluq);
435 com_err(program_name, status, " while fetching cluster data");
438 suppress_updates = 1;
439 while (sq_get_data(cluq, &argv)) {
440 mach = index(argv[2], ' ');
442 printf("Searching for filsys %s\n", argv[2]);
443 for (sq = fsq->q_next; sq != fsq; sq = sq->q_next)
444 if (!strcmp(argv[2], ((char **)sq->q_data)[0]))
445 addCluster(strsave(argv[0]));
448 if (suppress_updates > 1)
449 XawMListChange(clist, clusters, nclusters, 0, True);
450 suppress_updates = 0;
451 while (sq_get_data(fsq, &argv)) {
452 printf("filsys %s\n", argv[0]);
460 void selectClusterData()
465 PromptUser("Data:", buf, sizeof(buf));
467 for (i = 0; i < nclusters; i++)
468 if (substr(buf, &clusters[i][CLULEN]))
469 XawMListHighlight(clist, i);
472 void selectAllCluster()
476 for (i = 0; i < nclusters; i++)
477 XawMListHighlight(clist, i);
481 void deselectMachines()
483 XawMListReturnStruct *ret;
486 ret = XawMListShowCurrent(mlist, &count);
487 for (count--; count >= 0; count--)
488 XawMListUnhighlight(mlist, ret[count].list_index);
498 XawMListChange(mlist, machines, 0, 0, False);
502 void addMachine(mach, type)
505 XawMListReturnStruct *ret;
506 int count, i, j, new, addr;
510 he = gethostbyname(mach);
512 addr = *(int *)he->h_addr_list[0];
515 sprintf(buf, "%-32s %-8s %s", mach, type, inet_ntoa(addr));
517 /* find out where in sorted list new item will go */
518 for (new = 0; new < nmachines; new++) {
519 if ((i = strmcmp(machines[new], mach)) > 0)
522 if (strlen(mach) > strlen(machines[new])) {
524 machines[new] = strsave(buf);
525 strcpy(machattr[new].type, type);
526 machattr[new].addr = addr;
528 if (suppress_updates)
531 XawMListChange(mlist, machines, nmachines, 0, True);
536 /* unselect everything in list */
537 ret = XawMListShowCurrent(mlist, &count);
538 for (i = 0; i < count; i++)
539 XawMListUnhighlight(mlist, ret[i].list_index);
541 /* insert new item */
542 for (i = nmachines; i > new; i--) {
543 machines[i] = machines[i - 1];
544 machattr[i] = machattr[i - 1];
547 machines[new] = strsave(buf);
548 strcpy(machattr[new].type, type);
549 machattr[new].addr = addr;
551 if (suppress_updates)
554 XawMListChange(mlist, machines, nmachines, 0, True);
556 /* re-highlight (possibly moved) items */
557 for (i = 0; i < count; i++)
558 for (j = 0; j < nmachines; j++)
559 if (!strmcmp(ret[i].string, machines[j]))
560 XawMListHighlight(mlist, j);
565 void selectMachine(mach, type)
570 addMachine(mach, type);
571 for (i = 0; i < nmachines; i++)
572 if (!strmcmp(machines[i], mach)) {
573 XawMListHighlight(mlist, i);
580 char *mach, **argv, buf[BUFSIZ];
581 struct save_queue *sq;
585 PromptUser("Machine name:", buf, sizeof(buf));
586 mach = canonicalize_hostname(strsave(buf));
587 status = MoiraQuery("get_machine", 1, &mach, collect, sq);
589 com_err(program_name, status, " while fetching machines");
592 suppress_updates = 1;
593 while (sq_get_data(sq, &argv)) {
594 addMachine(argv[0], argv[1]);
598 if (suppress_updates > 1)
599 XawMListChange(mlist, machines, nmachines, 0, True);
600 suppress_updates = 0;
604 void selectMachines()
606 char *mach, **argv, buf[BUFSIZ];
607 struct save_queue *sq;
611 PromptUser("Machine name:", buf, sizeof(buf));
612 mach = canonicalize_hostname(strsave(buf));
613 status = MoiraQuery("get_machine", 1, &mach, collect, sq);
615 com_err(program_name, status, " while fetching machines");
618 suppress_updates = 1;
619 while (sq_get_data(sq, &argv)) {
620 selectMachine(argv[0], argv[1]);
624 if (suppress_updates > 1)
625 XawMListChange(mlist, machines, nmachines, 0, True);
626 suppress_updates = 0;
631 void getMachineCluster()
633 char **argv, **argv1, *qargv[2], buf[256];
634 struct save_queue *sq, *sq1;
639 PromptUser("Cluster name:", buf, sizeof(buf));
641 status = MoiraQuery("get_machine_to_cluster_map", 2, qargv, collect, sq);
643 com_err(program_name, status, " while fetching clusters");
645 suppress_updates = 1;
646 while (sq_get_data(sq, &argv)) {
647 addMachine(strsave(argv[0]), "");
650 status = MoiraQuery("get_machine", 1, argv, collect, sq1);
652 com_err(program_name, status, " while fetching machine type");
653 sq_get_data(sq1, &argv1);
654 addMachine(argv1[0], argv1[1]);
661 if (suppress_updates > 1)
662 XawMListChange(mlist, machines, nmachines, 0, True);
663 suppress_updates = 0;
667 void selectMachineCluster()
669 char **argv, **argv1, *qargv[2], buf[256];
670 struct save_queue *sq, *sq1;
675 PromptUser("Cluster name:", buf, sizeof(buf));
677 status = MoiraQuery("get_machine_to_cluster_map", 2, qargv, collect, sq);
679 com_err(program_name, status, " while fetching clusters");
681 suppress_updates = 1;
682 while (sq_get_data(sq, &argv)) {
683 selectMachine(strsave(argv[0]), "");
686 status = MoiraQuery("get_machine", 1, argv, collect, sq1);
688 com_err(program_name, status, " while fetching machine type");
689 sq_get_data(sq1, &argv1);
690 selectMachine(argv1[0], argv1[1]);
697 if (suppress_updates > 1)
698 XawMListChange(mlist, machines, nmachines, 0, True);
699 suppress_updates = 0;
703 void getMachineTypes()
705 char *mach, **argv, buf[256], *p;
706 int i, changed = 0, status, addr;
707 struct save_queue *sq;
711 for (i = 0; i < nmachines; i++) {
712 if (strlen(machattr[i].type) == 0) {
714 p = index(mach, ' ');
716 status = MoiraQuery("get_machine", 1, &mach, collect, sq);
718 com_err(program_name, status, " while fetching machine type");
719 sq_get_data(sq, &argv);
720 strcpy(machattr[i].type, argv[1]);
721 he = gethostbyname(mach);
723 addr = *(int *)he->h_addr_list[0];
726 sprintf(buf, "%-32s %-8s %s", mach, argv[1], inet_ntoa(addr));
727 machines[i] = strsave(buf);
728 machattr[i].addr = addr;
734 XawMListChange(mlist, machines, nmachines, 0, True);
739 void selectMachineType()
744 PromptUser("Machine type:", type, sizeof(type));
747 for (i = 0; i < nmachines; i++)
748 if (!strcasecmp(type, machattr[i].type))
749 XawMListHighlight(mlist, i);
753 void selectMachineSubnet()
759 PromptUser("Machine's subnet:", buf, sizeof(buf));
762 for (i = 0; i < nmachines; i++) {
763 /* Here we go hardcoding the subnet mask.... */
764 if (subnet == ((ntohl(machattr[i].addr) >> 16) & 0xff))
765 XawMListHighlight(mlist, i);
770 void selectAllMachine()
774 for (i = 0; i < nmachines; i++)
775 XawMListHighlight(mlist, i);
779 void addMachineCluster()
781 XawMListReturnStruct *machs, *clus;
782 int mcount, ccount, status, c, m;
785 machs = XawMListShowCurrent(mlist, &mcount);
786 clus = XawMListShowCurrent(clist, &ccount);
787 for (c = 0; c < ccount; c++) {
788 for (m = 0; m < mcount; m++) {
789 argv[0] = strsave(machines[machs[m].list_index]);
790 p = index(argv[0], ' ');
792 argv[1] = strsave(clusters[clus[c].list_index]);
793 p = index(argv[1], ' ');
795 status = MoiraQuery("add_machine_to_cluster", 2, argv,
798 com_err(program_name, status, " while adding machines to clusters");
808 void removeMachineCluster()
810 XawMListReturnStruct *machs, *clus;
811 int mcount, ccount, status, c, m;
814 machs = XawMListShowCurrent(mlist, &mcount);
815 clus = XawMListShowCurrent(clist, &ccount);
816 for (c = 0; c < ccount; c++) {
817 for (m = 0; m < mcount; m++) {
818 argv[0] = strsave(machs[m].string);
819 p = index(argv[0], ' ');
821 argv[1] = strsave(clus[c].string);
822 p = index(argv[1], ' ');
824 status = MoiraQuery("delete_machine_from_cluster", 2, argv,
827 com_err(program_name, status, " while deleting machines from clusters");
837 void removeMachineAllCluster()
839 XawMListReturnStruct *machs;
840 int mcount, ccount, status, c, m;
841 char *argv[2], *p, **args;
842 struct save_queue *sq;
844 machs = XawMListShowCurrent(mlist, &mcount);
846 for (m = 0; m < mcount; m++) {
848 argv[0] = strsave(machs[m].string);
849 p = index(argv[0], ' ');
852 status = MoiraQuery("get_machine_to_cluster_map", 2, argv,
855 com_err(program_name, status, " while getting cluster mapping");
858 while (sq_get_data(sq, &args)) {
859 status = MoiraQuery("delete_machine_from_cluster", 2, args,
862 com_err(program_name, status, " while deleting machines from clusters");
875 PromptUser("Filename:", buf, sizeof(buf));
876 out = fopen(buf, "w");
878 com_err(program_name, errno, " while opening output file \"%s\"", buf);
881 for (i = 0; i < nclusters; i++)
882 fprintf(out, "%s\n", clusters[i]);
884 com_err(program_name, errno, " while closing output file \"%s\"", buf);
894 PromptUser("Filename:", buf, sizeof(buf));
895 out = fopen(buf, "w");
897 com_err(program_name, errno, " while opening output file \"%s\"", buf);
900 for (i = 0; i < nmachines; i++)
901 fprintf(out, "%s\n", machines[i]);
903 com_err(program_name, errno, " while closing output file \"%s\"", buf);
907 /* Called from within the toolkit */
908 void localErrorHandler(s)
911 fprintf(stderr, "Moira X error: %s\n", s);
920 XtAppNextEvent(_XtDefaultAppContext(), &event);
921 XtDispatchEvent(&event);
925 int MoiraQuery(query, argc, argv, callback, data)
934 MakeWatchCursor(appShell);
935 status = mr_query(query, argc, argv, callback, data);
936 if (status != MR_ABORTED && status != MR_NOT_CONNECTED) {
937 MakeNormalCursor(appShell);
940 status = mr_connect(resources.server);
942 com_err(program_name, status, " while re-connecting to server %s",
944 MakeNormalCursor(appShell);
947 status = mr_auth("mmoira");
949 com_err(program_name, status, " while re-authenticating to server %s",
952 MakeNormalCursor(appShell);
955 status = mr_query(query, argc, argv, callback, data);
956 MakeNormalCursor(appShell);
961 MakeWatchCursor(w) {}
962 MakeNormalCursor(w) {}
964 static input_done_flag = 0;
972 PromptUser(msg, buf, bufsiz)
986 XtSetArg(args[0], XtNlabel, msg);
987 XtSetValues(WcFullNameToWidget(appShell, "*query*prompt"), args, 1);
989 XawTextReplace(WcFullNameToWidget(appShell, "*query*input"),
992 XtManageChild(WcFullNameToWidget(appShell, "*query"));
993 XRaiseWindow(dpy, XtWindow(WcFullNameToWidget(appShell, "*query")));
995 /* repeat main_loop here so we can check status & return */
997 while (!input_done_flag) {
998 XtAppNextEvent(_XtDefaultAppContext(), &e);
1002 XtSetArg(args[0], XtNstring, &data);
1003 XtGetValues(WcFullNameToWidget(appShell, "*query*input"), args, 1);
1004 strncpy(buf, data, bufsiz);
1006 XtUnmanageChild(WcFullNameToWidget(appShell, "*query"));
1010 void Help(w, s, unused)
1016 if (!strcmp(s, "moira"))
1017 tb.ptr = moira_help;
1018 else if (!strcmp(s, "program"))
1019 tb.ptr = program_help;
1020 else if (!strcmp(s, "author"))
1021 tb.ptr = author_help;
1022 else tb.ptr = unknown_help;
1025 tb.length = strlen(tb.ptr);
1026 tb.format = FMT8BIT;
1028 XawTextReplace(WcFullNameToWidget(appShell, "*msg"),
1031 XtPopup(WcFullNameToWidget(appShell, "*help"), XtGrabNone);
1040 for (i = 0; argv[i]; i++)
1046 /* compare machine strings. This is a separate routine instead of strcmp()
1047 * so that we can deal with the optional machine type after the space
1048 * padding. Usage is just like strcmp().
1054 if ((*s1 == ' ' || *s1 == 0) &&
1055 (*s2 == ' ' || *s2 == 0))
1058 return(strmcmp(s1+1, s2+1));
1065 /* search for a substring. Will scan string s looking for substring
1066 * f contained within it. Will return a pointer to the start of the
1067 * contained substring, or NULL if not found.
1075 while (p = index(s, *f)) {
1076 if (!strncmp(f, p, strlen(f)))
1085 void popup_error_hook(who, code, fmt, arg1, arg2, arg3, arg4, arg5)
1089 caddr_t arg1, arg2, arg3, arg4, arg5;
1091 char buf[BUFSIZ], *cp;
1095 (void) strcpy(buf, who);
1096 for (cp = buf; *cp; cp++);
1100 (void) strcpy(cp, error_message(code));
1104 sprintf(cp, fmt, arg1, arg2, arg3, arg4, arg5);
1108 tb.length = strlen(tb.ptr);
1109 tb.format = FMT8BIT;
1111 XawTextReplace(WcFullNameToWidget(appShell, "*errmsg"),
1113 XtCallActionProc(WcFullNameToWidget(appShell, "*errmsg"),
1114 "form-paragraph", &e, NULL, 0);
1116 XtPopup(WcFullNameToWidget(appShell, "*error"), XtGrabNone);