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