VARLINKCTL(1)

๐Ÿ‘‘ varlinkctl โ€” varlinkctl(1) ๐Ÿ’…

okay bestie, sit down, hydrate, because this is the varlinkctl(1) manual page and it's lowkey a whole personality. it's the tool for poking at Varlink services: introspecting them, calling them, serving them, the whole menu. no cap, this thing ate. ๐Ÿฆ‹


โœจ NAME โœจ

varlinkctl โ€” Introspect with and invoke Varlink services ๐Ÿ’–


๐ŸŒธ SYNOPSIS ๐ŸŒธ

okay so here's the vibe. every single one of these is a real invocation, character for character, don't come for me:

varlinkctl [OPTIONS...] info ADDRESS

varlinkctl [OPTIONS...] list-interfaces ADDRESS

varlinkctl [OPTIONS...] list-methods ADDRESS [INTERFACE...]

varlinkctl [OPTIONS...] introspect ADDRESS [INTERFACE...]

varlinkctl [OPTIONS...] call ADDRESS METHOD [ARGUMENTS]

varlinkctl [OPTIONS...] --exec call ADDRESS METHOD ARGUMENTS -- CMDLINE

varlinkctl [OPTIONS...] serve METHOD {CMDLINE...}

varlinkctl [OPTIONS...] list-registry

varlinkctl [OPTIONS...] list-sockets

varlinkctl [OPTIONS...] validate-idl [FILE]

notice how serve takes {CMDLINE...} in curly braces and call --exec has a -- in the middle? yeah. that's not a typo, that's the assignment. ๐Ÿ’…


๐Ÿ’œ DESCRIPTION ๐Ÿ’œ

so varlinkctl is your bestie for introspecting and invoking Varlink IPC[1] services, and it follows the UAPI.20 Varlink IPC[2] spec, periodt. โœจ

now, how do you even point at a service? there's a whole little ecosystem of address formats, and here they are, all of them, no skips:

  • a Varlink service reference starting with the "unix:" string, followed by an absolute AF_UNIX socket path, or by "@" and an arbitrary string (that second one is how you reference sockets in the abstract namespace). in this case, a stream socket connection is made to the specified socket. ๐Ÿซถ
  • a Varlink service reference starting with the "exec:" string, followed by an absolute path of a binary to execute. in this case, the specified process is forked off locally, with a connected stream socket passed in. iconic. ๐Ÿ”ฅ
  • a Varlink service reference starting with the "ssh-unix:" string, followed by an SSH host specification, followed by ":", followed by an absolute AF_UNIX socket path. โš ๏ธ heads up though: this requires OpenSSH 9.4 or newer on the server side, and abstract namespace sockets are not supported. (rude, i know.)
  • a Varlink service reference starting with the "ssh-exec:" string, followed by an SSH host specification, followed by ":", followed by a command line. in this case, the command is invoked and the Varlink protocol is spoken on the standard input and output of the invoked command. ๐Ÿ’ซ

and then, because the devs are generous and know we're busy, there are two extra simpler (redundant) service address syntaxes that are also supported:

  • a file system path to an AF_UNIX socket, either absolute (i.e. begins with "/") or relative (in which case it must begin with "./"). ๐ŸŒธ
  • a file system path to an executable, either absolute or relative (as above, must begin with "/" or "./", respectively). ๐ŸŽ€

๐ŸŽ€ COMMANDS ๐ŸŽ€

The following commands are understood โ€” and bestie, we're listing every single one:

  • info ADDRESS โ€” shows brief info about the specified service, including vendor name and list of implemented interfaces. expects a service address in one of the formats described above. ๐Ÿ’–

Added in version 255.

  • list-interfaces ADDRESS โ€” shows a list of interfaces implemented by the specified service. expects a service address in one of the formats described above. โœจ

Added in version 255.

  • list-methods ADDRESS [INTERFACE...] โ€” shows a list of methods implemented by the specified service. expects a service address in one of the formats described above, plus one or more interface names. if no interface name is specified, it lists all methods of all interfaces implemented by the service; otherwise, just the methods in the specified interfaces. ๐Ÿฆ‹

Added in version 257.

  • introspect ADDRESS [INTERFACE...] โ€” shows the interface definitions of the specified interfaces provided by the specified service. expects a service address in one of the formats described above and optionally one or more Varlink interface names. if no interface names are specified, it shows all provided interfaces by the service. ๐Ÿ‘‘

Added in version 255.

  • call ADDRESS METHOD [ARGUMENTS] โ€” calls the specified method of the specified service. expects a service address in the format described above, a fully qualified Varlink method name, and a JSON arguments object. if the arguments object is not specified, it is read from STDIN instead. ๐Ÿซถ and if you want to pass an empty list of parameters, you literally just specify the empty object "{}".

