1 /*
2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <sys/poll.h>
39 #include <sys/queue.h>
40 #include <sys/un.h>
41
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <libgen.h>
46 #include <regex.h>
47 #include <signal.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <syslog.h>
53 #include <unistd.h>
54
55 #include <libprop/proplib.h>
56 #include <sys/udev.h>
57 #define LIBDEVATTR_INTERNAL
58 #include "devattr.h"
59
60 struct udev {
61 int gp_fd;
62 int monitor_fd;
63 int refs;
64
65 void *userdata;
66 };
67
68 struct udev *
udev_ref(struct udev * udev_ctx)69 udev_ref(struct udev *udev_ctx)
70 {
71 atomic_add_int(&udev_ctx->refs, 1);
72
73 return udev_ctx;
74 }
75
76 void
udev_unref(struct udev * udev_ctx)77 udev_unref(struct udev *udev_ctx)
78 {
79 int refcount;
80
81 refcount = atomic_fetchadd_int(&udev_ctx->refs, -1);
82
83 if (refcount == 1) {
84 atomic_subtract_int(&udev_ctx->refs, 0x400); /* in destruction */
85 if (udev_ctx->gp_fd != -1)
86 close (udev_ctx->gp_fd);
87 if (udev_ctx->monitor_fd != -1)
88 close (udev_ctx->monitor_fd);
89
90 free(udev_ctx);
91 }
92 }
93
94 struct udev *
udev_new(void)95 udev_new(void)
96 {
97 struct udev *udev_ctx;
98 int ret, s;
99
100 ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s);
101 if (ret < 0)
102 return NULL;
103
104 udev_ctx = malloc(sizeof(struct udev));
105
106 udev_ctx->refs = 1;
107 udev_ctx->gp_fd = s;
108 udev_ctx->monitor_fd = -1;
109 udev_ctx->userdata = NULL;
110
111 return udev_ctx;
112 }
113
udev_get_dev_path(struct udev * udev_ctx __unused)114 const char *udev_get_dev_path(struct udev *udev_ctx __unused)
115 {
116 return "/dev";
117 }
118
119 void *
udev_get_userdata(struct udev * udev_ctx)120 udev_get_userdata(struct udev *udev_ctx)
121 {
122 return udev_ctx->userdata;
123 }
124
125 void
udev_set_userdata(struct udev * udev_ctx,void * userdata)126 udev_set_userdata(struct udev *udev_ctx, void *userdata)
127 {
128 udev_ctx->userdata = userdata;
129 }
130
131 int
udev_get_fd(struct udev * udev_ctx)132 udev_get_fd(struct udev *udev_ctx)
133 {
134 return udev_ctx->gp_fd;
135 }
136
137 int
send_xml(int s,char * xml)138 send_xml(int s, char *xml)
139 {
140 ssize_t r,n;
141 size_t sz;
142
143 sz = strlen(xml) + 1;
144
145 r = send(s, &sz, sizeof(sz), 0);
146 if (r <= 0)
147 return r;
148
149 r = 0;
150 while (r < (ssize_t)sz) {
151 n = send(s, xml+r, sz-r, 0);
152 if (n <= 0)
153 return n;
154 r += n;
155 }
156
157 return r;
158 }
159
160 int
read_xml(int s,char ** buf)161 read_xml(int s, char **buf)
162 {
163 char *xml;
164 size_t sz;
165 int n, r;
166
167 *buf = NULL;
168
169 n = recv(s, &sz, sizeof(sz), MSG_WAITALL);
170 if ((n <= 0) || (sz > 12*1024*1024)) /* Arbitrary limit */
171 return n;
172
173 xml = malloc(sz+2);
174 r = 0;
175 while (r < (ssize_t)sz) {
176 n = recv(s, xml+r, sz-r, MSG_WAITALL);
177 if (n <= 0) {
178 free(xml);
179 return n;
180 }
181 r += n;
182 }
183
184 *buf = xml;
185 return r;
186 }
187
188 int
_udev_dict_set_cstr(prop_dictionary_t dict,const char * key,char * str)189 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str)
190 {
191 prop_string_t ps;
192
193 ps = prop_string_create_cstring(str);
194 if (ps == NULL)
195 return ENOMEM;
196
197 if (prop_dictionary_set(dict, key, ps) == false) {
198 prop_object_release(ps);
199 return ENOMEM;
200 }
201
202 prop_object_release(ps);
203 return 0;
204 }
205
206 int
_udev_dict_set_int(prop_dictionary_t dict,const char * key,int64_t val)207 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val)
208 {
209 prop_number_t pn;
210
211 pn = prop_number_create_integer(val);
212 if (pn == NULL)
213 return ENOMEM;
214
215 if (prop_dictionary_set(dict, key, pn) == false) {
216 prop_object_release(pn);
217 return ENOMEM;
218 }
219
220 prop_object_release(pn);
221 return 0;
222 }
223
224 int
_udev_dict_set_uint(prop_dictionary_t dict,const char * key,uint64_t val)225 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val)
226 {
227 prop_number_t pn;
228
229 pn = prop_number_create_unsigned_integer(val);
230 if (pn == NULL)
231 return ENOMEM;
232
233 if (prop_dictionary_set(dict, key, pn) == false) {
234 prop_object_release(pn);
235 return ENOMEM;
236 }
237
238 prop_object_release(pn);
239 return 0;
240 }
241
242 int
conn_local_server(const char * sockfile,int socktype,int nonblock __unused,int * retsock)243 conn_local_server(const char *sockfile, int socktype, int nonblock __unused,
244 int *retsock)
245 {
246 int s;
247 struct sockaddr_un serv_addr;
248
249 *retsock = -1;
250 if ((s = socket(AF_UNIX, socktype, 0)) < 0)
251 return -1;
252
253 memset(&serv_addr, 0, sizeof(serv_addr));
254 serv_addr.sun_family = AF_UNIX;
255 strncpy(serv_addr.sun_path, sockfile, SOCKFILE_NAMELEN);
256 serv_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0';
257
258 *retsock = s;
259 return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
260 }
261
262 prop_dictionary_t
udevd_get_command_dict(char * command)263 udevd_get_command_dict(char *command)
264 {
265 prop_dictionary_t dict;
266 int error;
267
268 dict = prop_dictionary_create();
269 if (dict == NULL)
270 return NULL;
271
272 if ((error = _udev_dict_set_cstr(dict, "command", command)))
273 goto error_out;
274
275 return dict;
276
277 error_out:
278 prop_object_release(dict);
279 return NULL;
280 }
281
282 prop_array_t
udevd_request_devs(int s,prop_array_t filters)283 udevd_request_devs(int s, prop_array_t filters)
284 {
285 prop_array_t pa;
286 prop_dictionary_t dict;
287 char *xml;
288
289 int n;
290
291 dict = udevd_get_command_dict(__DECONST(char *, "getdevs"));
292 if (dict == NULL)
293 return NULL;
294
295 /* Add filters to message, if available */
296 if (filters != NULL) {
297 if (prop_dictionary_set(dict, "filters", filters) == false) {
298 prop_object_release(dict);
299 return NULL;
300 }
301 }
302
303 xml = prop_dictionary_externalize(dict);
304 prop_object_release(dict);
305 if (xml == NULL)
306 return NULL;
307
308 n = send_xml(s, xml);
309 free(xml);
310
311 if (n <= 0)
312 return NULL;
313
314 if ((n = read_xml(s, &xml)) <= 0)
315 return NULL;
316
317 xml[n+1] = '\0';
318 pa = prop_array_internalize(xml);
319 free(xml);
320 return (pa);
321 }
322