blob: f855bc7b697ae7c3b6f7fbc32181677eb3f62ed2 [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
8 * License as published by the Free Software Foundation version 2.1.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
Lucas De Marchi7e317da2011-11-30 19:20:19 -020020#include <assert.h>
Lucas De Marchi4462c4a2011-11-29 18:05:43 -020021#include <stdio.h>
22#include <stdlib.h>
23#include <stddef.h>
24#include <stdarg.h>
25#include <unistd.h>
26#include <errno.h>
27#include <string.h>
28#include <ctype.h>
29
30#include "libkmod.h"
31#include "libkmod-private.h"
32
33/*
34 * Read one logical line from a configuration file.
35 *
36 * Line endings may be escaped with backslashes, to form one logical line from
37 * several physical lines. No end of line character(s) are included in the
38 * result.
39 *
40 * If linenum is not NULL, it is incremented by the number of physical lines
41 * which have been read.
42 */
43char *getline_wrapped(FILE *fp, unsigned int *linenum)
44{
45 int size = 256;
46 int i = 0;
47 char *buf = malloc(size);
48 for(;;) {
49 int ch = getc_unlocked(fp);
50
51 switch(ch) {
52 case EOF:
53 if (i == 0) {
54 free(buf);
55 return NULL;
56 }
57 /* else fall through */
58
59 case '\n':
60 if (linenum)
61 (*linenum)++;
62 if (i == size)
63 buf = realloc(buf, size + 1);
64 buf[i] = '\0';
65 return buf;
66
67 case '\\':
68 ch = getc_unlocked(fp);
69
70 if (ch == '\n') {
71 if (linenum)
72 (*linenum)++;
73 continue;
74 }
75 /* else fall through */
76
77 default:
78 buf[i++] = ch;
79
80 if (i == size) {
81 size *= 2;
82 buf = realloc(buf, size);
83 }
84 }
85 }
86}
Lucas De Marchi8185fc92011-11-30 02:14:33 -020087
88/*
89 * Replace dashes with underscores.
90 * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
91 */
92char *underscores(struct kmod_ctx *ctx, char *s)
93{
94 unsigned int i;
95
96 if (!s)
97 return NULL;
98
99 for (i = 0; s[i]; i++) {
100 switch (s[i]) {
101 case '-':
102 s[i] = '_';
103 break;
104
105 case ']':
106 INFO(ctx, "Unmatched bracket in %s\n", s);
107 break;
108
109 case '[':
110 i += strcspn(&s[i], "]");
111 if (!s[i])
112 INFO(ctx, "Unmatched bracket in %s\n", s);
113 break;
114 }
115 }
116 return s;
117}
118
Lucas De Marchi7e317da2011-11-30 19:20:19 -0200119bool startswith(const char *s, const char *prefix) {
120 size_t sl, pl;
121
122 assert(s);
123 assert(prefix);
124
125 sl = strlen(s);
126 pl = strlen(prefix);
127
128 if (pl == 0)
129 return true;
130
131 if (sl < pl)
132 return false;
133
134 return memcmp(s, prefix, pl) == 0;
135}
Lucas De Marchie22c85f2011-12-02 17:21:18 -0200136
137inline void *memdup(const void *p, size_t n)
138{
139 void *r = malloc(n);
140
141 if (r == NULL)
142 return NULL;
143
144 return memcpy(r, p, n);
145}
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200146
147ssize_t read_str_safe(int fd, char *buf, size_t buflen) {
148 size_t todo = buflen;
149 size_t done;
150 do {
151 ssize_t r = read(fd, buf, todo);
152 if (r == 0)
153 break;
154 else if (r > 0)
155 todo -= r;
156 else {
157 if (errno == EAGAIN || errno == EWOULDBLOCK ||
158 errno == EINTR)
159 continue;
160 else
161 return -errno;
162 }
163 } while (todo > 0);
164 done = buflen - todo;
165 if (done == 0)
166 buf[0] = '\0';
167 else {
168 if (done < buflen)
169 buf[done] = '\0';
170 else if (buf[done - 1] != '\0')
171 return -ENOSPC;
172 }
173 return done;
174}
175
176int read_str_long(int fd, long *value, int base) {
177 char buf[32], *end;
178 long v;
179 int err;
180 *value = 0;
181 err = read_str_safe(fd, buf, sizeof(buf));
182 if (err < 0)
183 return err;
184 errno = 0;
185 v = strtol(buf, &end, base);
186 if (end == buf || !isspace(*end))
187 return -EINVAL;
188 *value = v;
189 return 0;
190}
191
192int read_str_ulong(int fd, unsigned long *value, int base) {
193 char buf[32], *end;
194 long v;
195 int err;
196 *value = 0;
197 err = read_str_safe(fd, buf, sizeof(buf));
198 if (err < 0)
199 return err;
200 errno = 0;
201 v = strtoul(buf, &end, base);
202 if (end == buf || !isspace(*end))
203 return -EINVAL;
204 *value = v;
205 return 0;
206}
Lucas De Marchiafca7802011-12-07 10:59:17 -0200207
208char *strchr_replace(char *s, int c, char r)
209{
210 char *p;
211
212 for (p = s; p != NULL; p = strchr(p, c))
213 *p = r;
214
215 return s;
216}
Lucas De Marchi3a468802011-12-07 13:50:52 -0200217
218bool path_is_absolute(const char *p)
219{
220 assert(p != NULL);
221
222 return p[0] == '/';
223}
Lucas De Marchi06363cc2011-12-07 13:51:40 -0200224
225char *path_make_absolute_cwd(const char *p)
226{
227 char *cwd, *r;
228 size_t plen;
229 size_t cwdlen;
230
231 if (path_is_absolute(p))
232 return strdup(p);
233
234 cwd = get_current_dir_name();
235 if (cwd == NULL)
236 return NULL;
237
238 plen = strlen(p);
239 cwdlen = strlen(cwd);
240
241 /* cwd + '/' + p + '\0' */
242 r = realloc(cwd, cwdlen + 1 + plen + 1);
243 if (r == NULL) {
244 free(cwd);
245 return NULL;
246 }
247
248 r[plen] = '/';
249 memcpy(&r[plen + 1], p, plen + 1);
250
251 return r;
252}