Skip to content

Commit 67d10bf

Browse files
committed
librc: improve RC_PATH and use XDG_CONFIG_DIRS only for --user
RC_PATH now behaves similarly to MANPATH, the first empty entry will be replaced with the default search path XDG_CONFIG_DIRS is a systemwide mirror of XDG_CONFIG_HOME, and not using the same subdir inside both is technically spen non-compliant there is no other system-level tool i could find that uses XDG_CONFIG_*, so i think it makes sense to reduce it to --user only
1 parent 78a46a2 commit 67d10bf

1 file changed

Lines changed: 108 additions & 70 deletions

File tree

src/librc/librc.c

Lines changed: 108 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,22 @@ rc_runlevel_stacks(const char *runlevel)
555555
return stack;
556556
}
557557

558+
static const char *config_path[] = {
559+
RC_SYSCONFDIR "/rc",
560+
RC_SYSCONFDIR,
561+
#ifdef RC_LOCAL_PREFIX
562+
RC_LOCAL_PREFIX "/etc/rc",
563+
RC_LOCAL_PREFIX "/etc",
564+
#endif
565+
#ifdef RC_PKG_PREFIX
566+
RC_PKG_PREFIX "/etc/rc",
567+
RC_PKG_PREFIX "/etc",
568+
#endif
569+
RC_LIBEXECDIR,
570+
RC_SVCDIR,
571+
NULL,
572+
};
573+
558574
static struct {
559575
bool set;
560576
char *svcdir, *confdir, *runleveldir;
@@ -564,7 +580,7 @@ static struct {
564580
char *buffer;
565581
size_t count;
566582
int *fds;
567-
const char **entries;
583+
const char **entries, **allocd;
568584
} rc_path;
569585

570586
static void
@@ -574,108 +590,130 @@ free_rc_dirs(void)
574590
X(rc_dirs.svcdir);
575591
X(rc_dirs.confdir);
576592
X(rc_dirs.runleveldir);
577-
593+
X(rc_path.allocd);
578594
X(rc_path.buffer);
579-
X(rc_path.entries);
580595
X(rc_path.fds);
581596
#undef X
582597
}
583598

584-
static inline size_t
585-
append_path(FILE *buf, int path_len, const char path[static path_len], const char *suffix)
599+
__attribute__((__format__(__printf__, 2, 3)))
600+
static void
601+
append_path(FILE *fp, const char *fmt, ...)
586602
{
587-
fprintf(buf, "%.*s%s%c", path_len, path, suffix ? suffix : "", '\0');
588-
return 1;
603+
va_list va;
604+
605+
va_start(va, fmt);
606+
vfprintf(fp, fmt, va);
607+
fputc('\0', fp);
608+
va_end(va);
609+
610+
rc_path.count++;
589611
}
590612

591-
static size_t
592-
append_path_string(FILE *buf, const char *path, const char *suffix)
613+
static const char *
614+
strnsep(const char **str, size_t *size, const char sep)
593615
{
594-
size_t count = 0;
616+
const char *ret = *str;
595617

596-
for (const char *entry = path; (path = strchrnul(entry, ':')); entry = path + 1) {
597-
size_t entry_len = path - entry;
618+
if (!ret)
619+
return NULL;
598620

599-
if (!entry_len)
600-
continue;
601-
count += append_path(buf, entry_len, entry, suffix);
602-
if (!*path)
603-
break;
604-
}
621+
*str = strchrnul(ret, sep);
622+
*size = *str - ret;
623+
if (!**str)
624+
*str = NULL;
625+
else
626+
*str += 1;
605627

606-
return count;
628+
return ret;
607629
}
608630

609-
static inline size_t
610-
append_path_xdg(FILE *buf, const char *home, const char *dirs, const char *fallback, bool user)
631+
static const char *
632+
strnullsep(const char **str, size_t *size)
611633
{
612-
const char *path;
613-
size_t count = 0;
634+
const char *ret = *str;
635+
size_t len;
636+
637+
if (!ret)
638+
return NULL;
639+
640+
len = strnlen(ret, *size - 1) + 1;
614641

615-
if (!(path = getenv(dirs)))
616-
path = fallback;
642+
if ((*size -= len))
643+
*str += len;
644+
else
645+
*str = NULL;
617646

618-
if (home)
619-
count += append_path(buf, strlen(home), home, NULL);
620-
return count + append_path_string(buf, path, user ? "/rc/user" : "/rc");
647+
return ret;
621648
}
622649

