aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'libq/profile.c')
-rw-r--r--libq/profile.c77
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);
+}