blob: c5550b9c858f4af21923407ebee5fc64e585b8bf [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 Marchi7e317da2011-11-30 19:20:19 -0200121bool startswith(const char *s, const char *prefix) {
122 size_t sl, pl;
123
124 assert(s);
125 assert(prefix);
126
127 sl = strlen(s);
128 pl = strlen(prefix);
129
130 if (pl == 0)
131 return true;
132
133 if (sl < pl)
134 return false;
135
136 return memcmp(s, prefix, pl) == 0;
137}
Lucas De Marchie22c85f2011-12-02 17:21:18 -0200138
139inline void *memdup(const void *p, size_t n)
140{
141 void *r = malloc(n);
142
143 if (r == NULL)
144 return NULL;
145
146 return memcpy(r, p, n);
147}
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200148
149ssize_t read_str_safe(int fd, char *buf, size_t buflen) {
150 size_t todo = buflen;
151 size_t done;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200152
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200153 do {
154 ssize_t r = read(fd, buf, todo);
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200155
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200156 if (r == 0)
157 break;
158 else if (r > 0)
159 todo -= r;
160 else {
161 if (errno == EAGAIN || errno == EWOULDBLOCK ||
162 errno == EINTR)
163 continue;
164 else
165 return -errno;
166 }
167 } while (todo > 0);
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200168
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200169 done = buflen - todo;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200170
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200171 if (done == 0)
172 buf[0] = '\0';
173 else {
174 if (done < buflen)
175 buf[done] = '\0';
176 else if (buf[done - 1] != '\0')
177 return -ENOSPC;
178 }
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200179
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200180 return done;
181}
182
183int read_str_long(int fd, long *value, int base) {
184 char buf[32], *end;
185 long v;
186 int err;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200187
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200188 *value = 0;
189 err = read_str_safe(fd, buf, sizeof(buf));
190 if (err < 0)
191 return err;
192 errno = 0;
193 v = strtol(buf, &end, base);
194 if (end == buf || !isspace(*end))
195 return -EINVAL;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200196
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200197 *value = v;
198 return 0;
199}
200
201int read_str_ulong(int fd, unsigned long *value, int base) {
202 char buf[32], *end;
203 long v;
204 int err;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200205
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200206 *value = 0;
207 err = read_str_safe(fd, buf, sizeof(buf));
208 if (err < 0)
209 return err;
210 errno = 0;
211 v = strtoul(buf, &end, base);
212 if (end == buf || !isspace(*end))
213 return -EINVAL;
214 *value = v;
215 return 0;
216}
Lucas De Marchiafca7802011-12-07 10:59:17 -0200217
218char *strchr_replace(char *s, int c, char r)
219{
220 char *p;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200221
Gustavo Sverzut Barbieribf8cf142011-12-10 19:45:37 -0200222 for (p = s; *p != '\0'; p++)
223 if (*p == c)
224 *p = r;
Lucas De Marchi28c175e2011-12-12 11:52:59 -0200225
Lucas De Marchiafca7802011-12-07 10:59:17 -0200226 return s;
227}
Lucas De Marchi3a468802011-12-07 13:50:52 -0200228
229bool path_is_absolute(const char *p)
230{
231 assert(p != NULL);
232
233 return p[0] == '/';
234}
Lucas De Marchi06363cc2011-12-07 13:51:40 -0200235
236char *path_make_absolute_cwd(const char *p)
237{
238 char *cwd, *r;
239 size_t plen;
240 size_t cwdlen;
241
242 if (path_is_absolute(p))
243 return strdup(p);
244
245 cwd = get_current_dir_name();
246 if (cwd == NULL)
247 return NULL;
248
249 plen = strlen(p);
250 cwdlen = strlen(cwd);
251
252 /* cwd + '/' + p + '\0' */
253 r = realloc(cwd, cwdlen + 1 + plen + 1);
254 if (r == NULL) {
255 free(cwd);
256 return NULL;
257 }
258
Lucas De Marchi4eb2c0f2011-12-08 10:37:56 -0200259 r[cwdlen] = '/';
260 memcpy(&r[cwdlen + 1], p, plen + 1);
Lucas De Marchi06363cc2011-12-07 13:51:40 -0200261
262 return r;
263}