static void load(struct userdata *u) {
    FILE *f;

    /* We never overwrite manually configured settings */

    if (u->core->configured_default_sink)
        pa_log_info("Manually configured default sink, not overwriting.");
    else if ((f = pa_fopen_cloexec(u->sink_filename, "r"))) {
        char ln[256] = "";

        if (fgets(ln, sizeof(ln)-1, f))
            pa_strip_nl(ln);
        fclose(f);

        if (!ln[0])
            pa_log_info("No previous default sink setting, ignoring.");
        else if (!pa_namereg_is_valid_name(ln))
            pa_log_warn("Invalid sink name: %s", ln);
        else {
            pa_log_info("Restoring default sink '%s'.", ln);
            pa_core_set_configured_default_sink(u->core, ln);
        }

    } else if (errno != ENOENT)
        pa_log("Failed to load default sink: %s", pa_cstrerror(errno));

    if (u->core->configured_default_source)
        pa_log_info("Manually configured default source, not overwriting.");
    else if ((f = pa_fopen_cloexec(u->source_filename, "r"))) {
        char ln[256] = "";

        if (fgets(ln, sizeof(ln)-1, f))
            pa_strip_nl(ln);
        fclose(f);

        if (!ln[0])
            pa_log_info("No previous default source setting, ignoring.");
        else if (!pa_namereg_is_valid_name(ln))
            pa_log_warn("Invalid source name: %s", ln);
        else {
            pa_log_info("Restoring default source '%s'.", ln);
            pa_core_set_configured_default_source(u->core, ln);
        }

    } else if (errno != ENOENT)
        pa_log("Failed to load default source: %s", pa_cstrerror(errno));
}
static void load(struct userdata *u) {
    FILE *f;

    /* We never overwrite manually configured settings */

    if (u->core->default_sink)
        pa_log_info("Manually configured default sink, not overwriting.");
    else if ((f = pa_fopen_cloexec(u->sink_filename, "r"))) {
        char ln[256] = "";
        pa_sink *s;

        if (fgets(ln, sizeof(ln)-1, f))
            pa_strip_nl(ln);
        fclose(f);

        if (!ln[0])
            pa_log_info("No previous default sink setting, ignoring.");
        else if ((s = pa_namereg_get(u->core, ln, PA_NAMEREG_SINK))) {
            pa_namereg_set_default_sink(u->core, s);
            pa_log_info("Restored default sink '%s'.", ln);
        } else
            pa_log_info("Saved default sink '%s' not existent, not restoring default sink setting.", ln);

    } else if (errno != ENOENT)
        pa_log("Failed to load default sink: %s", pa_cstrerror(errno));

    if (u->core->default_source)
        pa_log_info("Manually configured default source, not overwriting.");
    else if ((f = pa_fopen_cloexec(u->source_filename, "r"))) {
        char ln[256] = "";
        pa_source *s;

        if (fgets(ln, sizeof(ln)-1, f))
            pa_strip_nl(ln);
        fclose(f);

        if (!ln[0])
            pa_log_info("No previous default source setting, ignoring.");
        else if ((s = pa_namereg_get(u->core, ln, PA_NAMEREG_SOURCE))) {
            pa_namereg_set_default_source(u->core, s);
            pa_log_info("Restored default source '%s'.", ln);
        } else
            pa_log_info("Saved default source '%s' not existent, not restoring default source setting.", ln);

    } else if (errno != ENOENT)
            pa_log("Failed to load default sink: %s", pa_cstrerror(errno));
}
static int load_rules(struct userdata *u) {
    FILE *f;
    int n = 0;
    int ret = -1;
    char buf_name[256], buf_volume[256], buf_sink[256], buf_source[256];
    char *ln = buf_name;

    f = u->table_file ?
        fopen(u->table_file, "r") :
        pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "r");

    if (!f) {
        if (errno == ENOENT) {
            pa_log_info("starting with empty ruleset.");
            ret = 0;
        } else
            pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno));

        goto finish;
    }

    pa_lock_fd(fileno(f), 1);

    while (!feof(f)) {
        struct rule *rule;
        pa_cvolume v;
        pa_bool_t v_is_set;

        if (!fgets(ln, sizeof(buf_name), f))
            break;

        n++;

        pa_strip_nl(ln);

        if (ln[0] == '#')
            continue;

        if (ln == buf_name) {
            ln = buf_volume;
            continue;
        }

        if (ln == buf_volume) {
            ln = buf_sink;
            continue;
        }

        if (ln == buf_sink) {
            ln = buf_source;
            continue;
        }

        pa_assert(ln == buf_source);

        if (buf_volume[0]) {
            if (!parse_volume(buf_volume, &v)) {
                pa_log("parse failure in %s:%u, stopping parsing", u->table_file, n);
                goto finish;
            }

            v_is_set = TRUE;
        } else
            v_is_set = FALSE;

        ln = buf_name;

        if (pa_hashmap_get(u->hashmap, buf_name)) {
            pa_log("double entry in %s:%u, ignoring", u->table_file, n);
            continue;
        }

        rule = pa_xnew(struct rule, 1);
        rule->name = pa_xstrdup(buf_name);
        if ((rule->volume_is_set = v_is_set))
            rule->volume = v;
        rule->sink = buf_sink[0] ? pa_xstrdup(buf_sink) : NULL;
        rule->source = buf_source[0] ? pa_xstrdup(buf_source) : NULL;

        pa_hashmap_put(u->hashmap, rule->name, rule);
    }

    if (ln != buf_name) {
        pa_log("invalid number of lines in %s.", u->table_file);
        goto finish;
    }

    ret = 0;

finish:
    if (f) {
        pa_lock_fd(fileno(f), 0);
        fclose(f);
    }

    return ret;
}