BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file NCDUdevMonitor.c |
||
3 | * @author Ambroz Bizjak <ambrop7@gmail.com> |
||
4 | * |
||
5 | * @section LICENSE |
||
6 | * |
||
7 | * Redistribution and use in source and binary forms, with or without |
||
8 | * modification, are permitted provided that the following conditions are met: |
||
9 | * 1. Redistributions of source code must retain the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer. |
||
11 | * 2. Redistributions in binary form must reproduce the above copyright |
||
12 | * notice, this list of conditions and the following disclaimer in the |
||
13 | * documentation and/or other materials provided with the distribution. |
||
14 | * 3. Neither the name of the author nor the |
||
15 | * names of its contributors may be used to endorse or promote products |
||
16 | * derived from this software without specific prior written permission. |
||
17 | * |
||
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
21 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
28 | */ |
||
29 | |||
30 | #include <stddef.h> |
||
31 | |||
32 | #include <base/BLog.h> |
||
33 | #include <misc/find_program.h> |
||
34 | |||
35 | #include <udevmonitor/NCDUdevMonitor.h> |
||
36 | |||
37 | #include <generated/blog_channel_NCDUdevMonitor.h> |
||
38 | |||
39 | #define PARSER_BUF_SIZE 16384 |
||
40 | #define PARSER_MAX_PROPERTIES 256 |
||
41 | |||
42 | static void report_error (NCDUdevMonitor *o) |
||
43 | { |
||
44 | ASSERT(!o->process_running) |
||
45 | ASSERT(!o->input_running) |
||
46 | |||
47 | DEBUGERROR(&o->d_err, o->handler_error(o->user, (o->process_was_error || o->input_was_error))); |
||
48 | } |
||
49 | |||
50 | static void process_handler_terminated (NCDUdevMonitor *o, int normally, uint8_t normally_exit_status) |
||
51 | { |
||
52 | DebugObject_Access(&o->d_obj); |
||
53 | ASSERT(o->process_running) |
||
54 | |||
55 | BLog(BLOG_INFO, "process terminated"); |
||
56 | |||
57 | // set process not running (so we don't try to kill it) |
||
58 | o->process_running = 0; |
||
59 | |||
60 | // remember process error |
||
61 | o->process_was_error = !(normally && normally_exit_status == 0); |
||
62 | |||
63 | if (!o->input_running) { |
||
64 | report_error(o); |
||
65 | return; |
||
66 | } |
||
67 | } |
||
68 | |||
69 | static void process_handler_closed (NCDUdevMonitor *o, int is_error) |
||
70 | { |
||
71 | DebugObject_Access(&o->d_obj); |
||
72 | ASSERT(o->input_running) |
||
73 | |||
74 | if (is_error) { |
||
75 | BLog(BLOG_ERROR, "pipe error"); |
||
76 | } else { |
||
77 | BLog(BLOG_INFO, "pipe closed"); |
||
78 | } |
||
79 | |||
80 | // disconnect connector |
||
81 | StreamRecvConnector_DisconnectInput(&o->connector); |
||
82 | |||
83 | // set input not running |
||
84 | o->input_running = 0; |
||
85 | |||
86 | // remember input error |
||
87 | o->input_was_error = is_error; |
||
88 | |||
89 | if (!o->process_running) { |
||
90 | report_error(o); |
||
91 | return; |
||
92 | } |
||
93 | } |
||
94 | |||
95 | static void parser_handler (NCDUdevMonitor *o) |
||
96 | { |
||
97 | DebugObject_Access(&o->d_obj); |
||
98 | |||
99 | o->handler_event(o->user); |
||
100 | return; |
||
101 | } |
||
102 | |||
103 | int NCDUdevMonitor_Init (NCDUdevMonitor *o, BReactor *reactor, BProcessManager *manager, int mode, void *user, |
||
104 | NCDUdevMonitor_handler_event handler_event, |
||
105 | NCDUdevMonitor_handler_error handler_error) |
||
106 | { |
||
107 | ASSERT(mode == NCDUDEVMONITOR_MODE_MONITOR_UDEV || mode == NCDUDEVMONITOR_MODE_INFO || mode == NCDUDEVMONITOR_MODE_MONITOR_KERNEL) |
||
108 | |||
109 | // init arguments |
||
110 | o->user = user; |
||
111 | o->handler_event = handler_event; |
||
112 | o->handler_error = handler_error; |
||
113 | |||
114 | // find programs |
||
115 | char *stdbuf_exec = badvpn_find_program("stdbuf"); |
||
116 | char *udevadm_exec = badvpn_find_program("udevadm"); |
||
117 | if (!stdbuf_exec) { |
||
118 | BLog(BLOG_ERROR, "failed to find stdbuf program"); |
||
119 | goto fail0; |
||
120 | } |
||
121 | if (!udevadm_exec) { |
||
122 | BLog(BLOG_ERROR, "failed to find udevadm program"); |
||
123 | goto fail0; |
||
124 | } |
||
125 | |||
126 | // construct arguments |
||
127 | const char *argv_monitor_udev[] = {stdbuf_exec, "-o", "L", udevadm_exec, "monitor", "--udev", "--environment", NULL}; |
||
128 | const char *argv_monitor_kernel[] = {stdbuf_exec, "-o", "L", udevadm_exec, "monitor", "--kernel", "--environment", NULL}; |
||
129 | const char *argv_info[] = {stdbuf_exec, "-o", "L", udevadm_exec, "info", "--query", "all", "--export-db", NULL}; |
||
130 | |||
131 | // choose arguments based on mode |
||
132 | const char **argv = NULL; // to remove warning |
||
133 | switch (mode) { |
||
134 | case NCDUDEVMONITOR_MODE_MONITOR_UDEV: argv = argv_monitor_udev; break; |
||
135 | case NCDUDEVMONITOR_MODE_INFO: argv = argv_info; break; |
||
136 | case NCDUDEVMONITOR_MODE_MONITOR_KERNEL: argv = argv_monitor_kernel; break; |
||
137 | default: ASSERT(0); |
||
138 | } |
||
139 | |||
140 | // init process |
||
141 | if (!BInputProcess_Init(&o->process, reactor, manager, o, |
||
142 | (BInputProcess_handler_terminated)process_handler_terminated, |
||
143 | (BInputProcess_handler_closed)process_handler_closed |
||
144 | )) { |
||
145 | BLog(BLOG_ERROR, "BInputProcess_Init failed"); |
||
146 | goto fail0; |
||
147 | } |
||
148 | |||
149 | // init connector |
||
150 | StreamRecvConnector_Init(&o->connector, BReactor_PendingGroup(reactor)); |
||
151 | StreamRecvConnector_ConnectInput(&o->connector, BInputProcess_GetInput(&o->process)); |
||
152 | |||
153 | // init parser |
||
154 | if (!NCDUdevMonitorParser_Init(&o->parser, StreamRecvConnector_GetOutput(&o->connector), PARSER_BUF_SIZE, PARSER_MAX_PROPERTIES, |
||
155 | (mode == NCDUDEVMONITOR_MODE_INFO), BReactor_PendingGroup(reactor), o, |
||
156 | (NCDUdevMonitorParser_handler)parser_handler |
||
157 | )) { |
||
158 | BLog(BLOG_ERROR, "NCDUdevMonitorParser_Init failed"); |
||
159 | goto fail1; |
||
160 | } |
||
161 | |||
162 | // start process |
||
163 | if (!BInputProcess_Start(&o->process, stdbuf_exec, (char **)argv, NULL)) { |
||
164 | BLog(BLOG_ERROR, "BInputProcess_Start failed"); |
||
165 | goto fail2; |
||
166 | } |
||
167 | |||
168 | // set process running, input running |
||
169 | o->process_running = 1; |
||
170 | o->input_running = 1; |
||
171 | |||
172 | free(udevadm_exec); |
||
173 | free(stdbuf_exec); |
||
174 | |||
175 | DebugError_Init(&o->d_err, BReactor_PendingGroup(reactor)); |
||
176 | DebugObject_Init(&o->d_obj); |
||
177 | return 1; |
||
178 | |||
179 | fail2: |
||
180 | NCDUdevMonitorParser_Free(&o->parser); |
||
181 | fail1: |
||
182 | StreamRecvConnector_Free(&o->connector); |
||
183 | BInputProcess_Free(&o->process); |
||
184 | fail0: |
||
185 | free(udevadm_exec); |
||
186 | free(stdbuf_exec); |
||
187 | return 0; |
||
188 | } |
||
189 | |||
190 | void NCDUdevMonitor_Free (NCDUdevMonitor *o) |
||
191 | { |
||
192 | DebugObject_Free(&o->d_obj); |
||
193 | DebugError_Free(&o->d_err); |
||
194 | |||
195 | // free parser |
||
196 | NCDUdevMonitorParser_Free(&o->parser); |
||
197 | |||
198 | // free connector |
||
199 | StreamRecvConnector_Free(&o->connector); |
||
200 | |||
201 | // kill process it it's running |
||
202 | if (o->process_running) { |
||
203 | BInputProcess_Kill(&o->process); |
||
204 | } |
||
205 | |||
206 | // free process |
||
207 | BInputProcess_Free(&o->process); |
||
208 | } |
||
209 | |||
210 | void NCDUdevMonitor_Done (NCDUdevMonitor *o) |
||
211 | { |
||
212 | DebugObject_Access(&o->d_obj); |
||
213 | DebugError_AssertNoError(&o->d_err); |
||
214 | NCDUdevMonitorParser_AssertReady(&o->parser); |
||
215 | |||
216 | NCDUdevMonitorParser_Done(&o->parser); |
||
217 | } |
||
218 | |||
219 | int NCDUdevMonitor_IsReadyEvent (NCDUdevMonitor *o) |
||
220 | { |
||
221 | DebugObject_Access(&o->d_obj); |
||
222 | DebugError_AssertNoError(&o->d_err); |
||
223 | NCDUdevMonitorParser_AssertReady(&o->parser); |
||
224 | |||
225 | return NCDUdevMonitorParser_IsReadyEvent(&o->parser); |
||
226 | } |
||
227 | void NCDUdevMonitor_AssertReady (NCDUdevMonitor *o) |
||
228 | { |
||
229 | DebugObject_Access(&o->d_obj); |
||
230 | DebugError_AssertNoError(&o->d_err); |
||
231 | NCDUdevMonitorParser_AssertReady(&o->parser); |
||
232 | } |
||
233 | |||
234 | int NCDUdevMonitor_GetNumProperties (NCDUdevMonitor *o) |
||
235 | { |
||
236 | DebugObject_Access(&o->d_obj); |
||
237 | DebugError_AssertNoError(&o->d_err); |
||
238 | NCDUdevMonitorParser_AssertReady(&o->parser); |
||
239 | |||
240 | return NCDUdevMonitorParser_GetNumProperties(&o->parser); |
||
241 | } |
||
242 | |||
243 | void NCDUdevMonitor_GetProperty (NCDUdevMonitor *o, int index, const char **name, const char **value) |
||
244 | { |
||
245 | DebugObject_Access(&o->d_obj); |
||
246 | DebugError_AssertNoError(&o->d_err); |
||
247 | NCDUdevMonitorParser_AssertReady(&o->parser); |
||
248 | |||
249 | NCDUdevMonitorParser_GetProperty(&o->parser, index, name, value); |
||
250 | } |