the reply parameters are written as JSON objects to STDOUT. ๐Ÿ’…

Added in version 255.

  • serve METHOD CMDLINE... โ€” runs a Varlink server that accepts protocol upgrade requests for the specified method and connects the upgraded connection to the standard input and output of the specified command. this can act as a server-side counterpart to call --upgrade. ๐Ÿ”ฅ

the listening socket must be passed via socket activation (i.e. the $LISTEN_FDS protocol), which makes this command suitable for use in socket-activated service units. when a client calls the specified method with the upgrade flag, the server sends a reply confirming the upgrade, then forks and executes the given command line with the upgraded connection on its standard input and output. โœจ

this effectively turns any command that speaks a protocol over standard input/output into a Varlink service, discoverable via the service registry and authenticated via socket credentials. and because each connection is handled by a forked child process, the service unit can apply systemd's sandboxing options (such as ProtectSystem=, etc.) and does not operate in the caller's environment. that's main character energy fr fr. ๐ŸŒˆ

Added in version 261.

  • list-registry โ€” shows a list of Varlink services currently registered in the service registry, plus their entrypoint sockets. (currently, this simply enumerates the sockets and symlinked sockets in /run/varlink/registry/, see below.) ๐Ÿ“

Added in version 260.

  • list-sockets โ€” shows a list of listening AF_UNIX stream sockets on the local system that are marked as Varlink entrypoints, along with whether the calling user has write (i.e. connect) access to each of them. a socket is considered a Varlink entrypoint if its inode carries the user.varlink extended attribute set to "entrypoint". ๐Ÿ’ซ

sockets are enumerated via the kernel's sock_diag netlink interface, and hence this is not restricted to sockets in /run/varlink/registry/ (as list-registry is), but covers all file-system bound listening Varlink sockets, regardless of their location. ๐ŸŒธ this requires kernel support for extended attributes on socket inodes, which is available since Linux 7.0. (yes, 7.0. write it down.)

Added in version 262.

  • validate-idl [FILE] โ€” reads a Varlink interface definition file, parses and validates it, then outputs it with syntax highlighting. this checks for syntax and internal consistency of the interface. expects a file name to read the interface definition from. if omitted, it reads the interface definition from STDIN. ๐ŸŽ€

Added in version 255.

  • help โ€” shows command syntax help. the little lifesaver. ๐Ÿ™ˆ

Added in version 255.


โœจ OPTIONS โœจ

okay bestie, here's where the real customization lives ๐Ÿ’… every single one of these is a little dial you can turn:

  • --more โ€” when you use this with call, you're telling it "expect multiple method replies, babe." โœจ With this flag set, the method call goes out with the more flag set, which tells the service to generate multiple replies if it needs to. The command just keeps on running until the service sends a reply message that says it's the last one in the series (or until the configured timeout hits, see below ๐Ÿ‘‡). Only set this for method calls that actually support this mechanism, iykyk.

If this mode is on, output automatically switches to JSON-SEQ mode, so you can tell each individual reply object apart. So considerate of it, honestly. ๐ŸŽ€

This switch has no effect on the method call timeout applied by default. Whether or not you pass --more, the default timeout is 45s. Use --timeout= (below) to change it or turn it off completely. When you're invoking a method call that just keeps returning updates forever, you'll typically want to disable the timeout with --timeout=infinity. But on the flip side โ€” when you're doing a --more call just to enumerate objects (which will probably finish fast anyway), it's typically better to leave the timeout logic on, for robustness reasons. Bestie said "safety first" ๐Ÿซถ

Added in version 255.

  • -E โ€” a shortcut for --more --timeout=infinity. This one is so useful for method calls that implement subscription to a continuous stream of updates. It's giving "set it and forget it" energy ๐Ÿ’œ

Added in version 257.

  • --collect โ€” similar to --more, but instead of JSON-SEQ mode it collects all the responses into a JSON array and prints that. Different vibe, same energy. ๐ŸŒˆ

Added in version 256.

  • --oneway โ€” when used with call: do not expect a method reply. With this flag set, the method call is sent with the oneway flag set, and the command exits immediately after โ€” telling the service "don't bother replying, king." ๐Ÿ‘‘

Added in version 255.

  • --upgrade โ€” when used with call: request a protocol upgrade. The method call is sent with the upgrade flag set. The service is expected to send back a single reply confirming the upgrade. After that reply, the Varlink protocol is no longer in effect on the connection. bye varlink, it was real ๐Ÿ˜ญ

If --exec is not specified, varlinkctl acts as a bidirectional proxy: data read from standard input gets forwarded to the upgraded connection, and data received from the connection gets written to standard output. ๐Ÿฆ‹

