Add support to the profile library for /etc/foo/conf.d style directories
If a directory is passed to profile_init, then read all files which
match [0-9a-zA-Z]* in sort order.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 6e6c01c..24e03de 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,10 @@
+2006-01-05 Theodore Ts'o <tytso@mit.edu>
+
+ * profile.c (profile_init): If a directory is passed to
+ profile_init, then read all files which match [0-9a-zA-Z]*
+ in sort order. This allows handling of /etc/foo/conf.d
+ style directories.
+
2006-01-04 Theodore Ts'o <tytso@mit.edu>
* profile.c: Eliminate the prf_data_t data structure and fold it
diff --git a/e2fsck/profile.c b/e2fsck/profile.c
index e0c4e97..57623e5 100644
--- a/e2fsck/profile.c
+++ b/e2fsck/profile.c
@@ -63,6 +63,7 @@
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <dirent.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
@@ -204,50 +205,140 @@
* object.
*/
+static int compstr(const void *m1, const void *m2)
+{
+ const char *s1 = *((const char **) m1);
+ const char *s2 = *((const char **) m2);
+
+ return strcmp(s1, s2);
+}
+
+static void free_list(char **list)
+{
+ char **cp;
+
+ if (list == 0)
+ return;
+
+ for (cp = list; *cp; cp++)
+ free(*cp);
+ free(list);
+}
+
+static errcode_t get_dirlist(const char *dirname, char***ret_array)
+{
+ DIR *dir;
+ struct dirent *de;
+ struct stat st;
+ errcode_t retval;
+ char *fn, *cp;
+ char **array = 0, **new_array;
+ int max = 0, num = 0;
+
+ dir = opendir(dirname);
+ if (!dir)
+ return errno;
+
+ while ((de = readdir(dir)) != NULL) {
+ for (cp = de->d_name; *cp; cp++) {
+ if (!isalnum(*cp) &&
+ (*cp != '-') &&
+ (*cp != '_'))
+ break;
+ }
+ if (*cp)
+ continue;
+ fn = malloc(strlen(dirname) + strlen(de->d_name) + 2);
+ if (!fn) {
+ retval = ENOMEM;
+ goto errout;
+ }
+ sprintf(fn, "%s/%s", dirname, de->d_name);
+ if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) {
+ free(fn);
+ continue;
+ }
+ if (num >= max) {
+ max += 10;
+ new_array = realloc(array, sizeof(char *) * (max+1));
+ if (!new_array) {
+ retval = ENOMEM;
+ goto errout;
+ }
+ array = new_array;
+ }
+ array[num++] = fn;
+ }
+ qsort(array, num, sizeof(char *), compstr);
+ array[num++] = 0;
+ *ret_array = array;
+ closedir(dir);
+ return 0;
+errout:
+ closedir(dir);
+ free_list(array);
+ return retval;
+}
+
errcode_t
profile_init(const char **files, profile_t *ret_profile)
{
const char **fs;
profile_t profile;
- prf_file_t new_file, last = 0;
+ prf_file_t new_file, *last;
errcode_t retval = 0;
+ char **cpp, *cp, **array = 0;
profile = malloc(sizeof(struct _profile_t));
if (!profile)
return ENOMEM;
memset(profile, 0, sizeof(struct _profile_t));
profile->magic = PROF_MAGIC_PROFILE;
+ last = &profile->first_file;
/* if the filenames list is not specified return an empty profile */
if ( files ) {
for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) {
+ retval = get_dirlist(*fs, &array);
+ if (retval == 0) {
+ for (cpp = array; (cp = *cpp); cpp++) {
+ retval = profile_open_file(cp, &new_file);
+ if (retval == EACCES)
+ continue;
+ if (retval)
+ goto errout;
+ *last = new_file;
+ last = &new_file->next;
+ }
+ } else if (retval != ENOTDIR)
+ goto errout;
+
retval = profile_open_file(*fs, &new_file);
/* if this file is missing, skip to the next */
if (retval == ENOENT || retval == EACCES) {
continue;
}
- if (retval) {
- profile_release(profile);
- return retval;
- }
- if (last)
- last->next = new_file;
- else
- profile->first_file = new_file;
- last = new_file;
+ if (retval)
+ goto errout;
+ *last = new_file;
+ last = &new_file->next;
}
/*
- * If last is still null after the loop, then all the files were
- * missing, so return the appropriate error.
+ * If all the files were not found, return the appropriate error.
*/
- if (!last) {
+ if (!profile->first_file) {
profile_release(profile);
return ENOENT;
}
}
+ free_list(array);
*ret_profile = profile;
return 0;
+errout:
+ free_list(array);
+ profile_release(profile);
+ return retval;
}
void