chiark / gitweb /
replace strerror() usage with threadsafe "%m" format string
[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 struct name_entry *name_list_add(struct udev *udev, struct list_head *name_list, const char *name, int sort)
36 {
37         struct name_entry *name_loop;
38         struct name_entry *name_new;
39
40         /* avoid duplicate entries */
41         list_for_each_entry(name_loop, name_list, node) {
42                 if (strcmp(name_loop->name, name) == 0) {
43                         dbg(udev, "'%s' is already in the list\n", name);
44                         return name_loop;
45                 }
46         }
47
48         if (sort)
49                 list_for_each_entry(name_loop, name_list, node) {
50                         if (strcmp(name_loop->name, name) > 0)
51                                 break;
52                 }
53
54         name_new = malloc(sizeof(struct name_entry));
55         if (name_new == NULL)
56                 return NULL;
57         memset(name_new, 0x00, sizeof(struct name_entry));
58         util_strlcpy(name_new->name, name, sizeof(name_new->name));
59         dbg(udev, "adding '%s'\n", name_new->name);
60         list_add_tail(&name_new->node, &name_loop->node);
61
62         return name_new;
63 }
64
65 struct name_entry *name_list_key_add(struct udev *udev, struct list_head *name_list, const char *key, const char *value)
66 {
67         struct name_entry *name_loop;
68         struct name_entry *name_new;
69         size_t keylen = strlen(key);
70
71         list_for_each_entry(name_loop, name_list, node) {
72                 if (strncmp(name_loop->name, key, keylen) != 0)
73                         continue;
74                 if (name_loop->name[keylen] != '=')
75                         continue;
76                 dbg(udev, "key already present '%s', replace it\n", name_loop->name);
77                 snprintf(name_loop->name, sizeof(name_loop->name), "%s=%s", key, value);
78                 name_loop->name[sizeof(name_loop->name)-1] = '\0';
79                 return name_loop;
80         }
81
82         name_new = malloc(sizeof(struct name_entry));
83         if (name_new == NULL)
84                 return NULL;
85         memset(name_new, 0x00, sizeof(struct name_entry));
86         snprintf(name_new->name, sizeof(name_new->name), "%s=%s", key, value);
87         name_new->name[sizeof(name_new->name)-1] = '\0';
88         dbg(udev, "adding '%s'\n", name_new->name);
89         list_add_tail(&name_new->node, &name_loop->node);
90
91         return name_new;
92 }
93
94 int name_list_key_remove(struct udev *udev, struct list_head *name_list, const char *key)
95 {
96         struct name_entry *name_loop;
97         struct name_entry *name_tmp;
98         size_t keylen = strlen(key);
99         int retval = 0;
100
101         list_for_each_entry_safe(name_loop, name_tmp, name_list, node) {
102                 if (strncmp(name_loop->name, key, keylen) != 0)
103                         continue;
104                 if (name_loop->name[keylen] != '=')
105                         continue;
106                 list_del(&name_loop->node);
107                 free(name_loop);
108                 retval = 1;
109                 break;
110         }
111         return retval;
112 }
113
114 void name_list_cleanup(struct udev *udev, struct list_head *name_list)
115 {
116         struct name_entry *name_loop;
117         struct name_entry *name_tmp;
118
119         list_for_each_entry_safe(name_loop, name_tmp, name_list, node) {
120                 list_del(&name_loop->node);
121                 free(name_loop);
122         }
123 }
124
125 /* calls function for every file found in specified directory */
126 int add_matching_files(struct udev *udev, struct list_head *name_list, const char *dirname, const char *suffix)
127 {
128         struct dirent *ent;
129         DIR *dir;
130         char filename[UTIL_PATH_SIZE];
131
132         dbg(udev, "open directory '%s'\n", dirname);
133         dir = opendir(dirname);
134         if (dir == NULL) {
135                 err(udev, "unable to open '%s': %m\n", dirname);
136                 return -1;
137         }
138
139         while (1) {
140                 ent = readdir(dir);
141                 if (ent == NULL || ent->d_name[0] == '\0')
142                         break;
143
144                 if ((ent->d_name[0] == '.') || (ent->d_name[0] == '#'))
145                         continue;
146
147                 /* look for file matching with specified suffix */
148                 if (suffix != NULL) {
149                         const char *ext;
150
151                         ext = strrchr(ent->d_name, '.');
152                         if (ext == NULL)
153                                 continue;
154                         if (strcmp(ext, suffix) != 0)
155                                 continue;
156                 }
157                 dbg(udev, "put file '%s/%s' into list\n", dirname, ent->d_name);
158
159                 snprintf(filename, sizeof(filename), "%s/%s", dirname, ent->d_name);
160                 filename[sizeof(filename)-1] = '\0';
161                 name_list_add(udev, name_list, filename, 1);
162         }
163
164         closedir(dir);
165         return 0;
166 }
167
168 uid_t lookup_user(struct udev *udev, const char *user)
169 {
170         struct passwd *pw;
171         uid_t uid = 0;
172
173         errno = 0;
174         pw = getpwnam(user);
175         if (pw == NULL) {
176                 if (errno == 0 || errno == ENOENT || errno == ESRCH)
177                         err(udev, "specified user '%s' unknown\n", user);
178                 else
179                         err(udev, "error resolving user '%s': %m\n", user);
180         } else
181                 uid = pw->pw_uid;
182
183         return uid;
184 }
185
186 extern gid_t lookup_group(struct udev *udev, const char *group)
187 {
188         struct group *gr;
189         gid_t gid = 0;
190
191         errno = 0;
192         gr = getgrnam(group);
193         if (gr == NULL) {
194                 if (errno == 0 || errno == ENOENT || errno == ESRCH)
195                         err(udev, "specified group '%s' unknown\n", group);
196                 else
197                         err(udev, "error resolving group '%s': %m\n", group);
198         } else
199                 gid = gr->gr_gid;
200
201         return gid;
202 }
203