If --exec is specified, the upgraded connection socket is placed on both standard input and standard output of the invoked process. This is similar to the regular --exec behavior (without --upgrade), which places the method call reply on standard input. So the invoked process can just read from and write to stdin/stdout to talk over the upgraded protocol. easy! โœจ

Heads up bestie: this option may not be combined with --more, --oneway, --collect, --graceful=, or --push-fd=. Pick a lane. ๐Ÿšซ

Added in version 261.

  • --json=MODE โ€” picks the JSON output formatting. Either "pretty" for nicely indented, colorized output, or "short" for terse output with minimal whitespace and no newlines. Defaults to "short". ๐Ÿ’…

Added in version 255.

  • -j โ€” equivalent to --json=pretty when you invoke it interactively from a terminal. Otherwise it's equivalent to --json=short, especially when the output is piped to some other program. It just knows what you want. ๐Ÿ”ฎ

Added in version 255.

  • --quiet, -q โ€” suppresses output of method call replies. silence is golden, no cap. ๐Ÿคซ

Added in version 257.

  • --graceful= โ€” takes a qualified Varlink error name, i.e. an interface name, suffixed by an error name, separated by a dot, e.g. "org.varlink.service.InvalidParameter". It makes sure that if a method call fails with the specified error, that failure is treated as success โ€” meaning the varlinkctl invocation exits with a zero exit status. You can use this option more than once to treat multiple different errors as successes. "errors? never heard of her." ๐Ÿ’–

Added in version 257.

  • --timeout= โ€” expects a timeout in seconds as its parameter. By default a timeout of 45s is enforced. To turn the timeout off, specify "infinity" or an empty string. ๐Ÿ•

Added in version 257.

  • --exec โ€” once the method call issued via call completes successfully, chainload the specified command line, with the method call output parameters serialized to JSON passed into standard input (and standard output and standard error inherited from the invoking process). On top of that, any file descriptors passed back on the underlying communication socket get passed to the invoked process via the usual $LISTEN_FDS protocol. This is how you consume replies that come with associated file descriptors in a reasonable way. ๐ŸŽ€

Note that if --exec is specified, the third parameter to call is not optional (i.e. the method call parameters).

Added in version 258.

  • --push-fd= โ€” takes a numeric file descriptor number as parameter. Use it to pass a file descriptor along with the method call, if the underlying transport supports it. Can be used multiple times to pass multiple file descriptors, keeping the order in which they were specified. The specified file descriptors must be passed to the varlinkctl invocation. Optionally, instead of a numeric file descriptor number you can specify an absolute or relative file system path (relative ones must be prefixed with "./"), which gets opened in read-only mode. ๐Ÿ“‚

Added in version 258.

  • --system, --user โ€” decides whether to query the per-system or per-user registry when you're using the list-registry command. By default, the per-system registry is queried. ๐Ÿ–ฅ๏ธ

Added in version 260.

  • --no-ask-password โ€” do not query the user for authentication for privileged operations. no popups, no interruptions, we're busy. ๐Ÿ™ˆ
  • --no-pager โ€” do not pipe output into a pager.
  • -h, --help โ€” print a short help text and exit.
  • --version โ€” print a short version string and exit.

๐Ÿ—‚๏ธ FILES & DIRECTORIES ๐Ÿ—‚๏ธ

  • /run/varlink/registry/ โ€” the directory containing AF_UNIX entrypoint socket inodes (or symlinks pointing to them) for well-known, public Varlink interfaces on the local system. They're named after the Varlink interface they implement. iconic naming convention, honestly. โœจ

Use varlinkctl list-registry to show what's inside this directory. ๐Ÿ‘€

(Inodes that neither qualify as socket inodes nor as symlinks to them shall be ignored. A future extension might introduce regular files and directories to enhance the registry functionality. so watch this space ๐ŸŒธ)

Added in version 260.

๐Ÿ’– EXAMPLES ๐Ÿ’–

okay bestie, this is the part where it all clicks. real commands, real output, real "ohhhh THAT'S what it does" energy โœจ


๐ŸŒธ Example 1. Investigating a Service

these three commands go snooping on the io.systemd.Resolve service โ€” the one that systemd-resolved.service(8) runs. first you get the general service info and the list of interfaces it implements, then you pull up the actual interface definition of its primary interface. it's giving detective work, fr fr ๐Ÿ•ต๏ธโ€โ™€๏ธ

$ varlinkctl info /run/systemd/resolve/io.systemd.Resolve
    Vendor: The systemd Project
   Product: systemd (systemd-resolved)
   Version: 254 (254-1522-g4790521^)
       URL: https://systemd.io/
Interfaces: io.systemd
            io.systemd.Resolve
            org.varlink.service
