Difference between revisions of "Projects/Profile Includes"
(→Implementation Design) |
|||
(8 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | {{project- |
+ | {{project-rel|1.9}} |
==Background== |
==Background== |
||
− | In a [http://mailman.mit.edu/pipermail/krbdev/2010-July/ |
+ | In a [http://mailman.mit.edu/pipermail/krbdev/2010-July/009171.html 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. |
==Interface Design== |
==Interface Design== |
||
− | A profile file may contain a line "include FILENAME". FILENAME is read, and |
+ | 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 and underscores, are read and |
+ | 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. |
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. |
||
Line 17: | Line 17: | ||
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. |
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 contents will be |
+ | 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. |
==Implementation Design== |
==Implementation Design== |
||
Line 29: | Line 29: | ||
parse_line() recognizes lines beginning with "include" or "includedir" and passes the following text to new functions profile_include_file() and profile_include_dir(). |
parse_line() recognizes lines beginning with "include" or "includedir" and passes the following text to new functions profile_include_file() and profile_include_dir(). |
||
− | ==Open Issues== |
||
+ | 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. |
||
+ | |||
+ | ===Testing=== |
||
+ | |||
+ | Tests exercising the include and includedir directives will be added to the existing tcl-based profile tests. |
||
+ | |||
+ | ==Rationale== |
||
− | * glob() may not exist on all systems. Does it exist on Windows? If it does not exist, what fallback position should the code take? Options are: |
||
+ | * 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. |
||
− | ** Fail to compile if glob() does not exist. |
||
− | ** Disable include support if glob() does not exist. |
||
− | ** Allow only includes of explicit filenames if glob() does not exist. |
||
− | ** Provide a glob() implementation if it does not exist. This may be a substantial amount of code. |
||
− | * The syntax "include PATTERN" is simple and clear, but may not be optimal. It could break existing profile files which contain an "initial comment" (any text before the first line beginning with '[') with a line which happens to begin with "include". Also, adding an include directive anywhere other than the beginning of a krb5.conf file would cause earlier versions of krb5 to generate a syntax error. Other syntax options include: |
||
+ | * 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. |
||
− | ** Masquerade as a comment: #include PATTERN |
||
− | ** Masquerade as a section: [include PATTERN] |
||
− | ** Distinctive punctuation: @include PATTERN |
||
− | * Nothing in the design prevents include directives containing relative paths or patterns. Such an include directive would have unpredictable effects since the current working directory would be different for different invocations of the krb5 library. Should the profile library protect the administrator by restricting include directives to absolute paths? If so, how should it portably recognize an absolute path? |
||
+ | * 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. |
||
− | * Should an include directive ever result in a fatal error? Possible error cases include: |
||
+ | * Strict error handling is employed in order to quickly identify cases where included files are readable by root and not other users. |
||
− | ** Including an explicit filename (not a pattern) which does not exist. |
||
− | ** Including a pattern which has no matches. Note that it is impossible to distinguish this case from the previous one without breaking the abstraction barrier of glob(). |
||
− | ** Including a pattern or filename which attempts to descend into directories which the process has no permission to read. |
||
− | ** Including a pattern or filename which matches a file, but the file cannot be opened. |
||
− | Note that because of the profile library architecture, it cannot generate extended errors. |
Latest revision as of 11:37, 27 May 2014
Background
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.
Interface Design
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.
Implementation Design
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.
Testing
Tests exercising the include and includedir directives will be added to the existing tcl-based profile tests.
Rationale
- 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.