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 absoluteAF_UNIXsocket 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 absoluteAF_UNIXsocket 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_UNIXsocket, 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 fromSTDINinstead. ๐ซถ 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 tocall --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 listeningAF_UNIXstream 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 theuser.varlinkextended 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 fromSTDIN. ๐
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 withcall, you're telling it "expect multiple method replies, babe." โจ With this flag set, the method call goes out with themoreflag 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 withcall: do not expect a method reply. With this flag set, the method call is sent with theonewayflag set, and the command exits immediately after โ telling the service "don't bother replying, king." ๐
Added in version 255.
--upgradeโ when used withcall: request a protocol upgrade. The method call is sent with theupgradeflag 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=prettywhen 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 thevarlinkctlinvocation 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 viacallcompletes 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_FDSprotocol. 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 thevarlinkctlinvocation. 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 thelist-registrycommand. 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 containingAF_UNIXentrypoint 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 ๐
busctl(1)Varlink[1]
๐ NOTES ๐
- Varlink IPC โ
https://varlink.org/ - 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