Add Zsh completion files for public LTTng CLI commands
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 30 Aug 2023 16:33:13 +0000 (12:33 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 29 Feb 2024 22:22:53 +0000 (17:22 -0500)
Zsh is an extended Bourne shell with many improvements, including some
features of Bash, ksh, and tcsh. Zsh features a powerful completion
system which makes it possible to improve the interactive user
experience greatly when using an LTTng command.

Those four new files are Very Sophisticated Zsh completion files,
especially `extras/zsh-completion/_lttng`.

Notable features for all commands:

* Support of LTTng 2.5 through LTTng 2.14, with version-specific
  completion.

  Set `LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1` to disable the upper limit
  of the version check. This should be safe most of the time, but if
  there's a breaking change in option/argument interaction, the
  completions might be wrong.

* Exclusion of options and arguments depending on the current options
  and arguments, according to the manual pages.

  For example, for `lttng enable-channel`, you cannot specify
  `--buffers-uid` if you already specified `--kernel` (and vice versa).

Notable features for the `lttng` command:

* Full support, except for the condition and action specifiers of the
  `add-trigger` subcommand: although I may now add "skillful in Zsh
  completion" to my resume, the positional design of `--condition` and
  `--action` needs event more spicy Zsh wizardry which I didn't explore
  yet.

* Custom tags and support for the `verbose` style to customize the
  completion behaviour and look with `zstyle`.

* For any dynamic completion (relying on some output of the `lttng`
  command), connect to the right session daemon depending on the
  selected tracing group (`g`/`--group`).

* User/group ID completion with displayed corresponding Unix user/group
  names.

* Dynamic recording session name completion with a summary of properties
  (activity and mode).

  Only the relevant ones are added to the completion set. For example,
  names of active sessions are not part of the completion set for
  `lttng start`.

* Current recording session taken into account for subcommands needing
  one when you don't specify the dedicated recording session
  option/argument.

* Dynamic channel name completion depending on the selected recording
  session and tracing domain, with a summary of properties (status,
  tracing domain, event record loss mode).

  Only the relevant ones are added to the completion set. For example,
  names of enabled channels are not part of the completion set for
  `lttng enable-channel`.

* Dynamic recording event rule name condition completion for
  `lttng disable-event`.

* Dynamic instrumentation point name completion depending on the
  selected tracing domain

* Dynamic context field type completion depending on the selected
  tracing domain.

* Log level name completion depending on the selected tracing domain.

* Dynamic trigger name completion depending on the selected owner
  user ID.

Notable features for the `lttng-sessiond` command:

* LTTng kernel probe module name completion (checks within the
  `/usr/lib/modules` directory).

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: If8c2c58a50664f41ecc41ab1df72879127d1cd02

Makefile.am
extras/zsh-completion/_lttng [new file with mode: 0644]
extras/zsh-completion/_lttng-crash [new file with mode: 0644]
extras/zsh-completion/_lttng-relayd [new file with mode: 0644]
extras/zsh-completion/_lttng-sessiond [new file with mode: 0644]

index 04a76275493036d81e5f7b2ba095921031260f75..040d9df6c9c834c7196bbc00a8ae916cebc2c420 100644 (file)
@@ -17,6 +17,7 @@ dist_doc_DATA = LICENSE \
 dist_noinst_DATA = CodingStyle.md
 
 EXTRA_DIST = extras/lttng-bash_completion \
+            extras/zsh-completion \
             LICENSES/BSD-2-Clause \
             LICENSES/BSD-3-Clause \
             LICENSES/GPL-2.0 \
diff --git a/extras/zsh-completion/_lttng b/extras/zsh-completion/_lttng
new file mode 100644 (file)
index 0000000..a27915c
--- /dev/null
@@ -0,0 +1,2040 @@
+#compdef lttng
+#
+# Copyright (c) 2015-2023 Philippe Proulx <eeppeliteloop@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#
+# This is a Zsh completion function for the lttng(1) command (see
+# <https://lttng.org/>), for versions 2.5 to 2.14.
+#
+# If you want, at your own risk, the function to work with versions
+# above 2.14, set `LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1`.
+#
+# Each subcommand changes the command part of the current context so
+# that you can target a specific subcommand with `zstyle`, for
+# example:
+#
+#     $ zstyle ':completion:*:*:lttng-start:*:sessions' verbose yes
+#     $ zstyle ':completion:*:*:lttng-add-context:type-option:*' \
+#              group-order perf-context-types static-context-types
+#
+# The relevant style arguments and tags are:
+#
+# `actions` tag (with the `lttng-snapshot` command):
+#     Snapshot action names.
+#
+# `channel` argument and `channels` tag:
+#     Channel names.
+#
+#     The `verbose` style controls whether or not this function adds
+#     completions as a list (with channel information for each item) or
+#     simple channel names.
+#
+#     If the verbose style is enabled, then the information part of each
+#     item starts with either `  [enabled` or `  [disabled` (note the
+#     two leading spaces), depending on the status of the channel.
+#
+# `commands` tag:
+#     lttng(1) subcommand names.
+#
+# `log-levels` tag:
+#     Log level names.
+#
+# `session` argument and `sessions` tag:
+#     Recording session names.
+#
+#     The `verbose` style controls whether or not this function adds
+#     completions as a list (with recording session information for each
+#     item) or simple recording session names.
+#
+#     If the verbose style is enabled, then the information part of each
+#     item starts with either `  [active` or `  [inactive` (note the two
+#     leading spaces), depending on the status of the recording session.
+#
+# `type-option` argument:
+#     `static-context-types` tag:
+#         Statically-known context field types.
+#
+#     `perf-context-types` tag:
+#         perf counter context field types.
+#
+# `triggers` tag:
+#     Trigger names.
+
+# Sets the `minor_version` variable to the minor version of LTTng-tools,
+# or to `0` if not found.
+__lttng_set_minor_version() {
+  minor_version=0
+
+  local -a match
+
+  if [[ $($prog_name --version) =~ '[[:blank:]]+2\.([[:digit:]]+)' ]]; then
+    minor_version=$match[1]
+  fi
+}
+
+# Runs the `lttng` command with `"$@"` using `$tracing_group`.
+__lttng_run() {
+  $prog_name --no-sessiond --group=$tracing_group "$@" 2>/dev/null
+}
+
+# Runs the `lttng --mi=xml` command using the selected tracing group
+# (`$tracing_group`) with:
+#
+# `$1`:
+#     A message of what's expected to show on error.
+#
+# Other arguments:
+#     Passed to the command as is.
+#
+# This function returns 1 with LTTng-tools < 2.6 and if `xmllint` isn't
+# available.
+__lttng_mi_run() {
+  local -r msg=$1
+
+  shift
+
+  if ((minor_version < 6)); then
+    # MI output requires LTTng-tools ≥ 2.6
+    _message -e descriptions $msg
+    return 1
+  fi
+
+  if ((! $+commands[xmllint])); then
+    # XML output parsing requires xmllint
+    _message -e descriptions $msg
+    return 1
+  fi
+
+  __lttng_run --mi=xml "$@"
+
+  if (($? != 0)); then
+    # Command failed
+    _message -e descriptions $msg
+    return 1
+  fi
+}
+
+# Call this instead of _arguments() within this function when you don't
+# need the `-C` option.
+__lttng_arguments() {
+  _arguments -s -W : "$@"
+}
+
+# Returns whether or not the verbose style is enabled for the given
+# argument (`$1`) and tag (`$2`), using `$curcontext` for the other
+# parts of the full completion context.
+__lttng_style_is_verbose() {
+  local -r arg=$1 tag=$2
+  local -r ccparts=("${(@s.:.)curcontext}")
+
+  zstyle -t :completion:${ccparts[1]}:${ccparts[2]}:${ccparts[3]}:$arg:$tag verbose
+}
+
+# Returns 0 if a Linux kernel tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_kernel_domain_opt_is_set() {
+  (($+opt_args[-k] || $+opt_args[--kernel] ||
+    $+opt_args[domain--k] || $+opt_args[domain---kernel]))
+}
+
+# Returns 0 if a user space tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_user_domain_opt_is_set() {
+  (($+opt_args[-u] || $+opt_args[--userspace] ||
+    $+opt_args[domain--u] || $+opt_args[domain---userspace]))
+}
+
+# Returns 0 if a `java.util.logging` tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_jul_domain_opt_is_set() {
+  (($+opt_args[-j] || $+opt_args[--jul] ||
+    $+opt_args[domain--j] || $+opt_args[domain---jul]))
+}
+
+# Returns 0 if an Apache log4j tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_log4j_domain_opt_is_set() {
+  (($+opt_args[-l] || $+opt_args[--log4j] ||
+    $+opt_args[domain--l] || $+opt_args[domain---log4j]))
+}
+
+# Returns 0 if a Python tracing domain option is set in `$opt_args`,
+# or `1` otherwise.
+__lttng_python_domain_opt_is_set() {
+  (($+opt_args[-p] || $+opt_args[--python] ||
+    $+opt_args[domain--p] || $+opt_args[domain---python]))
+}
+
+# Adds completions for the name of an `lttng` command.
+__lttng_complete_cmd_name() {
+  # LTTng-tools 2.5+
+  local cmd_names=(
+    'add-context:add context fields to be recorded'
+    'create:create a recording session'
+    'destroy:destroy a recording session'
+    'disable-channel:disable channels'
+    'disable-event:disable recording event rules'
+    'enable-channel:create or enable a channel'
+    'enable-event:create or enable recording event rules'
+    'help:show the help of a command'
+    'list:list recording sessions and instrumentation points'
+    'set-session:set the current recording session'
+    'snapshot:take a recording session snapshot'
+    'start:start a recording session'
+    'stop:stop a recording session'
+    'version:show LTTng-tools version information'
+    'view:launch a trace reader'
+  )
+
+  # LTTng-tools 2.6+
+  if ((minor_version >= 6)); then
+    cmd_names+=(
+      'load:load recording session configurations'
+      'save:save recording session configurations'
+    )
+  fi
+
+  # LTTng-tools 2.7+
+  if ((minor_version >= 7)); then
+    cmd_names+=(
+      'track:allow specific processes to record events'
+      'untrack:disallow specific processes to record events'
+    )
+  fi
+
+  # LTTng-tools 2.8+
+  if ((minor_version >= 8)); then
+    cmd_names+=(
+      'status:show the status of the current recording session'
+    )
+  fi
+
+  # LTTng-tools 2.9+
+  if ((minor_version >= 9)); then
+    cmd_names+=(
+      'regenerate:regenerate specific recording session data'
+    )
+  fi
+
+  # LTTng-tools 2.11+
+  if ((minor_version >= 11)); then
+    cmd_names+=(
+      'rotate:archive the current trace chunk of a recording session'
+      'enable-rotation:set a recording session rotation schedule'
+      'disable-rotation:unset a recording session rotation schedule'
+    )
+  fi
+
+  # LTTng-tools 2.12+
+  if ((minor_version >= 12)); then
+    cmd_names+=(
+      'clear:clear a recording session'
+    )
+  fi
+
+  # LTTng-tools 2.13+
+  if ((minor_version >= 13)); then
+    cmd_names+=(
+      'add-trigger:add a trigger'
+      'list-triggers:list triggers'
+      'remove-trigger:remove a trigger'
+    )
+  fi
+
+  # Add completions
+  local expl
+
+  _describe -t commands command cmd_names
+}
+
+# Adds completions for the name of an `lttng snapshot` action.
+__lttng_complete_snapshot_action_name() {
+  local -r action_names=(
+    'add-output:add a snapshot output'
+    'del-output:remove a snapshot output'
+    'list-output:show the snapshot output'
+    'record:take a snapshot'
+  )
+
+  # Add completions
+  local expl
+
+  _describe -t actions 'snapshot action' action_names
+}
+
+# Adds user ID completions.
+#
+# The added completions are displayed as user names, but the actual
+# completions are corresponding user IDs.
+__lttng_complete_uid() {
+  if [[ ! -f /etc/passwd ]]; then
+    # Weird flex but ok
+    _message -e descriptions 'user ID'
+    return
+  fi
+
+  # Read user names and IDs from `/etc/passwd`
+  local line
+  local -a uids names fields
+
+  while read -r line; do
+    if [[ -z ${line// } ]]; then
+      # Skip empty line
+      continue
+    fi
+
+    # Extract user ID and name
+    fields=("${(@s/:/)line}")
+    uids+=($fields[3])
+    names+=("$fields[1]")
+  done < /etc/passwd
+
+  # Add completions
+  local expl
+
+  _wanted users expl 'user ID' compadd -d names -a uids
+}
+
+# Adds completions for a context field type (for the `--type` option of
+# the `add-context` command).
+#
+# This function replaces the argument field of the current context with
+# `type-option`.
+#
+# This function relies on the tracing domain options of `$opt_args` to
+# restrict the offered completions. Without a tracing domain option,
+# this function adds all the possible context field type completions.
+#
+# This function runs `lttng add-context --list` to get the list of
+# available context field types.
+#
+# This function adds completions with both the `static-context-types`
+# and `perf-context-types` tags so that the Zsh user can hide a group or
+# select them with the `group-order` and `tag-order` style.
+__lttng_complete_context_type() {
+  # Statically-known context field types
+  local kernel_types=(
+    pid procname prio nice vpid tid vtid ppid vppid hostname
+    interruptible preemptible need_reschedule migratable
+    callstack-kernel callstack-user cgroup_ns ipc_ns mnt_ns net_ns
+    pid_ns time_ns user_ns uts_ns uid euid suid gid egid sgid vuid veuid
+    vsuid vgid vegid vsgid
+  )
+  local user_types=(
+    vpid pthread_id procname ip cgroup_ns ipc_ns mnt_ns net_ns pid_ns
+    time_ns user_ns uts_ns vuid veuid vsuid vgid vegid vsgid
+  )
+
+  # Set `types` and `domain` depending on the selected tracing domain
+  local -a types
+  local domain descr_suffix
+
+  if __lttng_kernel_domain_opt_is_set; then
+    # Kernel context field types
+    types=($kernel_types)
+    domain=k
+  elif __lttng_user_domain_opt_is_set; then
+    # User space context field types
+    types=($user_types)
+    domain=u
+  else
+    # No supported tracing domain: offer all context field types
+    types=($user_types $kernel_types)
+    descr_suffix=' (all tracing domains)'
+  fi
+
+  # Get XML list of available context field types
+  local -r msg='context type'
+  local list_xml
+
+  list_xml=$(__lttng_mi_run $msg add-context --list)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Convert to one context field type per line
+  local lines
+
+  lines=$(__lttng_xmllint_xpath $list_xml '//*[local-name()="symbol"]/text()')
+
+  if (($? != 0)); then
+    _guard '^-*' $msg
+    return
+  fi
+
+  # Filter context field types depending on the selected tracing domain
+  local -a static_items perf_items
+  local line
+
+  while read -r line; do
+    if (($types[(Ie)$line])); then
+      # Statically-known context field type
+      static_items+=$line
+    elif [[ $line = perf:cpu:* && $domain != u ]]; then
+      # Per-CPU perf counter
+      perf_items+=$line
+    elif [[ $line = perf:thread:* && $domain != k ]]; then
+      # Per-thread perf counter
+      perf_items+=$line
+    elif [[ $line = perf:* && $domain != u ]]; then
+      # Other perf counter (Linux kernel tracing domain or none)
+      perf_items+=$line
+    fi
+  done <<< $lines
+
+  # Add completions
+  _alternative -C type-option \
+    "static-context-types:statically-known context type${descr_suffix}:compadd -a static_items" \
+    "perf-context-types:perf counter context type${descr_suffix}:compadd -a perf_items"
+}
+
+# Adds completions for a trigger name.
+#
+# Relies on `$opt_args[--owner-uid]` to restrict the offered
+# completions.
+__lttng_complete_trigger_name() {
+  # Get XML list of available triggers
+  local msg='trigger name'
+  local list_xml
+
+  list_xml=$(__lttng_mi_run $msg list-triggers)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Create the owner UID predicate XPath part
+  local owner_uid_xpath
+
+  if (($+opt_args[--owner-uid])); then
+    owner_uid_xpath="[./*[local-name()='owner_uid'] = ${opt_args[--owner-uid]}]"
+  fi
+
+  # Convert to one trigger name per line
+  local lines
+
+  lines=$(__lttng_xmllint_xpath $list_xml "//*[local-name()='trigger']$owner_uid_xpath/*[local-name()='name']/text()")
+
+  if (($? != 0)); then
+    _guard '^-*' $msg
+    return
+  fi
+
+  local -a trigger_names
+
+  while read -r line; do
+    trigger_names+=$line
+  done <<< $lines
+
+  # Add completions
+  local expl
+
+  _wanted triggers expl $msg compadd -a trigger_names
+}
+
+# Runs `xmllint` with:
+#
+# `$1`:
+#     An XML document to parse.
+#
+# `$2`:
+#     An XPath to extract data.
+__lttng_xmllint_xpath() {
+  local -r xml=$1 xpath=$2
+
+  xmllint --xpath $xpath - <<< $xml 2>/dev/null
+}
+
+# Prints the equivalent recording session status adjective (`active` or
+# `inactive`) for an `enabled` XML property, or `unknown` on error.
+__lttng_session_status_from_enabled_prop() {
+  local -r prop=$1
+
+  case $prop in
+    true) echo -n active;;
+    false) echo -n inactive;;
+    *) echo -n unknown;;
+  esac
+}
+
+# Prints the value of the immediate XML property named `$3` of the child
+# node named `$2` within the parent node `$1`.
+__lttng_immediate_prop_from_xml() {
+  local -r node_xml=$1 node_name=$2 prop_name=$3
+
+  __lttng_xmllint_xpath $node_xml "/*[local-name()='$node_name']/*[local-name()='$prop_name']/text()"
+}
+
+# Prints the value of the immediate XML `name` property of the child
+# node named `$2` within the parent node `$1`.
+__lttng_name_prop_from_xml() {
+  local -r node_xml=$1 node_name=$2
+
+  __lttng_immediate_prop_from_xml $node_xml $node_name name
+}
+
+# Prints the value of the immediate XML `enabled` property of the child
+# node named `$2` within the parent node `$1`.
+__lttng_enabled_prop_from_xml() {
+  local -r node_xml=$1 node_name=$2
+
+  __lttng_immediate_prop_from_xml $node_xml $node_name enabled
+}
+
+# Adds completions for a recording session name.
+#
+# Arguments:
+#
+# `$1`:
+#     One of:
+#
+#     `all`:
+#         Add completions for active and inactive recording sessions.
+#
+#     `active`:
+#         Only add completions for active recording sessions.
+#
+#     `inactive`:
+#         Only add completions for inactive recording sessions.
+#
+# `$2`:
+#     One of:
+#
+#     `all`:
+#         Add completions for recording sessions regardless of their
+#         mode.
+#
+#     `snapshot`:
+#         Only add completions for snapshot recording sessions.
+#
+#     `live`:
+#         Only add completions for LTTng live recording sessions.
+__lttng_complete_session_name() {
+  local -r req_status=$1 req_mode=$2
+
+  # Get XML document (summary of recording sessions)
+  local session_summaries_xml
+
+  session_summaries_xml=$(__lttng_mi_run 'recording session name' list)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Count recording sessions
+  local -i session_count
+
+  session_count=$(__lttng_xmllint_xpath $session_summaries_xml 'count(//*[local-name()="session"])')
+
+  if (($? != 0 || session_count == 0)); then
+    _guard '^-*' 'recording session name'
+    return
+  fi
+
+  # Append the name and info of one recording session at a time
+  local -a session_names session_infos
+  local -i index iprop
+  local session_name session_summary_xml snapshot_mode session_status session_info
+
+  # For each recording session summary
+  for index in {1..$session_count}; do
+    # Get recording session summary XML node
+    session_summary_xml=$(__lttng_xmllint_xpath $session_summaries_xml "//*[local-name()='session'][$index]")
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Get recording session name
+    session_name=$(__lttng_name_prop_from_xml $session_summary_xml session)
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Get recording session status
+    session_status=$(__lttng_enabled_prop_from_xml $session_summary_xml session)
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    session_status=$(__lttng_session_status_from_enabled_prop $session_status)
+
+    if [[ $req_status != all && $req_status != $session_status ]]; then
+      # Skip recording session with unexpected status
+      continue
+    fi
+
+    # Get recording session mode
+    session_mode=
+    iprop=$(__lttng_immediate_prop_from_xml $session_summary_xml session snapshot_mode)
+
+    if (($? == 0 && iprop)); then
+      session_mode=snapshot
+    else
+      iprop=$(__lttng_immediate_prop_from_xml $session_summary_xml session live_timer_interval)
+
+      if (($? == 0 && iprop)); then
+        session_mode=live
+      fi
+    fi
+
+    if [[ $req_mode != all && $req_mode != $session_mode ]]; then
+      # Skip recording session with unexpected mode
+      continue
+    fi
+
+    session_info=$session_status
+
+    if [[ -n $session_mode ]]; then
+      session_info+=", $session_mode mode"
+    fi
+
+    session_names+=("$session_name")
+    session_infos+=($session_info)
+  done
+
+  # No recording sessions: show message
+  if (($#session_names == 0)); then
+    _guard '^-*' 'recording session name'
+    return
+  fi
+
+  # Compute maximum session info length
+  local -i max_info_len=0 len
+
+  for session_info in $session_infos; do
+    len=$#session_info
+
+    if ((len > max_info_len)); then
+      max_info_len=$len
+    fi
+  done
+
+  # Compute maximum session name length
+  local -i max_name_len=0
+
+  for session_name in $session_names; do
+    len=$#session_name
+
+    if ((len > max_name_len)); then
+      max_name_len=$len
+    fi
+  done
+
+  # Some room for the longest info string, two spaces, and two brackets
+  local -ir max_possible_name_len=$((COLUMNS - max_info_len - 5))
+
+  if ((max_name_len > max_possible_name_len)); then
+    # Clamp
+    max_name_len=$max_possible_name_len
+  fi
+
+  # Create the dislay strings (name, status, mode)
+  local -a disps
+
+  for index in {1..${#session_names}}; do
+    disps+=("${(r:$max_name_len:: :)session_names[$index]}  [$session_infos[$index]]")
+  done
+
+  # Add completions
+  local expl
+
+  if __lttng_style_is_verbose session sessions; then
+    # Verbose mode (list with infos)
+    _wanted -C session sessions expl 'recording session name' \
+      compadd -d disps -l -a session_names
+  else
+    # Just the recording session names
+    _wanted -C session sessions expl 'recording session name' \
+      compadd -a session_names
+  fi
+}
+
+# Prints the name of the Unix user's current recording session, if any.
+__lttng_cur_session_name() {
+  local -r lttngrc_path=${LTTNG_HOME:-$HOME}/.lttngrc
+
+  if [[ ! -f $lttngrc_path ]]; then
+    return 1
+  fi
+
+  local cur_session_name
+  local -a match
+
+  while read -r line; do
+    if [[ $line =~ 'session=([^[:blank:]]+)' ]]; then
+      cur_session_name=$match[1]
+      break
+    fi
+  done < $lttngrc_path
+
+  if [[ -z $cur_session_name ]]; then
+    return 1
+  fi
+
+  echo -n $cur_session_name
+}
+
+# Prints the equivalent status adjective (`enabled` or `disabled`) for
+# an `enabled` XML property, or `unknown` on error.
+__lttng_status_from_enabled_prop() {
+  local -r prop=$1
+
+  case $prop in
+    true) echo -n enabled;;
+    false) echo -n disabled;;
+    *) echo -n unknown;;
+  esac
+}
+
+# Prints the XML document of `lttng list $2` (specifics of a single
+# recording session).
+#
+# `$1` is a message of what's expected to show on error.
+__lttng_session_xml() {
+  local -r msg=$1 session_name=$2
+
+  __lttng_mi_run $msg list $session_name
+}
+
+# Adds completions for a channel name.
+#
+# This function relies on the tracing domain options of `$opt_args`,
+# `$opt_args[-s]`, `$opt_args[--session]`, and the first non-option
+# argument to restrict the offered completions.
+#
+# Arguments:
+#
+# `$1`:
+#     One of:
+#
+#     `all`:
+#         Add completions for enabled and disabled channels.
+#
+#     `enabled`:
+#         Only add completions for enabled channels.
+#
+#     `disabled`:
+#         Only add completions for disabled channels.
+#
+# `$2`:
+#     `opt`:
+#         Use `$opt_args[-s]` and `$opt_args[--session]` to find the
+#         name of the selected recording session.
+#
+#     `arg`:
+#         Use `$line[1]` to find the name of the selected recording
+#         session.
+__lttng_complete_channel_name() {
+  local -r req_status=$1 session_name_src=$2
+
+  shift 2
+
+  # Find the recording session name to use
+  local session_name
+
+  if [[ $session_name_src = opt ]]; then
+    if (($+opt_args[-s])); then
+      session_name=$opt_args[-s]
+    elif (($+opt_args[--session])); then
+      session_name=$opt_args[--session]
+    fi
+  elif [[ $session_name_src = arg ]]; then
+    session_name=$line[1]
+  fi
+
+  if [[ -z $session_name ]]; then
+    # Fall back to current recording session
+    session_name=$(__lttng_cur_session_name)
+
+    if (($? != 0)); then
+      _guard '^-*' 'channel name'
+      return
+    fi
+  fi
+
+  # Get XML document (detailed recording session)
+  local session_xml
+
+  session_xml=$(__lttng_session_xml 'channel name' $session_name)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Count tracing domains
+  local -i domain_count
+
+  domain_count=$(__lttng_xmllint_xpath $session_xml 'count(//*[local-name()="domain"])')
+
+  if (($? != 0 || domain_count == 0)); then
+    _guard '^-*' 'channel name'
+    return
+  fi
+
+  # Append the name and info of one channel at a time
+  local domain_xml domain prop
+  local channel_xml channel_name channel_status channel_erl_mode
+  local -a channel_names channel_infos
+  local -i channel_count domain_index channel_index
+
+  # For each tracing domain
+  for domain_index in {1..$domain_count}; do
+    # Get tracing domain XML node
+    domain_xml=$(__lttng_xmllint_xpath $session_xml "//*[local-name()='domain'][$domain_index]")
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Get tracing domain type
+    domain=$(__lttng_xmllint_xpath $domain_xml '/*/*[local-name()="type"]/text()')
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Skip unexpected tracing domains
+    if [[ $domain = KERNEL ]]; then
+      if __lttng_user_domain_opt_is_set; then
+        # Skip unexpected Linux kernel tracing domain
+        continue
+      fi
+
+      domain='Linux kernel'
+    fi
+
+    if [[ $domain = UST ]]; then
+      if __lttng_kernel_domain_opt_is_set; then
+        # Skip unexpected user space tracing domain
+        continue
+      fi
+
+      domain='user space'
+    fi
+
+    # Count channels within tracing domain
+    channel_count=$(__lttng_xmllint_xpath $domain_xml 'count(//*[local-name()="channel"])')
+
+    if (($? != 0 || channel_count == 0)); then
+      continue
+    fi
+
+    # For each channel
+    for channel_index in {1..$channel_count}; do
+      # Get channel XML node
+      channel_xml=$(__lttng_xmllint_xpath $domain_xml "//*[local-name()='channel'][$channel_index]")
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      # Get channel name
+      channel_name=$(__lttng_name_prop_from_xml $channel_xml channel)
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      # Get channel status
+      channel_status=$(__lttng_enabled_prop_from_xml $channel_xml channel)
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      channel_status=$(__lttng_status_from_enabled_prop $channel_status)
+
+      if [[ $req_status != all && $req_status != $channel_status ]]; then
+        # Skip channel with unexpected status
+        continue
+      fi
+
+      # Get channel event record loss mode
+      channel_erl_mode=$(__lttng_xmllint_xpath $channel_xml '//*[local-name()="attributes"]/*[local-name()="overwrite_mode"]/text()')
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      if [[ $channel_erl_mode = DISCARD ]]; then
+        channel_erl_mode=discard
+      elif [[ $channel_erl_mode = OVERWRITE ]]; then
+        channel_erl_mode=overwrite
+      fi
+
+      channel_names+=("$channel_name")
+      channel_infos+=("$channel_status, $domain, $channel_erl_mode mode")
+    done
+  done
+
+  # No channels: show message
+  if (($#channel_names == 0)); then
+    _guard '^-*' 'channel name'
+    return
+  fi
+
+  # Compute maximum channel info length
+  local channel_info
+  local -i max_info_len=0 len
+
+  for channel_info in $channel_infos; do
+    len=$#channel_info
+
+    if ((len > max_info_len)); then
+      max_info_len=$len
+    fi
+  done
+
+  # Compute maximum channel name length
+  local -i max_name_len=0
+
+  for channel_name in $channel_names; do
+    len=$#channel_name
+
+    if ((len > max_name_len)); then
+      max_name_len=$len
+    fi
+  done
+
+  # Some room for the longest info string, two spaces, and two brackets
+  local -ir max_possible_name_len=$((COLUMNS - max_info_len - 5))
+
+  if ((max_name_len > max_possible_name_len)); then
+    # Clamp
+    max_name_len=$max_possible_name_len
+  fi
+
+  # Create the dislay strings (name, status, tracing domain, mode)
+  local -a disps
+
+  for channel_index in {1..${#channel_names}}; do
+    disps+=("${(r:$max_name_len:: :)channel_names[$channel_index]}  [$channel_infos[$channel_index]]")
+  done
+
+  # Add completions
+  local expl
+
+  if __lttng_style_is_verbose channel channels; then
+    # Verbose mode (list with infos).
+    #
+    # Using `-2` as Linux kernel and user space channels may have the
+    # same name, but we want to show the different infos.
+    _wanted -C channel channels expl 'channel name' \
+      compadd "$@" -2 -d disps -l -a channel_names
+  else
+    # Just the channel names, no duplicates
+    _wanted -C channel channels expl 'channel name' \
+      compadd "$@" -a channel_names
+  fi
+}
+
+# Add completions for instrumentation point names.
+#
+# This function relies on the tracing domain options of `$opt_args` and
+# `$opt_args[ip---syscall]` to restrict the offered completions.
+__lttng_complete_ip_name() {
+  local msg
+  local -a list_opts
+
+  if __lttng_kernel_domain_opt_is_set; then
+    list_opts=(-k)
+
+    if (($+opt_args[ip---syscall])); then
+      msg='system call name (no `sys_` prefix)'
+      list_opts+=(--syscall)
+    else
+      msg='Linux kernel tracepoint name'
+    fi
+  elif __lttng_user_domain_opt_is_set; then
+    msg='user space tracepoint name'
+    list_opts=(-u)
+  elif __lttng_jul_domain_opt_is_set; then
+    msg='`java.util.logging` logger name'
+    list_opts=(-j)
+  elif __lttng_log4j_domain_opt_is_set; then
+    msg='Apache log4j logger name'
+    list_opts=(-l)
+  elif __lttng_python_domain_opt_is_set; then
+    msg='Python logger name'
+    list_opts=(-p)
+  else
+    # No tracing domain option
+    _guard '^-*' 'instrumentation point or recording event rule name'
+    return
+  fi
+
+  # Get XML list of available instrumentation point names
+  local list_xml
+
+  list_xml=$(__lttng_mi_run $msg list $list_opts)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Convert to one instrumentation point name per line
+  local ip_names
+
+  ip_names=$(__lttng_xmllint_xpath $list_xml '//*[local-name()="event"]//*[local-name()="name"]/text()')
+
+  if (($? != 0)) || [[ -z $ip_names ]]; then
+    # `xmllint` error or no instrumentation points
+    _guard '^-*' $msg
+    return
+  fi
+
+  local ip_name
+  local -a items
+
+  while read -r ip_name; do
+    if [[ -z $ip_name ]]; then
+      continue
+    fi
+
+    items+=($ip_name)
+  done <<< $ip_names
+
+  # Add completions
+  local expl
+
+  _wanted instrumentation-points expl $msg compadd "$@" -a items
+}
+
+# Adds completions for the arguments of the `add-context` command.
+__lttng_complete_add_context_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(- : *)--list[list the available context field types]'
+    '(--list -s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name inactive all'
+    '(--list -c --channel)'{-c+,--channel=}'[select a specific channel]: : __lttng_complete_channel_name enabled opt'
+    '(--list)*'{-t+,--type=}'[add a context field to be recorded]: : __lttng_complete_context_type'
+    + '(domain)'
+    '(--list)'{-k,--kernel}'[select the Linux kernel tracing domain]'
+    '(--list)'{-u,--userspace}'[select the user space tracing domain]'
+  )
+
+  # The Java tracing domain options require LTTng-tools ≥ 2.8 (for
+  # application-specific context field types).
+  if ((minor_version >= 8)); then
+    specs+=(
+      '(--list)'{-j,--jul}'[select the `java.util.logging` tracing domain]'
+      '(--list)'{-l,--log4j}'[select the Apache log4j tracing domain]'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for log level names.
+#
+# This function relies on the tracing domain options of `$opt_args` to
+# restrict the offered completions.
+__lttng_complete_log_level() {
+  local -a log_levels
+
+  # Fill the `log_levels` array depending on the tracing domain option
+  if __lttng_user_domain_opt_is_set; then
+    log_levels=(
+      EMERG
+      ALERT
+      CRIT
+      ERR
+      WARNING
+      NOTICE
+      INFO
+      DEBUG_SYSTEM
+      DEBUG_PROGRAM
+      DEBUG_PROCESS
+      DEBUG_MODULE
+      DEBUG_UNIT
+      DEBUG_FUNCTION
+      DEBUG_LINE
+      DEBUG
+    )
+  elif __lttng_jul_domain_opt_is_set; then
+    log_levels=(
+      OFF
+      SEVERE
+      WARNING
+      INFO
+      CONFIG
+      FINE
+      FINER
+      FINEST
+      ALL
+    )
+  elif __lttng_log4j_domain_opt_is_set; then
+    log_levels=(
+      OFF
+      FATAL
+      ERROR
+      WARN
+      INFO
+      DEBUG
+      TRACE
+      ALL
+    )
+  elif __lttng_python_domain_opt_is_set; then
+    log_levels=(
+      CRITICAL
+      ERROR
+      WARNING
+      INFO
+      DEBUG
+      NOTSET
+    )
+  else
+    # No tracing domain option
+    _guard '^-*' 'log level name'
+  fi
+
+  # Add completions
+  local expl
+
+  _wanted log-levels expl 'log level name' compadd -a log_levels
+}
+
+# Adds completions for a trigger condition type.
+__lttng_complete_trigger_condition_type() {
+  local -r types=(
+    'event-rule-matches:an event rule matches an event'
+  )
+
+  # Add completions
+  local expl
+
+  _describe 'trigger condition type' types
+}
+
+# Adds completions for a trigger action type.
+__lttng_complete_trigger_action_type() {
+  local -r types=(
+    'notify:send a notification through the notification mechanism'
+    'start-session:start a recording session'
+    'stop-session:stop a recording session'
+    'rotate-session:archive the current trace chunk of a recording session'
+    'snapshot-session:take a recording session snapshot'
+  )
+
+  # Add completions
+  local expl
+
+  _describe 'trigger action type' types
+}
+
+# Adds completions for the arguments of the `add-trigger` command.
+#
+# Note that those completions are incomplete, in that:
+#
+# • A valid event rule specification, as per lttng-event-rule(7),
+#   must follow `--condition=event-rule-matches`.
+#
+# • `--capture` options are possible within an `event-rule-matches`
+#   condition specifier.
+#
+# • The `--rate-policy` option and other arguments, sometimes mandatory,
+#   are possible within an action specifier.
+#
+# Having full completion for condition and action specifiers require
+# more Zsh magic as _arguments(), like most command-line argument
+# parsers, doesn't take option positions into account.
+__lttng_complete_add_trigger_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-n --name)'{-n+,--name=}'[set the trigger name]:new trigger name:'
+    '--owner-uid=[add the trigger as another Unix user]: : __lttng_complete_uid'
+    '--condition=[set the condition type and arguments]: : __lttng_complete_trigger_condition_type'
+    '*--action=[set the action type and arguments]: : __lttng_complete_trigger_action_type'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `clear` command.
+__lttng_complete_clear_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-a --all):: : __lttng_complete_session_name all all'
+    '(1 -a --all)'{-a,--all}'[clear all recording sessions]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `create` command.
+__lttng_complete_create_cmd() {
+  local specs=(
+    $help_opt_specs
+    ':: :_guard "^-*" "new recording session name"'
+    '(-C --ctrl-url output)'{-C+,--ctrl-url=}'[set the control URL]:control URL:'
+    '(-D --data-url output)'{-D+,--data-url=}'[set the trace data output URL]:trace data output URL:'
+  )
+
+  # The `--shm-path` option LTTng-tools ≥ 2.7
+  if ((minor_version >= 7)); then
+    specs+=(
+      '--shm-path=[write shared memory files to a specific directory]:shared memory file directory:_files -/'
+    )
+  fi
+
+  # Add the remaining option groups
+  specs+=(
+    + '(output)'
+    '(-D --data-url -C --ctrl-url --live)--no-output[disable trace data output]'
+    '(-D --data-url -C --ctrl-url --live)'{-o+,--output=}'[set the local trace data output directory]:trace data output directory:_files -/'
+    '(-D --data-url -C --ctrl-url)'{-U+,--set-url=}'[set the trace data output and control URL]:trace data output and control URL:'
+    + '(mode)'
+    '(-o --output --no-output)--live=[create an LTTng live recording session]:live timer period (µs):'
+    '--snapshot[create a snapshot recording session]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `destroy` command.
+__lttng_complete_destroy_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-a --all):: : __lttng_complete_session_name all all'
+    '(1 -a --all)'{-a,--all}'[destroy all recording sessions]'
+  )
+
+  # The `--no-wait` option requires LTTng-tools ≥ 2.8
+  if ((minor_version >= 8)); then
+    specs+=(
+      '(-n --no-wait)'{-n,--no-wait}'[exit immediately]'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `disable-channel` command.
+__lttng_complete_disable_channel_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    ': : _sequence __lttng_complete_channel_name enabled opt'
+    + '(domain)'
+    {-k,--kernel}'[select the Linux kernel tracing domain]'
+    {-u,--userspace}'[select the user space tracing domain]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Prints the XML tracing domain name value depending on the tracing
+# domain option (in `$opt_args`), or prints nothing and returns 1 when
+# not available.
+__lttng_xml_domain_name_from_opt() {
+  if __lttng_kernel_domain_opt_is_set; then
+    echo -n KERNEL
+  elif __lttng_user_domain_opt_is_set; then
+    echo -n UST
+  elif __lttng_jul_domain_opt_is_set; then
+    echo -n JUL
+  elif __lttng_log4j_domain_opt_is_set; then
+    echo -n LOG4J
+  elif __lttng_python_domain_opt_is_set; then
+    echo -n PYTHON
+  else
+    return 1
+  fi
+}
+
+# Prints the XML instrumentation point type value depending on the
+# instrumentation point option (in `$opt_args`).
+__lttng_xml_ip_type_from_opt() {
+  if (($+opt_args[--syscall] || $+opt_args[ip---syscall])); then
+    echo -n SYSCALL
+  elif (($+opt_args[--probe] || $+opt_args[ip---probe])); then
+    echo -n PROBE
+  elif (($+opt_args[--function] || $+opt_args[ip---function])); then
+    echo -n FUNCTION
+  else
+    echo -n TRACEPOINT
+  fi
+}
+
+# Adds completions for an old, enabled recording event rule name
+# condition (for the `disable-event` command).
+__lttng_complete_old_enabled_er_name_cond() {
+  local -r msg='recording event rule name condition'
+
+  # Find the recording session name to use
+  local session_name
+
+  if (($+opt_args[-s])); then
+    session_name=$opt_args[-s]
+  elif (($+opt_args[--session])); then
+    session_name=$opt_args[--session]
+  else
+    # Fall back to current recording session
+    session_name=$(__lttng_cur_session_name)
+
+    if (($? != 0)); then
+      _guard '^-*' $msg
+    fi
+  fi
+
+  # Find the channel name to use (`channel0` is the default name)
+  local channel_name=channel0
+
+  if (($+opt_args[-c])); then
+    channel_name=$opt_args[-c]
+  elif (($+opt_args[--channel])); then
+    channel_name=$opt_args[--channel]
+  fi
+
+  # Create tracing domain XPath part
+  local domain_xpath
+  local xml_domain_val
+
+  xml_domain_val=$(__lttng_xml_domain_name_from_opt)
+
+  if (($? == 0)); then
+    domain_xpath="*[local-name() = 'domain'][*[local-name() = 'type'] = '$xml_domain_val']//"
+  fi
+
+  # Create channel XPath part
+  local -r channel_xpath="*[local-name() = 'channel'][*[local-name() = 'name'] = '$channel_name']//"
+
+  # Create instrumentation point type XPath part
+  local -r xml_ip_type_val=$(__lttng_xml_ip_type_from_opt)
+  local -r ip_type_xpath="[*[local-name() = 'type'] = '$xml_ip_type_val']"
+
+  # Get XML document (detailed recording session)
+  local session_xml
+
+  session_xml=$(__lttng_session_xml $msg $session_name)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Convert to one recording event rule name per line
+  local lines
+
+  lines=$(__lttng_xmllint_xpath $session_xml "//$domain_xpath${channel_xpath}*[local-name() = 'event']${ip_type_xpath}[*[local-name() = 'enabled'] = 'true']/*[local-name() = 'name']/text()")
+
+  if (($? != 0)); then
+    _guard '^-*' $msg
+    return
+  fi
+
+  local -a er_names
+
+  while read -r line; do
+    if [[ -z ${line// } ]]; then
+      # Skip empty line
+      continue
+    fi
+
+    er_names+=$line
+  done <<< $lines
+
+  # Add completions
+  local expl
+
+  _wanted -C event events expl $msg compadd "$@" -a er_names
+}
+
+# Adds completions for the arguments of the `disable-event` command.
+__lttng_complete_disable_event_cmd() {
+  local -r kernel_ip_opt_excl=(--syscall --probe --function)
+  local specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '(-c --channel)'{-c+,--channel=}'[select a specific channel]: : __lttng_complete_channel_name all opt'
+    + '(names)'
+    {-a,--all-events}'[disable all recording event rules]'
+    ': :_sequence __lttng_complete_old_enabled_er_name_cond'
+    + '(domain)'
+    {-k,--kernel}'[select the Linux kernel tracing domain]'
+    "($kernel_ip_opt_excl)"{-u,--userspace}'[select the user space tracing domain]'
+    "($kernel_ip_opt_excl)"{-j,--jul}'[select the `java.util.logging` tracing domain]'
+  )
+
+  # Add tracing domain option specifications based on the minor version
+  # of LTTng-tools.
+  if ((minor_version >= 6)); then
+    specs+=(
+      "($kernel_ip_opt_excl)"{-l,--log4j}'[select the Apache log4j tracing domain]'
+    )
+  fi
+
+  if ((minor_version >= 7)); then
+    specs+=(
+      "($kernel_ip_opt_excl)"{-p,--python}'[select the Python tracing domain]'
+    )
+  fi
+
+  # Add instrumentation point type option specifications based on the
+  # minor version of LTTng-tools.
+  if ((minor_version >= 6)); then
+    specs+=(
+      + '(ip)'
+      "($non_kernel_domain_opt_excl)--syscall[disable recording ER matching Linux system call events]"
+    )
+  fi
+
+  if ((minor_version >= 7)); then
+    specs+=(
+      '--tracepoint[disable recording ER matching tracepoint events]'
+      "($non_kernel_domain_opt_excl)--probe[disable recording ER matching kprobe events]"
+      "($non_kernel_domain_opt_excl)--function[disable recording ER matching kretprobe events]"
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `disable-rotation` command.
+__lttng_complete_disable_rotation_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '--timer[disable the periodic rotation schedule]'
+    '--size[disable the size-based rotation schedule]'
+  )
+
+  __lttng_arguments $specs
+}
+
+# Adds completions for a channel output type (`mmap` and, possibly,
+# `splice`) (for the `--output` option of the `enable-channel` command).
+#
+# This function replaces the argument field of the current context with
+# `output-opt`.
+#
+# This function relies on the user space tracing domain options of
+# `$opt_args` to restrict the offered completions. Without the user
+# space tracing domain option, this function adds the `splice`
+# completion too.
+__lttng_complete_channel_output_type() {
+  local output_types=(mmap)
+
+  if ! __lttng_user_domain_opt_is_set; then
+    # Linux kernel tracing domain or none
+    output_types+=(splice)
+  fi
+
+  local expl
+
+  _wanted -C 'output-opt' values expl 'output type' compadd -a output_types
+}
+
+# Adds completions for the non-option argument of the `enable-channel`
+# command.
+#
+# This function either, depending on the keys of `$opt_args`:
+#
+# At least one creation option:
+#     Shows a message to enter the new channel name.
+#
+# Otherwise:
+#     Adds completions for a comma-separated list of known channel names
+#     using __lttng_complete_channel_name().
+__lttng_complete_enable_channel_cmd_names() {
+  local key
+  local -r enable_opts=(
+    -s --session
+    domain---kernel domain--k
+    domain---userspace domain--u
+  )
+
+  # For each key of `$opt_args`
+  for key in "${(@k)opt_args}"; do
+    if (($enable_opts[(Ie)$key])); then
+      # Enabling option exists: skip
+      continue
+    fi
+
+    # Creation option exists: single name
+    _guard '^-*' 'new channel name'
+    return
+  done
+
+  # Comma-separated list of existing channel names
+  _sequence __lttng_complete_channel_name disabled opt
+}
+
+# Adds completions for the arguments of the `enable-channel` command.
+__lttng_complete_enable_channel_cmd() {
+  local specs=(
+    $help_opt_specs
+    '--switch-timer=[set the switch timer period]:switch timer period (µs):'
+    '--read-timer=[set the read timer period]:read timer period (µs):'
+    '--subbuf-size=[set the size of each sub-buffer]:sub-buffer size (bytes; `k`/`M`/`G` suffixes supported):'
+    '--num-subbuf=[set the number of sub-buffers per ring buffer]:sub-buffer count:'
+    '--tracefile-size=[set the maximum size of each trace file]:trace file size (bytes; `k`/`M`/`G` suffixes supported):'
+    '--tracefile-count=[set the maximum number of trace files]:maximum trace file count:'
+    '--output=[set the output type]: : __lttng_complete_channel_output_type'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    ': : __lttng_complete_enable_channel_cmd_names'
+  )
+
+  # The `--blocking-timeout` and `--monitor-timer` options require
+  # LTTng-tools ≥ 2.10.
+  if ((minor_version >= 10)); then
+    specs+=(
+      '(--kernel --overwrite --buffers-global)--blocking-timeout=[set the blocking timeout]:blocking timeout (µs):'
+      '--monitor-timer=[set the monitor timer period]:monitor timer period (µs):'
+    )
+  fi
+
+  # Add the remaining option groups
+  specs+=(
+    + '(domain)'
+    '(--blocking-timeout --buffers-uid --buffers-pid)'{-k,--kernel}'[select the Linux kernel tracing domain]'
+    '(--buffers-global)'{-u,--userspace}'[select the user space tracing domain]'
+    + '(loss-mode)'
+    '--discard[discard event records with no available sub-buffer]'
+    '(--blocking-timeout)--overwrite[overwrite oldest sub-buffer with no available sub-buffer]'
+    + '(buffering)'
+    '(-k --kernel)--buffers-uid[use per-user ring buffers]'
+    '(-k --kernel)--buffers-pid[use per-process ring buffers]'
+    '(-u --userspace --blocking-timeout)--buffers-global[use global ring buffers]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `enable-event` command.
+__lttng_complete_enable_event_cmd() {
+  local -r kernel_opts_excl=(
+    -k --kernel
+    --syscall
+    --probe
+    --userspace-probe
+    --function
+  )
+  local -r non_kernel_opts_excl=(
+    $non_kernel_domain_opt_excl
+    -x --exclude
+    log-level
+  )
+  local -r exclude_opt_excl=(
+    $kernel_opts_excl
+    -j --jul
+    -l --log4j
+    -p --python
+    -x --exclude
+  )
+  local ip_specs=(
+    '--tracepoint[only match LTTng tracepoint events]'
+    "($non_kernel_opts_excl)--syscall[only match Linux system call events]"
+    "($non_kernel_opts_excl)--probe=[only match kprobe events]:kprobe location:"
+    "($non_kernel_opts_excl)--function=[only match kretprobe events]:kretprobe location:"
+  )
+  local domain_specs=(
+    "($non_kernel_opts_excl)"{-k,--kernel}'[select the Linux kernel tracing domain]'
+    "($kernel_opts_excl)"{-u,--userspace}'[select the user space tracing domain]'
+    "($kernel_opts_excl -x --exclude)"{-j,--jul}'[select the `java.util.logging` tracing domain]'
+  )
+
+  # The Apache log4j tracing domain options require LTTng-tools ≥ 2.6
+  if ((minor_version >= 6)); then
+    domain_specs+=(
+      "($kernel_opts_excl -x --exclude)"{-l,--log4j}'[select the Apache log4j tracing domain]'
+    )
+  fi
+
+  # The Python tracing domain options require LTTng-tools 2.7
+  if ((minor_version >= 7)); then
+    domain_specs+=(
+      "($kernel_opts_excl -x --exclude)"{-p,--python}'[select the Python tracing domain]'
+    )
+  fi
+
+  # The Linux user space probe instrumentation options require LTTng-tools 2.11
+  if ((minor_version >= 11)); then
+    ip_specs+=(
+      "($non_kernel_opts_excl)--userspace-probe=[only match Linux user space probe events]:user space probe location:"
+    )
+  fi
+
+  # Add completions.
+  #
+  # There's no way, based on the command-line arguments, to distinguish
+  # between creating a new recording event rule and enabling an
+  # existing, disabled recording event rule here.
+  #
+  # For example, given this:
+  #
+  #     $ lttng enable-event --kernel --syscall <TAB>
+  #
+  # At this point, the user might want the list of existing, disabled
+  # kernel system call recording event rule names (current recording
+  # session, default channel name), or the full list of available system
+  # call instrumentation point names.
+  #
+  # This function makes the arbitrary choice to provide the available
+  # instrumentation point names (__lttng_complete_ip_name()) because,
+  # interactively, it seems to be more common/useful than disabling
+  # existing recording event rules.
+  local -r specs=(
+    $help_opt_specs
+    '(--probe --userspace-probe --function -f --filter)'{-f+,--filter=}'[only match events which satisfy an expression]:filter expression:'
+    "($exclude_opt_excl)"{-x+,--exclude=}'[exclude event name patterns]:comma-separated list of patterns:'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '(-c --channel)'{-c+,--channel=}'[select a specific channel]: : __lttng_complete_channel_name all opt'
+    + '(log-level)'
+    "($kernel_opts_excl)--loglevel=[only match events with specific log levels]: : __lttng_complete_log_level"
+    "($kernel_opts_excl)--loglevel-only=[only match events with an exact log level]: : __lttng_complete_log_level"
+    + '(names)'
+    {-a,--all}'[match events regardless of their name]'
+    ': :_sequence __lttng_complete_ip_name'
+    + '(ip)' $ip_specs
+    + '(domain)' $domain_specs
+  )
+
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `enable-rotation` command.
+__lttng_complete_enable_rotation_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '--timer=[rotate periodically]:period (µs; `ms`/`s`/`m`/`h` suffixes supported):'
+    '--size=[rotate based on flushed size of current trace chunk]:size (bytes; `k`/`M`/`G` suffixes supported):'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `help` command.
+__lttng_complete_help_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ': : __lttng_complete_cmd_name'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `list` command.
+__lttng_complete_list_cmd() {
+  local -r domain_opt_excl=(
+    -d --domain
+    -f --fields
+    -c --channel
+    -k --kernel
+    -u --userspace
+    -j --jul
+    -l --log4j
+    -p --python
+    --syscall
+  )
+  local specs=(
+    $help_opt_specs
+    '(-d --domain -f --fields --syscall -c --channel 1)'{-f,--fields}'[show instrumentation point fields]'
+    "($domain_opt_excl)"{-d,--domain}'[show tracing domains with at least one channel]'
+    '(-d --domain -f --fields --syscall -c --channel)'{-c+,--channel=}'[list the objects of a specific channel]: : __lttng_complete_channel_name all arg'
+    '(-d --domain -f --fields --syscall):recording session name: __lttng_complete_session_name all all'
+    '(-d --domain -k --kernel)'{-k,--kernel}'[list Linux kernel tracing domain objects]'
+    '(-d --domain -u --userspace)'{-u,--userspace}'[list user space tracing domain objects]'
+    '(-d --domain -j --jul)'{-j,--jul}'[list `java.util.logging` tracing domain objects]'
+  )
+
+  # The Apache log4j tracing domain and `--syscall` options require
+  # LTTng-tools ≥ 2.6.
+  if ((minor_version >= 6)); then
+    specs+=(
+      '(-d --domain -l --log4j)'{-l,--log4j}'[list Apache log4j tracing domain objects]'
+      '(-d --domain)--syscall[list Linux kernel system calls]'
+    )
+  fi
+
+  # The Python tracing domain options require LTTng-tools 2.7
+  if ((minor_version >= 7)); then
+    specs+=(
+      '(-d --domain -p --python)'{-p,--python}'[list Python tracing domain objects]'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `list-triggers` command.
+__lttng_complete_list_triggers_cmd() {
+  __lttng_arguments $help_opt_specs
+}
+
+# Adds completions for the arguments of the `load` command.
+__lttng_complete_load_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-f --force)'{-f,--force}'[overwrite existing recording sessions]'
+    '(-i --input-path)'{-i+,--input-path=}'[load recording session configurations from a specific path]:recording session configuration path:_files'
+    '(-a --all --override-name 1)'{-a,--all}'[load all recording session configurations]'
+    '(-a --all):recording session configuration name:_guard "^-*" "recording session name"'
+  )
+
+  if ((minor_version >= 9)); then
+    specs+=(
+      '--override-url=[override the loaded recording session output URL]:output URL:'
+      '(-a --all)--override-name=[override the loaded recording session name]:recording session name:'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `metadata` command
+# (deprecated).
+__lttng_complete_metadata_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ':action:(regenerate)'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `regenerate` command.
+__lttng_complete_regenerate_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ':trace data type:(metadata statedump)'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `remove-trigger` command.
+__lttng_complete_remove_trigger_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '--owner-uid=[remove the trigger as another Unix user]: : __lttng_complete_uid'
+    ': : __lttng_complete_trigger_name'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `rotate` command.
+__lttng_complete_rotate_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-n --no-wait)'{-n,--no-wait}'[exit immediately]'
+    ': : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `save` command.
+__lttng_complete_save_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-f --force)'{-f,--force}'[overwrite existing recording session configuration files]'
+    '(-o --output-path)'{-o+,--output-path=}'[save recording session configuration files to a specific directory]:recording session configuration directory:_files -/'
+    '(-a --all 1)'{-a,--all}'[save all recording session configurations]'
+    '(-a --all): : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `set-session` command.
+__lttng_complete_set_session_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ': : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `snapshot` command.
+__lttng_complete_snapshot_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-): : __lttng_complete_snapshot_action_name' \
+    '(-)*:: :->action-args' \
+  )
+
+  # Add action name completions
+  local curcontext=$curcontext state state_descr line
+  local -A opt_args
+
+  _arguments -C -s -W : $specs
+
+  if (($? == 0)); then
+    # Completions added: we're done
+    return
+  fi
+
+  # Add action-specific completions
+  local -r common_session_specs=(
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all snapshot'
+  )
+  local -r common_output_specs=(
+    '(-m --max-size)'{-m+,--max-size=}'[set the maximum total size of all snapshot files]:maximum size (bytes; `k`/`M`/`G` suffixes supported):'
+    '(-n --name)'{-n+,--name=}'[set the snapshot output name]:snapshot output name:'
+    '(1 -C --ctrl-url output)'{-C+,--ctrl-url=}'[set the control URL]:control URL:'
+    '(1 -D --data-url output)'{-D+,--data-url=}'[set the trace data output URL]:trace data output URL:'
+    '(-C --ctrl-url -D --data-url): :_guard "^-*" "snapshot output URL"'
+  )
+
+  if [[ $state[1] = action-args ]]; then
+    # Add completions for the arguments of the specific snapshot action
+    curcontext=${curcontext%:*:*}:lttng-snapshot-$line[1]:
+
+    case $line[1] in
+      add-output | record)
+        specs=($common_session_specs $common_output_specs);;
+      del-output)
+        specs=($common_session_specs ':snapshot output index:(1)');;
+      list-output)
+        specs=($common_session_specs);;
+      *)
+        _message "unknown snapshot action \`$line[1]\`"
+        return 1
+        ;;
+    esac
+
+    # Add completions
+    __lttng_arguments $specs
+    return
+  fi
+
+  return 1
+}
+
+# Adds completions for the arguments of the `start` command.
+__lttng_complete_start_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ': : __lttng_complete_session_name inactive all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `stop` command.
+__lttng_complete_stop_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-n --no-wait)'{-n,--no-wait}'[exit immediately]'
+    ': : __lttng_complete_session_name active all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `status` command.
+__lttng_complete_status_cmd() {
+  __lttng_arguments $help_opt_specs
+}
+
+# Adds completions for the arguments of the `track` command.
+__lttng_complete_track_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '(-a --all)'{-a,--all}'[add all possible values to the selected inclusion sets]'
+    '(-p --pid)'{-p+,--pid=}'[add values to the process ID inclusion set]:process ID(s):_sequence _pids'
+  )
+
+  # Virtual PID and user/group inclusion sets require LTTng-tools ≥ 2.12
+  if ((minor_version >= 12)); then
+    specs+=(
+      '--vpid=[add values to the virtual process ID inclusion set]:virtual process ID(s):_sequence _pids'
+      '(-u --userspace)--uid=[add values to the user ID inclusion set]:user(s):_sequence _users'
+      '--vuid=[add values to the virtual user ID inclusion set]:virtual user(s):_sequence _users'
+      '(-u --userspace)--gid=[add values to the group ID inclusion set]:group(s):_sequence _groups'
+      '--vgid=[add values to the virtual group ID inclusion set]:virtual group(s):_sequence _groups'
+    )
+  fi
+
+  # Append tracing domain specifications
+  specs+=(
+    + '(domain)'
+    {-k,--kernel}'[select the Linux kernel tracing domain]'
+    "(--uid --gid)"{-u,--userspace}'[select the user space tracing domain]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `untrack` command.
+__lttng_complete_untrack_cmd() {
+  # As of LTTng-tools 2.13, the `track` and `untrack` commands expect
+  # the same arguments.
+  __lttng_complete_track_cmd
+}
+
+# Adds completions for the arguments of the `version` command.
+__lttng_complete_version_cmd() {
+  __lttng_arguments $help_opt_specs
+}
+
+# Adds completions for the arguments of the `view` command.
+__lttng_complete_view_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-e --viewer)'{-e+,--viewer=}'[set the trace reader path]:trace reader path:_files'
+    '(-t --trace-path): : __lttng_complete_session_name all all'
+    '(1 -t --trace-path)'{-t+,--trace-path=}'[set the trace directory to pass to the reader]:trace directory:_files -/'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Add completions for the specific `lttng` command named `$line[1]`.
+__lttng_complete_cmd() {
+  # An lttng(1) command: replace `lttng` with `lttng-$line[1]` (for
+  # example, `lttng-add-trigger`).
+  curcontext=${curcontext%:*:*}:lttng-$line[1]:
+
+  # Keep the tracing group: we need to execute `lttng` for some
+  # completions and use the required tracing group to connect to the
+  # same session daemon.
+  #
+  # The default tracing group is `tracing`.
+  local tracing_group=tracing
+
+  if (($+opt_args[-g])); then
+    tracing_group=$opt_args[-g]
+  elif (($+opt_args[--group])); then
+    tracing_group=$opt_args[--group]
+  fi
+
+  # Add command completions: dispatch to a dedicated function
+  local -r func_name=__lttng_complete_${line[1]//-/_}_cmd
+
+  if ! typeset -f $func_name >/dev/null; then
+    _message "unknown command \`$line[1]\`"
+    return 1
+  fi
+
+  local -A opt_args
+
+  $func_name
+}
+
+# Save program name
+local -r prog_name=$words[1]
+
+# First, set the `minor_version` variable to the minor version of
+# LTTng-tools. Some features depend on a specific version and this
+# completion function supports many versions from LTTng-tools 2.5.
+local -i minor_version
+
+__lttng_set_minor_version
+
+# Exit now with LTTng-tools < 2.5 or LTTng-tools > 2.14
+local -r ignore_version_limit=${LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT:-0}
+
+if ((minor_version < 5 || (minor_version > 14 && !ignore_version_limit))); then
+  _message "completion not available for LTTng-tools 2.$minor_version; please update the completion files or set \`LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1\`"
+  return 1
+fi
+
+# Common help option specifications
+local -r help_opt_specs=(
+  '(- : *)'{-h,--help}'[show help]'
+)
+
+# Common non Linux kernel tracing domain option exclusions
+local -r non_kernel_domain_opt_excl=(-u --userspace -j --jul -l --log4j -p --python)
+
+# General option specifications
+local gen_opt_specs=(
+  $help_opt_specs
+  '(- : *)--list-commands[list the available commands and quit]'
+  '--relayd-path=[set the relay daemon path]:relay daemon path:_files -g \*lttng-relayd'
+  '--group=[set the tracing group]:tracing group:_groups'
+  '(-q --quiet)*'{-v,--verbose}'[increase verbosity]'
+  '(-q --quiet -v --verbose)'{-q,--quiet}'[suppress all messages, including warnings and errors]'
+  '(- : *)'{-V,--version}'[show version and quit]'
+)
+
+# MI output requires LTTng-tools ≥ 2.6
+if ((minor_version >= 6)); then
+  gen_opt_specs+=(
+    '(-m --mi)'{-m+,--mi=}'[use the machine interface output]:machine interface type:(xml)'
+  )
+fi
+
+# Append session daemon option specifications
+gen_opt_specs+=(
+  + '(sessiond)'
+  {-n,--no-sessiond}'[do not spawn a session daemon]'
+  '--sessiond-path=[set the session daemon path]:session daemon path:_files -g \*lttng-sessiond'
+)
+
+# Add general option and command name completions
+local curcontext=$curcontext state state_descr line
+local -A opt_args
+
+_arguments -C -s -W : \
+  '(-): : __lttng_complete_cmd_name' \
+  '(-)*:: :->cmd-args' \
+  $gen_opt_specs
+
+local -ir main_ret=$?
+
+if ((main_ret == 0)); then
+  # Completions added: we're done
+  return
+fi
+
+if [[ $state[1] = cmd-args ]]; then
+  # Add completions for the arguments of the specific command
+  __lttng_complete_cmd
+  return
+fi
+
+return $main_ret
diff --git a/extras/zsh-completion/_lttng-crash b/extras/zsh-completion/_lttng-crash
new file mode 100644 (file)
index 0000000..f595217
--- /dev/null
@@ -0,0 +1,75 @@
+#compdef lttng-crash
+#
+# Copyright (c) 2015-2023 Philippe Proulx <eeppeliteloop@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#
+# This is a Zsh completion function for the lttng-crash(1) command (see
+# <https://lttng.org/>), for versions 2.7 to 2.14.
+#
+# If you want, at your own risk, the function to work with versions
+# above 2.14, set `LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1`.
+
+# Sets the `minor_version` variable to the minor version of LTTng-tools,
+# or to `0` if not found.
+__lttng_set_minor_version() {
+  minor_version=0
+
+  local -a match
+
+  if [[ $($words[1] --version) =~ '[[:blank:]]+2\.([[:digit:]]+)' ]]; then
+    minor_version=$match[1]
+  fi
+}
+
+# Adds completions for the arguments of the `lttng-crash` command.
+__lttng_complete_lttng_crash() {
+  local curcontext=$curcontext state state_descr line
+  local -A opt_args
+  local specs=(
+    '*'{-v,--verbose}'[increase verbosity]'
+    '(- : *)'{-V,--version}'[show version and quit]'
+    '(- : *)'{-h,--help}'[show help]'
+    '(-x --extract)'{-x+,--extract=}'[set the path of the directory where to extract the trace]:trace extraction directory path:_directories'
+    '(-e --viewer)'{-e+,--viewer=}'[set the trace reader command]:trace reader command:_files'
+    '1:shared memory directory:_directories'
+  )
+
+  _arguments -C -s -w : $specs
+}
+
+# First, set the `minor_version` variable to the minor version of
+# LTTng-tools. Some features depend on a specific version and this
+# completion function supports many versions from LTTng-tools 2.7.
+local -i minor_version
+
+__lttng_set_minor_version
+
+# Exit now with LTTng-tools < 2.7 or LTTng-tools > 2.14
+local -r ignore_version_limit=${LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT:-0}
+
+if ((minor_version < 7 || (minor_version > 14 && !ignore_version_limit))); then
+  _message "completion not available for LTTng-tools 2.$minor_version; please update the completion files or set \`LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1\`"
+  return 1
+fi
+
+# Add completions for lttng-crash(1)
+__lttng_complete_lttng_crash "$@"
diff --git a/extras/zsh-completion/_lttng-relayd b/extras/zsh-completion/_lttng-relayd
new file mode 100644 (file)
index 0000000..8d1140f
--- /dev/null
@@ -0,0 +1,93 @@
+#compdef lttng-relayd
+#
+# Copyright (c) 2015-2023 Philippe Proulx <eeppeliteloop@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#
+# This is a Zsh completion function for the lttng-relayd(1) command
+# (see <https://lttng.org/>), for versions 2.5 to 2.14.
+#
+# If you want, at your own risk, the function to work with versions
+# above 2.14, set `LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1`.
+
+# Sets the `minor_version` variable to the minor version of LTTng-tools,
+# or to `0` if not found.
+__lttng_set_minor_version() {
+  minor_version=0
+
+  local -a match
+
+  if [[ $($words[1] --version) =~ '2\.([[:digit:]]+)' ]]; then
+    minor_version=$match[1]
+  fi
+}
+
+# Adds completions for the arguments of the `lttng-relayd` command.
+__lttng_complete_lttng_relayd() {
+  local curcontext=$curcontext state state_descr line
+  local -A opt_args
+
+  # LTTng-tools 2.5+
+  local specs=(
+    '*'{-v,--verbose}'[increase verbosity]'
+    '(- : *)'{-V,--version}'[show version and quit]'
+    '(- : *)'{-h,--help}'[show help]'
+    '(-d --daemonize -b --background)'{-d,--daemonize}'[start as daemon and close file descriptors (console)]'
+    '(-b --background -d --daemonize)'{-b,--background}'[start as daemon, but keep file descriptors (console) open]'
+    '(-C --control-port)'{-C+,--control-port=}'[set the control port URL]:control port URL: '
+    '(-D --data-port)'{-D+,--data-port=}'[set the data port URL]:data port URL: '
+    '(-L --live-port)'{-L+,--live-port=}'[set the live port URL]:live port URL: '
+    '(-o --output)'{-o+,--output=}'[set the trace output directory path]:trace output directory path:_directories'
+    '(-g --group)'{-g+,--group=}'[set the Unix tracing group name]:Unix tracing group name:_groups'
+    '(-f --config)'{-f+,--config=}'[set the path to the INI daemon configuration file]:configuration file path:_files'
+  )
+
+  # LTTng-tools 2.12+
+  if ((minor_version >= 12)); then
+    specs+=(
+      '(--fd-pool-size)--fd-pool-size=[set the size of the file descriptor pool]:file descriptor pool size: '
+      '(-w --working-directory)'{-w+,--working-directory=}'[set the working directory of the processes `lttng-relayd` creates]:working directory:_directories'
+      '(-p --group-output-by-host -s --group-output-by-session)'{-p,--group-output-by-host}'[group the written trace directories by hostname]'
+      '(-p --group-output-by-host -s --group-output-by-session)'{-s,--group-output-by-session}'[group the written trace directories by recording session name]'
+      '(-x --disallow-clear)'{-x,--disallow-clear}'[disallow clearing operations]'
+    )
+  fi
+
+  _arguments -C -s -w : $specs
+}
+
+# First, set the `minor_version` variable to the minor version of
+# LTTng-tools. Some features depend on a specific version and this
+# completion function supports many versions from LTTng-tools 2.5.
+local -i minor_version
+
+__lttng_set_minor_version
+
+# Exit now with LTTng-tools < 2.5 or LTTng-tools > 2.14
+local -r ignore_version_limit=${LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT:-0}
+
+if ((minor_version < 5 || (minor_version > 14 && !ignore_version_limit))); then
+  _message "completion not available for LTTng-tools 2.$minor_version; please update the completion files or set \`LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1\`"
+  return 1
+fi
+
+# Add completions for lttng-relayd(1)
+__lttng_complete_lttng_relayd "$@"
diff --git a/extras/zsh-completion/_lttng-sessiond b/extras/zsh-completion/_lttng-sessiond
new file mode 100644 (file)
index 0000000..7388c0c
--- /dev/null
@@ -0,0 +1,153 @@
+#compdef lttng-sessiond
+#
+# Copyright (c) 2015-2023 Philippe Proulx <eeppeliteloop@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#
+# This is a Zsh completion function for the lttng-sessiond(1) command
+# (see <https://lttng.org/>), for versions 2.5 to 2.14.
+#
+# If you want, at your own risk, the function to work with versions
+# above 2.14, set `LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1`.
+
+# Sets the `minor_version` variable to the minor version of LTTng-tools,
+# or to `0` if not found.
+__lttng_set_minor_version() {
+  minor_version=0
+
+  local -a match
+
+  if [[ $($words[1] --version) =~ '2\.([[:digit:]]+)' ]]; then
+    minor_version=$match[1]
+  fi
+}
+
+# Adds completions for an LTTng kernel probe name.
+__lttng_complete_probe_modules() {
+  # Find relevant kernel module files
+  local dir="/usr/lib/modules/$(uname -r)/extra"
+
+  if [[ ! -d $dir ]]; then
+    dir="/usr/lib/modules/$(uname -r)/updates"
+
+    if [[ ! -d $dir ]]; then
+      _message "cannot find directory \"$dir\""
+      return 1
+    fi
+  fi
+
+  local -a probe_files=("$dir"/**/lttng-probe-*.(ko|ko.gz|ko.zst)(:t))
+
+  if (($#probe_files == 0)); then
+    _message "no probe modules found in \"$dir\""
+    return 1
+  fi
+
+  # Strip prefix and extension
+  probe_files=(${probe_files#lttng-probe-})
+  probe_files=(${probe_files%.gz})
+  probe_files=(${probe_files%.zst})
+  probe_files=(${probe_files%.ko})
+
+  # Add completions
+  local expl
+
+  compadd "$@" -a - probe_files
+}
+
+# Adds completions for the arguments of the `lttng-sessiond` command.
+__lttng_complete_lttng_sessiond() {
+  local curcontext=$curcontext state state_descr line
+  local -A opt_args
+
+  # LTTng-tools 2.5+
+  local specs=(
+    '(-q --quiet)*'{-v,--verbose}'[increase verbosity]'
+    '(-q --quiet -v --verbose)'{-q,--quiet}'[suppress all messages, including warnings and errors]'
+    '(- : *)'{-V,--version}'[show version and quit]'
+    '(- : *)'{-h,--help}'[show help]'
+    '(-c --client-sock)'{-c+,--client-sock=}'[set the path to the client Unix socket]:client Unix socket path:_files'
+    '(-a --apps-sock)'{-a+,--apps-sock=}'[set the path to the app Unix socket]:app Unix socket path:_files'
+    '--kconsumerd-err-sock=[set the path to the kernel consumer daemon error socket]:kernel consumer daemon error Unix socket path:_files'
+    '--kconsumerd-cmd-sock=[set the path to the kernel consumer daemon command socket]:kernel consumer daemon command Unix socket path:_files'
+    '--ustconsumerd32-err-sock=[set the path to the 32-bit UST consumer daemon error Unix socket]:32-bit UST consumer daemon error Unix socket path:_files'
+    '--ustconsumerd32-cmd-sock=[set the path to the 32-bit UST consumer daemon command Unix socket]:32-bit UST consumer daemon command Unix socket path:_files'
+    '--ustconsumerd64-err-sock=[set the path to the 64-bit UST consumer daemon error Unix socket]:64-bit UST consumer daemon error Unix socket path:_files'
+    '--ustconsumerd64-cmd-sock=[set the path to the 64-bit UST consumer daemon command Unix socket]:64-bit UST consumer daemon command Unix socket path:_files'
+    '--consumerd32-path=[set the path to the 32-bit UST consumer daemon]:32-bit UST consumer daemon path:_files'
+    '--consumerd32-libdir=[set the path to the directory containing 32-bit UST consumer daemon libraries]:32-bit UST consumer daemon libraries directory path:_directories'
+    '--consumerd64-path=[set the path to the 64-bit UST consumer daemon]:64-bit UST consumer daemon path:_files'
+    '--consumerd64-libdir=[set the path to the directory containing 64-bit UST consumer daemon libraries]:64-bit UST consumer daemon libraries directory path:_directories'
+    '(-d --daemonize -b --background)'{-d,--daemonize}'[start as daemon and close file descriptors (console)]'
+    '(-b --background -d --daemonize)'{-b,--background}'[start as daemon, but keep file descriptors (console) open]'
+    '(-g --group)'{-g+,--group=}'[set the Unix tracing group name]:Unix tracing group name:_groups'
+    '(-S --sig-parent)'{-S,--sig-parent}'[send the USR1 signal to the parent process to notify readiness]'
+    '(-p --pidfile)'{-p+,--pidfile=}'[set the path to the PID file]:PID file path:_files'
+    "--verbose-consumer[increase verbosity of consumer daemon]"
+    '(--kmod-probes --extra-kmod-probes)--no-kernel[disable the kernel tracer]'
+    '(-f --config)'{-f+,--config=}'[set the path to the INI daemon configuration file]:configuration file path:_files'
+    '(-l --load)'{-l+,--load=}'[set the path from which to load recording session configurations]:recording session configurations path:_files'
+    '(--no-kernel --kmod-probes)--extra-kmod-probes=[extra kernel probe modules to load]:kernel probe module:_sequence __lttng_complete_probe_modules'
+  )
+
+  # LTTng-tools 2.5 only
+  if ((minor_version == 5)); then
+    specs+=(
+      '--jul-tcp-port=[set the TCP port on which to listen for `java.util.logging` application registration]:JUL application registration TCP port: '
+    )
+  fi
+
+  # LTTng-tools 2.6+
+  if ((minor_version >= 6)); then
+    specs+=(
+      '--agent-tcp-port=[set the TCP port on which to listen for agent application registration]:agent application registration TCP port: '
+      '(--no-kernel --extra-kmod-probes)--kmod-probes=[kernel probe modules to load]:kernel probe module:_sequence __lttng_complete_probe_modules'
+    )
+  fi
+
+  # LTTng-tools 2.13+
+  if ((minor_version >= 13)); then
+    specs+=(
+      '--event-notifier-error-buffer-size-kernel=[set the size of the kernel event notifier error counter buffers]:kernel event notifier error counter buffer size (slots): '
+      '--event-notifier-error-buffer-size-userspace=[set the size of the user space event notifier error counter buffers]:user space event notifier error counter buffer size (slots): '
+    )
+  fi
+
+  _arguments -C -s -w : $specs
+}
+
+# First, set the `minor_version` variable to the minor version of
+# LTTng-tools. Some features depend on a specific version and this
+# completion function supports many versions from LTTng-tools 2.5.
+local -i minor_version
+
+__lttng_set_minor_version
+
+# Exit now with LTTng-tools < 2.5 or LTTng-tools > 2.14
+local -r ignore_version_limit=${LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT:-0}
+
+if ((minor_version < 5 || (minor_version > 14 && !ignore_version_limit))); then
+  _message "completion not available for LTTng-tools 2.$minor_version; please update the completion files or set \`LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1\`"
+  return 1
+fi
+
+# Add completions for lttng-sessiond(1)
+__lttng_complete_lttng_sessiond "$@"
This page took 0.046245 seconds and 4 git commands to generate.