chiark / gitweb /
2cbb4d98ebbaa701816d391c13f844f03a9faf6d
[elogind.git] / udev / udev_utils.c
1 /*
2  * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <stddef.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <dirent.h>
27 #include <syslog.h>
28 #include <pwd.h>
29 #include <grp.h>
30 #include <sys/types.h>
31 #include <sys/utsname.h>
32
33 #include "udev.h"
34
35
36 int log_priority(const char *priority)
37 {
38         char *endptr;
39         int prio;
40
41         prio = strtol(priority, &endptr, 10);
42         if (endptr[0] == '\0')
43                 return prio;
44         if (strncasecmp(priority, "err", 3) == 0)
45                 return LOG_ERR;
46         if (strcasecmp(priority, "info") == 0)
47                 return LOG_INFO;
48         if (strcasecmp(priority, "debug") == 0)
49                 return LOG_DEBUG;
50         if (string_is_true(priority))
51                 return LOG_ERR;
52
53         return 0;
54 }
55
56 struct name_entry *name_list_add(struct udev *udev, struct list_head *name_list, const char *name, int sort)
57 {
58         struct name_entry *name_loop;
59         struct name_entry *name_new;
60
61         /* avoid duplicate entries */
62         list_for_each_entry(name_loop, name_list, node) {
63                 if (strcmp(name_loop->name, name) == 0) {
64                         dbg(udev, "'%s' is already in the list\n", name);
65                         return name_loop;
66                 }
67         }
68
69         if (sort)
70                 list_for_each_entry(name_loop, name_list, node) {
71                         if (strcmp(name_loop->name, name) > 0)
72                                 break;
73                 }
74
75         name_new = malloc(sizeof(struct name_entry));
76         if (name_new == NULL)
77                 return NULL;
78         memset(name_new, 0x00, sizeof(struct name_entry));
79         strlcpy(name_new->name, name, sizeof(name_new->name));
80         dbg(udev, "adding '%s'\n", name_new->name);
81         list_add_tail(&name_new->node, &name_loop->node);
82
83         return name_new;
84 }
85
86 struct name_entry *name_list_key_add(struct udev *udev, struct list_head *name_list, const char *key, const char *value)
87 {
88         struct name_entry *name_loop;
89         struct name_entry *name_new;
90         size_t keylen = strlen(key);
91
92         list_for_each_entry(name_loop, name_list, node) {
93                 if (strncmp(name_loop->name, key, keylen) != 0)
94                         continue;
95                 if (name_loop->name[keylen] != '=')
96                         continue;
97                 dbg(udev, "key already present '%s', replace it\n", name_loop->name);
98                 snprintf(name_loop->name, sizeof(name_loop->name), "%s=%s", key, value);
99                 name_loop->name[sizeof(name_loop->name)-1] = '\0';
100                 return name_loop;
101         }
102
103         name_new = malloc(sizeof(struct name_entry));
104         if (name_new == NULL)
105                 return NULL;
106         memset(name_new, 0x00, sizeof(struct name_entry));
107         snprintf(name_new->name, sizeof(name_new->name), "%s=%s", key, value);
108         name_new->name[sizeof(name_new->name)-1] = '\0';
109         dbg(udev, "adding '%s'\n", name_new->name);
110         list_add_tail(&name_new->node, &name_loop->node);
111
112         return name_new;
113 }
114
115 int name_list_key_remove(struct udev *udev, struct list_head *name_list, const char *key)
116 {
117         struct name_entry *name_loop;
118         struct name_entry *name_tmp;
119         size_t keylen = strlen(key);
120         int retval = 0;
121
122         list_for_each_entry_safe(name_loop, name_tmp, name_list, node) {
123                 if (strncmp(name_loop->name, key, keylen) != 0)
124                         continue;
125                 if (name_loop->name[keylen] != '=')
126                         continue;
127                 list_del(&name_loop->node);
128                 free(name_loop);
129                 retval = 1;
130                 break;
131         }
132         return retval;
133 }
134
135 void name_list_cleanup(struct udev *udev, struct list_head *name_list)
136 {
137         struct name_entry *name_loop;
138         struct name_entry *name_tmp;
139
140         list_for_each_entry_safe(name_loop, name_tmp, name_list, node) {
141                 list_del(&name_loop->node);
142                 free(name_loop);
143         }
144 }
145
146 /* calls function for every file found in specified directory */
147 int add_matching_files(struct udev *udev, struct list_head *name_list, const char *dirname, const char *suffix)
148 {
149         struct dirent *ent;
150         DIR *dir;
151         char filename[PATH_SIZE];
152
153         dbg(udev, "open directory '%s'\n", dirname);
154         dir = opendir(dirname);
155         if (dir == NULL) {
156                 err(udev, "unable to open '%s': %s\n", dirname, strerror(errno));
157                 return -1;
158         }
159
160         while (1) {
161                 ent = readdir(dir);
162                 if (ent == NULL || ent->d_name[0] == '\0')
163                         break;
164
165                 if ((ent->d_name[0] == '.') || (ent->d_name[0] == COMMENT_CHARACTER))
166                         continue;
167
168                 /* look for file matching with specified suffix */
169                 if (suffix != NULL) {
170                         const char *ext;
171
172                         ext = strrchr(ent->d_name, '.');
173                         if (ext == NULL)
174                                 continue;
175                         if (strcmp(ext, suffix) != 0)
176                                 continue;
177                 }
178                 dbg(udev, "put file '%s/%s' into list\n", dirname, ent->d_name);
179
180                 snprintf(filename, sizeof(filename), "%s/%s", dirname, ent->d_name);
181                 filename[sizeof(filename)-1] = '\0';
182                 name_list_add(udev, name_list, filename, 1);
183         }
184
185         closedir(dir);
186         return 0;
187 }
188
189 uid_t lookup_user(struct udev *udev, const char *user)
190 {
191         struct passwd *pw;
192         uid_t uid = 0;
193
194         errno = 0;
195         pw = getpwnam(user);
196         if (pw == NULL) {
197                 if (errno == 0 || errno == ENOENT || errno == ESRCH)
198                         err(udev, "specified user '%s' unknown\n", user);
199                 else
200                         err(udev, "error resolving user '%s': %s\n", user, strerror(errno));
201         } else
202                 uid = pw->pw_uid;
203
204         return uid;
205 }
206
207 extern gid_t lookup_group(struct udev *udev, const char *group)
208 {
209         struct group *gr;
210         gid_t gid = 0;
211
212         errno = 0;
213         gr = getgrnam(group);
214         if (gr == NULL) {
215                 if (errno == 0 || errno == ENOENT || errno == ESRCH)
216                         err(udev, "specified group '%s' unknown\n", group);
217                 else
218                         err(udev, "error resolving group '%s': %s\n", group, strerror(errno));
219         } else
220                 gid = gr->gr_gid;
221
222         return gid;
223 }
224