1 /*	$NetBSD: fifo_trigger.c,v 1.1.1.1 2009/06/23 10:08:59 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	fifo_trigger 3
6 /* SUMMARY
7 /*	wakeup fifo server
8 /* SYNOPSIS
9 /*	#include <trigger.h>
10 /*
11 /*	int	fifo_trigger(service, buf, len, timeout)
12 /*	const char *service;
13 /*	const char *buf;
14 /*	ssize_t	len;
15 /*	int	timeout;
16 /* DESCRIPTION
17 /*	fifo_trigger() wakes up the named fifo server by writing
18 /*	the contents of the specified buffer to the fifo. There is
19 /*	no guarantee that the written data will actually be received.
20 /*
21 /*	Arguments:
22 /* .IP service
23 /*	Name of the communication endpoint.
24 /* .IP buf
25 /*	Address of data to be written.
26 /* .IP len
27 /*	Amount of data to be written.
28 /* .IP timeout
29 /*	Deadline in seconds. Specify a value <= 0 to disable
30 /*	the time limit.
31 /* DIAGNOSTICS
32 /*	The result is zero when the fifo could be opened, -1 otherwise.
33 /* BUGS
34 /* LICENSE
35 /* .ad
36 /* .fi
37 /*	The Secure Mailer license must be distributed with this software.
38 /* AUTHOR(S)
39 /*	Wietse Venema
40 /*	IBM T.J. Watson Research
41 /*	P.O. Box 704
42 /*	Yorktown Heights, NY 10598, USA
43 /*--*/
44 
45 /* System library. */
46 
47 #include <sys_defs.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 
51 /* Utility library. */
52 
53 #include <msg.h>
54 #include <iostuff.h>
55 #include <safe_open.h>
56 #include <trigger.h>
57 
58 /* fifo_trigger - wakeup fifo server */
59 
60 int     fifo_trigger(const char *service, const char *buf, ssize_t len, int timeout)
61 {
62     static VSTRING *why;
63     const char *myname = "fifo_trigger";
64     VSTREAM *fp;
65     int     fd;
66 
67     if (why == 0)
68 	why = vstring_alloc(1);
69 
70     /*
71      * Write the request to the service fifo. According to POSIX, the open
72      * shall always return immediately, and shall return an error when no
73      * process is reading from the FIFO.
74      *
75      * Use safe_open() so that we don't follow symlinks, and so that we don't
76      * open files with multiple hard links. We're not (yet) going to bother
77      * the caller with safe_open() specific quirks such as the why argument.
78      */
79     if ((fp = safe_open(service, O_WRONLY | O_NONBLOCK, 0,
80 			(struct stat *) 0, -1, -1, why)) == 0) {
81 	if (msg_verbose)
82 	    msg_info("%s: open %s: %s", myname, service, vstring_str(why));
83 	return (-1);
84     }
85     fd = vstream_fileno(fp);
86 
87     /*
88      * Write the request...
89      */
90     non_blocking(fd, timeout > 0 ? NON_BLOCKING : BLOCKING);
91     if (write_buf(fd, buf, len, timeout) < 0)
92 	if (msg_verbose)
93 	    msg_warn("%s: write %s: %m", myname, service);
94 
95     /*
96      * Disconnect.
97      */
98     if (vstream_fclose(fp))
99 	if (msg_verbose)
100 	    msg_warn("%s: close %s: %m", myname, service);
101     return (0);
102 }
103 
104 #ifdef TEST
105 
106  /*
107   * Set up a FIFO listener, and keep triggering until the listener becomes
108   * idle, which should never happen.
109   */
110 #include <signal.h>
111 #include <stdlib.h>
112 
113 #include "events.h"
114 #include "listen.h"
115 
116 #define TEST_FIFO	"test-fifo"
117 
118 int     trig_count;
119 int     wakeup_count;
120 
121 static void cleanup(void)
122 {
123     unlink(TEST_FIFO);
124     exit(1);
125 }
126 
127 static void handler(int sig)
128 {
129     msg_fatal("got signal %d after %d triggers %d wakeups",
130 	      sig, trig_count, wakeup_count);
131 }
132 
133 static void read_event(int unused_event, char *context)
134 {
135     int     fd = CAST_CHAR_PTR_TO_INT(context);
136     char    ch;
137 
138     wakeup_count++;
139 
140     if (read(fd, &ch, 1) != 1)
141 	msg_fatal("read %s: %m", TEST_FIFO);
142 }
143 
144 int     main(int unused_argc, char **unused_argv)
145 {
146     int     listen_fd;
147 
148     listen_fd = fifo_listen(TEST_FIFO, 0600, NON_BLOCKING);
149     msg_cleanup(cleanup);
150     event_enable_read(listen_fd, read_event, CAST_INT_TO_CHAR_PTR(listen_fd));
151     signal(SIGINT, handler);
152     signal(SIGALRM, handler);
153     for (;;) {
154 	alarm(10);
155 	if (fifo_trigger(TEST_FIFO, "", 1, 0) < 0)
156 	    msg_fatal("trigger %s: %m", TEST_FIFO);
157 	trig_count++;
158 	if (fifo_trigger(TEST_FIFO, "", 1, 0) < 0)
159 	    msg_fatal("trigger %s: %m", TEST_FIFO);
160 	trig_count++;
161 	if (fifo_trigger(TEST_FIFO, "", 1, 0) < 0)
162 	    msg_fatal("trigger %s: %m", TEST_FIFO);
163 	trig_count++;
164 	event_loop(-1);
165 	event_loop(-1);
166 	event_loop(-1);
167     }
168 }
169 
170 #endif
171