chiark / gitweb /
2b2752bb54f24a84aecec695cb8aba660e55dd4a
[elogind.git] / src / udev / libudev-util-private.c
1 /*
2  * libudev - interface to udev device information
3  *
4  * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <ctype.h>
20 #include <pwd.h>
21 #include <grp.h>
22 #include <sys/param.h>
23
24 #include "libudev.h"
25 #include "libudev-private.h"
26
27 static int create_path(struct udev *udev, const char *path, bool selinux)
28 {
29         char p[UTIL_PATH_SIZE];
30         char *pos;
31         struct stat stats;
32         int err;
33
34         util_strscpy(p, sizeof(p), path);
35         pos = strrchr(p, '/');
36         if (pos == NULL)
37                 return 0;
38         while (pos != p && pos[-1] == '/')
39                 pos--;
40         if (pos == p)
41                 return 0;
42         pos[0] = '\0';
43
44         if (stat(p, &stats) == 0) {
45                 if ((stats.st_mode & S_IFMT) == S_IFDIR)
46                         return 0;
47                 else
48                         return -ENOTDIR;
49         }
50
51         err = util_create_path(udev, p);
52         if (err != 0)
53                 return err;
54
55         if (selinux)
56                 udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
57         err = mkdir(p, 0755);
58         if (err != 0) {
59                 err = -errno;
60                 if (err == -EEXIST && stat(p, &stats) == 0) {
61                         if ((stats.st_mode & S_IFMT) == S_IFDIR)
62                                 err = 0;
63                         else
64                                 err = -ENOTDIR;
65                 }
66         }
67         if (selinux)
68                 udev_selinux_resetfscreatecon(udev);
69         return err;
70 }
71
72 int util_create_path(struct udev *udev, const char *path)
73 {
74         return create_path(udev, path, false);
75 }
76
77 int util_create_path_selinux(struct udev *udev, const char *path)
78 {
79         return create_path(udev, path, true);
80 }
81
82 int util_delete_path(struct udev *udev, const char *path)
83 {
84         char p[UTIL_PATH_SIZE];
85         char *pos;
86         int err = 0;
87
88         if (path[0] == '/')
89                 while(path[1] == '/')
90                         path++;
91         util_strscpy(p, sizeof(p), path);
92         pos = strrchr(p, '/');
93         if (pos == p || pos == NULL)
94                 return 0;
95
96         for (;;) {
97                 *pos = '\0';
98                 pos = strrchr(p, '/');
99
100                 /* don't remove the last one */
101                 if ((pos == p) || (pos == NULL))
102                         break;
103
104                 err = rmdir(p);
105                 if (err < 0) {
106                         if (errno == ENOENT)
107                                 err = 0;
108                         break;
109                 }
110         }
111         return err;
112 }
113
114 uid_t util_lookup_user(struct udev *udev, const char *user)
115 {
116         char *endptr;
117         struct passwd pwbuf;
118         struct passwd *pw;
119         uid_t uid;
120         size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
121         char *buf = alloca(buflen);
122
123         if (strcmp(user, "root") == 0)
124                 return 0;
125         uid = strtoul(user, &endptr, 10);
126         if (endptr[0] == '\0')
127                 return uid;
128
129         errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw);
130         if (pw != NULL)
131                 return pw->pw_uid;
132         if (errno == 0 || errno == ENOENT || errno == ESRCH)
133                 err(udev, "specified user '%s' unknown\n", user);
134         else
135                 err(udev, "error resolving user '%s': %m\n", user);
136         return 0;
137 }
138
139 gid_t util_lookup_group(struct udev *udev, const char *group)
140 {
141         char *endptr;
142         struct group grbuf;
143         struct group *gr;
144         gid_t gid = 0;
145         size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
146         char *buf = alloca(buflen);
147
148         if (strcmp(group, "root") == 0)
149                 return 0;
150         gid = strtoul(group, &endptr, 10);
151         if (endptr[0] == '\0')
152                 return gid;
153         buf = NULL;
154         gid = 0;
155         for (;;) {
156                 char *newbuf;
157
158                 newbuf = realloc(buf, buflen);
159                 if (!newbuf)
160                         break;
161                 buf = newbuf;
162                 errno = getgrnam_r(group, &grbuf, buf, buflen, &gr);
163                 if (gr != NULL) {
164                         gid = gr->gr_gid;
165                 } else if (errno == ERANGE) {
166                         buflen *= 2;
167                         continue;
168                 } else if (errno == 0 || errno == ENOENT || errno == ESRCH) {
169                         err(udev, "specified group '%s' unknown\n", group);
170                 } else {
171                         err(udev, "error resolving group '%s': %m\n", group);
172                 }
173                 break;
174         }
175         free(buf);
176         return gid;
177 }
178
179 /* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
180 int util_resolve_subsys_kernel(struct udev *udev, const char *string,
181                                char *result, size_t maxsize, int read_value)
182 {
183         char temp[UTIL_PATH_SIZE];
184         char *subsys;
185         char *sysname;
186         struct udev_device *dev;
187         char *attr;
188
189         if (string[0] != '[')
190                 return -1;
191
192         util_strscpy(temp, sizeof(temp), string);
193
194         subsys = &temp[1];
195
196         sysname = strchr(subsys, '/');
197         if (sysname == NULL)
198                 return -1;
199         sysname[0] = '\0';
200         sysname = &sysname[1];
201
202         attr = strchr(sysname, ']');
203         if (attr == NULL)
204                 return -1;
205         attr[0] = '\0';
206         attr = &attr[1];
207         if (attr[0] == '/')
208                 attr = &attr[1];
209         if (attr[0] == '\0')
210                 attr = NULL;
211
212         if (read_value && attr == NULL)
213                 return -1;
214
215         dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
216         if (dev == NULL)
217                 return -1;
218
219         if (read_value) {
220                 const char *val;
221
222                 val = udev_device_get_sysattr_value(dev, attr);
223                 if (val != NULL)
224                         util_strscpy(result, maxsize, val);
225                 else
226                         result[0] = '\0';
227                 dbg(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
228         } else {
229                 size_t l;
230                 char *s;
231
232                 s = result;
233                 l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
234                 if (attr != NULL)
235                         util_strpcpyl(&s, l, "/", attr, NULL);
236                 dbg(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
237         }
238         udev_device_unref(dev);
239         return 0;
240 }