userland - Port TCP-MD5 (RFC 2385) implementation.
[dragonfly.git] / lib / libdevattr / devattr.c
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/device.h>
36 #include <sys/wait.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
39 #include <sys/poll.h>
40 #include <sys/queue.h>
41 #include <sys/un.h>
42 #include <cpu/inttypes.h>
43
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <libgen.h>
48 #include <regex.h>
49 #include <signal.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <syslog.h>
55 #include <unistd.h>
56 #include <pthread.h>
57
58 #include <libprop/proplib.h>
59 #include <sys/udev.h>
60 #define LIBDEVATTR_INTERNAL
61 #include "devattr.h"
62
63 struct udev {
64         int     gp_fd;
65         int     monitor_fd;
66         int     refs;
67
68         void    *userdata;
69 };
70
71 struct udev *
72 udev_ref(struct udev *udev_ctx)
73 {
74         atomic_add_int(&udev_ctx->refs, 1);
75
76         return udev_ctx;
77 }
78
79 void
80 udev_unref(struct udev *udev_ctx)
81 {
82         int refcount;
83
84         refcount = atomic_fetchadd_int(&udev_ctx->refs, -1);
85
86         if (refcount == 1) {
87                 atomic_subtract_int(&udev_ctx->refs, 0x400); /* in destruction */
88                 if (udev_ctx->gp_fd != -1)
89                         close (udev_ctx->gp_fd);
90                 if (udev_ctx->monitor_fd != -1)
91                         close (udev_ctx->monitor_fd);
92
93                 free(udev_ctx);
94         }
95 }
96
97 struct udev *
98 udev_new(void)
99 {
100         struct udev *udev_ctx;
101         int ret, s;
102
103         ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s);
104         if (ret < 0)
105                 return NULL;
106
107         udev_ctx = malloc(sizeof(struct udev));
108
109         udev_ctx->refs = 1;
110         udev_ctx->gp_fd = s;
111         udev_ctx->monitor_fd = -1;
112         udev_ctx->userdata = NULL;
113
114         return udev_ctx;
115 }
116
117 const char *udev_get_dev_path(struct udev *udev_ctx __unused)
118 {
119         return "/dev";
120 }
121
122 void *
123 udev_get_userdata(struct udev *udev_ctx)
124 {
125         return udev_ctx->userdata;
126 }
127
128 void
129 udev_set_userdata(struct udev *udev_ctx, void *userdata)
130 {
131         udev_ctx->userdata = userdata;
132 }
133
134 int
135 udev_get_fd(struct udev *udev_ctx)
136 {
137         return udev_ctx->gp_fd;
138 }
139
140 int
141 send_xml(int s, char *xml)
142 {
143         ssize_t r,n;
144         size_t sz;
145
146         sz = strlen(xml) + 1;
147
148         r = send(s, &sz, sizeof(sz), 0);
149         if (r <= 0)
150                 return r;
151
152         r = 0;
153         while (r < (ssize_t)sz) {
154                 n = send(s, xml+r, sz-r, 0);
155                 if (n <= 0)
156                         return n;
157                 r += n;
158         }
159
160         return r;
161 }
162
163 int
164 read_xml(int s, char **buf)
165 {
166         char *xml;
167         size_t sz;
168         int n, r;
169
170         *buf = NULL;
171
172         n = recv(s, &sz, sizeof(sz), MSG_WAITALL);
173         if ((n <= 0) || (sz > 12*1024*1024)) /* Arbitrary limit */
174                 return n;
175
176         xml = malloc(sz+2);
177         r = 0;
178         while (r < (ssize_t)sz) {
179                 n = recv(s, xml+r, sz-r, MSG_WAITALL);
180                 if (n <= 0) {
181                         free(xml);
182                         return n;
183                 }
184                 r += n;
185         }
186
187         *buf = xml;
188         return r;
189 }
190
191 int
192 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str)
193 {
194         prop_string_t   ps;
195
196         ps = prop_string_create_cstring(str);
197         if (ps == NULL)
198                 return ENOMEM;
199
200         if (prop_dictionary_set(dict, key, ps) == false) {
201                 prop_object_release(ps);
202                 return ENOMEM;
203         }
204
205         prop_object_release(ps);
206         return 0;
207 }
208
209 int
210 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val)
211 {
212         prop_number_t   pn;
213
214         pn = prop_number_create_integer(val);
215         if (pn == NULL)
216                 return ENOMEM;
217
218         if (prop_dictionary_set(dict, key, pn) == false) {
219                 prop_object_release(pn);
220                 return ENOMEM;
221         }
222
223         prop_object_release(pn);
224         return 0;
225 }
226
227 int
228 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val)
229 {
230         prop_number_t   pn;
231
232         pn = prop_number_create_unsigned_integer(val);
233         if (pn == NULL)
234                 return ENOMEM;
235
236         if (prop_dictionary_set(dict, key, pn) == false) {
237                 prop_object_release(pn);
238                 return ENOMEM;
239         }
240
241         prop_object_release(pn);
242         return 0;
243 }
244
245 int
246 conn_local_server(const char *sockfile, int socktype, int nonblock __unused,
247                   int *retsock)
248 {
249         int s;
250         struct sockaddr_un serv_addr;
251
252         *retsock = -1;
253         if ((s = socket(AF_UNIX, socktype, 0)) < 0)
254                 return -1;
255
256         memset(&serv_addr, 0, sizeof(serv_addr));
257         serv_addr.sun_family = AF_UNIX;
258         strncpy(serv_addr.sun_path, sockfile, SOCKFILE_NAMELEN);
259         serv_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0';
260
261         *retsock = s;
262         return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
263 }
264
265 prop_dictionary_t
266 udevd_get_command_dict(char *command)
267 {
268         prop_dictionary_t       dict;
269         int     error;
270
271         dict = prop_dictionary_create();
272         if (dict == NULL)
273                 return NULL;
274
275         if ((error = _udev_dict_set_cstr(dict, "command", command)))
276                 goto error_out;
277
278         return dict;
279
280 error_out:
281         prop_object_release(dict);
282         return NULL;
283 }
284
285 prop_array_t
286 udevd_request_devs(int s, prop_array_t filters)
287 {
288         prop_array_t    pa;
289         prop_dictionary_t       dict;
290         char *xml;
291
292         int n;
293
294         dict = udevd_get_command_dict(__DECONST(char *, "getdevs"));
295         if (dict == NULL)
296                 return NULL;
297
298         /* Add filters to message, if available */
299         if (filters != NULL) {
300                 if (prop_dictionary_set(dict, "filters", filters) == false) {
301                         prop_object_release(dict);
302                         return NULL;
303                 }
304         }
305
306         xml = prop_dictionary_externalize(dict);
307         prop_object_release(dict);
308         if (xml == NULL)
309                 return NULL;
310
311         n = send_xml(s, xml);
312         free(xml);
313
314         if (n <= 0)
315                 return NULL;
316
317         if ((n = read_xml(s, &xml)) <= 0)
318                 return NULL;
319
320         xml[n+1] = '\0';
321         pa = prop_array_internalize(xml);
322         free(xml);
323         return (pa);
324 }