In a July 2010 mailing list discussion about dynamic module discovery, consensus was reached that the profile library should gain support for include-file functionality with the ability to include a variable set of files within a directory. This project is to add that support.
A profile file may contain a line "include FILENAME". FILENAME is read, and relations from the file are added to the original profile. If FILENAME does not exist or cannot be read, profile parsing fails.
A profile file may include a line "includedir DIRNAME". If DIRNAME does not exist or is unreadable, profile parsing fails. Files within DIRNAME, whose names consist only of alphanumeric characters, dashes, and underscores, are read and their relations added to the original profile. The naming restrictions are to avoid parsing editor backup files, .rpmsave files, and the like. If any appropriately named file is unreadable, profile parsing fails.
Include directives may be used within included profile files as well as the original file.
An included file may add variable assignments to an existing section simply by switching to that section and making variable assignments within it. This functionality already exists within the profile library.
Currently there is no way to remove or replace an existing value from within an included file. This project does not propose to add that functionality.
Currently, the profile library recognizes when a profile file changes by stat()ing the file on each profile_get_value() call (though no more than once per second). If the file has changed, it is reread. The profile library will not automatically recognize when included files have changed.
The profile library has support for writing a profile file to disk using profile_flush() or a similar function. If such a function is used, the profile file's contents will be flattened into one file with no include directives. This is consistent with other limitations of profile_flush() such as not remembering comments.
All necessary changes can be made within util/profile/prof_parse.c.
The main body of profile_parse_file() needs to be split out to allow parsing a file's contents into an already existing state structure. The new helper function has the signature:
static errcode_t parse_file(FILE *f, struct parse_state *state);
parse_line() recognizes lines beginning with "include" or "includedir" and passes the following text to new functions profile_include_file() and profile_include_dir().
profile_include_file() creates a fresh parsing state sharing the root section with the parent state, and then opens and parses the file.
profile_include_dir() iterates over the directory and includes each validly named file within it.
Tests exercising the include and includedir directives will be added to the existing tcl-based profile tests.
- The original version of this proposal included glob pattern support. This was discarded in favor of "includedir" in order to simplify error cases and sidestep any portability issues of relying on the POSIX.2 glob() function.
- Several syntax options for the include directive were considered, such as "#include FILENAME" (masquerading as a comment to old versions of the library), [include FILENAME] (masquerading as a section name), "@include FILENAME" (not masquerading as anything, but reducing the likelihood of conflicting with an initial comment of an existing profile), and "[libdefaults] include = FILENAME". Rough consensus was that the simple "include FILENAME" was best.
- Several options were considered for handling the case of a profile including a relative pathname, since it is not generally useful in production to include a profile path relative to the process's current working directory. Rough consensus was that it was best to ignore the problem; including relative paths can be useful for testing.
- Strict error handling is employed in order to quickly identify cases where included files are readable by root and not other users.