blob: 177b51a5883044f94748a9515900756a3dfd637a [file] [log] [blame]
Lucas De Marchi4462c4a2011-11-29 18:05:43 -02001/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
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
Lucas De Marchicb451f32011-12-12 18:24:35 -02008 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
Lucas De Marchi4462c4a2011-11-29 18:05:43 -020010 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
Lucas De Marchi7e317da2011-11-30 19:20:19 -020021#include <assert.h>
Lucas De Marchi4462c4a2011-11-29 18:05:43 -020022#include <stdio.h>
23#include <stdlib.h>
24#include <stddef.h>
25#include <stdarg.h>
26#include <unistd.h>
27#include <errno.h>
28#include <string.h>
29#include <ctype.h>
30
31#include "libkmod.h"
32#include "libkmod-private.h"
33
34/*
35 * Read one logical line from a configuration file.
36 *
37 * Line endings may be escaped with backslashes, to form one logical line from
38 * several physical lines. No end of line character(s) are included in the
39 * result.
40 *
41 * If linenum is not NULL, it is incremented by the number of physical lines
42 * which have been read.
43 */
44char *getline_wrapped(FILE *fp, unsigned int *linenum)
45{
46 int size = 256;
47 int i = 0;
48 char *buf = malloc(size);
Lucas De Marchi28c175e2011-12-12 11:52:59 -020049
Lucas De Marchi4462c4a2011-11-29 18:05:43 -020050 for(;;) {
51 int ch = getc_unlocked(fp);
52
53 switch(ch) {
54 case EOF:
55 if (i == 0) {
56 free(buf);
57 return NULL;
58 }
59 /* else fall through */
60
61 case '\n':
62 if (linenum)
63 (*linenum)++;
64 if (i == size)
65 buf = realloc(buf, size + 1);
66 buf[i] = '\0';
67 return buf;
68
69 case '\\':
70 ch = getc_unlocked(fp);
71
72 if (ch == '\n') {
73 if (linenum)
74 (*linenum)++;
75 continue;
76 }
77 /* else fall through */
78
79 default:
80 buf[i++] = ch;
81
82 if (i == size) {
83 size *= 2;
84 buf = realloc(buf, size);
85 }
86 }
87 }
88}
Lucas De Marchi8185fc92011-11-30 02:14:33 -020089
90/*
91 * Replace dashes with underscores.
92 * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
93 */
94char *underscores(struct kmod_ctx *ctx, char *s)
95{
96 unsigned int i;
97
98 if (!s)
99 return NULL;
100
101 for (i = 0; s[i]; i++) {
102 switch (s[i]) {
103 case '-':
104 s[i] = '_';
105 break;
106
107 case ']':
108 INFO(ctx, "Unmatched bracket in %s\n", s);
109 break;
110
111 case '[':
112 i += strcspn(&s[i], "]");
113 if (!s[i])
114 INFO(ctx, "Unmatched bracket in %s\n", s);
115 break;
116 }
117 }
118 return s;
119}
120
Lucas De Marchib148b862011-12-13 10:24:22 -0200121inline int alias_normalize(const char *alias, char buf[NAME_MAX], size_t *len)
122{
123 size_t s;
124
125 for (s = 0; s < NAME_MAX - 1; s++) {
126 const char c = alias[s];
127 switch (c) {
128 case '-':
129 buf[s] = '_';
130 break;
131 case ']':
132 return -EINVAL;
133 case '[':
134 while (alias[s] != ']' &&
135 alias[s] != '.' && alias[s] != '\0')
136 s++;
137
138 if (alias[s] != ']')
139 return -EINVAL;
140
141 s++;
142 break;
143 case '\0':
144 case '.':
145 goto finish;
146 default:
147 buf[s] = c;
148 }
149 }
150
151finish:
152 buf[s] = '\0';
153
154 if (len)
155 *len = s;
156
157 return 0;
158}
159
Lucas De Marchi7e317da2011-11-30 19:20:19 -0200160bool startswith(const char *s, const char *prefix) {
161 size_t sl, pl;
162
163 assert(s);
164 assert(prefix);
165
166 sl = strlen(s);
167 pl = strlen(prefix);
168
169 if (pl == 0)
170 return true;
171
172 if (sl < pl)
173 return false;
174
175 return memcmp(s, prefix, pl) == 0;
176}
Lucas De Marchie22c85f2011-12-02 17:21:18 -0200177
178inline void *memdup(const void *p, size_t n)
179{
180 void *r = malloc(n);
181
182 if (r == NULL)
183 return NULL;
184
185 return memcpy(r, p, n);
186}
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200187
188ssize_t read_str_safe(int fd, char *buf, size_t buflen) {
189 size_t todo = buflen;
190 size_t done;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200191
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200192 do {
193 ssize_t r = read(fd, buf, todo);
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200194
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200195 if (r == 0)
196 break;
197 else if (r > 0)
198 todo -= r;
199 else {
200 if (errno == EAGAIN || errno == EWOULDBLOCK ||
201 errno == EINTR)
202 continue;
203 else
204 return -errno;
205 }
206 } while (todo > 0);
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200207
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200208 done = buflen - todo;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200209
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200210 if (done == 0)
211 buf[0] = '\0';
212 else {
213 if (done < buflen)
214 buf[done] = '\0';
215 else if (buf[done - 1] != '\0')
216 return -ENOSPC;
217 }
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200218
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200219 return done;
220}
221
222int read_str_long(int fd, long *value, int base) {
223 char buf[32], *end;
224 long v;
225 int err;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200226
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200227 *value = 0;
228 err = read_str_safe(fd, buf, sizeof(buf));
229 if (err < 0)
230 return err;
231 errno = 0;
232 v = strtol(buf, &end, base);
233 if (end == buf || !isspace(*end))
234 return -EINVAL;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200235
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200236 *value = v;
237 return 0;
238}
239
240int read_str_ulong(int fd, unsigned long *value, int base) {
241 char buf[32], *end;
242 long v;
243 int err;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200244
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200245 *value = 0;
246 err = read_str_safe(fd, buf, sizeof(buf));
247 if (err < 0)
248 return err;
249 errno = 0;
250 v = strtoul(buf, &end, base);
251 if (end == buf || !isspace(*end))
252 return -EINVAL;
253 *value = v;
254 return 0;
255}
Lucas De Marchiafca7802011-12-07 10:59:17 -0200256
257char *strchr_replace(char *s, int c, char r)
258{
259 char *p;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200260
Gustavo Sverzut Barbieribf8cf142011-12-10 19:45:37 -0200261 for (p = s; *p != '\0'; p++)
262 if (*p == c)
263 *p = r;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200264
Lucas De Marchiafca7802011-12-07 10:59:17 -0200265 return s;
266}
Lucas De Marchi3a468802011-12-07 13:50:52 -0200267
268bool path_is_absolute(const char *p)
269{
270 assert(p != NULL);
271
272 return p[0] == '/';
273}
Lucas De Marchi06363cc2011-12-07 13:51:40 -0200274
275char *path_make_absolute_cwd(const char *p)
276{
277 char *cwd, *r;
278 size_t plen;
279 size_t cwdlen;
280
281 if (path_is_absolute(p))
282 return strdup(p);
283
284 cwd = get_current_dir_name();
285 if (cwd == NULL)
286 return NULL;
287
288 plen = strlen(p);
289 cwdlen = strlen(cwd);
290
291 /* cwd + '/' + p + '\0' */
292 r = realloc(cwd, cwdlen + 1 + plen + 1);
293 if (r == NULL) {
294 free(cwd);
295 return NULL;
296 }
297
Lucas De Marchi4eb2c0f2011-12-08 10:37:56 -0200298 r[cwdlen] = '/';
299 memcpy(&r[cwdlen + 1], p, plen + 1);
Lucas De Marchi06363cc2011-12-07 13:51:40 -0200300
301 return r;
302}