Skip to content

Commit db65bb5

Browse files
committed
feat: support --config=path and fix config parsing
Allow specifying the config file using --config=path syntax. Also fixed a potential double free when the config path is specified multiple times or in certain edge cases.
1 parent 0753fc4 commit db65bb5

3 files changed

Lines changed: 102 additions & 43 deletions

File tree

src/main.c

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "log.h"
44
#include "util.h"
55

6+
#include <ctype.h>
67
#include <errno.h>
78
#include <unistd.h>
89
#include <sys/stat.h>
@@ -62,8 +63,21 @@ int main(int argc, char **argv)
6263
*/
6364
for (int i = 1; i < argc; i++) {
6465
add_arg(&all_argv, &all_argc, argv[i]);
65-
if (!strcmp(argv[i], "--config")) {
66-
config_path = strdup(argv[i + 1]);
66+
if (!strncmp(argv[i], "--config=", 9)) {
67+
if (argv[i][9] == '\0') {
68+
lprintf(fatal, "--config requires a path\n");
69+
}
70+
FREE(config_path);
71+
config_path = STRDUP(argv[i] + 9);
72+
} else if (!strcmp(argv[i], "--config")) {
73+
if (i + 1 >= argc || argv[i + 1][0] == '\0'
74+
|| argv[i + 1][0] == '-') {
75+
lprintf(fatal, "--config requires a path\n");
76+
}
77+
FREE(config_path);
78+
config_path = STRDUP(argv[i + 1]);
79+
add_arg(&all_argv, &all_argc, argv[i + 1]);
80+
i++;
6781
}
6882
}
6983

@@ -176,7 +190,7 @@ static char *get_XDG_CONFIG_HOME(void)
176190

177191
const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
178192
if (xdg_config_home) {
179-
config_dir = strndup(xdg_config_home, MAX_PATH_LEN);
193+
config_dir = STRNDUP(xdg_config_home, MAX_PATH_LEN);
180194
} else {
181195
const char *user_home = getenv("HOME");
182196
if (user_home) {
@@ -205,42 +219,54 @@ void parse_config_file(char ***argv, int *argc)
205219
full_path = config_path;
206220
}
207221

208-
/*
209-
* The buffer has to be able to fit a URL
210-
*/
211-
int buf_len = MAX_PATH_LEN;
212-
char buf[buf_len];
222+
char *buf = NULL;
223+
size_t buf_len = 0;
213224
FILE *config = fopen(full_path, "r");
214-
if (config) {
215-
while (fgets(buf, buf_len, config)) {
216-
if (buf[0] == '-') {
217-
(*argc)++;
218-
buf[strnlen(buf, buf_len) - 1] = '\0';
219-
char *space;
220-
space = strchr(buf, ' ');
225+
if (!config) {
226+
if (config_path) {
227+
lprintf(fatal, "Could not open config file %s: %s\n", full_path,
228+
strerror(errno));
229+
}
230+
} else {
231+
while (getline(&buf, &buf_len, config) != -1) {
232+
// Remove trailing whitespace
233+
size_t len = strlen(buf);
234+
while (len > 0 && isspace((unsigned char)buf[len - 1])) {
235+
buf[--len] = '\0';
236+
}
237+
238+
char *line = buf;
239+
while (*line && isspace((unsigned char)*line)) {
240+
line++;
241+
}
242+
243+
if (line[0] == '-') {
244+
char *space = strpbrk(line, " \t");
221245
if (!space) {
222-
*argv = (char **)realloc((void *)*argv,
223-
*argc * sizeof(char *));
224-
(*argv)[*argc - 1] = strndup(buf, buf_len);
246+
add_arg(argv, argc, line);
225247
} else {
226-
(*argc)++;
227-
*argv = (char **)realloc((void *)*argv,
228-
*argc * sizeof(char *));
248+
*space = '\0';
249+
add_arg(argv, argc, line);
229250
/*
230-
* Only copy up to the space character
251+
* Starts copying after the space, skipping leading
252+
* whitespace
231253
*/
232-
(*argv)[*argc - 2] = strndup(buf, space - buf);
233-
/*
234-
* Starts copying after the space
235-
*/
236-
(*argv)[*argc - 1]
237-
= strndup(space + 1, buf_len - (space + 1 - buf));
254+
char *value = space + 1;
255+
while (*value && isspace((unsigned char)*value)) {
256+
value++;
257+
}
258+
if (*value != '\0') {
259+
add_arg(argv, argc, value);
260+
}
238261
}
239262
}
240263
}
264+
FREE(buf);
241265
fclose(config);
242266
}
243-
FREE(full_path);
267+
if (full_path != config_path) {
268+
FREE(full_path);
269+
}
244270
}
245271

246272
static int parse_arg_list(int argc, char **argv, char ***fuse_argv,
@@ -313,24 +339,24 @@ static int parse_arg_list(int argc, char **argv, char ***fuse_argv,
313339
add_arg(fuse_argv, fuse_argc, "-s");
314340
break;
315341
case 'u':
316-
CONFIG.http_username = strdup(optarg);
342+
CONFIG.http_username = STRDUP(optarg);
317343
break;
318344
case 'p':
319-
CONFIG.http_password = strdup(optarg);
345+
CONFIG.http_password = STRDUP(optarg);
320346
break;
321347
case 'P':
322-
CONFIG.proxy = strdup(optarg);
348+
CONFIG.proxy = STRDUP(optarg);
323349
break;
324350
case 'L':
325351
/*
326352
* Long options
327353
*/
328354
switch (long_index) {
329355
case 6:
330-
CONFIG.proxy_username = strdup(optarg);
356+
CONFIG.proxy_username = STRDUP(optarg);
331357
break;
332358
case 7:
333-
CONFIG.proxy_password = strdup(optarg);
359+
CONFIG.proxy_password = STRDUP(optarg);
334360
break;
335361
case 8:
336362
CONFIG.cache_enabled = 1;
@@ -345,19 +371,19 @@ static int parse_arg_list(int argc, char **argv, char ***fuse_argv,
345371
CONFIG.max_conns = (int)strtol(optarg, NULL, 10);
346372
break;
347373
case 12:
348-
CONFIG.user_agent = strdup(optarg);
374+
CONFIG.user_agent = STRDUP(optarg);
349375
break;
350376
case 13:
351377
CONFIG.http_wait_sec = (int)strtol(optarg, NULL, 10);
352378
break;
353379
case 14:
354-
CONFIG.cache_dir = strdup(optarg);
380+
CONFIG.cache_dir = STRDUP(optarg);
355381
break;
356382
case 15:
357-
CONFIG.sonic_username = strdup(optarg);
383+
CONFIG.sonic_username = STRDUP(optarg);
358384
break;
359385
case 16:
360-
CONFIG.sonic_password = strdup(optarg);
386+
CONFIG.sonic_password = STRDUP(optarg);
361387
break;
362388
case 17:
363389
CONFIG.sonic_id3 = 1;
@@ -380,10 +406,10 @@ static int parse_arg_list(int argc, char **argv, char ***fuse_argv,
380406
CONFIG.mode = SINGLE;
381407
break;
382408
case 23:
383-
CONFIG.cafile = strdup(optarg);
409+
CONFIG.cafile = STRDUP(optarg);
384410
break;
385411
case 24:
386-
CONFIG.proxy_cafile = strdup(optarg);
412+
CONFIG.proxy_cafile = STRDUP(optarg);
387413
break;
388414
case 25:
389415
CONFIG.refresh_timeout = (int)strtol(optarg, NULL, 10);
@@ -420,11 +446,16 @@ static int parse_arg_list(int argc, char **argv, char ***fuse_argv,
420446
*/
421447
void add_arg(char ***fuse_argv_ptr, int *fuse_argc, char *opt_string)
422448
{
449+
char **tmp = (char **)realloc((void *)*fuse_argv_ptr,
450+
((size_t)*fuse_argc + 1) * sizeof(char *));
451+
if (!tmp) {
452+
lprintf(fatal, "realloc failed: %s\n", strerror(errno));
453+
return;
454+
}
455+
*fuse_argv_ptr = tmp;
423456
(*fuse_argc)++;
424-
*fuse_argv_ptr
425-
= (char **)realloc((void *)*fuse_argv_ptr, *fuse_argc * sizeof(char *));
426457
char **fuse_argv = *fuse_argv_ptr;
427-
fuse_argv[*fuse_argc - 1] = strdup(opt_string);
458+
fuse_argv[*fuse_argc - 1] = STRDUP(opt_string);
428459
}
429460

430461
static void print_help(char *program_name, int long_help)

src/util.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,21 @@ char *str_to_hex(char *s)
276276
}
277277
return hex;
278278
}
279+
280+
char *STRDUP(const char *s)
281+
{
282+
char *ptr = strdup(s);
283+
if (!ptr) {
284+
lprintf(fatal, "%s!\n", strerror(errno));
285+
}
286+
return ptr;
287+
}
288+
289+
char *STRNDUP(const char *s, size_t n)
290+
{
291+
char *ptr = strndup(s, n);
292+
if (!ptr) {
293+
lprintf(fatal, "%s!\n", strerror(errno));
294+
}
295+
return ptr;
296+
}

src/util.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ void FREE(void *ptr);
128128
*/
129129
char *str_to_hex(char *s);
130130

131+
/**
132+
* \brief wrapper for strdup(), with error handling
133+
*/
134+
char *STRDUP(const char *s);
135+
136+
/**
137+
* \brief wrapper for strndup(), with error handling
138+
*/
139+
char *STRNDUP(const char *s, size_t n);
140+
131141
/**
132142
* \brief initialise the configuration data structure
133143
*/

0 commit comments

Comments
 (0)