From e47405eaac2ce161f73404f6a6fa3e2cdf9047b4 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Thu, 2 May 2024 14:20:28 +0200 Subject: [PATCH 01/12] alternatives: fix memory leak Error: RESOURCE_LEAK (CWE-772): chkconfig-1.26/alternatives.c:328: alloc_fn: Storage is returned from allocation function "parseLine". chkconfig-1.26/alternatives.c:328: var_assign: Assigning: "line" = storage returned from "parseLine(&buf)". chkconfig-1.26/alternatives.c:331: leaked_storage: Variable "line" going out of scope leaks the storage it points to. 329| if (!line || *line != '/') { 330| fprintf(stderr, _("bad primary link in %s\n"), path); 331|-> return 1; 332| } 333| --- alternatives.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/alternatives.c b/alternatives.c index 19ce6cf4..4b1ab1ff 100644 --- a/alternatives.c +++ b/alternatives.c @@ -106,7 +106,7 @@ static int usage(int rc) { exit(rc); } -/* +/* * Function to clean path form unnecessary backslashes * It will make from //abcd///efgh/ -> /abcd/efgh/ */ @@ -120,7 +120,7 @@ const char *normalize_path(const char *s) { } while (*dst == '/' && *src == '/'); dst++; } - } + } return (const char *)s; } @@ -328,6 +328,7 @@ static int readConfig(struct alternativeSet *set, const char *title, line = parseLine(&buf); if (!line || *line != '/') { fprintf(stderr, _("bad primary link in %s\n"), path); + free(line); return 1; } From 5140aa7ebe5f568eea7130b783460f59fc47a06e Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Thu, 2 May 2024 14:56:01 +0200 Subject: [PATCH 02/12] alternatives: initialize parameters in main to NULL This should be a no-op but it hardens the code and also makes static analyzers a bit more happy. --- alternatives.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/alternatives.c b/alternatives.c index 4b1ab1ff..b98e2331 100644 --- a/alternatives.c +++ b/alternatives.c @@ -1254,7 +1254,9 @@ static int listServices(const char *altDir, const char *stateDir, int flags) { int main(int argc, const char **argv) { const char **nextArg; char *end; - char *title, *target, *followerTitle; + char *title = NULL; + char *target = NULL; + char *followerTitle = NULL; enum programModes mode = MODE_UNKNOWN; struct alternative newAlt = {-1, {NULL, NULL, NULL}, NULL, NULL, 0, NULL}; int flags = 0; From caaa4d692248f5c95dd7df36f8fba69392870ffc Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Thu, 2 May 2024 15:50:59 +0200 Subject: [PATCH 03/12] alternatives: fix memory leak Error: RESOURCE_LEAK (CWE-772): chkconfig-1.26/alternatives.c:441: alloc_fn: Storage is returned from allocation function "parseLine". chkconfig-1.26/alternatives.c:441: var_assign: Assigning: "line" = storage returned from "parseLine(&buf)". chkconfig-1.26/alternatives.c:445: overwrite_var: Overwriting "line" in "line = parseLine(&buf)" leaks the storage that "line" points to. 443| 444| while (line) { 445|-> line = parseLine(&buf); 446| if (line && *line) { 447| fprintf(stderr, _("unexpected line in %s: %s\n"), path, line); --- alternatives.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/alternatives.c b/alternatives.c index b98e2331..752693a5 100644 --- a/alternatives.c +++ b/alternatives.c @@ -446,8 +446,10 @@ static int readConfig(struct alternativeSet *set, const char *title, line = parseLine(&buf); if (line && *line) { fprintf(stderr, _("unexpected line in %s: %s\n"), path, line); + free(line); return 1; } + free(line); } leader_path = alloca(strlen(altDir) + strlen(set->alts[0].leader.title) + 2); From c296618d679514ab1a01d58b188c0a685169b650 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Thu, 2 May 2024 15:52:57 +0200 Subject: [PATCH 04/12] alternatives: fix memory leak Error: RESOURCE_LEAK (CWE-772): chkconfig-1.26/alternatives.c:339: alloc_fn: Storage is returned from allocation function "parseLine". chkconfig-1.26/alternatives.c:339: var_assign: Assigning: "line" = storage returned from "parseLine(&buf)". chkconfig-1.26/alternatives.c:342: noescape: Resource "line" is not freed or pointed-to in "fprintf". [Note: The source code implementation of the function has been overridden by a builtin model.] chkconfig-1.26/alternatives.c:343: leaked_storage: Variable "line" going out of scope leaks the storage it points to. 341| if (*line == '/') { 342| fprintf(stderr, _("path %s unexpected in %s\n"), line, path); 343|-> return 1; 344| } 345| --- alternatives.c | 1 + 1 file changed, 1 insertion(+) diff --git a/alternatives.c b/alternatives.c index 752693a5..a11af16c 100644 --- a/alternatives.c +++ b/alternatives.c @@ -341,6 +341,7 @@ static int readConfig(struct alternativeSet *set, const char *title, while (line && *line) { if (*line == '/') { fprintf(stderr, _("path %s unexpected in %s\n"), line, path); + free(line); return 1; } From ec56116e7b9160a0bd26e958834878a728443371 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Tue, 7 May 2024 09:28:05 +0200 Subject: [PATCH 05/12] alternatives: fix leak Error: RESOURCE_LEAK (CWE-772): [#def1] [important] chkconfig-1.26/alternatives.c:312:5: alloc_fn: Storage is returned from allocation function "parseLine". chkconfig-1.26/alternatives.c:312:5: var_assign: Assigning: "line" = storage returned from "parseLine(&buf)". chkconfig-1.26/alternatives.c:318:5: noescape: Resource "line" is not freed or pointed-to in "strcmp". chkconfig-1.26/alternatives.c:320:12: noescape: Resource "line" is not freed or pointed-to in "strcmp". chkconfig-1.26/alternatives.c:324:9: leaked_storage: Variable "line" going out of scope leaks the storage it points to. 322| } else { 323| fprintf(stderr, _("bad mode on line 1 of %s\n"), path); 324|-> return 1; 325| } 326| free(line); --- alternatives.c | 1 + 1 file changed, 1 insertion(+) diff --git a/alternatives.c b/alternatives.c index a11af16c..cf7ff836 100644 --- a/alternatives.c +++ b/alternatives.c @@ -321,6 +321,7 @@ static int readConfig(struct alternativeSet *set, const char *title, set->mode = MANUAL; } else { fprintf(stderr, _("bad mode on line 1 of %s\n"), path); + free(line); return 1; } free(line); From e8dd7ab77ee84911dfd0b758236475bdd2fac5d9 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Tue, 7 May 2024 10:16:35 +0200 Subject: [PATCH 06/12] alternatives: fix all the leaks of read line in readConfig --- alternatives.c | 107 +++++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/alternatives.c b/alternatives.c index cf7ff836..7803c010 100644 --- a/alternatives.c +++ b/alternatives.c @@ -134,6 +134,12 @@ int streq(const char *a, const char *b) { return 0; } +char * strsteal(char **ptr) { + char *ret = *ptr; + *ptr = NULL; + return ret; +} + int altBetter(struct alternative new, struct alternative old, char *family) { if (!family || (streq(old.family, family) == streq(new.family, family))) return new.priority > old.priority; @@ -261,6 +267,11 @@ char *parseLine(char **buf) { return strdup(start); } +void nextLine(char **buf, char **line) { + free(*line); + *line = parseLine(buf); +} + static int readConfig(struct alternativeSet *set, const char *title, const char *altDir, const char *stateDir, int flags) { char *path; @@ -270,13 +281,15 @@ static int readConfig(struct alternativeSet *set, const char *title, struct stat sb; char *buf; char *end; - char *line; + char *line = NULL; + char *ptr; struct { char *facility; char *title; } *groups = NULL; int numGroups = 0; char linkBuf[PATH_MAX]; + int r = 0; set->alts = NULL; set->numAlts = 0; @@ -309,10 +322,11 @@ static int readConfig(struct alternativeSet *set, const char *title, close(fd); buf[sb.st_size] = '\0'; - line = parseLine(&buf); + nextLine(&buf, &line); if (!line) { fprintf(stderr, _("%s empty!\n"), path); - return 1; + r = 1; + goto finish; } if (!strcmp(line, "auto")) { @@ -321,63 +335,65 @@ static int readConfig(struct alternativeSet *set, const char *title, set->mode = MANUAL; } else { fprintf(stderr, _("bad mode on line 1 of %s\n"), path); - free(line); - return 1; + r = 1; + goto finish; } - free(line); - line = parseLine(&buf); + nextLine(&buf, &line); if (!line || *line != '/') { fprintf(stderr, _("bad primary link in %s\n"), path); - free(line); - return 1; + r = 1; + goto finish; } groups = realloc(groups, sizeof(*groups)); groups[0].title = strdup(title); - groups[0].facility = line; + groups[0].facility = strsteal(&line); numGroups = 1; - line = parseLine(&buf); + nextLine(&buf, &line); while (line && *line) { if (*line == '/') { fprintf(stderr, _("path %s unexpected in %s\n"), line, path); - free(line); - return 1; + r = 1; + goto finish; } groups = realloc(groups, sizeof(*groups) * (numGroups + 1)); - groups[numGroups].title = line; + groups[numGroups].title = strsteal(&line); - line = parseLine(&buf); + nextLine(&buf, &line); if (!line || !*line) { fprintf(stderr, _("missing path for follower %s in %s\n"), line, path); - return 1; + r = 1; + goto finish; } - groups[numGroups++].facility = line; + groups[numGroups++].facility = strsteal(&line); - line = parseLine(&buf); + nextLine(&buf, &line); } if (!line) { fprintf(stderr, _("unexpected end of file in %s\n"), path); - return 1; + r = 1; + goto finish; } - line = parseLine(&buf); + nextLine(&buf, &line); while (line && *line) { set->alts = realloc(set->alts, (set->numAlts + 1) * sizeof(*set->alts)); if (*line != '/') { fprintf(stderr, _("path to alternate expected in %s\n"), path); fprintf(stderr, _("unexpected line in %s: %s\n"), path, line); - return 1; + r = 1; + goto finish; } set->alts[set->numAlts].leader.facility = strdup(normalize_path(groups[0].facility)); set->alts[set->numAlts].leader.title = strdup(groups[0].title); - set->alts[set->numAlts].leader.target = line; + set->alts[set->numAlts].leader.target = strsteal(&line); set->alts[set->numAlts].numFollowers = numGroups - 1; if (numGroups > 1) set->alts[set->numAlts].followers = malloc( @@ -385,32 +401,36 @@ static int readConfig(struct alternativeSet *set, const char *title, else set->alts[set->numAlts].followers = NULL; - line = parseLine(&buf); set->alts[set->numAlts].priority = -1; set->alts[set->numAlts].initscript = NULL; set->alts[set->numAlts].family = NULL; - if (line && line[0] == '@') { - line++; - end = strchr(line, '@'); - if (!end || (end == line)) { + nextLine(&buf, &line); + ptr = line; + + if (ptr && ptr[0] == '@') { + ptr++; + end = strchr(ptr, '@'); + if (!end || (end == ptr)) { fprintf(stderr, _("closing '@' missing or the family is empty in %s\n"), path); fprintf(stderr, _("unexpected line in %s: %s\n"), path, line); - return 1; + r = 1; + goto finish; } *end = '\0'; - set->alts[set->numAlts].family = strdup(line); - line = end + 1; + set->alts[set->numAlts].family = strdup(ptr); + ptr = end + 1; } - set->alts[set->numAlts].priority = strtol(line, &end, 0); + set->alts[set->numAlts].priority = strtol(ptr, &end, 0); - if (!end || (end == line)) { + if (!end || (end == ptr)) { fprintf(stderr, _("numeric priority expected in %s\n"), path); fprintf(stderr, _("unexpected line in %s: %s\n"), path, line); - return 1; + r = 1; + goto finish; } if (end) { while (*end && isspace(*end)) @@ -424,11 +444,12 @@ static int readConfig(struct alternativeSet *set, const char *title, set->best = set->numAlts; for (i = 1; i < numGroups; i++) { - line = parseLine(&buf); + nextLine(&buf, &line); if (line && strlen(line) && *line != '/') { fprintf(stderr, _("follower path expected in %s\n"), path); fprintf(stderr, _("unexpected line in %s: %s\n"), path, line); - return 1; + r = 1; + goto finish; } set->alts[set->numAlts].followers[i - 1].title = @@ -436,22 +457,21 @@ static int readConfig(struct alternativeSet *set, const char *title, set->alts[set->numAlts].followers[i - 1].facility = strdup(normalize_path(groups[i].facility)); set->alts[set->numAlts].followers[i - 1].target = - (line && strlen(line)) ? line : NULL; + (line && strlen(line)) ? strsteal(&line) : NULL; } set->numAlts++; - line = parseLine(&buf); + nextLine(&buf, &line); } while (line) { - line = parseLine(&buf); + nextLine(&buf, &line); if (line && *line) { fprintf(stderr, _("unexpected line in %s: %s\n"), path, line); - free(line); - return 1; + r = 1; + goto finish; } - free(line); } leader_path = alloca(strlen(altDir) + strlen(set->alts[0].leader.title) + 2); @@ -485,8 +505,9 @@ static int readConfig(struct alternativeSet *set, const char *title, } set->currentLink = strdup(normalize_path(linkBuf)); - - return 0; +finish: + free(line); + return r; } static int isLink(char *path) { From 44ba44f441835faf67c9fcc02acc91f9004a1174 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Tue, 7 May 2024 11:21:31 +0200 Subject: [PATCH 07/12] alternatives: fix all the leaks of groups in readConfig --- alternatives.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/alternatives.c b/alternatives.c index 7803c010..14080cbb 100644 --- a/alternatives.c +++ b/alternatives.c @@ -480,7 +480,8 @@ static int readConfig(struct alternativeSet *set, const char *title, if (((i = readlink(leader_path, linkBuf, sizeof(linkBuf) - 1)) < 0)) { fprintf(stderr, _("failed to read link %s: %s\n"), set->alts[0].leader.facility, strerror(errno)); - return 2; + r = 2; + goto finish; } linkBuf[i] = '\0'; @@ -506,6 +507,11 @@ static int readConfig(struct alternativeSet *set, const char *title, set->currentLink = strdup(normalize_path(linkBuf)); finish: + for (i = 1; i < numGroups; i++) { + free(groups[i].title); + free(groups[i].facility); + } + free(groups); free(line); return r; } From c247ff1313d02d919bf31c998c761baba812e109 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Tue, 7 May 2024 12:16:10 +0200 Subject: [PATCH 08/12] alternatives: fix possible overrun Error: STRING_NULL (CWE-170): [#def1] [important] chkconfig-1.26/alternatives.c:591:13: string_null_source: Function "readlink" does not terminate string "buf". [Note: The source code implementation of the function has been overridden by a builtin model.] chkconfig-1.26/alternatives.c:593:13: string_null: Passing unterminated string "buf" to "streq", which expects a null-terminated string. 591| readlink(l->facility, buf, sizeof(buf)); 592| 593|-> if(!streq(sl, buf)) { 594| unlink(l->facility); 595| Error: STRING_NULL (CWE-170): [#def2] [important] chkconfig-1.26/alternatives.c:609:9: string_null_source: Function "readlink" does not terminate string "buf". [Note: The source code implementation of the function has been overridden by a builtin model.] chkconfig-1.26/alternatives.c:611:9: string_null: Passing unterminated string "buf" to "streq", which expects a null-terminated string. 609| readlink(sl, buf, sizeof(buf)); 610| 611|-> if(!streq(l->target, buf)) { 612| if (unlink(sl) && errno != ENOENT) { 613| fprintf(stderr, _("failed to remove link %s: %s\n"), sl, --- alternatives.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alternatives.c b/alternatives.c index 14080cbb..42271eb2 100644 --- a/alternatives.c +++ b/alternatives.c @@ -588,7 +588,7 @@ static int makeLinks(struct linkSet *l, const char *altDir, int flags) { printf(_("would link %s -> %s\n"), l->facility, sl); } else { memset(buf, 0, sizeof(buf)); - readlink(l->facility, buf, sizeof(buf)); + readlink(l->facility, buf, sizeof(buf)-1); if(!streq(sl, buf)) { unlink(l->facility); @@ -606,7 +606,7 @@ static int makeLinks(struct linkSet *l, const char *altDir, int flags) { printf(_("would link %s -> %s\n"), sl, l->target); } else { memset(buf, 0, sizeof(buf)); - readlink(sl, buf, sizeof(buf)); + readlink(sl, buf, sizeof(buf)-1); if(!streq(l->target, buf)) { if (unlink(sl) && errno != ENOENT) { From d71bac522bba0787b2295671a4e005de97731dab Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Tue, 7 May 2024 12:18:42 +0200 Subject: [PATCH 09/12] alternatives: fix leak Error: RESOURCE_LEAK (CWE-772): [#def3] [important] chkconfig-1.26/alternatives.c:794:9: alloc_fn: Storage is returned from allocation function "malloc". chkconfig-1.26/alternatives.c:794:9: var_assign: Assigning: "newLinks" = storage returned from "malloc(24UL * template.numFollowers)". chkconfig-1.26/alternatives.c:798:9: identity_transfer: Passing "newLinks" as argument 1 to function "memset", which returns that argument. [Note: The source code implementation of the function has been overridden by a builtin model.] chkconfig-1.26/alternatives.c:798:9: noescape: Resource "newLinks" is not freed or pointed-to in "memset". [Note: The source code implementation of the function has been overridden by a builtin model.] chkconfig-1.26/alternatives.c:798:9: var_assign: Assigning: "newLinks" = storage returned from "memset(newLinks, 0, 24UL * template.numFollowers)". chkconfig-1.26/alternatives.c:817:21: leaked_storage: Variable "newLinks" going out of scope leaks the storage it points to. 815| set->alts[k].followers[i].title, 816| template.followers[j].facility, template.followers[j].title); 817|-> return 2; 818| } 819| newLinks[j] = set->alts[k].followers[i]; --- alternatives.c | 1 + 1 file changed, 1 insertion(+) diff --git a/alternatives.c b/alternatives.c index 42271eb2..832aefda 100644 --- a/alternatives.c +++ b/alternatives.c @@ -814,6 +814,7 @@ static int matchFollowers(struct alternativeSet *set, set->alts[k].followers[i].facility, set->alts[k].followers[i].title, template.followers[j].facility, template.followers[j].title); + free(newLinks); return 2; } newLinks[j] = set->alts[k].followers[i]; From 0268377bc4fe90f2791405037e7ff884e3268bfa Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Tue, 7 May 2024 12:20:32 +0200 Subject: [PATCH 10/12] alternatives: fix leak Error: RESOURCE_LEAK (CWE-772): [#def4] [important] chkconfig-1.26/alternatives.c:1255:5: alloc_fn: Storage is returned from allocation function "opendir". chkconfig-1.26/alternatives.c:1255:5: var_assign: Assigning: "dir" = storage returned from "opendir(stateDir)". chkconfig-1.26/alternatives.c:1259:5: noescape: Resource "dir" is not freed or pointed-to in "readdir". chkconfig-1.26/alternatives.c:1259:5: noescape: Resource "dir" is not freed or pointed-to in "readdir". chkconfig-1.26/alternatives.c:1267:5: noescape: Resource "dir" is not freed or pointed-to in "rewinddir". chkconfig-1.26/alternatives.c:1269:5: noescape: Resource "dir" is not freed or pointed-to in "readdir". chkconfig-1.26/alternatives.c:1274:13: leaked_storage: Variable "dir" going out of scope leaks the storage it points to. 1272| 1273| if (readConfig(&set, ent->d_name, altDir, stateDir, flags)) 1274|-> return 2; 1275| 1276| printf("%-*s\t%s\t%s\n", max_name, ent->d_name, --- alternatives.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/alternatives.c b/alternatives.c index 832aefda..b91cc74e 100644 --- a/alternatives.c +++ b/alternatives.c @@ -1271,8 +1271,10 @@ static int listServices(const char *altDir, const char *stateDir, int flags) { if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; - if (readConfig(&set, ent->d_name, altDir, stateDir, flags)) + if (readConfig(&set, ent->d_name, altDir, stateDir, flags)) { + closedir(dir); return 2; + } printf("%-*s\t%s\t%s\n", max_name, ent->d_name, set.mode == AUTO ? "auto " : "manual", set.currentLink); From 5e2658dbf7236fa2503cce2ffc009b92925a9456 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Tue, 7 May 2024 12:23:57 +0200 Subject: [PATCH 11/12] alternatives: use exit in main instead of return for critical failures --- alternatives.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alternatives.c b/alternatives.c index b91cc74e..2817e331 100644 --- a/alternatives.c +++ b/alternatives.c @@ -1420,12 +1420,12 @@ int main(int argc, const char **argv) { if (stat(altDir, &sb) || !S_ISDIR(sb.st_mode) || access(altDir, F_OK)) { fprintf(stderr, _("altdir %s invalid\n"), altDir); - return (2); + exit(2); } if (stat(stateDir, &sb) || !S_ISDIR(sb.st_mode) || access(stateDir, F_OK)) { fprintf(stderr, _("admindir %s invalid\n"), stateDir); - return (2); + exit(2); } switch (mode) { From e406ed838f765c8dfb8643c2656b3f4c5f28a19e Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Mon, 13 May 2024 13:54:01 +0200 Subject: [PATCH 12/12] alternatives: properly handle chars with const in normalize_path --- alternatives.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/alternatives.c b/alternatives.c index 2817e331..d15eb2e7 100644 --- a/alternatives.c +++ b/alternatives.c @@ -110,7 +110,7 @@ static int usage(int rc) { * Function to clean path form unnecessary backslashes * It will make from //abcd///efgh/ -> /abcd/efgh/ */ -const char *normalize_path(const char *s) { +char *normalize_path(char *s) { if (s) { const char *src = s; char *dst = (char *)s; @@ -121,7 +121,12 @@ const char *normalize_path(const char *s) { dst++; } } - return (const char *)s; + return s; +} + +char *normalize_path_alloc(const char *s) { + char *ret = strdup(s); + return normalize_path(ret); } int streq(const char *a, const char *b) { @@ -197,7 +202,7 @@ static void setupDoubleArg(enum programModes *mode, const char ***nextArgPtr, if (!*nextArg) usage(2); - *target = strdup(normalize_path(*nextArg)); + *target = normalize_path_alloc(*nextArg); *nextArgPtr = nextArg + 1; } @@ -218,7 +223,7 @@ static void setupTripleArg(enum programModes *mode, const char ***nextArgPtr, if (!*nextArg) usage(2); - *target = strdup(normalize_path(*nextArg)); + *target = normalize_path_alloc(*nextArg); nextArg++; if (!*nextArg) @@ -232,7 +237,7 @@ static void setupLinkSet(struct linkSet *set, const char ***nextArgPtr) { if (!*nextArg || **nextArg != '/') usage(2); - set->facility = strdup(normalize_path(*nextArg)); + set->facility = normalize_path_alloc(*nextArg); nextArg++; if (!*nextArg || **nextArg == '/') @@ -242,7 +247,7 @@ static void setupLinkSet(struct linkSet *set, const char ***nextArgPtr) { if (!*nextArg || **nextArg != '/') usage(2); - set->target = strdup(normalize_path(*nextArg)); + set->target = normalize_path_alloc(*nextArg); *nextArgPtr = nextArg + 1; } @@ -391,7 +396,7 @@ static int readConfig(struct alternativeSet *set, const char *title, goto finish; } - set->alts[set->numAlts].leader.facility = strdup(normalize_path(groups[0].facility)); + set->alts[set->numAlts].leader.facility = normalize_path_alloc(groups[0].facility); set->alts[set->numAlts].leader.title = strdup(groups[0].title); set->alts[set->numAlts].leader.target = strsteal(&line); set->alts[set->numAlts].numFollowers = numGroups - 1; @@ -455,7 +460,7 @@ static int readConfig(struct alternativeSet *set, const char *title, set->alts[set->numAlts].followers[i - 1].title = strdup(groups[i].title); set->alts[set->numAlts].followers[i - 1].facility = - strdup(normalize_path(groups[i].facility)); + normalize_path_alloc(groups[i].facility); set->alts[set->numAlts].followers[i - 1].target = (line && strlen(line)) ? strsteal(&line) : NULL; } @@ -505,7 +510,7 @@ static int readConfig(struct alternativeSet *set, const char *title, set->current = i; } - set->currentLink = strdup(normalize_path(linkBuf)); + set->currentLink = normalize_path_alloc(linkBuf); finish: for (i = 1; i < numGroups; i++) { free(groups[i].title); @@ -1400,13 +1405,13 @@ int main(int argc, const char **argv) { nextArg++; if (!*nextArg) usage(2); - altDir = strdup(normalize_path(*nextArg)); + altDir = normalize_path_alloc(*nextArg); nextArg++; } else if (!strcmp(*nextArg, "--admindir")) { nextArg++; if (!*nextArg) usage(2); - stateDir = strdup(normalize_path(*nextArg)); + stateDir = normalize_path_alloc(*nextArg); nextArg++; } else if (!strcmp(*nextArg, "--list")) { if (mode != MODE_UNKNOWN)