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