2 * libudev - interface to udev device information
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include <sys/socket.h>
34 #include "libudev-private.h"
43 struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
45 struct udev_monitor *udev_monitor;
46 struct sockaddr_un saddr;
52 if (socket_path == NULL)
54 udev_monitor = malloc(sizeof(struct udev_monitor));
55 if (udev_monitor == NULL)
57 memset(udev_monitor, 0x00, sizeof(struct udev_monitor));
58 udev_monitor->refcount = 1;
59 udev_monitor->udev = udev;
61 memset(&saddr, 0x00, sizeof(saddr));
62 saddr.sun_family = AF_LOCAL;
63 strcpy(saddr.sun_path, socket_path);
64 addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
66 /* translate leading '@' to abstract namespace */
67 if (saddr.sun_path[0] == '@')
68 saddr.sun_path[0] = '\0';
70 udev_monitor->socket = socket(AF_LOCAL, SOCK_DGRAM, 0);
71 if (udev_monitor->socket == -1) {
72 log_err(udev, "error getting socket: %s\n", strerror(errno));
77 if (bind(udev_monitor->socket, (struct sockaddr *) &saddr, addrlen) < 0) {
78 log_err(udev, "bind failed: %s\n", strerror(errno));
79 close(udev_monitor->socket);
84 /* enable receiving of the sender credentials */
85 setsockopt(udev_monitor->socket, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
86 log_info(udev_monitor->udev, "udev_monitor: %p created\n", udev_monitor);
91 struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
93 if (udev_monitor == NULL)
95 udev_monitor->refcount++;
99 void udev_monitor_unref(struct udev_monitor *udev_monitor)
101 if (udev_monitor == NULL)
103 udev_monitor->refcount--;
104 if (udev_monitor->refcount > 0)
106 close(udev_monitor->socket);
107 log_info(udev_monitor->udev, "udev_monitor: %p released\n", udev_monitor);
111 struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
113 if (udev_monitor == NULL)
115 return udev_monitor->udev;
118 int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
120 if (udev_monitor == NULL)
122 return udev_monitor->socket;
125 struct udev_device *udev_monitor_get_device(struct udev_monitor *udev_monitor)
127 struct udev_device *udev_device;
129 struct cmsghdr *cmsg;
132 char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
136 if (udev_monitor == NULL)
138 memset(buf, 0x00, sizeof(buf));
140 iov.iov_len = sizeof(buf);
141 memset (&smsg, 0x00, sizeof(struct msghdr));
144 smsg.msg_control = cred_msg;
145 smsg.msg_controllen = sizeof(cred_msg);
147 if (recvmsg(udev_monitor->socket, &smsg, 0) < 0) {
149 log_info(udev_monitor->udev, "unable to receive message");
152 cmsg = CMSG_FIRSTHDR(&smsg);
153 cred = (struct ucred *)CMSG_DATA (cmsg);
155 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
156 log_info(udev_monitor->udev, "no sender credentials received, message ignored");
160 if (cred->uid != 0) {
161 log_info(udev_monitor->udev, "sender uid=%d, message ignored", cred->uid);
166 bufpos = strlen(buf) + 1;
167 if (bufpos < sizeof("a@/d") || bufpos >= sizeof(buf)) {
168 log_info(udev_monitor->udev, "invalid message length");
172 /* check message header */
173 if (strstr(buf, "@/") == NULL) {
174 log_info(udev_monitor->udev, "unrecognized message header");
178 udev_device = device_init(udev_monitor->udev);
179 if (udev_device == NULL) {
183 while (bufpos < sizeof(buf)) {
188 keylen = strlen(key);
191 bufpos += keylen + 1;
193 if (strncmp(key, "DEVPATH=", 8) == 0) {
194 udev_device->devpath = strdup(&key[8]);
195 } else if (strncmp(key, "SUBSYSTEM=", 10) == 0) {
196 udev_device->subsystem = strdup(&key[10]);
197 } else if (strncmp(key, "DEVNAME=", 8) == 0) {
198 udev_device->devname = strdup(&key[8]);
199 } else if (strncmp(key, "DEVLINKS=", 9) == 0) {
200 char *slink = &key[9];
201 char *next = strchr(slink, ' ');
203 while (next != NULL) {
205 name_list_add(&udev_device->link_list, slink, 0);
207 next = strchr(slink, ' ');
209 if (slink[0] != '\0')
210 name_list_add(&udev_device->link_list, slink, 0);
212 name_list_add(&udev_device->env_list, key, 0);