SD_JSON_PARSE(3)

πŸ“¦
version 262.1 Β· 3 versions
, in arch rolling

πŸ’– 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. see sd_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, or null, 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, or null, parsing fails with -EINVAL.

Added in version 261.

  • SD_JSON_PARSE_SEEK0 β€” before reading, seeks the input to its beginning (i.e. file offset 0). this flag does nothing when parsing from a string. and when used together with SD_JSON_PARSE_REOPEN_FD in sd_json_parse_fd() it's redundant, because a freshly reopened file descriptor already starts at offset 0 anyway. so like, extra. πŸ™ˆ

Added in version 261.

  • SD_JSON_PARSE_DONATE_FD β€” only does anything on sd_json_parse_fd(). if set, ownership of the file descriptor passed in fd is 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 of fd and the function works on an internally duplicated descriptor instead. this flag may not be combined with SD_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 on sd_json_parse_fd(). if set, the file descriptor passed in fd is 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 with O_PATH). the caller keeps ownership of the original descriptor, which is left untouched. this flag may not be combined with SD_JSON_PARSE_DONATE_FD. ✨

Added in version 261.

and if you set both SD_JSON_PARSE_MUST_BE_OBJECT and SD_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-_continue variants), or a top-level type constraint specified via SD_JSON_PARSE_MUST_BE_OBJECT or SD_JSON_PARSE_MUST_BE_ARRAY was violated.
  • -ENODATA β€” the input string is empty or NULL.
  • -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 uses getenv(3), which is declared to be not multi-thread-safe. that means code calling these functions must not call setenv(3) from a parallel thread. the recommendation is to only call setenv() 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