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 } 325