diff options
Diffstat (limited to 'libq/profile.c')
-rw-r--r-- | libq/profile.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/libq/profile.c b/libq/profile.c new file mode 100644 index 00000000..79e9577d --- /dev/null +++ b/libq/profile.c @@ -0,0 +1,77 @@ +typedef void *(q_profile_callback_t)(void *, char *, FILE *); + +_q_static void * +q_profile_walk_at(int dir_fd, const char *dir, const char *file, + q_profile_callback_t callback, void *data) +{ + FILE *fp; + int subdir_fd, fd; + size_t buflen; + char *buf; + + /* Pop open this profile dir */ + subdir_fd = openat(dir_fd, dir, O_RDONLY|O_CLOEXEC); + if (subdir_fd < 0) + return data; + + /* Then open the file */ + fd = openat(subdir_fd, file, O_RDONLY|O_CLOEXEC); + if (fd < 0) + goto walk_parent; + + fp = fdopen(fd, "r"); + if (!fp) { + close(fd); + goto walk_parent; + } + + /* hand feed the file to the callback */ + buf = NULL; + while (getline(&buf, &buflen, fp) != -1) + data = callback(data, buf, fp); + free(buf); + + /* does close(fd) for us */ + fclose(fp); + + /* Now walk the parents */ + walk_parent: + fd = openat(subdir_fd, "parent", O_RDONLY|O_CLOEXEC); + if (fd < 0) + goto done; + fp = fdopen(fd, "r"); + if (!fp) { + close(fd); + goto done; + } + + buf = NULL; + while (getline(&buf, &buflen, fp) != -1) { + char *s; + + s = strchr(buf, '#'); + if (s) + *s = '\0'; + rmspace(buf); + + data = q_profile_walk_at(subdir_fd, buf, file, callback, data); + } + free(buf); + + /* does close(fd) for us */ + fclose(fp); + + done: + if (subdir_fd != AT_FDCWD) + close(subdir_fd); + + return data; +} + +_q_static void * +q_profile_walk(const char *file, q_profile_callback_t callback, void *data) +{ + /* Walk the profiles and read the file in question */ + data = q_profile_walk_at(AT_FDCWD, EPREFIX "/etc/make.profile", file, callback, data); + return q_profile_walk_at(AT_FDCWD, EPREFIX "/etc/portage/make.profile", file, callback, data); +} |