diff options
Diffstat (limited to 'cmd/libsnap-confine-private')
| -rw-r--r-- | cmd/libsnap-confine-private/infofile-test.c | 86 | ||||
| -rw-r--r-- | cmd/libsnap-confine-private/infofile.c | 182 |
2 files changed, 15 insertions, 253 deletions
diff --git a/cmd/libsnap-confine-private/infofile-test.c b/cmd/libsnap-confine-private/infofile-test.c index 39daf346e2..c499ed940b 100644 --- a/cmd/libsnap-confine-private/infofile-test.c +++ b/cmd/libsnap-confine-private/infofile-test.c @@ -145,88 +145,4 @@ static void test_infofile_get_key(void) { fclose(stream); } -static void test_infofile_get_key_scanner(void) { - sc_error *err; - int rc; - - /* scanner_state cannot be NULL. */ - rc = sc_infofile_get_key_scanner(NULL, &err); - g_assert_cmpint(rc, ==, -1); - g_assert_nonnull(err); - g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_ERROR); - g_assert_cmpint(sc_error_code(err), ==, SC_BUG); - g_assert_cmpstr(sc_error_msg(err), ==, "scanner_state cannot be NULL"); - sc_error_free(err); - - sc_infofile_scanner_state scanner_state = {0}; - - /* scanner_state->key cannot be NULL. */ - rc = sc_infofile_get_key_scanner(&scanner_state, &err); - g_assert_cmpint(rc, ==, -1); - g_assert_nonnull(err); - g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_ERROR); - g_assert_cmpint(sc_error_code(err), ==, SC_BUG); - g_assert_cmpstr(sc_error_msg(err), ==, "scanner_state->key cannot be NULL"); - sc_error_free(err); - - scanner_state.key = "key"; - - /* scanner_state->value cannot be NULL. */ - rc = sc_infofile_get_key_scanner(&scanner_state, &err); - g_assert_cmpint(rc, ==, -1); - g_assert_nonnull(err); - g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_ERROR); - g_assert_cmpint(sc_error_code(err), ==, SC_BUG); - g_assert_cmpstr(sc_error_msg(err), ==, "scanner_state->value cannot be NULL"); - sc_error_free(err); - - scanner_state.value = "value"; - - /* scanner_state->caller_state cannot be NULL. */ - rc = sc_infofile_get_key_scanner(&scanner_state, &err); - g_assert_cmpint(rc, ==, -1); - g_assert_nonnull(err); - g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_ERROR); - g_assert_cmpint(sc_error_code(err), ==, SC_BUG); - g_assert_cmpstr(sc_error_msg(err), ==, "scanner_state->caller_state cannot be NULL"); - sc_error_free(err); - - sc_infofile_get_key_state caller_state = {NULL}; - scanner_state.caller_state = &caller_state; - - /* caller_state->wanted_key cannot be NULL. */ - rc = sc_infofile_get_key_scanner(&scanner_state, &err); - g_assert_cmpint(rc, ==, -1); - g_assert_nonnull(err); - g_assert_cmpstr(sc_error_domain(err), ==, SC_LIBSNAP_ERROR); - g_assert_cmpint(sc_error_code(err), ==, SC_BUG); - g_assert_cmpstr(sc_error_msg(err), ==, "caller_state->wanted_key cannot be NULL"); - sc_error_free(err); - - caller_state.wanted_key = "other-key"; - caller_state.stored_value = (void *)0xfefefefe; - - /* if wanted_key doesn't match key then the value is not stored and scanner continues. */ - rc = sc_infofile_get_key_scanner(&scanner_state, &err); - g_assert_cmpint(rc, ==, 0); - g_assert_null(err); - g_assert_false(scanner_state.stop); - g_assert_cmpuint((intptr_t)caller_state.stored_value, ==, (intptr_t)0xfefefefe); - - caller_state.wanted_key = "key"; - - /* if wanted_key matches key the value is copied and the scanner stops. */ - rc = sc_infofile_get_key_scanner(&scanner_state, &err); - g_assert_cmpint(rc, ==, 0); - g_assert_null(err); - g_assert_true(scanner_state.stop); - g_assert_nonnull(caller_state.stored_value); - g_assert_cmpstr(caller_state.stored_value, ==, "value"); - g_assert_cmpuint((intptr_t)caller_state.stored_value, !=, (intptr_t) "value"); - free(caller_state.stored_value); -} - -static void __attribute__((constructor)) init(void) { - g_test_add_func("/infofile/get_key", test_infofile_get_key); - g_test_add_func("/infofile/get_key_scanner", test_infofile_get_key_scanner); -} +static void __attribute__((constructor)) init(void) { g_test_add_func("/infofile/get_key", test_infofile_get_key); } diff --git a/cmd/libsnap-confine-private/infofile.c b/cmd/libsnap-confine-private/infofile.c index 7d635c5fa8..0fe78e054b 100644 --- a/cmd/libsnap-confine-private/infofile.c +++ b/cmd/libsnap-confine-private/infofile.c @@ -27,132 +27,15 @@ #include "../libsnap-confine-private/string-utils.h" #include "../libsnap-confine-private/utils.h" -/** - * sc_infofile_scanner_state represents the state of the scanner. - * - * The fields, lineno, key and value are read-only and are meant to be consumed - * by the scanner callback function. The fields caller_state and stop can be - * modified by the scanner callback function to alter the caller state and to - * stop further scanning, respectively. - **/ -typedef struct sc_infofile_scanner_state { - /* in variables */ - int lineno; - const char *key; - const char *value; - /* out variables */ - void *caller_state; - bool stop; -} sc_infofile_scanner_state; - -/** - * sc_infofile_scanner_fn is a callback type that assists sc_infofile_scan. - * - * The state is the same value that was provided to sc_infofile_scan and can - * be used by the caller to pass a structure or anything else that makes sense - * to retrieve useful information later. - * - * Both the key and the value strings are pointing into a temporary buffer and - * are NUL terminated. The callback function must either use them in-place - * (e.g. mark their presence) or perform a copy in case the values need to - * outlive the call to sc_infofile_scan. - * - * The function prototype includes err_out and int return code, which behave - * exactly the same as in sc_infofile_scan, that is, return value is zero on - * success, -1 on failure. In both cases err_out is set to either NULL or an - * error object. If an error object cannot be stored the program dies. In - * practice sc_infofile_scan always provides an error receiver so that the - * error can be forwarded to the caller. - **/ -typedef int (*sc_infofile_scanner_fn)(sc_infofile_scanner_state *scanner_state, sc_error **err_out); - -/** - * sc_infofile_scanner_conf represents the configuration of the scanner. - * - * The configuration is comprised of the FILE stream to scan, the scanner function - * as well as the caller state that is provided by the caller and conveyed into the - * scanner function. - **/ -typedef struct sc_infofile_scanner_conf { - FILE *stream; - sc_infofile_scanner_fn scanner_fn; - void *caller_state; -} sc_infofile_scanner_conf; - -/** - * sc_infofile_scan performs linear scan of a given stream, extracting - * key=value pairs and passing them along to the scanner function. - * - * The stream is scanned exactly once, using internally managed buffer. The - * buffer is reused as key/value storage for the purpose of the scanner - * function. The values provided to the scanner function must be copied if they - * need to outlive the lifetime of the call into the scanner. - * - * Each line must be of the format key=value where key and value are arbitrary - * strings, excluding the NUL byte which would be confusing in traditional C - * strings. - * - * On success the return value is zero and err_out, if not NULL, is deferences - * and set to NULL. On failure the return value is -1 is and detailed error - * information is stored by dereferencing err_out. If an error occurs and - * err_out is NULL then the program dies, printing the error message. - **/ -static int sc_infofile_scan(sc_infofile_scanner_conf *scanner_conf, sc_error **err_out); - -/** - * sc_infofile_get_key_state represents caller state for sc_infofile_get_key. - * - * The state gets passed to sc_infofile_scan and is used to convey the key - * that is being looked for as well as the value that was found. - **/ -typedef struct sc_infofile_get_key_state { - const char *wanted_key; - char *stored_value; -} sc_infofile_get_key_state; - -/** - * sc_infofile_get_key_scanner is the scanner callback for sc_infofile_get_key. - * - * The callback unpacks the scanner state and if a key is found, stores the value - * into the caller state and stops the scanning process. - **/ -static int sc_infofile_get_key_scanner(sc_infofile_scanner_state *scanner_state, sc_error **err_out) { - sc_error *err = NULL; - if (scanner_state == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_BUG, "scanner_state cannot be NULL"); - goto out; - } - if (scanner_state->key == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_BUG, "scanner_state->key cannot be NULL"); - goto out; - } - if (scanner_state->value == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_BUG, "scanner_state->value cannot be NULL"); - goto out; - } - sc_infofile_get_key_state *caller_state = scanner_state->caller_state; - if (caller_state == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_BUG, "scanner_state->caller_state cannot be NULL"); - goto out; - } - if (caller_state->wanted_key == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_BUG, "caller_state->wanted_key cannot be NULL"); - goto out; - } - - if (sc_streq(caller_state->wanted_key, scanner_state->key)) { - caller_state->stored_value = sc_strdup(scanner_state->value); - scanner_state->stop = true; - } - -out: - return sc_error_forward(err_out, err); -} - int sc_infofile_get_key(FILE *stream, const char *key, char **value, sc_error **err_out) { sc_error *err = NULL; + size_t line_size = 0; + char *line_buf SC_CLEANUP(sc_cleanup_string) = NULL; - /* NOTE: stream is checked by sc_infofile_scan */ + if (stream == NULL) { + err = sc_error_init(SC_LIBSNAP_ERROR, SC_API_MISUSE, "stream cannot be NULL"); + goto out; + } if (key == NULL) { err = sc_error_init(SC_LIBSNAP_ERROR, SC_API_MISUSE, "key cannot be NULL"); goto out; @@ -162,44 +45,14 @@ int sc_infofile_get_key(FILE *stream, const char *key, char **value, sc_error ** goto out; } - sc_infofile_get_key_state get_key_state = {.wanted_key = key}; - sc_infofile_scanner_conf scanner_conf = { - .stream = stream, - .scanner_fn = sc_infofile_get_key_scanner, - .caller_state = &get_key_state, - }; + /* Store NULL in case we don't find the key. + * This makes the value always well-defined. */ *value = NULL; - if (sc_infofile_scan(&scanner_conf, &err) < 0) { - goto out; - } - *value = get_key_state.stored_value; - -out: - return sc_error_forward(err_out, err); -} - -static int sc_infofile_scan(sc_infofile_scanner_conf *scanner_conf, sc_error **err_out) { - sc_error *err = NULL; - size_t line_size = 0; - char *line_buf SC_CLEANUP(sc_cleanup_string) = NULL; - - if (scanner_conf == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_API_MISUSE, "scanner_conf cannot be NULL"); - goto out; - } - if (scanner_conf->stream == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_API_MISUSE, "stream cannot be NULL"); - goto out; - } - if (scanner_conf->scanner_fn == NULL) { - err = sc_error_init(SC_LIBSNAP_ERROR, SC_API_MISUSE, "scanner_fn cannot be NULL"); - goto out; - } /* This loop advances through subsequent lines. */ for (int lineno = 1;; ++lineno) { errno = 0; - ssize_t nread = getline(&line_buf, &line_size, scanner_conf->stream); + ssize_t nread = getline(&line_buf, &line_size, stream); if (nread < 0 && errno != 0) { err = sc_error_init_from_errno(errno, "cannot read beyond line %d", lineno); goto out; @@ -233,18 +86,11 @@ static int sc_infofile_scan(sc_infofile_scanner_conf *scanner_conf, sc_error **e /* Replace the first '=' with string terminator byte. */ *eq_ptr = '\0'; - /* Call the scanner callback with the state for this location. */ - sc_infofile_scanner_state scanner_state = { - .key = line_buf, - .value = eq_ptr + 1, - .lineno = lineno, - .caller_state = scanner_conf->caller_state, - }; - if (scanner_conf->scanner_fn(&scanner_state, &err) < 0) { - goto out; - } - /* Stop scanning if the callback asked us to do so. */ - if (scanner_state.stop) { + /* If the key matches the one we are looking for, store it and stop scanning. */ + const char *scanned_key = line_buf; + const char *scanned_value = eq_ptr + 1; + if (sc_streq(scanned_key, key)) { + *value = sc_strdup(scanned_value); break; } } |
