+static int is_conf_command(char *buffer, const char *command)
+{
+ int len = strlen(command);
+ return ((strstr(buffer, command) == buffer) &&
+ isspace(buffer[len]));
+}
+
+/*
+ * This function reads aliases and default module options from a configuration file
+ * (/etc/modprobe.conf syntax). It supports includes (only files, no directories).
+ */
+static void include_conf(struct dep_t **first, struct dep_t **current, char *buffer, int buflen, int fd)
+{
+ int continuation_line = 0;
+
+ // alias parsing is not 100% correct (no correct handling of continuation lines within an alias)!
+
+ while (reads(fd, buffer, buflen)) {
+ int l;
+
+ *strchrnul(buffer, '#') = '\0';
+
+ l = strlen(buffer);
+
+ while (l && isspace(buffer[l-1])) {
+ buffer[l-1] = '\0';
+ l--;
+ }
+
+ if (l == 0) {
+ continuation_line = 0;
+ continue;
+ }
+
+ if (continuation_line)
+ continue;
+
+ if (is_conf_command(buffer, "alias")) {
+ char *alias, *mod;
+
+ if (parse_tag_value(buffer + 6, &alias, &mod)) {
+ /* handle alias as a module dependent on the aliased module */
+ if (!*current) {
+ (*first) = (*current) = xzalloc(sizeof(struct dep_t));
+ } else {
+ (*current)->m_next = xzalloc(sizeof(struct dep_t));
+ (*current) = (*current)->m_next;
+ }
+ (*current)->m_name = xstrdup(alias);
+ (*current)->m_isalias = 1;
+
+ if ((strcmp(mod, "off") == 0) || (strcmp(mod, "null") == 0)) {
+ /*(*current)->m_depcnt = 0; - done by xzalloc */
+ /*(*current)->m_deparr = 0;*/
+ } else {
+ (*current)->m_depcnt = 1;
+ (*current)->m_deparr = xmalloc(sizeof(char *));
+ (*current)->m_deparr[0] = xstrdup(mod);
+ }
+ /*(*current)->m_next = NULL; - done by xzalloc */
+ }
+ } else if (is_conf_command(buffer, "options")) {
+ char *mod, *opt;
+
+ /* split the line in the module/alias name, and options */
+ if (parse_tag_value(buffer + 8, &mod, &opt)) {
+ struct dep_t *dt;
+
+ /* find the corresponding module */
+ for (dt = *first; dt; dt = dt->m_next) {
+ if (strcmp(dt->m_name, mod) == 0)
+ break;
+ }
+ if (dt) {
+ if (ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS) {
+ char* new_opt = NULL;
+ while ((opt = parse_command_string(opt, &new_opt))) {
+ dt->m_options = append_option(dt->m_options, new_opt);
+ }
+ } else {
+ dt->m_options = append_option(dt->m_options, opt);
+ }
+ }
+ }
+ } else if (is_conf_command(buffer, "include")) {
+ int fdi;
+ char *filename;
+
+ filename = skip_whitespace(buffer + 8);
+ fdi = open(filename, O_RDONLY);
+ if (fdi >= 0) {
+ include_conf(first, current, buffer, buflen, fdi);
+ close(fdi);
+ }
+ } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST &&
+ (is_conf_command(buffer, "blacklist"))) {
+ char *mod;
+ struct dep_t *dt;
+
+ mod = skip_whitespace(buffer + 10);
+ for (dt = *first; dt; dt = dt->m_next) {
+ if (strcmp(dt->m_name, mod) == 0)
+ break;
+ }
+ if (dt)
+ dt->m_isblacklisted = 1;
+ }
+ } /* while (reads(...)) */