ybox 0.9.8.1__py3-none-any.whl → 0.9.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. ybox/__init__.py +1 -1
  2. ybox/cmd.py +17 -1
  3. ybox/conf/completions/ybox.fish +2 -0
  4. ybox/conf/distros/arch/init-user.sh +2 -2
  5. ybox/conf/distros/arch/init.sh +1 -0
  6. ybox/conf/distros/arch/pkgdeps.py +2 -0
  7. ybox/conf/distros/deb-generic/pkgdeps.py +2 -1
  8. ybox/conf/profiles/apps.ini +10 -5
  9. ybox/conf/profiles/basic.ini +48 -23
  10. ybox/conf/profiles/dev.ini +4 -6
  11. ybox/conf/resources/entrypoint-cp.sh +1 -1
  12. ybox/conf/resources/entrypoint-root.sh +4 -3
  13. ybox/conf/resources/entrypoint-user.sh +5 -3
  14. ybox/conf/resources/entrypoint.sh +24 -22
  15. ybox/conf/resources/prime-run +0 -2
  16. ybox/conf/resources/run-in-dir +30 -16
  17. ybox/conf/resources/run-user-bash-cmd +17 -1
  18. ybox/conf/resources/ybox-systemd.template +24 -0
  19. ybox/config.py +9 -1
  20. ybox/env.py +18 -7
  21. ybox/migrate/{0.9.0-0.9.7:0.9.8.py → 0.9.0-0.9.10:0.9.11.py} +6 -5
  22. ybox/pkg/clean.py +1 -7
  23. ybox/pkg/info.py +1 -7
  24. ybox/pkg/inst.py +40 -22
  25. ybox/pkg/list.py +1 -6
  26. ybox/pkg/mark.py +1 -1
  27. ybox/pkg/repair.py +4 -0
  28. ybox/pkg/search.py +1 -7
  29. ybox/run/cmd.py +2 -1
  30. ybox/run/control.py +107 -25
  31. ybox/run/create.py +254 -63
  32. ybox/run/destroy.py +89 -4
  33. ybox/run/graphics.py +37 -17
  34. ybox/run/logs.py +2 -1
  35. ybox/run/ls.py +2 -1
  36. ybox/run/pkg.py +49 -7
  37. ybox/state.py +22 -3
  38. ybox/util.py +5 -5
  39. {ybox-0.9.8.1.dist-info → ybox-0.9.11.dist-info}/METADATA +68 -34
  40. ybox-0.9.11.dist-info/RECORD +77 -0
  41. {ybox-0.9.8.1.dist-info → ybox-0.9.11.dist-info}/WHEEL +1 -1
  42. ybox-0.9.8.1.dist-info/RECORD +0 -76
  43. {ybox-0.9.8.1.dist-info → ybox-0.9.11.dist-info}/entry_points.txt +0 -0
  44. {ybox-0.9.8.1.dist-info → ybox-0.9.11.dist-info/licenses}/LICENSE +0 -0
  45. {ybox-0.9.8.1.dist-info → ybox-0.9.11.dist-info}/top_level.txt +0 -0
ybox/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  """`ybox` is a tool to easily manage linux distributions in containers"""
2
- __version__ = "0.9.8.1"
2
+ __version__ = "0.9.11"
ybox/cmd.py CHANGED
@@ -10,6 +10,7 @@ import sys
10
10
  from enum import Enum
11
11
  from typing import Callable, Iterable, Optional, Union
12
12
 
13
+ from ybox import __version__ as product_version
13
14
  from ybox.config import Consts
14
15
 
15
16
  from .print import print_error, print_info, print_notice, print_warn
