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 #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, size_t buf_sz) 164 { 165 size_t sz; 166 int n, r; 167 168 n = recv(s, &sz, sizeof(sz), MSG_WAITALL); 169 if (n <= 0) 170 return n; 171 172 r = 0; 173 while ((r < (ssize_t)sz) && (r < (ssize_t)buf_sz)) { 174 n = recv(s, buf+r, sz-r, MSG_WAITALL); 175 if (n <= 0) 176 return n; 177 r += n; 178 } 179 180 return r; 181 } 182 183 int 184 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str) 185 { 186 prop_string_t ps; 187 188 ps = prop_string_create_cstring(str); 189 if (ps == NULL) 190 return ENOMEM; 191 192 if (prop_dictionary_set(dict, key, ps) == false) { 193 prop_object_release(ps); 194 return ENOMEM; 195 } 196 197 prop_object_release(ps); 198 return 0; 199 } 200 201 int 202 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val) 203 { 204 prop_number_t pn; 205 206 pn = prop_number_create_integer(val); 207 if (pn == NULL) 208 return ENOMEM; 209 210 if (prop_dictionary_set(dict, key, pn) == false) { 211 prop_object_release(pn); 212 return ENOMEM; 213 } 214 215 prop_object_release(pn); 216 return 0; 217 } 218 219 int 220 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val) 221 { 222 prop_number_t pn; 223 224 pn = prop_number_create_unsigned_integer(val); 225 if (pn == NULL) 226 return ENOMEM; 227 228 if (prop_dictionary_set(dict, key, pn) == false) { 229 prop_object_release(pn); 230 return ENOMEM; 231 } 232 233 prop_object_release(pn); 234 return 0; 235 } 236 237 int 238 conn_local_server(const char *sockfile, int socktype, int nonblock __unused, 239 int *retsock) 240 { 241 int s; 242 struct sockaddr_un serv_addr; 243 244 *retsock = -1; 245 if ((s = socket(AF_UNIX, socktype, 0)) < 0) 246 return -1; 247 248 memset(&serv_addr, 0, sizeof(serv_addr)); 249 serv_addr.sun_family = AF_UNIX; 250 strncpy(serv_addr.sun_path, sockfile, SOCKFILE_NAMELEN); 251 serv_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0'; 252 253 *retsock = s; 254 return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); 255 } 256 257 prop_dictionary_t 258 udevd_get_command_dict(char *command) 259 { 260 prop_dictionary_t dict; 261 int error; 262 263 dict = prop_dictionary_create(); 264 if (dict == NULL) 265 return NULL; 266 267 if ((error = _udev_dict_set_cstr(dict, "command", command))) 268 goto error_out; 269 270 return dict; 271 272 error_out: 273 prop_object_release(dict); 274 return NULL; 275 } 276 277 prop_array_t 278 udevd_request_devs(int s, prop_array_t filters) 279 { 280 prop_array_t pa; 281 prop_dictionary_t dict; 282 char *xml; 283 284 int n; 285 286 dict = udevd_get_command_dict(__DECONST(char *, "getdevs")); 287 if (dict == NULL) 288 return NULL; 289 290 /* Add filters to message, if available */ 291 if (filters != NULL) { 292 if (prop_dictionary_set(dict, "filters", filters) == false) { 293 prop_object_release(dict); 294 return NULL; 295 } 296 } 297 298 xml = prop_dictionary_externalize(dict); 299 prop_object_release(dict); 300 if (xml == NULL) 301 return NULL; 302 303 n = send_xml(s, xml); 304 free(xml); 305 306 if (n <= 0) 307 return NULL; 308 309 xml = malloc(12*1024*1024); /* generous 12 MB */ 310 if ((n = read_xml(s, xml, 12*1024*1024)) <= 0) { 311 free(xml); 312 return NULL; 313 } 314 315 xml[n+1] = '\0'; 316 pa = prop_array_internalize(xml); 317 free(xml); 318 return (pa); 319 } 320