xref: /dragonfly/lib/libdevattr/devattr_device.c (revision 0c8103dd622e5016512e2eedb2ceb865982089a5)
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/stat.h>
42 #include <sys/un.h>
43 
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <inttypes.h>
48 #include <libgen.h>
49 #include <regex.h>
50 #include <signal.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <syslog.h>
56 #include <unistd.h>
57 
58 #include <libprop/proplib.h>
59 #include <sys/udev.h>
60 #define LIBDEVATTR_INTERNAL
61 #include "devattr.h"
62 
63 struct udev_device {
64           struct udev         *udev_ctx;
65           prop_dictionary_t   dict;
66           int       ev_type;
67           int       refs;
68 };
69 
70 struct udev_device *
udev_device_new_from_dictionary(struct udev * udev_ctx,prop_dictionary_t dict)71 udev_device_new_from_dictionary(struct udev *udev_ctx, prop_dictionary_t dict)
72 {
73           struct udev_device *udev_dev;
74 
75           udev_dev = malloc(sizeof(struct udev_device));
76           if (udev_dev == NULL)
77                     return NULL;
78 
79           udev_dev->refs = 1;
80           udev_dev->ev_type = UDEV_EVENT_NONE;
81 
82           if (dict != NULL)
83                     prop_object_retain(dict);
84 
85           udev_dev->dict = dict;
86           udev_dev->udev_ctx = udev_ref(udev_ctx);
87 
88           return udev_dev;
89 }
90 
91 struct udev_device *
udev_device_ref(struct udev_device * udev_device)92 udev_device_ref(struct udev_device *udev_device)
93 {
94           atomic_add_int(&udev_device->refs, 1);
95 
96           return udev_device;
97 }
98 
99 void
udev_device_unref(struct udev_device * udev_device)100 udev_device_unref(struct udev_device *udev_device)
101 {
102           int refcount;
103 
104           refcount = atomic_fetchadd_int(&udev_device->refs, -1);
105 
106           if (refcount == 1) {
107                     atomic_subtract_int(&udev_device->refs, 0x400); /* in destruction */
108                     if (udev_device->dict != NULL)
109                               prop_object_release(udev_device->dict);
110 
111                     udev_unref(udev_device->udev_ctx);
112                     free(udev_device);
113           }
114 }
115 
116 void
udev_device_set_action(struct udev_device * udev_device,int action)117 udev_device_set_action(struct udev_device *udev_device, int action)
118 {
119           udev_device->ev_type = action;
120 }
121 
122 const char *
udev_device_get_action(struct udev_device * udev_device)123 udev_device_get_action(struct udev_device *udev_device)
124 {
125           const char *action;
126 
127           switch (udev_device->ev_type) {
128           case UDEV_EVENT_ATTACH:
129                     action = "add";
130                     break;
131 
132           case UDEV_EVENT_DETACH:
133                     action = "remove";
134                     break;
135 
136           default:
137                     action = "none";
138                     break;
139           }
140 
141           return action;
142 }
143 
144 dev_t
udev_device_get_devnum(struct udev_device * udev_device)145 udev_device_get_devnum(struct udev_device *udev_device)
146 {
147           prop_number_t pn;
148           dev_t devnum;
149 
150           if (udev_device->dict == NULL)
151                     return 0;
152 
153           pn = prop_dictionary_get(udev_device->dict, "devnum");
154           if (pn == NULL)
155                     return 0;
156 
157           devnum = prop_number_unsigned_integer_value(pn);
158 
159           return devnum;
160 }
161 
162 uint64_t
udev_device_get_kptr(struct udev_device * udev_device)163 udev_device_get_kptr(struct udev_device *udev_device)
164 {
165           prop_number_t pn;
166           uint64_t kptr;
167 
168           if (udev_device->dict == NULL)
169                     return 0;
170 
171           pn = prop_dictionary_get(udev_device->dict, "kptr");
172           if (pn == NULL)
173                     return 0;
174 
175           kptr = prop_number_unsigned_integer_value(pn);
176 
177           return kptr;
178 }
179 
180 int32_t
udev_device_get_major(struct udev_device * udev_device)181 udev_device_get_major(struct udev_device *udev_device)
182 {
183           prop_number_t pn;
184           int32_t major;
185 
186           if (udev_device->dict == NULL)
187                     return 0;
188 
189           pn = prop_dictionary_get(udev_device->dict, "major");
190           if (pn == NULL)
191                     return 0;
192 
193           major = (int32_t)prop_number_integer_value(pn);
194 
195           return major;
196 }
197 
198 int32_t
udev_device_get_minor(struct udev_device * udev_device)199 udev_device_get_minor(struct udev_device *udev_device)
200 {
201           prop_number_t pn;
202           int32_t minor;
203 
204           if (udev_device->dict == NULL)
205                     return 0;
206 
207           pn = prop_dictionary_get(udev_device->dict, "minor");
208           if (pn == NULL)
209                     return 0;
210 
211           minor = (int32_t)prop_number_integer_value(pn);
212 
213           return minor;
214 }
215 
216 const char *
udev_device_get_devnode(struct udev_device * udev_device)217 udev_device_get_devnode(struct udev_device *udev_device)
218 {
219           dev_t devnum;
220 
221           devnum = udev_device_get_devnum(udev_device);
222           if (devnum == 0)
223                     return 0;
224 
225           return devname(devnum, S_IFCHR);
226 }
227 
228 const char *
udev_device_get_property_value(struct udev_device * udev_device,const char * key)229 udev_device_get_property_value(struct udev_device *udev_device,
230                                         const char *key)
231 {
232           prop_object_t       po;
233           prop_number_t       pn;
234           prop_string_t       ps;
235           static char buf[128]; /* XXX: might cause trouble */
236           const char *str = NULL;
237 
238           if (udev_device->dict == NULL)
239                     return NULL;
240 
241           if ((po = prop_dictionary_get(udev_device->dict, key)) == NULL)
242                     return NULL;
243 
244           if (prop_object_type(po) == PROP_TYPE_STRING) {
245                     ps = po;
246                     str = __DECONST(char *, prop_string_cstring_nocopy(ps));
247           } else if (prop_object_type(po) == PROP_TYPE_NUMBER) {
248                     pn = po;
249                     if (prop_number_unsigned(pn)) {
250                               snprintf(buf, sizeof(buf), "%" PRIu64,
251                                   prop_number_unsigned_integer_value(pn));
252                     } else {
253                               snprintf(buf, sizeof(buf), "%" PRIi64,
254                                   prop_number_integer_value(pn));
255                     }
256                     str = buf;
257           }
258           return str;
259 }
260 
261 const char *
udev_device_get_subsystem(struct udev_device * udev_device)262 udev_device_get_subsystem(struct udev_device *udev_device)
263 {
264           return udev_device_get_property_value(udev_device, "subsystem");
265 }
266 
267 const char *
udev_device_get_driver(struct udev_device * udev_device)268 udev_device_get_driver(struct udev_device *udev_device)
269 {
270           return udev_device_get_property_value(udev_device, "driver");
271 }
272 
273 prop_dictionary_t
udev_device_get_dictionary(struct udev_device * udev_device)274 udev_device_get_dictionary(struct udev_device *udev_device)
275 {
276           return udev_device->dict;
277 }
278 
279 struct udev *
udev_device_get_udev(struct udev_device * udev_device)280 udev_device_get_udev(struct udev_device *udev_device)
281 {
282           return udev_device->udev_ctx;
283 }
284 
285