@@ -207,7 +208,7 @@ def run_command(cmd: Union[str, list[str]], capture_output: bool = False,
207
208
  sys.exit(result.returncode)
208
209
  else:
209
210
  return result.returncode
210
- if capture_output and result.stderr:
211
+ if capture_output and result.stderr and error_msg != "SKIP":
211
212
  print_warn(result.stderr.decode("utf-8"), file=sys.stderr)
212
213
  return result.stdout.decode("utf-8") if capture_output else result.returncode
213
214
 
@@ -221,6 +222,21 @@ def _print_subprocess_output(result: subprocess.CompletedProcess[bytes]) -> None
221
222
  print_warn(result.stderr.decode("utf-8"), file=sys.stderr)
222
223
 
223
224
 
225
+ def parser_version_check(parser: argparse.ArgumentParser, argv: list[str]) -> None:
226
+ """
227
+ Update command-line parser to add `--version` option to existing ones that will output the
228
+ ybox product version and exit if specified in the given list of arguments.
229
+
230
+ :param parser: instance of :class:`argparse.ArgumentParser` having the command-line parser
231
+ :param argv: the list of arguments to be parsed
232
+ """
233
+ parser.add_argument("--version", action="store_true", help="output ybox version")
234
+ # argv may have required positional arguments, hence check for --version separately
235
+ if "--version" in argv:
236
+ print(product_version)
237
+ sys.exit(0)
238
+
239
+
224
240
  def parse_opt_deps_args(argv: list[str]) -> argparse.Namespace:
225
241
  """
226
242
  Common command-line parser for `opt_deps` utilities (see [pkgmgr] section of distro.ini)
@@ -29,6 +29,8 @@ end
29
29
  complete -f -c ybox-create -s h -l help -d "show help"
30
30
  complete -c ybox-create -s n -l name -d "name of the ybox container" -r
31
31
  complete -f -c ybox-create -s F -l force-own-orphans -d "force ownership of orphans on shared root"
32
+ complete -f -c ybox-create -s C -l distribution-config -d "path to custom distribution configuration file"
33
+ complete -f -c ybox-create -l distribution-image -d "custom container image"
32
34
  complete -f -c ybox-create -s q -l quiet -d "skip interactive questions"
33
35
  complete -f -c ybox-create -n "not __fish_seen_subcommand_from (__fish_ybox_complete_distributions)" -a "(__fish_ybox_complete_distributions)"
34
36
 
@@ -10,8 +10,8 @@ current_user="$(id -un)"
10
10
  # install binaries for paru from paru-bin (paru takes too long to compile)
11
11
  PARU="paru --noconfirm"
12
12
  echo_color "$fg_cyan" "Installing AUR helper 'paru'" >> $status_file
13
- export HOME="$(eval echo "~$current_user")"
14
- cd ~
13
+ export HOME=$(getent passwd "$current_user" | cut -d: -f6)
14
+ cd "$HOME"
15
15
  rm -rf paru-bin
16
16
  git clone https://aur.archlinux.org/paru-bin.git
17
17
  cd paru-bin
@@ -6,6 +6,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
6
 
7
7
  source "$SCRIPT_DIR/entrypoint-common.sh"
8
8
 
9
+ export HOME=/root
9
10
  # pacman configuration
10
11
  PAC="pacman --noconfirm"
11
12
  echo_color "$fg_cyan" "Configuring pacman" >> $status_file
@@ -17,6 +17,8 @@ where:
17
17
  newlines in the description
18
18
  """
19
19
 
20
+ # TODO: SW: this is returning back installed packages too which should be skipped
21
+
20
22
  import gzip
21
23
  import os
22
24
  import re
@@ -11,7 +11,7 @@ where:
11
11
  and so on; resolution of level > 2 is not required since caller currently ignores those
12
12
  * <order>: this is a simple counter assigned to the dependencies where the value itself is of no
13
13
  significance but if multiple dependencies have the same value then it means that they
14
- are ORed dependencies and only one of them should normlly be selected for installation
14
+ are ORed dependencies and only one of them need to be selected for installation
15
15
  * <installed>: true if the dependency already installed and false otherwise
16
16
  * <description>: detailed description of the dependency; it can contain literal \n to indicate
17
17
  newlines in the description
@@ -69,6 +69,7 @@ class PkgDetail(Enum):
69
69
  OPTIONAL_DEP = 5
70
70
 
71
71
 
72
+ # noinspection PyUnusedLocal
72
73
  def process_next_item(line: str, parse_line: Callable[[str], tuple[PkgDetail, str]],
73
74
  parse_dep: Callable[[str], Iterable[tuple[str, str, Optional[str]]]],
74
75
  installed: Callable[[str], bool], max_level: int,
@@ -1,6 +1,7 @@
1
1
  [base]
2
2
  name = Profile for CLI and GUI apps
3
3
  includes = basic.ini
4
+ ssh_agent = on
4
5
 
5
6
  [security]
6
7
  # SYS_PTRACE may be required by mesa which is invoked indirectly by both firefox and chromium.
@@ -9,6 +10,9 @@ includes = basic.ini
9
10
  caps_add = SYS_PTRACE
10
11
 
11
12
  [mounts]
13
+ # export the host's ssh keys for use by ssh-agent in the container as required ("ro" mode
14
+ # implies that known_hosts and other files within ~/.ssh cannot be changed)
15
+ ssh = $HOME/.ssh:$TARGET_HOME/.ssh:ro
12
16
  music = $HOME/Music:$TARGET_HOME/Music:ro
13
17
  pictures = $HOME/Pictures:$TARGET_HOME/Pictures:ro
14
18
  videos = $HOME/Videos:$TARGET_HOME/Videos:ro
@@ -19,8 +23,9 @@ videos = $HOME/Videos:$TARGET_HOME/Videos:ro
19
23
 
20
24
  [app_flags]
21
25
  # These flags will be added to Exec line of google-chrome.desktop when it is copied to host.
22
- # /dev/shm usage is disabled for chrome because that requires ipc=host or mounting host
23
- # /dev/shm in read-write mode which can be insecure.
24
- google-chrome = !p --disable-dev-shm-usage !a
25
- google-chrome-beta = !p --disable-dev-shm-usage !a
26
- google-chrome-unstable = !p --disable-dev-shm-usage !a
26
+
27
+ # the --disable-dev-shm-usage flag in chrome/chromium based browsers disables use of /dev/shm
28
+ # which can reduce memory footprint at the cost of performance and increased disk activity
29
+ #google-chrome = !p --disable-dev-shm-usage !a
30
+ #google-chrome-beta = !p --disable-dev-shm-usage !a
31
+ #google-chrome-unstable = !p --disable-dev-shm-usage !a
@@ -20,7 +20,8 @@
20
20
  # - YBOX_SYS_CONF_DIR: path to system configuration directory where configuration directory
21
21
  # shipped with ybox is installed (or the string form of
22
22
  # the directory if it is not on filesystem like an egg or similar)
23
- # - TARGET_HOME: set to the home directory of the container user
23
+ # - TARGET_HOME: set to the home directory of the container user in the container
24
+ # (which is same as the host user's $HOME for podman and /root for docker)
24
25
  # Additionally a special notation can be used for current date+time with this notation:
25
26
  # ${NOW:<fmt>}. The <fmt> uses the format supported by python strftime
26
27
  # (https://docs.python.org/3/library/datetime.html#datetime.datetime.strftime)
@@ -66,7 +67,7 @@ includes =
66
67
  # to freely create as many containers as desired to achieve best isolation without worrying
67
68
  # about dramatic increase in disk and/or memory usage.
68
69
  shared_root = $HOME/.local/share/ybox/SHARED_ROOTS/$YBOX_DISTRIBUTION_NAME
69
- # Bind mount the container $HOME to this local path (aka $TARGET_HOME). This makes it
70
+ # Bind mount the container $HOME to this local path. This makes it
70
71
  # easier for backup software and otherwise to read useful container data.
71
72
  # If not provided then you should explicitly mount required directories in the [mounts]
72
73
  # section otherwise home will remain completely ephemeral which is not recommended.
@@ -99,6 +100,16 @@ pulseaudio = on
99
100
  dbus = on
100
101
  # If enabled then the system dbus from the host is available to the container.
101
102
  dbus_sys = off
103
+ # If enabled then the socket for SSH agent, if present, is made available to the container.
104
+ # The $SSH_AUTH_SOCK environment variables must be set in the host environment for this to work.
105
+ # You can also mount $HOME/.ssh with appropriate flags ("ro" if possible) in the [mounts]
106
+ # section to enable the container use the host's ssh keys.
107
+ ssh_agent = off
108
+ # If enabled then the socket for GPG agent, if present, is made available to the container.
109
+ # The $GPG_AGENT_INFO environment variable must be set in the host environment for this to work.
110
+ # You can also mount $HOME/.gnupg with appropriate flags ("ro" if possible) in the [mounts]
111
+ # section to enable the container use the host's gpg keys.
112
+ gpg_agent = off
102
113
  # If enabled then Direct Rendering Infrastructure for accelerated graphics is available to
103
114
  # the container.
104
115
  dri = on
@@ -115,15 +126,15 @@ nvidia = off
115
126
  # works well on most Linux distros (https://wiki.archlinux.org/title/docker or
116
127
  # https://wiki.archlinux.org/title/podman), and the official NVIDIA docs:
117
128
  # https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
118
- # For example on ubuntu with podman, configure the apt repository from the previous link
129
+ # For example, on ubuntu with podman, configure the apt repository from the previous link
119
130
  # and install the package as noted there, then run
120
131
  # `sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml`.
121
132
  # This will need to be repeated if nvidia driver version is upgraded.
122
133
  #
123
134
  # This will take precedence if both "nvidia" and "nvidia_ctk" are enabled.
124
135
  nvidia_ctk = off
125
- # default podman/docker shm-size is 64m which can be insufficient for many apps
126
- shm_size = 1g
136
+ # default podman/docker shm-size is only 64m which can be insufficient for many apps
137
+ shm_size = 2g
127
138
  # Limit the maximum number of processes in the container (to avoid stuff like fork bombs).
128
139
  pids_limit = 2048
129
140
  # Logging driver to use. Default for podman/docker is to use journald in modern Linux
@@ -136,6 +147,9 @@ log_driver = json-file
136
147
  # Example for docker that does not support `path`
137
148
  log_opts = max-size=10m,max-file=3
138
149
 
150
+ # Comma separated list of additional devices that should be made available to the container using
151
+ # the --device option to podman/docker run. Example: devices = /dev/video0,/dev/ttyUSB0
152
+ devices =
139
153
 
140
154
  # The security-opt and other security options passed to podman/docker.
141
155
  # You should restrict these as required.
@@ -200,29 +214,41 @@ documents = $HOME/Documents:$TARGET_HOME/Documents:ro
200
214
  # section) to a directory that is mounted read-only.
201
215
  #
202
216
  # The value has two parts separated by "->" with the LHS of this being the source that
203
- # is to be copied while the RHS is the required relative path in the target directory.
204
- # On the target container the same is used to symlink from the target on RHS to source on LHS.
217
+ # is to be copied while the RHS is the required relative path in the container's home directory.
218
+ # Any spaces around "->" are excluded from the LHS and RHS names.
205
219
  # Source is skipped if it does not exist or not readable with a message on standard output.
206
220
  #
207
221
  # Typically this will contain shell, vim and other common configuration files.
208
222
  # These can be either files or directories and are skipped if they do not exist.
209
- # The keys here have no special significance other than the fact that they should be
210
- # unique and can be used to override in later files that include this one.
223
+ # The keys here should be unique and can be used to override in later files that include this one.
211
224
  #
212
- # Note: The files are symlinks in the container user area and are mounted on a read-only
213
- # mount by default, so if you need to change a file within a container then you will
214
- # need to first remove the symlink and make a copy of the file. This will remove the
225
+ # Two special suffixes can be used in the key names:
226
+ # 1) ":dir" : this suffix indicates that the source is a directory and entire directory structure
227
+ # should be replicated in the target with symlinks only for the individual files;
228
+ # this helps in cases where user needs to make a separate copy of a file inside
229
+ # the directory (using either ":copy" suffix or manually)
230
+ # 2) ":copy": this suffix indicates that the source should be copied to the target; if a
231
+ # file/directory to be copied lies inside another directory that is being linked,
232
+ # then it should be mentioned before this and marked with ":dir" so that directory
233
+ # structure is replicated in the target (see example of fish shell config below)
234
+ #
235
+ # Note: The files from the host are mounted read-only by default in the target container, so if
236
+ # you need to change a file within a container then you can use the ":copy" suffix in the key name
237
+ # or manually remove the symlink and make a copy of the file. This will remove the
215
238
  # direct sharing between the two which has to be done manually thereon if required.
216
239
  # The sharing behavior also depends on "config_hardlinks" as described in its comment above
217
240
  # in the [base] section.
218
241
  #
219
- # Note: The HOME environment variable here will be evaluated both in the host
220
- # session (for the source to be transferred) and inside the container session
221
- # (for the target). Do not use TARGET_HOME here which can be incorrect for the host session.
242
+ # Note: The LHS should typically have a path having $HOME while RHS will be relative to the
243
+ # target's home inside the container. Do not use $TARGET_HOME on RHS since path the assumed
244
+ # to be a relative one and $TARGET_HOME already inserted as required.
222
245
  [configs]
246
+ env_conf = $HOME/.config/environment.d -> .config/environment.d
223
247
  bashrc = $HOME/.bashrc -> .bashrc
224
248
  starship = $HOME/.config/starship.toml -> .config/starship.toml
225
- fishrc = $HOME/.config/fish -> .config/fish
249
+ # replicate fish configuration directory with copy of fish_variables but symlinks for the rest
250
+ fish_conf:dir = $HOME/.config/fish -> .config/fish
251
+ fish_vars:copy = $HOME/.config/fish/fish_variables -> .config/fish/fish_variables
226
252
  omf = $HOME/.config/omf -> .config/omf
227
253
  omf_data = $HOME/.local/share/omf -> .local/share/omf
228
254
  zshrc = $HOME/.zshrc -> .zshrc
@@ -261,10 +287,11 @@ speechconf = $HOME/.config/speech-dispatcher -> .config/speech-dispatcher
261
287
  [env]
262
288
  TERM
263
289
  TERMINFO_DIRS = /usr/share/terminfo:/var/lib/terminfo
264
- XDG_CURRENT_DESKTOP
265
- XDG_SESSION_DESKTOP
290
+ # always pretend desktop to be GNOME since KDE/*DE apps required by xdg-* are not installed
291
+ XDG_CURRENT_DESKTOP = GNOME
292
+ XDG_SESSION_DESKTOP = GNOME
293
+ DESKTOP_SESSION = gnome
266
294
  XDG_SESSION_TYPE
267
- DESKTOP_SESSION
268
295
  GTK_IM_MODULE
269
296
  QT_IM_MODULE
270
297
  SDL_IM_MODULE
@@ -290,14 +317,12 @@ XMODIFIERS
290
317
  [app_flags]
291
318
  # These flags/arguments will be added to Exec line of chromium.desktop when it is copied to
292
319
  # host as well as in the wrapper chromium executable created on the host.
293
- # You can use "!p" here for the first argument in the 'Exec='/'TryExec=' line in the desktop
320
+ # You can use "!p" here for the first argument in the 'Exec=' line in the desktop
294
321
  # file and '!a' for rest of the arguments. When linking to an executable program, '!p' will
295
322
  # refer to the full path of the executable while '!a' will be replaced by "$@" in the shell
296
323
  # script. Use '!!p' for a literal '!p' and '!!a' for a literal '!a'.
297
324
 
298
- # /dev/shm usage is disabled for chromium because that requires ipc=host or mounting host
299
- # /dev/shm in read-write mode which is quite insecure.
300
- chromium = !p --disable-dev-shm-usage --enable-chrome-browser-cloud-management !a
325
+ chromium = !p --enable-chrome-browser-cloud-management !a
301
326
 
302
327
 
303
328
  # Startup programs you want to run when starting the container. These are run using
@@ -1,6 +1,7 @@
1
1
  [base]
2
2
  name = Profile for creating development environment
3
3
  includes = basic.ini
4
+ ssh_agent = on
4
5
 
5
6
  [security]
6
7
  # SYS_PTRACE is required by mesa and without this, the following warning can be seen:
@@ -8,16 +9,13 @@ includes = basic.ini
8
9
  caps_add = SYS_PTRACE
9
10
 
10
11
  [mounts]
12
+ # export the host's ssh keys for use by ssh-agent in the container as required ("ro" mode
13
+ # implies that known_hosts and other files within ~/.ssh cannot be changed)
14
+ ssh = $HOME/.ssh:$TARGET_HOME/.ssh:ro
11
15
  # add your projects and other directories having source code
12
16
  #projects = $HOME/projects:$TARGET_HOME/projects
13
17
  #pyenv = $HOME/.pyenv:$TARGET_HOME/.pyenv:ro
14
18
 
15
- [env]
16
- # always pretend desktop to be GNOME since KDE apps required by xdg-* are not installed
17
- XDG_CURRENT_DESKTOP = GNOME
18
- XDG_SESSION_DESKTOP = GNOME
19
- DESKTOP_SESSION = gnome
20
-
21
19
  [apps]
22
20
  # some packages for Arch Linux - uncomment and update for your distribution as required
23
21
  #ides = intellij-idea-community-edition-jre,visual-studio-code-bin,zed
@@ -28,5 +28,5 @@ echo_color "$fg_purple" "Copying data from container to shared root mounted on '
28
28
  IFS="," read -ra shared_dirs_arr <<< "$shared_dirs"
29
29
  for dir in "${shared_dirs_arr[@]}"; do
30
30
  echo_color "$fg_orange" "Copying $dir to $shared_bind$dir"
31
- cp -a "$dir" "$shared_bind$dir"
31
+ cp -an "$dir" "$shared_bind$dir"
32
32
  done
@@ -8,10 +8,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
8
 
9
9
  source "$SCRIPT_DIR/entrypoint-common.sh"
10
10
 
11
+ export HOME=/root
11
12
  echo_color "$fg_cyan" "Copying prime-run, run-in-dir and run-user-bash-cmd" >> $status_file
12
- cp -a "$SCRIPT_DIR/prime-run" /usr/local/bin/prime-run
13
- cp -a "$SCRIPT_DIR/run-in-dir" /usr/local/bin/run-in-dir
14
- cp -a "$SCRIPT_DIR/run-user-bash-cmd" /usr/local/bin/run-user-bash-cmd
13
+ cp -af "$SCRIPT_DIR/prime-run" /usr/local/bin/prime-run
14
+ cp -af "$SCRIPT_DIR/run-in-dir" /usr/local/bin/run-in-dir
15
+ cp -af "$SCRIPT_DIR/run-user-bash-cmd" /usr/local/bin/run-user-bash-cmd
15
16
  chmod 0755 /usr/local/bin/prime-run /usr/local/bin/run-in-dir /usr/local/bin/run-user-bash-cmd
16
17
 
17
18
  # invoke the NVIDIA setup script if present
@@ -13,9 +13,11 @@ mkdir -p "$user_home/.gnupg" && chmod 0700 "$user_home/.gnupg"
13
13
  echo "keyserver $DEFAULT_GPG_KEY_SERVER" > "$user_home/.gnupg/dirmngr.conf"
14
14
  rm -f "$user_home"/.gnupg/*/*.lock
15
15
 
16
- echo_color "$fg_cyan" "Enabling python pip installation for $current_user" >> $status_file
17
- mkdir -p "$user_home/.config/pip"
18
- cat > "$user_home/.config/pip/pip.conf" << EOF
16
+ if [ ! -e "$user_home/.config/pip/pip.conf" ]; then
17
+ echo_color "$fg_cyan" "Enabling python pip installation for $current_user" >> $status_file
18
+ mkdir -p "$user_home/.config/pip"
19
+ cat > "$user_home/.config/pip/pip.conf" << EOF
19
20
  [global]
20
21
  break-system-packages = true
21
22
  EOF
23
+ fi
@@ -22,7 +22,7 @@ echo -n > $status_file
22
22
  # the current user as well as the group of the normal user
23
23
  uid="$(id -u)"
24
24
  gid="$(id -g)"
25
- chown $uid:$YBOX_HOST_GID $status_file
25
+ chown $uid:${YBOX_HOST_GID:-$gid} $status_file
26
26
  chmod 0660 $status_file
27
27
  if [ "$uid" -eq 0 ]; then
28
28
  SUDO=""
@@ -47,31 +47,22 @@ function show_usage() {
47
47
  echo " -h show this help message and exit"
48
48
  }
49
49
 
50
- # link the configuration files in HOME to the target directory having the required files
51
- function link_config_files() {
50
+ # copy/link the configuration files in HOME to the target directory having the required files
51
+ function replicate_config_files() {
52
52
  # line is of the form <src> -> <dest>; pattern below matches this while trimming spaces
53
53
  echo_color "$fg_orange" "Linking configuration files from $config_dir to user's home" >> $status_file
54
- pattern='(.*[^[:space:]]+)[[:space:]]*->[[:space:]]*(.*)'
54
+ pattern='(COPY|LINK_DIR|LINK):(.*)'
55
55
  while read -r config; do
56
56
  if [[ "$config" =~ $pattern ]]; then
57
- home_file="${BASH_REMATCH[1]}"
58
- # expand env variables
59
- eval home_file="$home_file"
57
+ home_file="$HOME/${BASH_REMATCH[2]}"
60
58
  dest_file="$config_dir/${BASH_REMATCH[2]}"
61
59
  # only replace the file if it is already a link (assuming the link target may
62
- # have changed in the config_list file), or a directory containing links
60
+ # have changed in the config_list file), or a directory containing only links
63
61
  if [ -e "$dest_file" ]; then
64
62
  if [ -L "$home_file" ]; then
65
63
  rm -f "$home_file"
66
64
  elif [ -d "$home_file" ]; then
67
- do_rmdir=true
68
- for f in "$home_file"/*; do
69
- if [ -e "$f" -a ! -L "$f" ]; then
70
- do_rmdir=false
71
- break
72
- fi
73
- done
74
- if [ "$do_rmdir" = true ]; then
65
+ if [ -z $(find "$home_file" -type f -print -quit) ]; then
75
66
  rm -rf "$home_file"
76
67
  fi
77
68
  fi
@@ -80,7 +71,15 @@ function link_config_files() {
80
71
  mkdir -p "$home_filedir"
81
72
  fi
82
73
  if [ ! -e "$home_file" ]; then
83
- ln -s "$dest_file" "$home_file"
74
+ if [ "${BASH_REMATCH[1]}" = "COPY" ]; then
75
+ cp -r "$dest_file" "$home_file"
76
+ elif [ "${BASH_REMATCH[1]}" = "LINK_DIR" ]; then
77
+ # if dest_file is a directory, then replicate the directory structure in home and
78
+ # symlink individual files which is accomplished with "cp -sr"
79
+ cp -sr "$dest_file" "$home_file"
80
+ else # "${BASH_REMATCH[1]}" = "LINK"
81
+ ln -s "$dest_file" "$home_file"
82
+ fi
84
83
  fi
85
84
  fi
86
85
  else
@@ -180,7 +179,7 @@ run_dir=${XDG_RUNTIME_DIR:-/run/user/$uid}
180
179
  if [ -d $run_dir ]; then
181
180
  $SUDO chown $uid:$gid $run_dir 2>/dev/null || true
182
181
  fi
183
- if [ -n "$(ls $run_dir 2>/dev/null)" ]; then
182
+ if compgen -G "$run_dir/*" >/dev/null; then
184
183
  $SUDO chown $uid:$gid $run_dir/* 2>/dev/null || true
185
184
  fi
186
185
 
@@ -212,7 +211,7 @@ fi
212
211
 
213
212
  # process config files, application installs and invoke startup apps
214
213
  if [ -n "$config_list" ]; then
215
- link_config_files
214
+ replicate_config_files
216
215
  fi
217
216
  if [ -n "$app_list" ]; then
218
217
  install_apps
@@ -231,14 +230,17 @@ function cleanup() {
231
230
  # clear status file first just in case other operations do not finish before SIGKILL comes
232
231
  echo -n > $status_file
233
232
  # first send SIGTERM to all "docker exec" processes that will have parent PID as 0 or 1
233
+ kill_sent=0
234
234
  exec_pids="$(ps -e -o ppid=,pid= | \
235
235
  awk '{ if (($1 == 0 || $1 == 1) && $2 != 1 && $2 != '$childPID') print $2 }')"
236
236
  for pid in $exec_pids; do
237
- echo "Sending SIGTERM to $pid"
238
- kill -TERM $pid
237
+ if kill -TERM $pid 2>/dev/null; then
238
+ kill_sent=1
239
+ echo "Sent SIGTERM to $pid"
240
+ fi
239
241
  done
240
242
  # sleep a bit for $exec_pids to finish
241
- [ -n "$exec_pids" ] && sleep 3
243
+ [ $kill_sent -eq 1 ] && sleep 3
242
244
  # lastly kill the infinite tail process
243
245
  kill -TERM $childPID
244
246
  }
@@ -1,7 +1,5 @@
1
1
  #!/bin/sh
2
2
 
3
- set -e
4
-
5
3
  __NV_PRIME_RENDER_OFFLOAD=1
6
4
  __GLX_VENDOR_LIBRARY_NAME=nvidia
7
5
  __VK_LAYER_NV_optimus=NVIDIA_only
@@ -9,24 +9,34 @@ if [ -n "$dir" -a -d "$dir" ]; then
9
9
  cd "$dir"
10
10
  fi
11
11
 
12
- # XAUTHORITY file can change after a re-login or a restart, so search for the passed one
13
- # by podman/docker exec in the mount point of its parent directory
14
- if [ -n "$XAUTHORITY" -a -n "$XAUTHORITY_ORIG" -a ! -r "$XAUTHORITY" ]; then
15
- # XAUTHORITY is assumed to be either in /run/user or in /tmp
16
- run_dir="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
17
- if [[ "$XAUTHORITY" == $run_dir/* ]]; then
18
- host_dir="$run_dir"
19
- elif [[ "$XAUTHORITY" == /tmp/* ]]; then
20
- host_dir=/tmp
12
+ # XAUTHORITY, SSH_AUTH_SOCK and GPG_AGENT_INFO files can change after a re-login or a restart,
13
+ # so search for the passed one by podman/docker exec in the mount point of its parent directory
14
+ for env_var in XAUTHORITY SSH_AUTH_SOCK GPG_AGENT_INFO; do
15
+ env_var_orig=${env_var}_ORIG
16
+ var_val=${!env_var}
17
+ var_val_orig=${!env_var_orig}
18
+ if [ -n "$var_val" -a -n "$var_val_orig" ]; then
19
+ if [ ! -r "$var_val" ]; then
20
+ # the value should be in /run/user/<uid> or in /tmp, or else the parent directory is used
21
+ run_dir="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
22
+ if [[ "$var_val" == $run_dir/* ]]; then
23
+ host_dir="$run_dir"
24
+ elif [[ "$var_val" == /tmp/* ]]; then
25
+ host_dir=/tmp
26
+ else
27
+ host_dir="$(dirname "$var_val")"
28
+ fi
29
+ new_val="${var_val/#$host_dir/${host_dir}-host}" # replace $host_dir by ${host_dir}-host
30
+ if [ ! -r "$new_val" ]; then
31
+ new_val="$var_val_orig"
32
+ fi
33
+ export $env_var="$new_val"
34
+ fi
21
35
  else
22
- host_dir="$(dirname "$XAUTHORITY")"
23
- fi
24
- XAUTHORITY="${XAUTHORITY/#$host_dir/${host_dir}-host}" # replace $host_dir by ${host_dir}-host
25
- if [ ! -r "$XAUTHORITY" ]; then
26
- XAUTHORITY="$XAUTHORITY_ORIG"
36
+ # remove unset variable in the container else apps can misbehave
37
+ unset $env_var
27
38
  fi
28
- export XAUTHORITY
29
- fi
39
+ done
30
40
 
31
41
  # In case NVIDIA driver has been updated, the updated libraries and other files may need to be
32
42
  # linked again, so check for a missing library file and invoke the setup script if present
@@ -49,6 +59,7 @@ if [ -e "$nvidia_setup" ]; then
49
59
  flock -x -w 60 $lock_fd || /bin/true
50
60
  trap "flock -u $lock_fd || /bin/true" 0 1 2 3 4 5 6 7 8 10 11 12 13 14 15
51
61
  if ! is_nvidia_valid; then
62
+ # set umask for root execution to ensure that other users have read/execute permissions
52
63
  umask 022
53
64
  sudo /bin/bash "$nvidia_setup" || /bin/true
54
65
  fi
@@ -57,4 +68,7 @@ if [ -e "$nvidia_setup" ]; then
57
68
  fi
58
69
  fi
59
70
 
71
+ # reset to more conservative umask setting
72
+ umask 027
73
+
60
74
  exec "$@"
@@ -1,5 +1,11 @@
1
1
  #!/bin/bash
2
2
 
3
+ # This script either runs a given command using bash directly, or if YBOX_HOST_UID environment
4
+ # variable is set to something other than the UID of the current user, then uses sudo to run
5
+ # the command as that UID (plus YBOX_HOST_GID as the GID). This latter case happens for rootless
6
+ # docker where the ybox container runs as the root user (due to absence of --userns=keep-id like
7
+ # in podman) but some commands need to be run as a normal user like Arch's paru/yay AUR helpers.
8
+
3
9
  set -e
4
10
 
5
11
  if [ "$#" -ne 1 ]; then
@@ -8,7 +14,17 @@ if [ "$#" -ne 1 ]; then
8
14
  fi
9
15
 
10
16
  if [ "$(id -u)" -eq 0 -a -n "$YBOX_HOST_UID" ] && getent passwd $YBOX_HOST_UID > /dev/null; then
11
- exec sudo -u "#$YBOX_HOST_UID" -g "#$YBOX_HOST_GID" /bin/bash -c "$1"
17
+ sudo -u "#$YBOX_HOST_UID" -g "#$YBOX_HOST_GID" /bin/bash -c "$1"
18
+ status=$?
19
+ if [ $status -ne 0 ]; then
20
+ echo "FAILED (exit code = $status) in sudo execution of: $1"
21
+ exit $status
22
+ fi
12
23
  else
13
24
  eval "$1"
25
+ status=$?
26
+ if [ $status -ne 0 ]; then
27
+ echo "FAILED (exit code = $status) in execution of: $1"
28
+ exit $status
29
+ fi
14
30
  fi
@@ -0,0 +1,24 @@
1
+ # ybox-{name}.service
2
+ #
3
+ # Autogenerated by ybox-create {version} on {date}
4
+
5
+ [Unit]
6
+ Description={manager_name} ybox-{name}.service
7
+ Wants=network-online.target
8
+ After=network-online.target
9
+ {docker_requires}
10
+ [Service]
11
+ Environment=PATH={sys_path}:{ybox_bin_dir}
12
+ EnvironmentFile=%h/.config/systemd/user/{env_file}
13
+ Type=notify
14
+ NotifyAccess=all
15
+ Restart=on-failure
16
+ # sleep to allow for initialization of the user's login/graphical environment
17
+ ExecStartPre=/usr/bin/sleep $SLEEP_SECS
18
+ ExecStart=/bin/sh -c 'ybox-control start {name} && systemd-notify --ready && exec ybox-control wait {name}'
19
+ ExecStop=/bin/sh -c 'ybox-control stop -t 20 --ignore-stopped {name}'
20
+ ExecStopPost=/bin/sh -c 'ybox-control stop -t 20 --ignore-stopped {name}'
21
+ TimeoutStopSec=60
22
+
23
+ [Install]
24
+ WantedBy=default.target
ybox/config.py CHANGED
@@ -142,6 +142,9 @@ class Consts:
142
142
  Defines fixed file/path and other names used by ybox that are not configurable.
143
143
  """
144
144
 
145
+ # standard system executable paths
146
+ _SYS_BIN_DIRS = ("/usr/bin", "/bin", "/usr/sbin", "/sbin", "/usr/local/bin", "/usr/local/sbin")
147
+ # regex pattern to match all manual page directories
145
148
  _MAN_DIRS_PATTERN = re.compile(r"/usr(/local)?(/share)?/man(/[^/]*)?/man[0-9][a-zA-Z_]*")
146
149
 
147
150
  @staticmethod
@@ -216,13 +219,18 @@ class Consts:
216
219
  @staticmethod
217
220
  def container_bin_dirs() -> Iterable[str]:
218
221
  """directories on the container that has executables that may need to be wrapped"""
219
- return ("/usr/bin", "/usr/sbin", "/bin", "/sbin", "/usr/local/bin", "/usr/local/sbin")
222
+ return Consts._SYS_BIN_DIRS
220
223
 
221
224
  @staticmethod
222
225
  def container_man_dir_pattern() -> re.Pattern[str]:
223
226
  """directory regex pattern on the container having man-pages that may need to be linked"""
224
227
  return Consts._MAN_DIRS_PATTERN
225
228
 
229
+ @staticmethod
230
+ def sys_bin_dirs() -> Iterable[str]:
231
+ """standard directories to search for system installed executables"""
232
+ return Consts._SYS_BIN_DIRS
233
+
226
234
  @staticmethod
227
235
  def nvidia_target_base_dir() -> str:
228
236
  """base directory path where NVIDIA libs/data are linked in the container"""