623-
static inline size_t
624-
append_path_array(FILE *buf, size_t path_len, const char **path, bool user)
650+
static void
651+
append_user_path(FILE *fp)
625652
{
626-
size_t count = 0;
627-
while (count < path_len) {
628-
const char *entry = path[count++];
629-
append_path(buf, strlen(entry), entry, user ? "/user" : "");
630-
}
631-
return count;
653+
const char *xdg, *entry;
654+
size_t size;
655+
656+
append_path(fp, "%s", rc_dirs.confdir);
657+
if (!(xdg = getenv("XDG_CONFIG_DIRS")))
658+
append_path(fp, "/etc/xdg/rc");
659+
else while ((entry = strnsep(&xdg, &size, ':')))
660+
if (size) append_path(fp, "%.*s/rc", (int) size, entry);
661+
662+
for (size_t i = 0; i < ARRAY_SIZE(config_path) - 2; i++)
663+
append_path(fp, "%s/user", config_path[i]);
664+
append_path(fp, "%s", rc_dirs.svcdir);
632665
}
633666

634667
static void
635-
load_dynamic_path(bool user)
668+
append_rc_path(FILE *fp, const char *path, bool user)
636669
{
637-
static const char *config_path[] = {
638-
RC_SYSCONFDIR "/rc",
639-
RC_SYSCONFDIR,
640-
#ifdef RC_LOCAL_PREFIX
641-
RC_LOCAL_PREFIX "/etc/rc",
642-
RC_LOCAL_PREFIX "/etc",
643-
#endif
644-
#ifdef RC_PKG_PREFIX
645-
RC_PKG_PREFIX "/etc/rc",
646-
RC_PKG_PREFIX "/etc",
647-
#endif
648-
RC_LIBEXECDIR,
649-
};
650-
651-
const char *path;
670+
bool has_user = false;
671+
const char *entry;
652672
size_t size;
653-
FILE *fp = xopen_memstream(&rc_path.buffer, &size);
654-
655-
rc_path.count = 0;
656-
if ((path = getenv("RC_PATH"))) {
657-
rc_path.count += append_path_string(fp, path, NULL);
658-
} else {
659-
const char *svcdir = rc_dirs.svcdir ? rc_dirs.svcdir : RC_SVCDIR;
660673

661-
/* first check config paths, then data paths.
662-
* and within those, check dynamic paths first, then hardcoded ones */
663-
rc_path.count += append_path_xdg(fp, rc_dirs.confdir, "XDG_CONFIG_DIRS", "/etc/xdg", user);
664-
rc_path.count += append_path_array(fp, ARRAY_SIZE(config_path), config_path, user);
665-
rc_path.count += append_path(fp, strlen(svcdir), svcdir, NULL);
674+
while ((entry = strnsep(&path, &size, ':'))) {
675+
if (size)
676+
append_path(fp, "%.*s", (int)size, entry);
677+
else if (user && !has_user)
678+
append_user_path(fp), has_user = true;
679+
else if (!user) while (*rc_path.entries)
680+
append_path(fp, "%s", *rc_path.entries++);
666681
}
667-
xclose_memstream(fp);
668-
669-
rc_path.entries = calloc(rc_path.count + 1, sizeof(*rc_path.entries));
682+
}
670683

671-
for (size_t count = 0, i = 0; i < size && count < rc_path.count; i += strlen(&rc_path.buffer[i]) + 1)
672-
rc_path.entries[count++] = &rc_path.buffer[i];
673-
rc_path.entries[rc_path.count] = NULL;
684+
static void
685+
load_dynamic_path(bool user)
686+
{
687+
const char *path, *entry;
688+
size_t size, count = 0;
689+
FILE *fp;
674690

675691
if (!rc_dirs.set) {
676692
atexit(free_rc_dirs);
677693
rc_dirs.set = true;
678694
}
695+
696+
rc_path.entries = config_path;
697+
rc_path.count = ARRAY_SIZE(config_path) - 1;
698+
699+
if (!(path = getenv("RC_PATH")) && !user)
700+
return;
701+
702+
rc_path.count = 0;
703+
fp = xopen_memstream(&rc_path.buffer, &size);
704+
if (path)
705+
append_rc_path(fp, path, user);
706+
else
707+
append_user_path(fp);
708+
xclose_memstream(fp);
709+
710+
rc_path.allocd = rc_path.entries = calloc(rc_path.count + 1, sizeof(*rc_path.entries));
711+
712+
path = rc_path.buffer;
713+
714+
while ((entry = strnullsep(&path, &size)) && count < rc_path.count)
715+
rc_path.entries[count++] = entry;
716+
rc_path.entries[rc_path.count] = NULL;
679717
}
680718

681719
static bool is_user = false;

0 commit comments

Comments
 (0)