$ varlinkctl list-interfaces /run/systemd/resolve/io.systemd.Resolve
io.systemd
io.systemd.Resolve
org.varlink.service
$ varlinkctl introspect /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve
interface io.systemd.Resolve
type ResolvedAddress(
        ifindex: ?int,
        ...
the interface definition got chopped off in the example above, purely to keep things short. it's not broken, i promise ๐Ÿซถ

๐ŸŒธ Example 2. Invoking a Method

this one resolves a hostname through systemd-resolved.service(8)'s ResolveHostname method call. look at it go ๐Ÿ’…

$ varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name":"systemd.io","family":2}' -j
{
        "addresses" : [
                {
                        "ifindex" : 2,
                        "family" : 2,
                        "address" : [
                                185,
                                199,
                                111,
                                153
                        ]
                }
        ],
        "name" : "systemd.io",
        "flags" : 1048577
}

๐ŸŒธ Example 3. Investigating a Service Executable

now we're looking at an executable instead of a running service. this inspects /usr/lib/systemd/systemd-pcrextend and all the IPC APIs it provides, and then it actually invokes a method on it. icon behaviour honestly ๐Ÿ‘‘

# varlinkctl info /usr/lib/systemd/systemd-pcrextend
    Vendor: The systemd Project
   Product: systemd (systemd-pcrextend)
   Version: 254 (254-1536-g97734fb)
       URL: https://systemd.io/
Interfaces: io.systemd
            io.systemd.PCRExtend
            org.varlink.service
# varlinkctl introspect /usr/lib/systemd/systemd-pcrextend io.systemd.PCRExtend
interface io.systemd.PCRExtend

method Extend(
        pcr: int,
        text: ?string,
        data: ?string
) -> ()
# varlinkctl call /usr/lib/systemd/systemd-pcrextend io.systemd.PCRExtend.Extend '{"pcr":15,"text":"foobar"}'
{}

๐ŸŒธ Example 4. Invoking a method remotely via SSH

remote bestie hours ๐Ÿฆ‹ this command grabs a report about the identity of a remote host called "somehost" from systemd-hostnamed.service(8) โ€” and it does it by SSH-ing over to the AF_UNIX socket that service is listening on.

# varlinkctl call ssh-unix:somehost:/run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}'

and if you'd rather invoke a Varlink service binary directly on the remote host instead of talking to a service through AF_UNIX, it goes like this:

# varlinkctl call ssh-exec:somehost:systemd-creds org.varlink.service.GetInfo '{}'

๐ŸŒธ Example 5. Serving a Sandboxed Decompressor via Protocol Upgrade

this one is genuinely so cool, no cap. these socket and service units expose xz decompression as a Varlink service. clients connect, send compressed data over the upgraded connection, and get decompressed output back. it's giving โœจmagic trickโœจ

# /etc/systemd/system/varlink-decompress-xz.socket
[Socket]
ListenStream=/run/varlink/registry/com.example.Decompress.XZ

[Install]
WantedBy=sockets.target
# /etc/systemd/system/varlink-decompress-xz.service
[Service]
ExecStart=varlinkctl serve com.example.Decompress.XZ xz -d
DynamicUser=yes
PrivateNetwork=yes
ProtectSystem=strict
ProtectHome=yes
NoNewPrivileges=yes
SystemCallFilter=~@privileged @resources
MemoryMax=256M

then a client can decompress data straight through that service:

$ echo "hello" | xz | varlinkctl call --upgrade \
        unix:/run/varlink/registry/com.example.Decompress.XZ \
        com.example.Decompress.XZ '{}'
hello

and if you just wanna test something real quick without writing unit files at all? systemd-socket-activate can hand you the listening socket instead:

$ systemd-socket-activate -l /tmp/decompress.sock -- varlinkctl serve com.example.Decompress.XZ xz -d &
$ echo "hello" | xz | varlinkctl call --upgrade unix:/tmp/decompress.sock com.example.Decompress.XZ '{}'
hello

โœจ SEE ALSO โœจ

go read these next, bestie, i'm obsessed with them for you ๐Ÿ’œ


๐ŸŽ€ NOTES ๐ŸŽ€

  1. Varlink IPC โ€” https://varlink.org/
  2. UAPI.20 Varlink IPC โ€” https://uapi-group.org/specifications/specs/varlink/

okay that's the whole page, we did it ๐Ÿฅณ you just read the entire VARLINKCTL(1) manual page and honestly? main character energy. this one comes from systemd 262.1 โ€” VARLINKCTL(1) โ€” so go forth and varlink responsibly, bestie. mwah ๐Ÿ’–๐Ÿฆ‹โœจ

๐Ÿ“ฆ where this page comes from
  • arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms