cvsimport
[fvwm.git] / fvwm / module_list.c
blob0079953389e410ec146c06e8b5bf5f6409344a94
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #include "config.h"
19 #include <errno.h>
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h>
22 #endif
24 /* for F_CMD_ARGS */
25 #include "fvwm/fvwm.h"
26 #include "execcontext.h"
27 /* end of for CMD_ARGS */
29 /*for debug message*/
30 #include "fvwm.h"
31 #include "misc.h"
32 /* end of for debug message */
34 /* for get_current_read_file */
35 #include "read.h"
36 /* for busy cursor */
37 #include "cursor.h"
39 /* for Scr global */
40 #include "screen.h"
42 #include "externs.h"
44 /* for module syncronous */
45 #include "libs/ftime.h"
46 #include "libs/System.c"
47 #include "libs/envvar.h"
48 #include "libs/Parse.h"
49 #include "libs/Strings.h"
50 #include "libs/wild.h"
51 #include "libs/fvwmsignal.h"
52 #include "events.h"
53 #include "bindings.h"
55 /* for positive write */
57 #include "module_list.h"
58 #include "module_interface.h"
60 * Use POSIX behaviour if we can, otherwise use SysV instead
61 * should this be here?
63 #ifndef O_NONBLOCK
64 # define O_NONBLOCK O_NDELAY
65 #endif
67 #define MOD_NOGRABMASK(m) ((m)->xNoGrabMask)
68 #define MOD_SYNCMASK(m) ((m)->xSyncMask)
70 typedef struct
72 unsigned long *data;
73 int size;
74 int done;
75 } mqueue_object_type;
78 /* the linked list pointers to the first and last modules */
79 static fmodule_list module_list = NULL;
80 /* keep to-be-deleted modules in a deathrow until they are deleted safely. */
81 static fmodule_list death_row = NULL;
84 * static functions
86 static fmodule *module_alloc(void);
87 static void module_free(fmodule *module);
90 * list handling functions
92 static inline void module_list_insert(fmodule *module, fmodule_list *list);
93 static inline fmodule *module_list_remove(fmodule *module, fmodule_list *list);
94 static inline void module_list_destroy(fmodule_list *list);
95 static inline int module_list_len(fmodule_list *list);
97 static void KillModuleByName(char *name, char *alias);
98 static char *get_pipe_name(fmodule *module);
99 static void DeleteMessageQueueBuff(fmodule *module);
101 static inline void msg_mask_set(
102 msg_masks_t *msg_mask, unsigned long m1, unsigned long m2);
103 static void set_message_mask(msg_masks_t *mask, unsigned long msg);
106 void module_kill_all(void)
108 module_list_destroy(&module_list);
110 return;
113 static fmodule *module_alloc(void)
115 fmodule *module;
117 module = (fmodule *)safemalloc(sizeof(fmodule));
118 MOD_SET_CMDLINE(module, 0);
119 MOD_READFD(module) = -1;
120 MOD_WRITEFD(module) = -1;
121 fqueue_init(&MOD_PIPEQUEUE(module));
122 msg_mask_set(&MOD_PIPEMASK(module), DEFAULT_MASK, DEFAULT_MASK);
123 msg_mask_set(&MOD_NOGRABMASK(module), 0, 0);
124 msg_mask_set(&MOD_SYNCMASK(module), 0, 0);
125 MOD_NAME(module) = NULL;
126 MOD_ALIAS(module) = NULL;
128 return module;
131 /* closes the pipes and frees every data associated with a module record */
132 static void module_free(fmodule *module)
134 if (module == NULL)
136 return;
138 close(MOD_WRITEFD(module));
139 close(MOD_READFD(module));
141 if (MOD_NAME(module) != NULL)
143 free(MOD_NAME(module));
145 if (MOD_ALIAS(module) != NULL)
147 free(MOD_ALIAS(module));
149 while (!FQUEUE_IS_EMPTY(&(MOD_PIPEQUEUE(module))))
151 DeleteMessageQueueBuff(module);
153 free(module);
155 return;
158 static inline void module_list_insert(fmodule *module, fmodule_list *list)
160 fmodule_store *new_store;
161 DBUG("module_list_insert", "inserting module");
162 if (module == NULL)
164 return;
166 new_store = (fmodule_store*)safemalloc(sizeof(fmodule_store));
167 new_store->module = module;
168 new_store->next = *list;
169 *list = new_store;
171 return;
174 static inline fmodule *module_list_remove(fmodule *module, fmodule_list *list)
176 fmodule_store **position;
178 if (module == NULL)
180 return NULL;
183 for (
184 position = list; *position != NULL;
185 position = &((*position)->next))
187 if ((*position)->module == module)
189 /* found it */
190 fmodule_store *current;
192 DBUG("module_list_remove", "Removing from module list");
193 current = *position;
194 *position = (*position)->next;
195 free(current);
197 return module;
201 /* module not found */
202 DBUG("module_list_remove", "Tried to remove a not listed module!");
204 return NULL;
207 static inline void module_list_destroy(fmodule_list *list)
209 fmodule_store *current;
210 fmodule_store *next;
212 for (current = *list; current != NULL; current = next)
214 next = current->next;
215 module_free(current->module);
216 free(current);
218 *list = NULL;
220 return;
223 static fmodule *do_execute_module(
224 F_CMD_ARGS, Bool desperate, Bool do_listen_only)
226 int fvwm_to_app[2], app_to_fvwm[2];
227 int i, val, nargs = 0;
228 char *cptr = NULL;
229 char **args = NULL;
230 char *arg1 = NULL;
231 char arg2[20];
232 char arg3[20];
233 char arg5[20];
234 char arg6[20];
235 char *token;
236 extern char *ModulePath;
237 Window win;
238 FvwmWindow * const fw = exc->w.fw;
239 fmodule *module;
241 fvwm_to_app[0] = -1;
242 fvwm_to_app[1] = -1;
243 app_to_fvwm[1] = -1;
244 app_to_fvwm[0] = -1;
245 args = (char **)safemalloc(7 * sizeof(char *));
246 /* Olivier: Why ? */
247 /* if (eventp->type != KeyPress) */
248 /* UngrabEm(); */
249 if (action == NULL)
251 goto err_exit;
253 if (fw)
255 win = FW_W(fw);
257 else
259 win = None;
261 action = GetNextToken(action, &cptr);
262 if (!cptr)
264 goto err_exit;
266 arg1 = searchPath(ModulePath, cptr, EXECUTABLE_EXTENSION, X_OK);
267 if (arg1 == NULL)
269 /* If this function is called in 'desparate' mode this means
270 * fvwm is trying a module name as a last resort. In this case
271 * the error message is inappropriate because it was most
272 * likely a typo in a command, not a module name. */
273 if (!desperate)
275 fvwm_msg(
276 ERR, "executeModule",
277 "No such module '%s' in ModulePath '%s'",
278 cptr, ModulePath);
280 goto err_exit;
282 #ifdef REMOVE_EXECUTABLE_EXTENSION
284 char *p;
286 p = arg1 + strlen(arg1) - strlen(EXECUTABLE_EXTENSION);
287 if (strcmp(p, EXECUTABLE_EXTENSION) == 0)
289 *p = 0;
292 #endif
294 /* I want one-ended pipes, so I open two two-ended pipes,
295 * and close one end of each. I need one ended pipes so that
296 * I can detect when the module crashes/malfunctions */
297 if (do_listen_only == True)
299 fvwm_to_app[0] = -1;
300 fvwm_to_app[1] = -1;
302 else if (pipe(fvwm_to_app) != 0)
304 fvwm_msg(ERR, "executeModule", "Failed to open pipe");
305 goto err_exit;
307 if (pipe(app_to_fvwm) != 0)
309 fvwm_msg(ERR, "executeModule", "Failed to open pipe2");
310 goto err_exit;
312 if (
313 fvwm_to_app[0] >= fvwmlib_max_fd ||
314 fvwm_to_app[1] >= fvwmlib_max_fd ||
315 app_to_fvwm[0] >= fvwmlib_max_fd ||
316 app_to_fvwm[1] >= fvwmlib_max_fd)
318 fvwm_msg(ERR, "executeModule", "too many open fds");
319 goto err_exit;
322 /* all ok, create the space and fill up */
323 module = module_alloc();
325 MOD_NAME(module) = stripcpy(cptr);
326 free(cptr);
327 sprintf(arg2, "%d", app_to_fvwm[1]);
328 sprintf(arg3, "%d", fvwm_to_app[0]);
329 sprintf(arg5, "%lx", (unsigned long)win);
330 sprintf(arg6, "%lx", (unsigned long)exc->w.wcontext);
331 args[0] = arg1;
332 args[1] = arg2;
333 args[2] = arg3;
334 args[3] = (char *)get_current_read_file();
335 if (!args[3])
337 args[3] = "none";
339 args[4] = arg5;
340 args[5] = arg6;
341 for (nargs = 6; action = GetNextToken(action, &token), token; nargs++)
343 args = (char **)saferealloc(
344 (void *)args, (nargs + 2) * sizeof(char *));
345 args[nargs] = token;
346 if (MOD_ALIAS(module) == NULL)
348 const char *ptr = skipModuleAliasToken(args[nargs]);
350 if (ptr && *ptr == '\0')
352 MOD_ALIAS(module) = stripcpy(args[nargs]);
356 args[nargs] = NULL;
358 /* Try vfork instead of fork. The man page says that vfork is better!
360 /* Also, had to change exit to _exit() */
361 /* Not everyone has vfork! */
362 val = fork();
363 if (val > 0)
365 /* This fork remains running fvwm */
366 /* close appropriate descriptors from each pipe so
367 * that fvwm will be able to tell when the app dies */
368 close(app_to_fvwm[1]);
369 /* dont't care that this may be -1 */
370 close(fvwm_to_app[0]);
372 /* add these pipes to fvwm's active pipe list */
373 MOD_WRITEFD(module) = fvwm_to_app[1];
374 MOD_READFD(module) = app_to_fvwm[0];
375 msg_mask_set(
376 &MOD_PIPEMASK(module), DEFAULT_MASK, DEFAULT_MASK);
377 free(arg1);
378 if (DoingCommandLine)
380 /* add to the list of command line modules */
381 DBUG("executeModule", "starting commandline module\n");
382 MOD_SET_CMDLINE(module, 1);
385 /* make the PositiveWrite pipe non-blocking. Don't want to jam
386 * up fvwm because of an uncooperative module */
387 if (MOD_WRITEFD(module) >= 0)
389 fcntl(MOD_WRITEFD(module), F_SETFL, O_NONBLOCK);
391 /* Mark the pipes close-on exec so other programs
392 * won`t inherit them */
393 if (fcntl(MOD_READFD(module), F_SETFD, 1) == -1)
395 fvwm_msg(
396 ERR, "executeModule",
397 "module close-on-exec failed");
399 if (
400 MOD_WRITEFD(module) >= 0 &&
401 fcntl(MOD_WRITEFD(module), F_SETFD, 1) == -1)
403 fvwm_msg(
404 ERR, "executeModule",
405 "module close-on-exec failed");
407 /* module struct is completed, insert into the list */
408 module_list_insert(module, &module_list);
410 for (i = 6; i < nargs; i++)
412 if (args[i] != 0)
414 free(args[i]);
418 else if (val ==0)
420 /* this is the child */
421 /* this fork execs the module */
422 #ifdef FORK_CREATES_CHILD
423 /* dont't care that this may be -1 */
424 close(fvwm_to_app[1]);
425 close(app_to_fvwm[0]);
426 #endif
427 fvmm_deinstall_signals();
428 if (!Pdefault)
430 char visualid[32];
431 char colormap[32];
433 sprintf(
434 visualid, "FVWM_VISUALID=%lx",
435 XVisualIDFromVisual(Pvisual));
436 flib_putenv("FVWM_VISUALID", visualid);
437 sprintf(colormap, "FVWM_COLORMAP=%lx", Pcmap);
438 flib_putenv("FVWM_COLORMAP", colormap);
440 else
442 flib_unsetenv("FVWM_VISUALID");
443 flib_unsetenv("FVWM_COLORMAP");
446 /* Why is this execvp?? We've already searched the module
447 * path! */
448 execvp(arg1,args);
449 fvwm_msg(
450 ERR, "executeModule", "Execution of module failed: %s",
451 arg1);
452 perror("");
453 close(app_to_fvwm[1]);
454 /* dont't care that this may be -1 */
455 close(fvwm_to_app[0]);
456 #ifdef FORK_CREATES_CHILD
457 exit(1);
458 #endif
460 else
462 fvwm_msg(ERR, "executeModule", "Fork failed");
463 free(arg1);
464 for (i = 6; i < nargs; i++)
466 if (args[i] != 0)
468 free(args[i]);
471 free(args);
472 module_free(module);
474 return NULL;
476 free(args);
478 return module;
480 err_exit:
481 if (arg1 != NULL)
483 free(arg1);
485 if (cptr != NULL)
487 free(cptr);
489 if (args != NULL)
491 free(args);
493 /* dont't care that these may be -1 */
494 close(fvwm_to_app[0]);
495 close(fvwm_to_app[1]);
496 close(app_to_fvwm[0]);
497 close(app_to_fvwm[1]);
499 return NULL;
502 fmodule *executeModuleDesperate(F_CMD_ARGS)
504 fmodule *m;
506 m = do_execute_module(F_PASS_ARGS, True, False);
508 return m;
511 void module_kill(fmodule *module)
513 module_list_insert(
514 module_list_remove(module, &module_list), &death_row);
516 return;
519 /* free modules in the deathrow */
520 void module_cleanup(void)
522 module_list_destroy(&death_row);
524 return;
527 /* void module_send(fmodule *module, unsigned long *ptr, int size) */
528 /* This used to be marked "fvwm_inline". I removed this
529 when I added the lockonsend logic. The routine seems too big to
530 want to inline. dje 9/4/98 */
531 extern int myxgrabcount; /* defined in libs/Grab.c */
532 extern char *ModuleUnlock; /* defined in libs/Module.c */
533 void PositiveWrite(fmodule *module, unsigned long *ptr, int size)
535 extern int moduleTimeout;
536 msg_masks_t mask;
538 if (ptr == NULL)
540 return;
542 if (MOD_WRITEFD(module) == -1)
544 return;
546 if (!IS_MESSAGE_IN_MASK(&(MOD_PIPEMASK(module)), ptr[1]))
548 return;
551 /* a dirty hack to prevent FvwmAnimate triggering during Recapture */
552 /* would be better to send RecaptureStart and RecaptureEnd messages. */
553 /* If module is lock on send for iconify message and it's an
554 * iconify event and server grabbed, then return */
555 mask.m1 = (MOD_NOGRABMASK(module).m1 & MOD_SYNCMASK(module).m1);
556 mask.m2 = (MOD_NOGRABMASK(module).m2 & MOD_SYNCMASK(module).m2);
557 if (IS_MESSAGE_IN_MASK(&mask, ptr[1]) && myxgrabcount != 0)
559 return;
562 /* DV: This was once the AddToMessageQueue function. Since it was only
563 * called once, put it in here for better performance. */
565 mqueue_object_type *c;
567 c = (mqueue_object_type *)malloc(
568 sizeof(mqueue_object_type) + size);
569 if (c == NULL)
571 fvwm_msg(ERR, "PositiveWrite", "malloc failed\n");
572 exit(1);
574 c->size = size;
575 c->done = 0;
576 c->data = (unsigned long *)(c + 1);
577 memcpy((void*)c->data, (const void*)ptr, size);
578 fqueue_add_at_end(&(MOD_PIPEQUEUE(module)), c);
581 /* dje, from afterstep, for FvwmAnimate, allows modules to sync with
582 * fvwm. this is disabled when the server is grabbed, otherwise
583 * deadlocks happen. M_LOCKONSEND has been replaced by a separated
584 * mask which defines on which messages the fvwm-to-module
585 * communication need to be lock on send. olicha Nov 13, 1999 */
586 /* migo (19-Aug-2000): removed !myxgrabcount to sync M_DESTROY_WINDOW
588 /* dv (06-Jul-2002): added the !myxgrabcount again. Deadlocks *do*
589 * happen without it. There must be another way to fix
590 * M_DESTROY_WINDOW handling in FvwmEvent. */
591 /*if (IS_MESSAGE_IN_MASK(&(MOD_SYNCMASK(module)), ptr[1]))*/
592 if (
593 IS_MESSAGE_IN_MASK(
594 &(MOD_SYNCMASK(module)), ptr[1]) && !myxgrabcount)
596 fd_set readSet;
597 int channel = MOD_READFD(module);
598 struct timeval timeout;
599 Bool done = False;
600 fmodule_input *input;
602 FlushMessageQueue(module);
604 while (!done)
606 int rc = 0;
608 * We give the read a long timeout; if the module
609 * fails to respond within this time then it deserves
610 * to be KILLED!
612 * NOTE: rather than impose an arbitrary timeout on the
613 * user, we will make this a configuration parameter.
617 timeout.tv_sec = moduleTimeout;
618 timeout.tv_usec = 0;
619 FD_ZERO(&readSet);
620 FD_SET(channel, &readSet);
622 /* Wait for input to arrive on just one
623 * descriptor, with a timeout (fvwmSelect <= 0)
624 * or read() returning wrong size is bad news
626 rc = fvwmSelect(
627 channel + 1, &readSet, NULL, NULL,
628 &timeout);
629 /* retry if select() failed with EINTR */
630 } while (rc < 0 && !isTerminated && (errno == EINTR));
632 if ( isTerminated )
634 break;
637 if (rc > 0)
639 input = module_receive(module);
640 if (
641 input == NULL ||
642 module_input_expect(input,
643 ModuleUnlockResponse))
645 module_input_discard(input);
646 done = True;
648 else
650 module_input_execute(input);
654 else
656 char *name;
658 name = get_pipe_name(module);
659 /* Doh! Something has gone wrong - get rid of
660 * the offender! */
661 fvwm_msg(ERR, "PositiveWrite",
662 "Failed to read descriptor from"
663 " '%s':\n"
664 "- data available=%c\n"
665 "- terminate signal=%c\n",
666 name,
667 (FD_ISSET(channel, &readSet) ?
668 'Y' : 'N'),
669 isTerminated ? 'Y' : 'N');
670 module_kill(module);
671 break;
675 /* Execute all messages from the module until UNLOCK is
676 * received N.B. This may cause recursion if a command
677 * results in a sync message to another module, which
678 * in turn may send a command that results in another
679 * sync message to this module.
680 * Hippo: I don't think this will cause deadlocks, but
681 * the third time we get here the first times UNLOCK
682 * will be read and then on returning up the third
683 * level UNLOCK will be read at the first level. This
684 * could be difficult to fix without turning queueing
685 * on. Turning queueing on may be bad because it can
686 * be useful for modules to be able to inject commands
687 * from modules in a synchronous manner. e.g.
688 * FvwmIconMan can tell FvwmAnimate to do an animation
689 * when a window is de-iconified from the IconMan,
690 * queueing make s this happen too late. */
694 return;
697 fmodule_input *module_receive(fmodule *module)
699 unsigned long size;
700 unsigned long cont;
701 Window win;
702 int n;
703 fmodule_input *input = NULL;
705 n = read(MOD_READFD(module), &win, sizeof(Window));
706 if (n < sizeof(Window))
708 /* exit silently, module should have died.. */
709 goto err;
712 n = read(MOD_READFD(module), &size, sizeof(size));
713 if (n < sizeof(size))
715 fvwm_msg(
716 ERR, "module_receive",
717 "Fail to read command size (Module: %p, read: %i, "
718 "size: %i)", module, n, (int)sizeof(size));
719 goto err;
722 if (size > MAX_MODULE_INPUT_TEXT_LEN)
724 fvwm_msg(ERR, "module_receive",
725 "Module(%p) command is too big (%ld), limit is %d",
726 module, size, MAX_MODULE_INPUT_TEXT_LEN);
727 /* The rest of the output from this module is going to be
728 * scrambled so let's kill it rather than risk interpreting
729 * garbage */
730 goto err;
733 /* allocate all storage at once */
734 /* also save space for the '\0' termination character */
735 input = (fmodule_input *)safemalloc(
736 sizeof(fmodule_input) + sizeof(char)*(size + 1));
738 input->module = module;
739 input->window = win;
740 input->command = (char*)input + sizeof(fmodule_input);
742 n = read(MOD_READFD(module), input->command, size);
743 if (n < size)
745 fvwm_msg(
746 ERR, "module_receive",
747 "Fail to read command (Module: %p, read: %i, size:"
748 " %ld)", module, n, size);
749 goto err;
751 input->command[n] = '\0';
752 n = read(MOD_READFD(module), &cont, sizeof(cont));
753 if (n < sizeof(cont))
755 fvwm_msg(ERR, "module_receive",
756 "Module %p, Size Problems (read: %d, size: %d)",
757 module, n, (int)sizeof(cont));
758 goto err;
760 if (cont == 0)
762 /* this is documented as a valid way for a module to quit
763 * so let's not complain */
764 module_kill(module);
767 return input;
768 err:
769 module_kill(module);
770 module_input_discard(input);
771 return NULL;
774 /* frees the module input data struct */
775 void module_input_discard(fmodule_input *input)
777 if (input==NULL)
779 return;
781 free(input);
784 /* returns true if the module command matches "expect", false otherwise */
785 Bool module_input_expect(fmodule_input *input, char *expect)
787 if (input == NULL || input->command == NULL || expect == NULL)
789 return False;
792 if (strncasecmp(input->command, expect, strlen(expect)) == 0)
794 /* the module sent the expected string */
795 return True;
798 return False;
801 void module_list_itr_init(fmodule_list_itr *itr)
803 *itr = module_list;
805 return;
808 fmodule *module_list_itr_next(fmodule_list_itr *itr)
810 fmodule *module;
812 if (*itr == NULL)
814 return NULL;
816 module = (*itr)->module;
817 *itr = (*itr)->next;
819 return module;
822 int module_list_len(fmodule_list *list)
824 int count=0;
825 fmodule_store *current=*list;
826 while (current != NULL)
828 current = current->next;
829 count++;
832 return count;
835 static void KillModuleByName(char *name, char *alias)
837 fmodule_list_itr moditr;
838 fmodule *module;
840 if (name == NULL)
842 return;
844 module_list_itr_init(&moditr);
845 while ( (module = module_list_itr_next(&moditr)) != NULL)
847 if (
848 MOD_NAME(module) != NULL &&
849 matchWildcards(name, MOD_NAME(module)) &&
850 (!alias || (
851 MOD_ALIAS(module) &&
852 matchWildcards(alias, MOD_ALIAS(module)))))
854 module_kill(module);
858 return;
861 static char *get_pipe_name(fmodule *module)
863 char *name="";
865 if (MOD_NAME(module) != NULL)
867 if (MOD_ALIAS(module) != NULL)
869 name = CatString3(
870 MOD_NAME(module), " ", MOD_ALIAS(module));
872 else
874 name = MOD_NAME(module);
877 else
879 name = CatString3("(null)", "", "");
882 return name;
886 * returns a pointer inside a string (just after the alias) if ok or NULL
888 char *skipModuleAliasToken(const char *string)
890 #define is_valid_first_alias_char(ch) (isalpha(ch) || (ch) == '/')
891 #define is_valid_alias_char(ch) (is_valid_first_alias_char(ch) \
892 || isalnum(ch) || (ch) == '-' || \
893 (ch) == '.' || (ch) == '/')
895 if (is_valid_first_alias_char(*string))
897 int len = 1;
898 string++;
899 while (*string && is_valid_alias_char(*string))
901 if (++len > MAX_MODULE_ALIAS_LEN)
903 return NULL;
905 string++;
907 return (char *)string;
910 return NULL;
911 #undef is_valid_first_alias_char
912 #undef is_valid_alias_char
915 /* message mask handling - does this belong here? */
917 static inline void msg_mask_set(
918 msg_masks_t *msg_mask, unsigned long m1, unsigned long m2)
920 msg_mask->m1 = m1;
921 msg_mask->m2 = m2;
923 return;
927 * Sets the mask to the specific value. If M_EXTENDED_MSG is set in mask, the
928 * function operates only on the extended messages, otherwise it operates only
929 * on normal messages.
931 static void set_message_mask(msg_masks_t *mask, unsigned long msg)
933 if (msg & M_EXTENDED_MSG)
935 mask->m2 = (msg & ~M_EXTENDED_MSG);
937 else
939 mask->m1 = msg;
942 return;
946 /* message queues */
948 static void DeleteMessageQueueBuff(fmodule *module)
950 mqueue_object_type *obj;
952 if (fqueue_get_first(&(MOD_PIPEQUEUE(module)), (void **)&obj) == 1)
954 /* remove from queue */
955 fqueue_remove_or_operate_from_front(
956 &(MOD_PIPEQUEUE(module)), NULL, NULL, NULL, NULL);
957 /* we don't need to free the obj->data here because it's in the
958 * same malloced block as the obj itself. */
959 free(obj);
962 return;
965 void FlushMessageQueue(fmodule *module)
967 extern int moduleTimeout;
968 mqueue_object_type *obj;
969 char *dptr;
970 int a;
972 if (module == NULL)
974 return;
977 while (fqueue_get_first(&(MOD_PIPEQUEUE(module)), (void **)&obj) == 1)
979 dptr = (char *)obj->data;
980 while (obj->done < obj->size)
982 a = write(MOD_WRITEFD(module), &dptr[obj->done],
983 obj->size - obj->done);
984 if (a >=0)
986 obj->done += a;
988 /* the write returns EWOULDBLOCK or EAGAIN if the pipe
989 * is full. (This is non-blocking I/O). SunOS returns
990 * EWOULDBLOCK, OSF/1 returns EAGAIN under these
991 * conditions. Hopefully other OSes return one of these
992 * values too. Solaris 2 doesn't seem to have a man
993 * page for write(2) (!) */
994 else if (errno == EWOULDBLOCK || errno == EAGAIN)
996 fd_set writeSet;
997 struct timeval timeout;
998 int channel = MOD_WRITEFD(module);
999 int rc = 0;
1003 /* Wait until the pipe accepts further
1004 * input */
1005 timeout.tv_sec = moduleTimeout;
1006 timeout.tv_usec = 0;
1007 FD_ZERO(&writeSet);
1008 FD_SET(channel, &writeSet);
1009 rc = fvwmSelect(
1010 channel + 1, NULL, &writeSet,
1011 NULL, &timeout);
1012 /* retry if select() failed with EINTR
1014 } while ((rc < 0) && !isTerminated &&
1015 (errno == EINTR));
1017 if ( isTerminated )
1019 return;
1021 if (!FD_ISSET(channel, &writeSet))
1023 char *name;
1025 name = get_pipe_name(module);
1026 /* Doh! Something has gone wrong - get
1027 * rid of the offender! */
1028 fvwm_msg(
1029 ERR, "FlushMessageQueue",
1030 "Failed to write descriptor to"
1031 " '%s':\n"
1032 "- select rc=%d\n"
1033 "- terminate signal=%c\n",
1034 name, rc, isTerminated ?
1035 'Y' : 'N');
1036 module_kill(module);
1038 return;
1041 /* pipe accepts further input; continue */
1042 continue;
1044 else if (errno != EINTR)
1046 module_kill(module);
1048 return;
1051 DeleteMessageQueueBuff(module);
1054 return;
1057 void FlushAllMessageQueues(void)
1059 fmodule_list_itr moditr;
1060 fmodule *module;
1062 module_list_itr_init(&moditr);
1063 while ( (module = module_list_itr_next(&moditr)) != NULL)
1065 FlushMessageQueue(module);
1068 return;
1071 /* empty, only here so that the signal handling initialization code is the
1072 * same for modules and fvwm */
1073 RETSIGTYPE DeadPipe(int sig)
1075 SIGNAL_RETURN;
1078 void CMD_Module(F_CMD_ARGS)
1080 do_execute_module(F_PASS_ARGS, False, False);
1082 return;
1085 void CMD_ModuleListenOnly(F_CMD_ARGS)
1087 do_execute_module(F_PASS_ARGS, False, True);
1089 return;
1092 void CMD_KillModule(F_CMD_ARGS)
1094 char *name;
1095 char *alias = NULL;
1097 action = GetNextToken(action,&name);
1098 if (!name)
1100 return;
1103 GetNextToken(action, &alias);
1104 KillModuleByName(name, alias);
1105 free(name);
1106 if (alias)
1108 free(alias);
1110 return;
1113 void CMD_ModuleSynchronous(F_CMD_ARGS)
1115 int sec = 0;
1116 char *next;
1117 char *token;
1118 char *expect = ModuleFinishedStartupResponse;
1119 fmodule *module;
1120 fd_set in_fdset;
1121 fd_set out_fdset;
1122 time_t start_time;
1123 Bool done = False;
1124 Bool need_ungrab = False;
1125 char *escape = NULL;
1126 XEvent tmpevent;
1128 if (!action)
1130 return;
1133 token = PeekToken(action, &next);
1134 if (StrEquals(token, "expect"))
1136 token = PeekToken(next, &next);
1137 if (token)
1139 expect = alloca(strlen(token) + 1);
1140 strcpy(expect, token);
1142 action = next;
1143 token = PeekToken(action, &next);
1145 if (token && StrEquals(token, "timeout"))
1147 if (GetIntegerArguments(next, &next, &sec, 1) > 0 && sec > 0)
1149 /* we have a delay, skip the number */
1150 action = next;
1152 else
1154 fvwm_msg(ERR, "executeModuleSync", "illegal timeout");
1155 return;
1159 if (!action)
1161 /* no module name */
1162 return;
1165 module = do_execute_module(F_PASS_ARGS, False, False);
1166 if (module == NULL)
1168 /* executing the module failed, just return */
1169 return;
1172 /* Busy cursor stuff */
1173 if (Scr.BusyCursor & BUSY_MODULESYNCHRONOUS)
1175 if (GrabEm(CRS_WAIT, GRAB_BUSY))
1176 need_ungrab = True;
1179 /* wait for module input */
1180 start_time = time(NULL);
1182 while (!done)
1184 struct timeval timeout;
1185 int num_fd;
1187 /* A signal here could interrupt the select call. We would
1188 * then need to restart our select, unless the signal was
1189 * a "terminate" signal. Note that we need to reinitialise
1190 * all of select's parameters after it has returned. */
1193 FD_ZERO(&in_fdset);
1194 FD_ZERO(&out_fdset);
1196 FD_SET(MOD_READFD(module), &in_fdset);
1198 if (!FQUEUE_IS_EMPTY(&MOD_PIPEQUEUE(module)))
1200 FD_SET(MOD_WRITEFD(module), &out_fdset);
1202 timeout.tv_sec = 0;
1203 timeout.tv_usec = 1;
1204 num_fd = fvwmSelect(
1205 fvwmlib_max_fd, &in_fdset, &out_fdset, 0,
1206 &timeout);
1207 } while (num_fd < 0 && !isTerminated);
1209 /* Exit if we have received a "terminate" signal */
1210 if (isTerminated)
1212 break;
1215 if (num_fd > 0)
1217 if (FD_ISSET(MOD_READFD(module), &in_fdset))
1219 fmodule_input * input;
1221 /* Check for module input. */
1222 input = module_receive(module);
1223 if (
1224 input == NULL ||
1225 module_input_expect(input,expect))
1227 module_input_discard(input);
1228 done = True;
1230 else
1232 module_input_execute(input);
1237 if ((MOD_WRITEFD(module) >= 0) &&
1238 FD_ISSET(MOD_WRITEFD(module), &out_fdset))
1240 FlushMessageQueue(module);
1244 usleep(1000);
1245 if (difftime(time(NULL), start_time) >= sec && sec)
1247 /* timeout */
1248 done = True;
1251 /* Check for "escape function" */
1252 if (FPending(dpy) &&
1253 FCheckMaskEvent(dpy, KeyPressMask, &tmpevent))
1255 int context;
1256 XClassHint *class;
1257 char *name;
1258 Window w;
1260 context = GetContext(
1261 NULL, exc->w.fw, &tmpevent, &w);
1262 if (exc->w.fw != NULL)
1264 class = &(exc->w.fw->class);
1265 name = exc->w.fw->name.name;
1267 else
1269 class = NULL;
1270 name = NULL;
1272 escape = CheckBinding(
1273 Scr.AllBindings, STROKE_ARG(0)
1274 tmpevent.xkey.keycode, tmpevent.xkey.state,
1275 GetUnusedModifiers(), context, BIND_KEYPRESS,
1276 class, name);
1277 if (escape != NULL)
1279 if (!strcasecmp(escape,"escapefunc"))
1281 done = True;
1285 } /* while */
1287 if (need_ungrab)
1289 UngrabEm(GRAB_BUSY);
1292 return;
1295 /* mask handling - does this belong here? */
1297 void CMD_set_mask(F_CMD_ARGS)
1299 unsigned long val;
1301 if (exc->m.module == NULL)
1303 return;
1305 if (!action || sscanf(action, "%lu", &val) != 1)
1307 val = 0;
1309 set_message_mask(&(MOD_PIPEMASK(exc->m.module)), (unsigned long)val);
1311 return;
1314 void CMD_set_sync_mask(F_CMD_ARGS)
1316 unsigned long val;
1318 if (exc->m.module == NULL)
1320 return;
1322 if (!action || sscanf(action,"%lu",&val) != 1)
1324 val = 0;
1326 set_message_mask(&(MOD_SYNCMASK(exc->m.module)), (unsigned long)val);
1328 return;
1331 void CMD_set_nograb_mask(F_CMD_ARGS)
1333 unsigned long val;
1335 if (exc->m.module == NULL)
1337 return;
1339 if (!action || sscanf(action,"%lu",&val) != 1)
1341 val = 0;
1343 set_message_mask(&(MOD_NOGRABMASK(exc->m.module)), (unsigned long)val);
1345 return;