SD_JSON_PARSE(3)
π NAME π
okay bestie, gather round, because this is the sd_json_parse(3) page from the sd_json_parse manual and it's literally a whole friend group of functions: sd_json_parse, sd_json_parse_continue, sd_json_parse_with_source, sd_json_parse_with_source_continue, sd_json_parse_file, sd_json_parse_file_at, sd_json_parse_fd, plus the flag besties SD_JSON_PARSE_SENSITIVE, SD_JSON_PARSE_MUST_BE_OBJECT, SD_JSON_PARSE_MUST_BE_ARRAY, SD_JSON_PARSE_SEEK0, SD_JSON_PARSE_DONATE_FD, and SD_JSON_PARSE_REOPEN_FD.
and what do they do?? they parse JSON strings and files into JSON variant objects. that's the whole vibe. slay. π
β¨ SYNOPSIS β¨
#include <systemd/sd-json.h>
int sd_json_parse(const char *string, sd_json_parse_flags_t flags,
sd_json_variant **ret, unsigned *reterr_line,
unsigned *reterr_column);
int sd_json_parse_continue(const char **p, sd_json_parse_flags_t flags,
sd_json_variant **ret, unsigned *reterr_line,
unsigned *reterr_column);
int sd_json_parse_with_source(const char *string, const char *source,
sd_json_parse_flags_t flags,
sd_json_variant **ret,
unsigned *reterr_line,
unsigned *reterr_column);
int sd_json_parse_with_source_continue(const char **p,
const char *source,
sd_json_parse_flags_t flags,
sd_json_variant **ret,
unsigned *reterr_line,
unsigned *reterr_column);
int sd_json_parse_file(FILE *f, const char *path,
sd_json_parse_flags_t flags,
sd_json_variant **ret, unsigned *reterr_line,
unsigned *reterr_column);
int sd_json_parse_file_at(FILE *f, int dir_fd, const char *path,
sd_json_parse_flags_t flags,
sd_json_variant **ret, unsigned *reterr_line,
unsigned *reterr_column);
int sd_json_parse_fd(const char *path, int fd,
sd_json_parse_flags_t flags, sd_json_variant **ret,
unsigned *reterr_line, unsigned *reterr_column);
πΈ DESCRIPTION πΈ
okay so sd_json_parse() takes the JSON string sitting in string and hands you back the resulting JSON variant object in ret. the tea here is that the input has to contain exactly one JSON value β object, array, string, number, boolean, or null, pick your fighter. and if there's any trailing non-whitespace content after that first parsed value? nope, that's an error. periodt. π
if parsing fails, reterr_line and reterr_column get set to the line and column (both one-based, yes bestie we count from one) where the parse error happened. you can pass one or both as NULL if you literally don't care about error location info, no judgement. on success the return value is non-negative and ret points at a freshly allocated JSON variant object β which you must free with sd_json_variant_unref(3) when you're done with it, don't just leave it there π. and hey, ret can also be NULL, in which case the input gets validated but no object comes back.
sd_json_parse_continue() is giving the same energy, but it's built for parsing a sequence of concatenated JSON values out of one single input string. instead of taking a const char * directly, it takes a pointer to a const char * pointer. after every successful parse the pointer gets advanced past the consumed input, so the next call parses the next JSON value. iconic for newline-delimited JSON (NDJSON) streams or similar concatenated JSON formats. and unlike sd_json_parse(), trailing content after the first JSON value is not an error here β it's expected to be the beginning of the next value. it's giving "to be continued". π¦
sd_json_parse_with_source() and sd_json_parse_with_source_continue() are the same as sd_json_parse() and sd_json_parse_continue() respectively, except they take an extra source argument. source is a human-readable string (typically a file name or some other origin identifier) that gets attached to the parsed JSON variant object and can be retrieved later via sd_json_variant_get_source(3). if source is NULL, no source info gets attached. and plot twist: sd_json_parse() and sd_json_parse_continue() are literally equivalent to calling their _with_source counterparts with source set to NULL. the lore. π
sd_json_parse_file() reads and parses a JSON value from a file. if f is non-NULL, the JSON text is read from that FILE stream. if f is NULL, the file indicated by path gets opened and read instead. and path is doing double duty here, bestie β it's used for opening the file (when f is NULL) and recorded as source information in the resulting JSON variant (see above). multitasking queen. π
sd_json_parse_file_at() is like sd_json_parse_file() but takes an extra dir_fd argument, which is a file descriptor referring to the directory that relative paths in path get resolved against. if it's set to AT_FDCWD, relative paths resolve against the current working directory β which is also the default behaviour of sd_json_parse_file().
sd_json_parse_fd() reads and parses a JSON value from the file referenced by the file descriptor fd. by default the descriptor is internally duplicated and the caller's descriptor is left untouched β though heads up, the current file offset will be shared with the original file descriptor. the JSON text is read starting at the descriptor's current file offset. you can switch this up with the SD_JSON_PARSE_SEEK0, SD_JSON_PARSE_DONATE_FD and SD_JSON_PARSE_REOPEN_FD flags (see below π). the path argument is not used to open anything in this case β it's only recorded as source info in the resulting JSON variant (see above) and may be passed as NULL.
π the flags argument π
flags is a bitmask of zero or more of the following, bestie:
SD_JSON_PARSE_SENSITIVEβ marks the resulting JSON variant as "sensitive", meaning it holds secret key material or similar confidential data. sensitive variants get erased from memory when freed and are excluded from certain debug logging and introspection operations. seesd_json_variant_sensitive(3)for the details. πSD_JSON_PARSE_MUST_BE_OBJECTβ requires the top-level JSON value to be a JSON object (i.e.{...}). if the top-level value is an array, string, number, boolean, ornull, parsing fails with-EINVAL. strict much? no but fr.
Added in version 261.
SD_JSON_PARSE_MUST_BE_ARRAYβ requires the top-level JSON value to be a JSON array (i.e.[...]). if the top-level value is an object, string, number, boolean, ornull, parsing fails with-EINVAL.
Added in version 261.
SD_JSON_PARSE_SEEK0β before reading, seeks the input to its beginning (i.e. file offset0). this flag does nothing when parsing from a string. and when used together withSD_JSON_PARSE_REOPEN_FDinsd_json_parse_fd()it's redundant, because a freshly reopened file descriptor already starts at offset0anyway. so like, extra. π
Added in version 261.
SD_JSON_PARSE_DONATE_FDβ only does anything onsd_json_parse_fd(). if set, ownership of the file descriptor passed infdis transferred into the call: the descriptor is consumed and closed before the function returns, including in the error path. if not set (that's the default), the caller keeps ownership offdand the function works on an internally duplicated descriptor instead. this flag may not be combined withSD_JSON_PARSE_REOPEN_FD. it's giving "here bestie, it's yours now". π«Ά
Added in version 261.
SD_JSON_PARSE_REOPEN_FDβ only does anything onsd_json_parse_fd(). if set, the file descriptor passed infdis reopened (read-only) before reading, instead of being duplicated. mainly useful for getting an independent file offset (positioned at the beginning of the file) and a clean, read-only access mode, even if the original descriptor was opened differently (for example withO_PATH). the caller keeps ownership of the original descriptor, which is left untouched. this flag may not be combined withSD_JSON_PARSE_DONATE_FD. β¨
Added in version 261.
and if you set bothSD_JSON_PARSE_MUST_BE_OBJECTandSD_JSON_PARSE_MUST_BE_ARRAY? then both objects and arrays are accepted β but non-container values (strings, numbers, booleans,null) are still refused. bestie said "containers only, I don't make the rules". π
π RETURN VALUE π
on success, these functions return 0. on failure, they return a negative errno-style error code. simple as that.
π Errors
the errors you might catch may indicate the following problems:
-EINVALβ the input is not valid JSON, the input contains trailing content after the parsed value (only for the non-_continuevariants), or a top-level type constraint specified viaSD_JSON_PARSE_MUST_BE_OBJECTorSD_JSON_PARSE_MUST_BE_ARRAYwas violated.-ENODATAβ the input string is empty orNULL.-ENOMEMβ memory allocation failed. π
π§ NOTES π§
the functions described here are available as a shared library, which you can compile against and link to with the libsystemd pkg-config(1) file. π
β οΈ important bestie: the code described here usesgetenv(3), which is declared to be not multi-thread-safe. that means code calling these functions must not callsetenv(3)from a parallel thread. the recommendation is to only callsetenv()from an early phase of the program, when no other threads have been started yet. no cap, do it early. π«Ά
β HISTORY β
sd_json_parse(), sd_json_parse_continue(), sd_json_parse_with_source(), sd_json_parse_with_source_continue(), sd_json_parse_file(), and sd_json_parse_file_at() were added in version 257.
sd_json_parse_fd() and the SD_JSON_PARSE_MUST_BE_OBJECT, SD_JSON_PARSE_MUST_BE_ARRAY, SD_JSON_PARSE_SEEK0, SD_JSON_PARSE_DONATE_FD and SD_JSON_PARSE_REOPEN_FD flags were added in version 261.
π₯ SEE ALSO π₯
systemd(1), sd-json(3), sd_json_variant_unref(3), sd_json_variant_get_source(3), sd_json_dispatch(3)
and that's the whole page, bestie π go forth and parse responsibly. this lil manual moment was brought to you by systemd 262.1 β mwah, ily, see u in the next man page πβ¨π¦
π¦ where this page comes from
- arch rolling: systemd-libs 262.1-1 Β· LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later WITH Linux-syscall-note
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms