diff options
65 files changed, 987 insertions, 194 deletions
@@ -8,7 +8,7 @@ # go generate /cmd/hakurei/LICENSE -/cmd/mbf/internal/pkgserver/ui/static +/cmd/mbf/internal/pkgsite/ui/static /pkg/internal/testtool/testtool /internal/rosa/hakurei_current.tar.gz @@ -1,4 +1,4 @@ -Copyright (c) 2024-2025 Ophestra +Copyright (c) 2024-2026 Rosa OS Developers 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: @@ -1,19 +1,6 @@ -<p align="center"> - <a href="https://git.gensokyo.uk/rosa/hakurei"> - <picture> - <img src="https://basement.gensokyo.uk/images/yukari1.png" width="200px" alt="Yukari"> - </picture> - </a> -</p> - -<p align="center"> - <a href="https://pkg.go.dev/hakurei.app"><img src="https://pkg.go.dev/badge/hakurei.app.svg" alt="Go Reference" /></a> - <a href="https://git.gensokyo.uk/rosa/hakurei/actions"><img src="https://git.gensokyo.uk/rosa/hakurei/actions/workflows/test.yml/badge.svg?branch=staging&style=flat-square" alt="Gitea Workflow Status" /></a> - <br/> - <a href="https://git.gensokyo.uk/rosa/hakurei/releases"><img src="https://img.shields.io/gitea/v/release/rosa/hakurei?gitea_url=https%3A%2F%2Fgit.gensokyo.uk&color=purple" alt="Release" /></a> - <a href="https://git.gensokyo.uk/rosa/hakurei/src/branch/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-pink" alt="MIT License" /></a> - <a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a> -</p> +<p align="center"><a href="https://src.rosa.moe/hakurei"><picture> + <img src="https://basement.gensokyo.uk/images/yukari1.png" width="200px" alt="Yukari"> +</picture></a></p> Hakurei is a tool for running sandboxed desktop applications as dedicated subordinate users on the Linux kernel. It implements the application container @@ -24,6 +11,9 @@ Interaction with hakurei happens entirely through structures described by package [hst](https://pkg.go.dev/hakurei.app/hst). No native API is available due to internal details of uid isolation. +Our canonical Git repository is located at https://src.rosa.moe/hakurei. +There is a mirror of the repository https://git.gensokyo.uk/rosa/hakurei. + ## Notable Packages Package [container](https://pkg.go.dev/hakurei.app/container) is general purpose diff --git a/cmd/app/app.go b/cmd/app/app.go index 9679413f..ca809334 100644 --- a/cmd/app/app.go +++ b/cmd/app/app.go @@ -14,6 +14,24 @@ import ( "hakurei.app/hst" ) +// base is the root of the persistent state directory. +type base check.Absolute + +// append calls filepath.Join with b as the first element. +func (b *base) append(elem ...string) *check.Absolute { + return (*check.Absolute)(b).Append(elem...) +} + +// initial returns the pathname of the bottom layer. +func (b *base) initial() *check.Absolute { + return b.append("initial") +} + +// state returns the pathname of the home directory for id. +func (b *base) state(id string) *check.Absolute { + return b.append("state", id) +} + // parsePair parses a NUL-delimited quoted paths pair. func parsePair(s string) (source, target *check.Absolute, err error) { var p string @@ -35,7 +53,7 @@ func parsePair(s string) (source, target *check.Absolute, err error) { // corresponding [hst.Config]. func parse( id string, - base *check.Absolute, + base *base, r io.Reader, templateP *string, ) (*hst.Config, error) { @@ -44,7 +62,7 @@ func parse( root := hst.FSOverlay{ Target: fhs.AbsRoot, - Lower: []*check.Absolute{base.Append("initial")}, + Lower: []*check.Absolute{base.initial()}, } c := hst.Config{ ID: id, @@ -65,7 +83,7 @@ func parse( {FilesystemConfig: &root}, {FilesystemConfig: &hst.FSBind{ Target: home, - Source: base.Append("state", id), + Source: base.state(id), Write: true, Ensure: true, }}, @@ -110,7 +128,7 @@ func parse( *templateP = template } c.Identity = v - root.Upper = base.Append("template", template) + root.Upper = base.template(template) } if err := scanOnce(); err != nil { diff --git a/cmd/app/app_merged.go b/cmd/app/app_merged.go new file mode 100644 index 00000000..e0a31f94 --- /dev/null +++ b/cmd/app/app_merged.go @@ -0,0 +1,15 @@ +//go:build merge + +package main + +import "hakurei.app/check" + +// template returns the pathname of an upperdir. +func (b *base) template(template string) *check.Absolute { + return b.append("template", template, "upper") +} + +// work returns the pathname of a workdir. +func (b *base) work(template string) *check.Absolute { + return b.append("template", template, "work") +} diff --git a/cmd/app/app_sep.go b/cmd/app/app_sep.go new file mode 100644 index 00000000..9ec98e41 --- /dev/null +++ b/cmd/app/app_sep.go @@ -0,0 +1,15 @@ +//go:build !merge + +package main + +import "hakurei.app/check" + +// template returns the pathname of an upperdir. +func (b *base) template(template string) *check.Absolute { + return b.append("template", template) +} + +// work returns the pathname of a workdir. +func (b *base) work(template string) *check.Absolute { + return b.append("work", template) +} diff --git a/cmd/app/app_test.go b/cmd/app/app_test.go index 1aab4759..90c0068e 100644 --- a/cmd/app/app_test.go +++ b/cmd/app/app_test.go @@ -13,7 +13,7 @@ import ( func TestParse(t *testing.T) { t.Parallel() - base := fhs.AbsProc.Append("nonexistent") + b := (*base)(fhs.AbsProc.Append("nonexistent")) testCases := []struct { name string data string @@ -74,13 +74,13 @@ talk com.canonical.Unity {FilesystemConfig: &hst.FSOverlay{ Target: fhs.AbsRoot, Lower: []*check.Absolute{ - base.Append("initial"), + b.initial(), }, - Upper: base.Append("template", "nonfree"), + Upper: b.template("nonfree"), }}, {FilesystemConfig: &hst.FSBind{ Target: hst.AbsPrivateTmp.Append("home"), - Source: base.Append("state", "com.discordapp.Discord"), + Source: b.state("com.discordapp.Discord"), Write: true, Ensure: true, }}, @@ -128,7 +128,7 @@ talk com.canonical.Unity got, err := parse( tc.name, - base, + b, strings.NewReader(tc.data), nil, ) diff --git a/cmd/app/doc.go b/cmd/app/doc.go new file mode 100644 index 00000000..8c5397fd --- /dev/null +++ b/cmd/app/doc.go @@ -0,0 +1,362 @@ +/* +The app program is a proof-of-concept frontend for cmd/hakurei. + +This program is not covered by the compatibility promise. The command line +interface and configuration syntax may change at any time. + +# Installation + +Compile cmd/app with these arguments: + + go build -trimpath \ + -ldflags='-s -w + -buildid= + -X hakurei.app/internal/info.hsuPath=/usr/local/bin/hsu' \ + ./cmd/app + +Replace /usr/local/bin/hsu with the hakurei installation's absolute hsu +pathname. + +# Sharing files + +Sharing files between apps is only possible with the permissionless shared +filesystem ([cmd/sharefs]), as apps generally do not share credentials. It can +be built without any special linker flags. Create a symlink at +/usr/bin/mount.fuse.sharefs pointing to the sharefs binary when mounting sharefs +via fstab: + + sharefs /sdcard fuse.sharefs rw,noexec,nosuid,nodev,noatime,allow_other,mkdir,source=/var/lib/sdcard,setuid=1023,setgid=1023 0 0 + +Replace /var/lib/sdcard with the location of the backing directory. User and +group id must be specified in numerical form, it must own the backing directory. +The mount point does not have to be /sdcard. + +# General setup + +The entire directory structure containing persistent app data must be created +manually for now, due to the different ownership requirements being impossible +to set up directly through cmd/hsu. + +The environment variable ROSA_APP_PATH should be set to the absolute pathname of +the persistent state directory. This document will use $ROSA_APP_PATH to refer +to the persistent state directory. The $ROSA_APP_PATH directory should be owned +by the user declared in /etc/hsurc and invoking cmd/app, and must be readable +and executable by all subordinate users. This can be done by making it +world-readable and executable, or by adding a group directive to the common +file. + +The $ROSA_APP_PATH/app directory contains app configuration files, named after +their reverse-DNS style application identifier string. It should be owned by +the user invoking cmd/app. + +The $ROSA_APP_PATH/initial directory contains the read-only base of every +app template. Everything within it, including the directory itself, should be +owned by the reserved user, its user and group id obtained by the command: + + app id + +This document assumes a [Void Linux rootfs tarball] is unpacked here. It is +possible to use other Linux distributions; Void linux is selected here because +its package manager works correctly out of the box in the hakurei container +environment. If the use case does not require glibc, [Alpine Linux] or +[Chimera Linux] might be more suitable. + +Once the tarball is unpacked at $ROSA_APP_PATH/initial, create a directory named +chronos in $ROSA_APP_PATH/initial/home, and directories block, bus, class, dev, +and devices in $ROSA_APP_PATH/initial/sys. Then, recursively change ownerships +of files and directories in $ROSA_APP_PATH/initial to the reserved user/group. + +The $ROSA_APP_PATH/lock directory contains lock files guarding entry into +mutable and app containers of every template. It must be owned by the user +invoking cmd/app. + +The $ROSA_APP_PATH/state directory contains app home directories, named after +their reverse-DNS style application identifier string. The directory itself +should be owned by the user invoking cmd/app; each directory inside must be +owned by the subordinate user/group id of its app, obtained by the command: + + app id "$APPID" + +where "$APPID" is the second component of the first line in the configuration +file of the corresponding app. It is considered good practice, but not required, +for these directory to have the permission bits set to 0700. + +The $ROSA_APP_PATH/template directory contains templates that apps are based +on, which are all derived from the initial layer. The directory itself +should be owned by the user invoking cmd/app, and each directory inside should +be owned by the reserved user/group. Their names are used in the first component +of the first line in the configuration file of each app, to specify that the +file is derived from that template. + +The $ROSA_APP_PATH/work directory contains overlay work directories for mutable +containers. It must contain one manually created, empty directory for each +template, named after the template directory itself, owned by the reserved +user/group. The directory itself and its contents should have the permission +bits set to 0700. + +# Snapshots and cloning + +To reduce disk space used by templates, [ZFS clones] or an equivalent can be +used. In such a setup, where each template occupies a different filesystem, the +"merge" build tag is required, and the work directory can be omitted during +directory creation. Instead, the individual template directories contain both +upper and work directories. + +# Configuring the base template + +This section describes basic setup required for the typical desktop use case. +Generally, multiple templates are created to mitigate the global nature of +conventional package managers. The setup described in this section applies to +all templates. For convenience, a "base" template should be created, containing +this setup, and all future templates should be copied from the base template. +This section assumes the template is named "base". + +Create an empty directory at $ROSA_APP_PATH/template/base, owned by the reserved +user, with permission bits set to 0755. Create its corresponding work directory +at $ROSA_APP_PATH/work/base, also owned by the reserved user, with permission +bits set to 0700. Once this is complete, enter its mutable container with the +command: + + app enter --shell=/bin/sh base + +This command overrides the container configuration to use the shell program at +/bin/sh. Normally, cmd/app uses zsh, which is not yet installed. + +Once in the container, populate /etc/resolv.conf with some well-known DNS +service, for example: + + nameserver 8.8.8.8 + nameserver 8.8.4.4 + +The mutable container does not bind the host /etc/resolv.conf. It is generally +recommended to populate it with a well-known service here to avoid trouble in +future template changes. A later section configures regular app containers to +use host configuration. + +After populating nameserver configuration, install zsh using the package manager +provided by the distribution unpacked earlier. On Void Linux, this is done by +the command: + + xbps-install zsh + +Wait for the package installation to complete, configure zsh if necessary, then +exit from the shell, and re-enter the container without overriding the login +shell: + + app enter base + +Some packages are generally required in the container for the typical desktop +use case: xdg-user-dirs to reconfigure "well known" user directories to point +to the inner sharefs mount point, mesa to interact with the GPU, dconf to +configure GTK, xdg-desktop-portal-gtk to have gtk talk to dconf. Fonts generally +need to be installed as well. Additionally, a text editor can be installed for +editing configuration files later on. On Void Linux, these packages are +installed by the command: + + xbps-install \ + vim \ + mesa \ + mesa-dri \ + mesa-intel-dri \ + mesa-vaapi \ + mesa-vulkan-intel \ + mesa-vulkan-radeon \ + mesa-vulkan-overlay-layer \ + dconf \ + xdg-user-dirs \ + xdg-desktop-portal-gtk \ + noto-fonts-ttf \ + noto-fonts-ttf-variable \ + noto-fonts-ttf-extra \ + noto-fonts-emoji \ + noto-fonts-cjk \ + noto-fonts-cjk-variable \ + noto-fonts-cjk-sans \ + noto-fonts-cjk-sans-variable \ + noto-fonts-cjk-serif \ + noto-fonts-cjk-serif-variable + +Add -32bit variants of mesa packages if multilib support is required. Adjust +the package selection based on use case. + +Edit /etc/xdg/user-dirs.defaults and point directories to the inner sharefs +mount point as required. The resulting file should look like this: + + # Default settings for user directories + # + # The values are relative pathnames from the home directory and + # will be translated on a per-path-element basis into the users locale + DESKTOP=../../sdcard/Desktop + DOWNLOAD=../../sdcard/Download + TEMPLATES=../../sdcard/Templates + PUBLICSHARE=../../sdcard/Public + DOCUMENTS=../../sdcard/Documents + MUSIC=../../sdcard/Music + PICTURES=../../sdcard/Pictures + VIDEOS=../../sdcard/Movies + PROJECTS=../../sdcard/Projects + # Another alternative is: + #MUSIC=Documents/Music + #PICTURES=Documents/Pictures + #VIDEOS=Documents/Videos + +If this is configured, it must be applied to the home directory of each app +individually. This can be done for all apps via the shell expression: + + app run | xargs -n 1 echo app run --command=xdg-user-dirs-update + +This must also be done for every newly created app. + +The /etc/dconf directory can be set up to provide defaults across all apps. To +do so, edit /etc/dconf/profile/user: + + user-db:user + system-db:local + system-db:site + system-db:distro + +Then, place files in /etc/dconf/db/local.d containing dconf configuration. For +example: + + [org/gnome/desktop/interface] + gtk-enable-primary-paste=true + color-scheme='prefer-dark' + gtk-theme='adw-gtk3-dark' + icon-theme='Papirus-Dark' + +Themes must be installed in the container. Change colour-scheme and themes +accordingly. Setting gtk-enable-primary-paste restores clipboard behaviour that +GNOME maintainers decided to break. + +After editing these configuration files, update dconf system databases: + + dconf update + +# Common configuration + +The optional $ROSA_APP_PATH/common file contains common configuration included +after the specific configuration of each app. Some bind mounts are required for +almost every graphical program, and many widely used libraries are configured +through the environment. For most setups, these directives are generally +required: + + ; for libudev + ro "/sys/block" + ro "/sys/bus" + ro "/sys/class" + ro "/sys/dev" + ro "/sys/devices" + + env EDITOR=vim + ; for apps to play nice with xdg-dbus-proxy + ro+ "/etc/machine-id" + ; template must have a /etc/resolv.conf file + ro+ "/etc/resolv.conf" + ; group name of the sharefs group configured on host + group media_rw + ; for sharefs + rw "/sdcard" + ; refer to /usr/share/zoneinfo + env TZ=Asia/Tokyo + + ; must be installed first + env XCURSOR_THEME=volantes_cursors + ; must be generated first if using glibc + env LANG=en_GB.UTF-8 + env LC_COLLATE=C + +# Installing an app + +An app is defined by a configuration file in $ROSA_APP_PATH/app, and a +persistent state directory in $ROSA_APP_PATH/state. Before creating an app, its +identity must be decided. Different apps should generally not share an identity. +The next unused identity can be found using the command: + + app next + +If the -v argument is added before the "next" command, cmd/app will additionally +show apps sharing the same identity. + +Once the identity is decided, the subordinate user/group id can be obtained by +the command: + + app id "$APPID" + +where "$APPID" is the identity of this app. A directory must be created under +$ROSA_APP_PATH/state, owned by this user and group id. Its permission bits +should be set to 0700. A configuration file with the same name, owned by the +user invoking cmd/app, must be placed in $ROSA_APP_PATH/app. Its contents are +described in the next section. The reverse-DNS style application identifier +string is submitted to the Wayland display server, and used as part of the +dbus preset if enabled, so the correct identifier must be obtained. If no such +identifier exist, use the domain of the app home page. + +# Configuring an app + +The configuration file starts with two structural directives, and the remaining +lines are freestanding directives applied in order. + +The first structural directive is a line containing two components separated by +the ':' byte. The first component is the template used by the app. the second +component is the decimal representation of the app identity. The second +structural directive is a shell expression passed to the shell serving as the +initial process of the app. + +After the structural directives, each line contains exactly one directive or +comment. Comment lines begin with a ';' byte: these lines are not interpreted by +cmd/app in any way. + +The following section documents currently available freestanding directives. + +# Directives + + interactive start initial process as an interactive shell + gpu expose GPU devices to the container + system_bus enable system bus in the dbus proxy + + wayland expose a Wayland pathname socket via security-context-v1 + x11 expose the X11 pathname socket + dbus enable the per-container xdg-dbus-proxy daemon + pipewire expose a pipewire pathname socket via SecurityContext + + multiarch unblock system calls required for multiarch to work on + multiarch-enabled targets (amd64, arm64) + devel unblock ptrace and friends + userns unblock userns creation and container setup syscalls + net enable network access + abstract enable access to external abstract unix sockets + tty unblock dangerous terminal I/O (faking input) + mapuid map the target user id to the user id of the user + invoking cmd/app in the container user namespace + device mount /dev/ from the init mount namespace as is in the + container mount namespace + + share_runtime share XDG_RUNTIME_DIR between containers under the same + identity + share_tmpdir share TMPDIR between containers under the same identity + + username <name> set username of the emulated user + hostname <name> set container hostname + env KEY=VALUE set an environment variable for the initial process + + ro "pathname" make a host path available to the container; the string + must be presented in Go string literal syntax, to + specify a different inner pathname, end the outer + pathname with NUL and specify the inner pathname after + the NUL byte + rw "pathname" like ro, but the resulting mount entry is made writable + ro+ "pathname" like ro, but is skipped if pathname does not exist + rw+ "pathname" like ro+, but the resulting mount entry is made writable + + own name add an own policy for the dbus proxy + own_system name like own, but for the system bus if enabled + talk name add a talk policy for the dbus proxy + talk_system name like talk, but for the system bus if enabled + +[cmd/sharefs]: https://pkg.go.dev/hakurei.app/cmd/sharefs +[Void Linux rootfs tarball]: https://voidlinux.org/download +[Alpine Linux]: https://alpinelinux.org +[Chimera Linux]: https://chimera-linux.org +[ZFS clones]: https://openzfs.github.io/openzfs-docs/man/v2.4/8/zfs-clone.8.html +*/ +package main diff --git a/cmd/app/lock.go b/cmd/app/lock.go index 88068381..2a419ea1 100644 --- a/cmd/app/lock.go +++ b/cmd/app/lock.go @@ -8,7 +8,6 @@ import ( "strings" "syscall" - "hakurei.app/check" "hakurei.app/fhs" "hakurei.app/hst" "hakurei.app/internal/env" @@ -24,15 +23,15 @@ func (e MutationConflictError) Error() string { } // informTemplate guards intention of a template or its derivatives. -func informTemplate(base *check.Absolute, name string, mutable bool) (func() error, error) { - mu := lockedfile.MutexAt(base.Append("lock", name).String()) +func informTemplate(b *base, name string, mutable bool) (func() error, error) { + mu := lockedfile.MutexAt(b.append("lock", name).String()) if unlock, err := mu.Lock(); err != nil { return nil, err } else { defer unlock() } - marker := base.Append("lock", "."+name) + marker := b.append("lock", "."+name) if p, err := os.ReadFile(marker.String()); err == nil { if _, err = os.Stat(fhs.AbsProc.Append(string(p)).String()); err == nil { return nil, MutationConflictError(p) @@ -72,8 +71,8 @@ func informTemplate(base *check.Absolute, name string, mutable bool) (func() err if !root.Target.Is(fhs.AbsRoot) || len(root.Lower) != 1 || - !root.Lower[0].Is(base.Append("initial")) || - !root.Upper.Is(base.Append("template", name)) || + !root.Lower[0].Is(b.initial()) || + !root.Upper.Is(b.template(name)) || root.Work != nil { continue } @@ -102,12 +101,12 @@ func informTemplate(base *check.Absolute, name string, mutable bool) (func() err } // acquireTemplate obtains exclusivity of a template. -func acquireTemplate(base *check.Absolute, name string) (remove func() error, err error) { - return informTemplate(base, name, true) +func acquireTemplate(b *base, name string) (remove func() error, err error) { + return informTemplate(b, name, true) } // enterTemplate checks against exclusivity of a template. -func enterTemplate(base *check.Absolute, name string) error { - _, err := informTemplate(base, name, false) +func enterTemplate(b *base, name string) error { + _, err := informTemplate(b, name, false) return err } diff --git a/cmd/app/main.go b/cmd/app/main.go index 00bceb57..9b51d601 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -1,24 +1,25 @@ -// The app program is a proof-of-concept frontend for cmd/hakurei. -// -// This program is not covered by the compatibility promise. The command line -// interface and configuration syntax may change at any time. package main import ( "context" "errors" + "fmt" "io" "log" "os" "os/exec" "os/signal" "path/filepath" + "slices" + "strconv" + "strings" "syscall" "hakurei.app/check" "hakurei.app/command" "hakurei.app/fhs" "hakurei.app/hst" + "hakurei.app/internal/outcome" "hakurei.app/message" ) @@ -36,7 +37,7 @@ func main() { flagBase string flagInsecure bool - base, template, initial *check.Absolute + b *base ) c := command.New(os.Stderr, log.Printf, "app", func([]string) (err error) { msg.SwapVerbose(flagVerbose) @@ -44,14 +45,15 @@ func main() { if flagBase == "" { flagBase = "state" } + + var a *check.Absolute if flagBase, err = filepath.Abs(flagBase); err != nil { return - } else if base, err = check.NewAbs(flagBase); err != nil { + } else if a, err = check.NewAbs(flagBase); err != nil { return } + b = (*base)(a) - template = base.Append("template") - initial = base.Append("initial") return }).Flag( &flagVerbose, @@ -76,7 +78,7 @@ func main() { "enter", "Enter mutable state template", func(args []string) error { if len(args) != 1 { - return list(template, true) + return list(b.append("template"), true) } config := hst.Config{ @@ -86,9 +88,9 @@ func main() { Filesystem: []hst.FilesystemConfigJSON{ {FilesystemConfig: &hst.FSOverlay{ Target: fhs.AbsRoot, - Lower: []*check.Absolute{initial}, - Upper: template.Append(args[0]), - Work: base.Append("work", args[0]), + Lower: []*check.Absolute{b.initial()}, + Upper: b.template(args[0]), + Work: b.work(args[0]), }}, {FilesystemConfig: &hst.FSEphemeral{ Target: fhs.AbsTmp, @@ -122,7 +124,7 @@ func main() { config.Container.Home = a } - remove, err := acquireTemplate(base, args[0]) + remove, err := acquireTemplate(b, args[0]) if err != nil { return err } @@ -148,19 +150,19 @@ func main() { "run", "Start the named application", func(args []string) error { if len(args) < 1 { - return list(base.Append("app"), false) + return list(b.append("app"), false) } var config *hst.Config var r io.Reader - f, err := os.Open(base.Append("app", args[0]).String()) + f, err := os.Open(b.append("app", args[0]).String()) if err != nil { return err } r = f var common *os.File - if common, err = os.Open(base.Append("common").String()); err != nil { + if common, err = os.Open(b.append("common").String()); err != nil { if !errors.Is(err, os.ErrNotExist) { _ = f.Close() return err @@ -170,7 +172,7 @@ func main() { } var name string - config, err = parse(args[0], base, r, &name) + config, err = parse(args[0], b, r, &name) if closeErr := f.Close(); err == nil { err = closeErr } @@ -187,7 +189,7 @@ func main() { config.Container.Args[2] = flagCommand } - if err = enterTemplate(base, name); err != nil { + if err = enterTemplate(b, name); err != nil { return err } return run(ctx, msg, flagInsecure, config, args[1:]...) @@ -200,6 +202,105 @@ func main() { ) } + c.NewCommand( + "id", "Show user/group id of the specified appid", + func(args []string) error { + var appid int + switch len(args) { + case 0: + log.Println("appid not specified, assuming reserved user") + break + + case 1: + var err error + appid, err = strconv.Atoi(args[0]) + if err != nil { + return os.ErrInvalid + } + break + + default: + return errors.New("id requires 1 argument") + } + + fmt.Println(hst.ToUser(outcome.Info().User, appid)) + return nil + }, + ) + + c.NewCommand( + "next", "Find next unused identity", + func([]string) error { + var names []string + if dents, err := os.ReadDir(b.append("app").String()); err != nil { + return err + } else { + names = make([]string, 0, len(dents)) + for _, dent := range dents { + name := dent.Name() + if dent.IsDir() || (len(name) > 0 && name[0] == '.') { + continue + } + names = append(names, name) + } + } + + apps := make([]*hst.Config, len(names)) + for i, name := range names { + r, err := os.Open(b.append("app", name).String()) + if err != nil { + return err + } + + apps[i], err = parse(name, b, r, nil) + if closeErr := r.Close(); err == nil { + err = closeErr + } + if err != nil { + return err + } + } + + p := make(map[int][]*hst.Config) + for _, config := range apps { + p[config.Identity] = append(p[config.Identity], config) + } + + identities := make([]int, 0, len(p)) + for identity, a := range p { + identities = append(identities, identity) + if msg.IsVerbose() && len(a) != 1 { + ids := make([]string, len(a)) + for i, config := range a { + ids[i] = config.ID + } + slices.Sort(ids) + msg.Verbosef( + "%s shares identity %d", + strings.Join(ids, ", "), identity, + ) + } + } + + if len(identities) == 0 { + // 0 is the reserved identity + fmt.Println(1) + return nil + } + + slices.Sort(identities) + next := identities[0] - 1 + for _, identity := range identities { + if identity != next+1 { + break + } + next = identity + } + fmt.Println(next + 1) + return nil + }, + ) + c.MustParse(os.Args[1:], func(err error) { if e, ok := errors.AsType[*exec.ExitError](err); ok && e != nil { os.Exit(e.ExitCode()) diff --git a/cmd/mbf/internal/pkgserver/api.go b/cmd/mbf/internal/pkgsite/api.go index 68ccd471..a3094359 100644 --- a/cmd/mbf/internal/pkgserver/api.go +++ b/cmd/mbf/internal/pkgsite/api.go @@ -1,5 +1,5 @@ -// Package pkgserver implements the package metadata service backend. -package pkgserver +// Package pkgsite implements the package metadata website. +package pkgsite import ( "context" diff --git a/cmd/mbf/internal/pkgserver/api_test.go b/cmd/mbf/internal/pkgsite/api_test.go index 1552fec9..d2c21d81 100644 --- a/cmd/mbf/internal/pkgserver/api_test.go +++ b/cmd/mbf/internal/pkgsite/api_test.go @@ -1,4 +1,4 @@ -package pkgserver +package pkgsite import ( "net/http" diff --git a/cmd/mbf/internal/pkgserver/index.go b/cmd/mbf/internal/pkgsite/index.go index 2a9b6de5..760806c0 100644 --- a/cmd/mbf/internal/pkgserver/index.go +++ b/cmd/mbf/internal/pkgsite/index.go @@ -1,4 +1,4 @@ -package pkgserver +package pkgsite import ( "cmp" diff --git a/cmd/mbf/internal/pkgserver/index_test.go b/cmd/mbf/internal/pkgsite/index_test.go index 8f3b5530..abf78876 100644 --- a/cmd/mbf/internal/pkgserver/index_test.go +++ b/cmd/mbf/internal/pkgsite/index_test.go @@ -1,4 +1,4 @@ -package pkgserver +package pkgsite import ( "bytes" diff --git a/cmd/mbf/internal/pkgserver/search.go b/cmd/mbf/internal/pkgsite/search.go index 15947804..ef7cd76f 100644 --- a/cmd/mbf/internal/pkgserver/search.go +++ b/cmd/mbf/internal/pkgsite/search.go @@ -1,4 +1,4 @@ -package pkgserver +package pkgsite import ( "cmp" diff --git a/cmd/mbf/internal/pkgserver/ui/index.html b/cmd/mbf/internal/pkgsite/ui/index.html index 6a5d72b4..6a5d72b4 100644 --- a/cmd/mbf/internal/pkgserver/ui/index.html +++ b/cmd/mbf/internal/pkgsite/ui/index.html diff --git a/cmd/mbf/internal/pkgserver/ui/index.ts b/cmd/mbf/internal/pkgsite/ui/index.ts index 0784b81f..0784b81f 100644 --- a/cmd/mbf/internal/pkgserver/ui/index.ts +++ b/cmd/mbf/internal/pkgsite/ui/index.ts diff --git a/cmd/mbf/internal/pkgserver/ui/style.css b/cmd/mbf/internal/pkgsite/ui/style.css index b4f281ac..b4f281ac 100644 --- a/cmd/mbf/internal/pkgserver/ui/style.css +++ b/cmd/mbf/internal/pkgsite/ui/style.css diff --git a/cmd/mbf/internal/pkgserver/ui/tsconfig.json b/cmd/mbf/internal/pkgsite/ui/tsconfig.json index 24df4936..24df4936 100644 --- a/cmd/mbf/internal/pkgserver/ui/tsconfig.json +++ b/cmd/mbf/internal/pkgsite/ui/tsconfig.json diff --git a/cmd/mbf/internal/pkgserver/ui/ui.go b/cmd/mbf/internal/pkgsite/ui/ui.go index 3fc0d89c..3fc0d89c 100644 --- a/cmd/mbf/internal/pkgserver/ui/ui.go +++ b/cmd/mbf/internal/pkgsite/ui/ui.go diff --git a/cmd/mbf/internal/pkgserver/ui/ui_full.go b/cmd/mbf/internal/pkgsite/ui/ui_full.go index 564787dc..564787dc 100644 --- a/cmd/mbf/internal/pkgserver/ui/ui_full.go +++ b/cmd/mbf/internal/pkgsite/ui/ui_full.go diff --git a/cmd/mbf/internal/pkgserver/ui/ui_stub.go b/cmd/mbf/internal/pkgsite/ui/ui_stub.go index daf010f8..daf010f8 100644 --- a/cmd/mbf/internal/pkgserver/ui/ui_stub.go +++ b/cmd/mbf/internal/pkgsite/ui/ui_stub.go diff --git a/cmd/mbf/main.go b/cmd/mbf/main.go index 4f471d6a..22bfbc3e 100644 --- a/cmd/mbf/main.go +++ b/cmd/mbf/main.go @@ -43,8 +43,8 @@ import ( "hakurei.app/message" "hakurei.app/pkg" - "hakurei.app/cmd/mbf/internal/pkgserver" - "hakurei.app/cmd/mbf/internal/pkgserver/ui" + "hakurei.app/cmd/mbf/internal/pkgsite" + "hakurei.app/cmd/mbf/internal/pkgsite/ui" ) // builtin contains native and embedded [rosa.Artifact] registrations. @@ -343,7 +343,7 @@ func main() { var mux http.ServeMux ui.Register(&mux) - if err = pkgserver.Register(ctx, &mux, r); err != nil { + if err = pkgsite.Register(ctx, &mux, r); err != nil { return } @@ -40,6 +40,8 @@ var ( AbsDev = unsafeAbs(Dev) // AbsDevShm is [DevShm] as [check.Absolute]. AbsDevShm = unsafeAbs(DevShm) + // AbsDevKvm is [DevKvm] as [check.Absolute]. + AbsDevKvm = unsafeAbs(DevKvm) // AbsProc is [Proc] as [check.Absolute]. AbsProc = unsafeAbs(Proc) // AbsProcSys is [ProcSys] as [check.Absolute]. @@ -35,6 +35,8 @@ const ( // DevShm is the place for POSIX shared memory segments, as created via // shm_open(3). DevShm = "/dev/shm/" + // DevKvm is the KVM system device. + DevKvm = "/dev/kvm" // Proc points to a virtual kernel file system exposing the process list and // other functionality. Proc = "/proc/" diff --git a/internal/rosa/package/acl/package.az b/internal/rosa/package/acl/package.az index 0e06f227..06c9abe2 100644 --- a/internal/rosa/package/acl/package.az +++ b/internal/rosa/package/acl/package.az @@ -5,7 +5,7 @@ package attr { version# = "2.6.0"; source = remoteTar { - url = "https://download.savannah.nongnu.org/releases/attr/"+ + url = "https://download-mirror.savannah.nongnu.org/releases/attr/"+ "attr-"+version+".tar.gz"; checksum = "pp-NvD1cMIwZycNwZGW2ez-PbTEpHxrRnVH27csj9QdN4oEBkEbJOZX1IIvKnTWS"; compress = gzip; @@ -28,7 +28,7 @@ package acl { version# = "2.4.0"; source = remoteTar { - url = "https://download.savannah.nongnu.org/releases/acl/"+ + url = "https://download-mirror.savannah.nongnu.org/releases/acl/"+ "acl-"+version+".tar.gz"; checksum = "U2eaAsWrhhzEfhyprwHQQG55bFPZxtsHk1Usnd9Jb_g-H__pJod4H3RTrL4ipXDw"; compress = gzip; diff --git a/internal/rosa/package/cryptsetup.az b/internal/rosa/package/cryptsetup.az index 0886d222..2c3b679c 100644 --- a/internal/rosa/package/cryptsetup.az +++ b/internal/rosa/package/cryptsetup.az @@ -3,12 +3,12 @@ package cryptsetup { website = "https://gitlab.com/cryptsetup/cryptsetup"; anitya = 13709; - version# = "2.8.7"; + version# = "2.8.8"; source = remoteGitLab { domain = "gitlab.com"; suffix = "cryptsetup/cryptsetup"; ref = "v"+version; - checksum = "eDi_UaMtwhIzqpsdcA91aVb56zCYDrsDzeMWfWXAnPbuvn2bEgeH5dFs7mouHz8V"; + checksum = "Q88h-7N-QFJcBe-MbtkFu0fSjrhRUF8WYCH4vhznbtFjniXLXRKMku-JoZAtHQMS"; }; bin = [ "bash" ]; diff --git a/internal/rosa/package/dbus.az b/internal/rosa/package/dbus.az index 4d2dd6ec..402cc6fb 100644 --- a/internal/rosa/package/dbus.az +++ b/internal/rosa/package/dbus.az @@ -36,11 +36,11 @@ package xdg-dbus-proxy { website = "https://github.com/flatpak/xdg-dbus-proxy"; anitya = 58434; - version# = "0.1.8"; + version# = "0.1.9"; source = remoteGitHub { suffix = "flatpak/xdg-dbus-proxy"; tag = version; - checksum = "ygdW0EEvZ-_PJfnFTNoobITmRzqJecTinBsJd_iJQrRvzidwqESCjeNkB55smZ2y"; + checksum = "HfAi2M60v3wE_TbESYZ4eMB4G2-spBt0x0UrKaRp7FNVywDbg9d_L3_kr2QXzlfp"; }; exec = meson { diff --git a/internal/rosa/package/firmware.az b/internal/rosa/package/firmware.az index f04b39e9..e87a34c1 100644 --- a/internal/rosa/package/firmware.az +++ b/internal/rosa/package/firmware.az @@ -3,12 +3,12 @@ package firmware { website = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git"; anitya = 141464; - version# = "20260810"; + version# = "20260916"; source = remoteGitLab { domain = "gitlab.com"; suffix = "kernel-firmware/linux-firmware"; ref = version; - checksum = "XNUhz9QstaDKNegM3Bl0-TtZzpsvX7-E8WMnDCO7KBhBC6t_TxsdG05-ETdXynry"; + checksum = "Yv3yaffN6-ARSFSnDm-0gHM3T7m3ZwMqBLIP8UA3Jpe23Jk8MyNLUE44wJMy_DH6"; }; // dedup creates temporary file diff --git a/internal/rosa/package/freetype.az b/internal/rosa/package/freetype.az index cfa5933a..19af2dd4 100644 --- a/internal/rosa/package/freetype.az +++ b/internal/rosa/package/freetype.az @@ -5,7 +5,7 @@ package freetype { version# = "2.14.3"; source = remoteTar { - url = "https://download.savannah.gnu.org/releases/freetype/"+ + url = "https://download-mirror.savannah.gnu.org/releases/freetype/"+ "freetype-"+version+".tar.gz"; checksum = "-WfLv8fVJNyCHpP_lriiDzOcVbBL9ajdQ3tl8AzIIUa9-8sVpU9irxOmSMgRHWYz"; compress = gzip; diff --git a/internal/rosa/package/fribidi.az b/internal/rosa/package/fribidi.az index 0bd45693..28df4375 100644 --- a/internal/rosa/package/fribidi.az +++ b/internal/rosa/package/fribidi.az @@ -3,11 +3,11 @@ package fribidi { website = "https://github.com/fribidi/fribidi"; anitya = 857; - version# = "1.0.16"; + version# = "1.0.17"; source = remoteGitHub { suffix = "fribidi/fribidi"; tag = "v"+version; - checksum = "Sn9hwdgViXW9_MOi8ovAcBgQy6s6o4cc0o260k76nqCRzxmxxD1-B37GVkJ2EoMy"; + checksum = "yJWcJqYDmzdyFB-kc9J1JDPLiqWHTw2n2bheXvqzP66bk56HYWW9sz_w-TMUqiEV"; }; exec = meson { diff --git a/internal/rosa/package/fuse/package.az b/internal/rosa/package/fuse/package.az index 31000e07..3e43c3c6 100644 --- a/internal/rosa/package/fuse/package.az +++ b/internal/rosa/package/fuse/package.az @@ -3,12 +3,12 @@ package fuse { website = "https://github.com/libfuse/libfuse"; anitya = 861; - version# = "3.18.2"; + version# = "3.18.3"; source = remoteGitHubRelease { suffix = "libfuse/libfuse"; tag = "fuse-"+version; name = "fuse-"+version+".tar.gz"; - checksum = "iL-7b7eUtmlVSf5cSq0dzow3UiqSjBmzV3cI_ENPs1tXcHdktkG45j1V12h-4jZe"; + checksum = "zQuo1ZLCePjlgxbOO8BuiLPPHwjbU0IItSo3K9_BtcxIid027b7XQWfm07c1T5D4"; compress = gzip; }; patches = [ "example-include.patch" ]; @@ -20,12 +20,8 @@ package fuse { "useroot": "false"; "initscriptdir": "/system/etc"; }; - - postCompile = "python3 -m pytest test/"; - // this project uses pytest - test = false; }; - tools = [ python-pytest ]; + tools = [ bash ]; inputs = [ kernel-headers ]; } diff --git a/internal/rosa/package/git.az b/internal/rosa/package/git.az index 07abe88e..7ebb8113 100644 --- a/internal/rosa/package/git.az +++ b/internal/rosa/package/git.az @@ -63,6 +63,7 @@ disable_test t5515-fetch-merge-logic disable_test t4124-apply-ws-rule disable_test t3404-rebase-interactive disable_test t7527-builtin-fsmonitor +disable_test t5702-protocol-v2 `; check = [ diff --git a/internal/rosa/package/glib/package.az b/internal/rosa/package/glib/package.az index 14ff0450..5c82be35 100644 --- a/internal/rosa/package/glib/package.az +++ b/internal/rosa/package/glib/package.az @@ -3,11 +3,11 @@ package glib { website = "https://developer.gnome.org/glib"; anitya = 10024; - version# = "2.89.4"; + version# = "2.90.0"; source = remoteGit { url = "https://gitlab.gnome.org/GNOME/glib.git"; tag = version; - checksum = "I_nTEVp4rpOQ4VCmJpesjvq3VbFJ3oLRAUVvsdJEfFiY4XXsvi0ITTqCEWe9Lr47"; + checksum = "7TWtYVOWNTkqg1SLAtNyhkUnvXB9jshJHCModCZl9JAzogKKoBebfMDmq2edOpXm"; }; files = { diff --git a/internal/rosa/package/gnu.az b/internal/rosa/package/gnu.az index 3eb48ab5..c3f1be64 100644 --- a/internal/rosa/package/gnu.az +++ b/internal/rosa/package/gnu.az @@ -66,10 +66,10 @@ package automake { website = "https://www.gnu.org/software/automake"; anitya = 144; - version# = "1.18.1"; + version# = "1.19"; source = remoteTar { url = "https://mirrors.kernel.org/gnu/automake/automake-"+version+".tar.gz"; - checksum = "FjvLG_GdQP7cThTZJLDMxYpRcKdpAVG-YDs1Fj1yaHlSdh_Kx6nRGN14E0r_BjcG"; + checksum = "p-EeV6uh3lSbLtsnxI-l0HxC_QAnANoEdrQTI2l_VCRtYQpvmbwXIglo8S6DAI7G"; compress = gzip; }; @@ -130,10 +130,10 @@ package gzip { website = "https://www.gnu.org/software/gzip"; anitya = 1290; - version# = "1.14"; + version# = "1.15"; source = remoteTar { url = "https://mirrors.kernel.org/gnu/gzip/gzip-"+version+".tar.gz"; - checksum = "NWhjUavnNfTDFkZJyAUonL9aCOak8GVajWX2OMlzpFnuI0ErpBFyj88mz2xSjz0q"; + checksum = "N8v7cH-Vhmxvk1PYaF-B1vH-r-rMT3Z3VyMdCFXhBd74a8v62wT3dKes-u1JCvUG"; compress = gzip; }; @@ -339,10 +339,10 @@ package coreutils { website = "https://www.gnu.org/software/coreutils"; anitya = 343; - version# = "9.11"; + version# = "9.12"; source = remoteTar { url = "https://mirrors.kernel.org/gnu/coreutils/coreutils-"+version+".tar.gz"; - checksum = "t8UMed5wpFEoC56aa42_yidfOAaRGzOfj7MRtQkkqgGbpXiskNA8bd-EmVSQkZie"; + checksum = "MYYday_Pwp2YFSgVHeCQWJBhJCBhqkIkfML4_a_uHvM_FsKbYQ4vbXy60FprcUoo"; compress = gzip; }; diff --git a/internal/rosa/package/hakurei.az b/internal/rosa/package/hakurei.az index 4e9a8d2c..f8b03b74 100644 --- a/internal/rosa/package/hakurei.az +++ b/internal/rosa/package/hakurei.az @@ -4,7 +4,7 @@ package hakurei-source { version# = "0.4.8"; output = remoteGit { - url = "https://git.gensokyo.uk/rosa/hakurei.git"; + url = "https://src.rosa.moe/hakurei"; tag = "v"+version; checksum = "B6aoojyXblZ7eYwdc3Ak3wDbBpu63j8S79Gpiul9Obb8diqzBIJ2qNCgWVH6qLsc"; }; diff --git a/internal/rosa/package/harfbuzz.az b/internal/rosa/package/harfbuzz.az index 7e10f0f2..89de6df7 100644 --- a/internal/rosa/package/harfbuzz.az +++ b/internal/rosa/package/harfbuzz.az @@ -3,11 +3,11 @@ package harfbuzz { website = "https://harfbuzz.github.io"; anitya = 1299; - version# = "14.4.0"; + version# = "14.5.0"; source = remoteGitHub { suffix = "harfbuzz/harfbuzz"; tag = version; - checksum = "Avi4h70Src2_E7l8ag1NP64KH2moVvAWb_cCay4b9FB_5zAJzcTTJLCTf_-nnCHw"; + checksum = "d5NdKP_w04g9mMLc8bW7s7DqC9uKz3vi5TczEHasJ2Wmm6vV9dvj0thuebR-7vz7"; }; exec = meson { diff --git a/internal/rosa/package/kernel/amd64.config b/internal/rosa/package/kernel/amd64.config index b52bfbd4..81601250 100644 --- a/internal/rosa/package/kernel/amd64.config +++ b/internal/rosa/package/kernel/amd64.config @@ -1,16 +1,16 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.18.49 Kernel Configuration +# Linux/x86 6.18.52 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="clang version 23.1.0" +CONFIG_CC_VERSION_TEXT="clang version 23.1.1" CONFIG_GCC_VERSION=0 CONFIG_CC_IS_CLANG=y -CONFIG_CLANG_VERSION=230100 +CONFIG_CLANG_VERSION=230101 CONFIG_AS_IS_LLVM=y -CONFIG_AS_VERSION=230100 +CONFIG_AS_VERSION=230101 CONFIG_LD_VERSION=0 CONFIG_LD_IS_LLD=y -CONFIG_LLD_VERSION=230100 +CONFIG_LLD_VERSION=230101 CONFIG_RUSTC_VERSION=0 CONFIG_RUSTC_LLVM_VERSION=0 CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y @@ -658,7 +658,7 @@ CONFIG_ACPI_IPMI=m CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_PROCESSOR_AGGREGATOR=m CONFIG_ACPI_THERMAL=m -CONFIG_ACPI_PLATFORM_PROFILE=m +CONFIG_ACPI_PLATFORM_PROFILE=y CONFIG_ACPI_CUSTOM_DSDT_FILE="" CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y CONFIG_ACPI_TABLE_UPGRADE=y @@ -730,6 +730,7 @@ CONFIG_X86_INTEL_PSTATE=y CONFIG_X86_PCC_CPUFREQ=m CONFIG_X86_AMD_PSTATE=y CONFIG_X86_AMD_PSTATE_DEFAULT_MODE=3 +CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP=y CONFIG_X86_AMD_PSTATE_UT=m CONFIG_X86_ACPI_CPUFREQ=m CONFIG_X86_ACPI_CPUFREQ_CPB=y @@ -1044,6 +1045,7 @@ CONFIG_FUNCTION_ALIGNMENT_16B=y CONFIG_FUNCTION_ALIGNMENT=16 CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y CONFIG_ARCH_HAS_CPU_ATTACK_VECTORS=y +CONFIG_HAVE_ARCH_GET_SECUREBOOT=y # end of General architecture-dependent options CONFIG_RT_MUTEXES=y diff --git a/internal/rosa/package/kernel/arm64.config b/internal/rosa/package/kernel/arm64.config index 9c6951b7..78fc713b 100644 --- a/internal/rosa/package/kernel/arm64.config +++ b/internal/rosa/package/kernel/arm64.config @@ -1,16 +1,16 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm64 6.18.49 Kernel Configuration +# Linux/arm64 6.18.52 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="clang version 23.1.0" +CONFIG_CC_VERSION_TEXT="clang version 23.1.1" CONFIG_GCC_VERSION=0 CONFIG_CC_IS_CLANG=y -CONFIG_CLANG_VERSION=230100 +CONFIG_CLANG_VERSION=230101 CONFIG_AS_IS_LLVM=y -CONFIG_AS_VERSION=230100 +CONFIG_AS_VERSION=230101 CONFIG_LD_VERSION=0 CONFIG_LD_IS_LLD=y -CONFIG_LLD_VERSION=230100 +CONFIG_LLD_VERSION=230101 CONFIG_RUSTC_VERSION=0 CONFIG_RUSTC_LLVM_VERSION=0 CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y @@ -575,7 +575,6 @@ CONFIG_ARM64_TLB_RANGE=y # CONFIG_AS_HAS_ARMV8_5=y CONFIG_ARM64_BTI=y -CONFIG_ARM64_BTI_KERNEL=y CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y CONFIG_ARM64_E0PD=y CONFIG_ARM64_AS_HAS_MTE=y @@ -975,6 +974,7 @@ CONFIG_HAVE_GCC_PLUGINS=y CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_ALIGNMENT=4 CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y +CONFIG_HAVE_ARCH_GET_SECUREBOOT=y # end of General architecture-dependent options CONFIG_RT_MUTEXES=y @@ -12217,9 +12217,10 @@ CONFIG_PXA1908_PM_DOMAINS=m # CONFIG_MTK_SCPSYS=y CONFIG_MTK_SCPSYS_PM_DOMAINS=y -CONFIG_AIROHA_CPU_PM_DOMAIN=m # end of MediaTek PM Domains +CONFIG_AIROHA_CPU_PM_DOMAIN=m + # # Qualcomm PM Domains # @@ -14220,11 +14221,9 @@ CONFIG_CRYPTO_DEV_SUN4I_SS=m CONFIG_CRYPTO_DEV_SUN8I_CE=m # CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG is not set # CONFIG_CRYPTO_DEV_SUN8I_CE_HASH is not set -# CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG is not set # CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG is not set CONFIG_CRYPTO_DEV_SUN8I_SS=m # CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG is not set -# CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG is not set # CONFIG_CRYPTO_DEV_SUN8I_SS_HASH is not set CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON=m CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC=m diff --git a/internal/rosa/package/kernel/package.az b/internal/rosa/package/kernel/package.az index f2be2890..5a0ffae6 100644 --- a/internal/rosa/package/kernel/package.az +++ b/internal/rosa/package/kernel/package.az @@ -3,11 +3,11 @@ package kernel-source { website = "https://kernel.org"; exclude = true; - version# = "6.18.49"; + version# = "6.18.52"; output = remoteTar { url = "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+ "snapshot/linux-"+version+".tar.gz"; - checksum = "J0FT9987a7mlYBGcACXWeTsmfScbS8FM_JAG9LLl917UdlcFRP_UDj73yR82bvGR"; + checksum = "3OysuyxqFKX0FvKqkwH-Y9t0gB0PpE-ErMb2lITWAJtN0OSDqlHTbeifhgn6VgkV"; compress = gzip; }; } @@ -46,8 +46,8 @@ cat \ checksum = arch { default = ""; - amd64 = "uwTZX3iLp6iPsR0-F0Jz2aUviLMMqv4xGQHoKeemo2HrNLD7fDlIDqqYT--i_5HJ"; - arm64 = "A9EWzTGEChVLJVm5BP1GzpibdUddXUN2hIjAGkD-KQr5sc6RuEeIQle8VAiAYUqp"; + amd64 = "yLzBQuYIpzbjEglADpiAjDsI5OhsOZejLUG-3w1DlVfmU4LaH44W5KercoxrEuGQ"; + arm64 = "aah3h8pHdYNrevRBBIkt8DFi6wzRWZe9uxWcrTwEf1l3X-UWxRfnGxCwJdn0VySM"; riscv64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; }; diff --git a/internal/rosa/package/kernel/version.h b/internal/rosa/package/kernel/version.h index 4fc45286..e8d4316f 100644 --- a/internal/rosa/package/kernel/version.h +++ b/internal/rosa/package/kernel/version.h @@ -1,5 +1,5 @@ -#define LINUX_VERSION_CODE 397870 +#define LINUX_VERSION_CODE 397876 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c))) #define LINUX_VERSION_MAJOR 6 #define LINUX_VERSION_PATCHLEVEL 18 -#define LINUX_VERSION_SUBLEVEL 46 +#define LINUX_VERSION_SUBLEVEL 52 diff --git a/internal/rosa/package/libglvnd.az b/internal/rosa/package/libglvnd.az index dbcf198b..9be9e2a9 100644 --- a/internal/rosa/package/libglvnd.az +++ b/internal/rosa/package/libglvnd.az @@ -22,6 +22,7 @@ export DISPLAY=':0' Xvfb & XVFB_PID="$!" trap 'kill $XVFB_PID && wait $XVFB_PID' EXIT +while [ ! -e /tmp/.X11-unix/X0 ]; do sleep 0.1; done `; }; diff --git a/internal/rosa/package/libinput.az b/internal/rosa/package/libinput.az index aeb54f77..3769f680 100644 --- a/internal/rosa/package/libinput.az +++ b/internal/rosa/package/libinput.az @@ -3,12 +3,12 @@ package libinput { website = "https://www.freedesktop.org/wiki/Software/libinput"; anitya = 5781; - version# = "1.31.3"; + version# = "1.32.0"; source = remoteGitLab { domain = "gitlab.freedesktop.org"; suffix = "libinput/libinput"; ref = version; - checksum = "GxBGPN6YybQxrD2MDsIL8gdDYImXn4NAJi6EvTx_Hb_1jcbjwCrjeyjY2upUyTMi"; + checksum = "hjuI9afDPrCORLCCM5koBjyRNmTr_YCUmmF4Tl0bqK_7fz0beC8125wt3lmimtgL"; }; bin = [ "bash" ]; diff --git a/internal/rosa/package/libliftoff/0001-test-Disable-alloc-deadline-on-tests.patch b/internal/rosa/package/libliftoff/0001-test-Disable-alloc-deadline-on-tests.patch new file mode 100644 index 00000000..6747ac01 --- /dev/null +++ b/internal/rosa/package/libliftoff/0001-test-Disable-alloc-deadline-on-tests.patch @@ -0,0 +1,139 @@ +From 343a7d02cf5417e0732d8ba73089f86dd6173253 Mon Sep 17 00:00:00 2001 +From: David Turner <david.turner@raspberrypi.com> +Date: Wed, 5 Mar 2025 16:02:25 +0000 +Subject: [PATCH] test: Disable alloc deadline on tests + +I've been seeing occasional spurious CI failures due to +liftoff_output_apply() deadline timeouts, presumably when the runner is +busy. Disable the allocation deadline in all tests to stop this +happening. +--- + test/test_alloc.c | 16 ++++++++++++---- + test/test_candidate.c | 4 +++- + test/test_dynamic.c | 8 ++++++-- + test/test_priority.c | 4 +++- + test/test_prop.c | 4 +++- + 5 files changed, 27 insertions(+), 9 deletions(-) + +diff --git a/test/test_alloc.c b/test/test_alloc.c +index 8d0caf7..a002c46 100644 +--- a/test/test_alloc.c ++++ b/test/test_alloc.c +@@ -803,7 +803,9 @@ run_test(const struct test_case *test) + } + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(output, req, 0, NULL); ++ ret = liftoff_output_apply(output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(drm_fd, req, 0, NULL); + assert(ret == 0); +@@ -875,7 +877,9 @@ test_basic(void) + liftoff_mock_plane_add_compatible_layer(mock_plane, layer); + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(output, req, 0, NULL); ++ ret = liftoff_output_apply(output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(drm_fd, req, 0, NULL); + assert(ret == 0); +@@ -913,7 +917,9 @@ test_no_props_fail(void) + liftoff_mock_plane_add_compatible_layer(mock_plane, layer); + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(output, req, 0, NULL); ++ ret = liftoff_output_apply(output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(drm_fd, req, 0, NULL); + assert(ret == 0); +@@ -959,7 +965,9 @@ test_composition_no_props(void) + liftoff_mock_plane_add_compatible_layer(mock_plane, layer_with_fb); + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(output, req, 0, NULL); ++ ret = liftoff_output_apply(output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(drm_fd, req, 0, NULL); + assert(ret == 0); +diff --git a/test/test_candidate.c b/test/test_candidate.c +index 5e7f698..74a0bcb 100644 +--- a/test/test_candidate.c ++++ b/test/test_candidate.c +@@ -60,7 +60,9 @@ test_basic(void) + liftoff_layer_set_property(layer, "COLOR_RANGE", 0); + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(output, req, 0, NULL); ++ ret = liftoff_output_apply(output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(drm_fd, req, 0, NULL); + assert(ret == 0); +diff --git a/test/test_dynamic.c b/test/test_dynamic.c +index 3a95a7f..8c1049d 100644 +--- a/test/test_dynamic.c ++++ b/test/test_dynamic.c +@@ -50,7 +50,9 @@ first_commit(struct context *ctx) + assert(ctx->commit_count == 0); + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(ctx->output, req, 0, NULL); ++ ret = liftoff_output_apply(ctx->output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(ctx->drm_fd, req, 0, NULL); + assert(ret == 0); +@@ -72,7 +74,9 @@ second_commit(struct context *ctx, bool want_reuse_prev_alloc) + int ret; + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(ctx->output, req, 0, NULL); ++ ret = liftoff_output_apply(ctx->output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + if (want_reuse_prev_alloc) { + /* The library should perform only one TEST_ONLY commit with the +diff --git a/test/test_priority.c b/test/test_priority.c +index cf2e4c5..41ede18 100644 +--- a/test/test_priority.c ++++ b/test/test_priority.c +@@ -76,7 +76,9 @@ main(int argc, char *argv[]) + + liftoff_layer_set_property(layer, "FB_ID", fbs[j % 2]); + +- ret = liftoff_output_apply(output, req, 0, NULL); ++ ret = liftoff_output_apply(output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(drm_fd, req, 0, NULL); + assert(ret == 0); +diff --git a/test/test_prop.c b/test/test_prop.c +index 05193c7..093b581 100644 +--- a/test/test_prop.c ++++ b/test/test_prop.c +@@ -34,7 +34,9 @@ commit(int drm_fd, struct liftoff_output *output) + int ret; + + req = drmModeAtomicAlloc(); +- ret = liftoff_output_apply(output, req, 0, NULL); ++ ret = liftoff_output_apply(output, req, 0, &(struct liftoff_output_apply_options){ ++ .timeout_ns = INT64_MAX, ++ }); + assert(ret == 0); + ret = drmModeAtomicCommit(drm_fd, req, 0, NULL); + assert(ret == 0); +-- +2.55.0 + diff --git a/internal/rosa/package/libliftoff.az b/internal/rosa/package/libliftoff/package.az index a1c23fd8..7d8900bc 100644 --- a/internal/rosa/package/libliftoff.az +++ b/internal/rosa/package/libliftoff/package.az @@ -10,6 +10,7 @@ package libliftoff { ref = "v"+version; checksum = "anxKfrW56iK7l6-bm6RGcaC_uk-Kc8x3_VqKaywmSjv5HLCs6A2sHyjGUbOC9xZv"; }; + patches = [ "0001-test-Disable-alloc-deadline-on-tests.patch" ]; exec = meson {}; diff --git a/internal/rosa/package/libtirpc.az b/internal/rosa/package/libtirpc.az index 0b12a92e..b1a49c79 100644 --- a/internal/rosa/package/libtirpc.az +++ b/internal/rosa/package/libtirpc.az @@ -3,7 +3,7 @@ package libtirpc { website = "https://sourceforge.net/projects/libtirpc"; anitya = 1740; - version# = "1.3.7"; + version# = "1.3.8"; source = remoteGit { url = "git://linux-nfs.org/~steved/libtirpc"; tag = "libtirpc-"+join { @@ -14,7 +14,7 @@ package libtirpc { }; sep = "-"; }; - checksum = "nzFfu7LNvnSNiNAryD1vtnNWnU-Xqee8KqfXUKoBf5yjb5-dkeRkYuRijdCoYLof"; + checksum = "OYM7CljjvlHv3Xzc9bXC2WRfBQY0QcBEZ9ubE8qVDweq9ZvQPrAWxSOFVhFBoToz"; }; exec = make { @@ -29,6 +29,10 @@ package libtirpc { automake, libtool, pkgconf, + + // version script assignment of 'TIRPC_1.3.7' to symbol 'authdes_getucred' failed: symbol not defined + // version script assignment of 'TIRPC_1.3.7' to symbol 'rpc_gss_getcred' failed: symbol not defined + binutils, ]; inputs = [ diff --git a/internal/rosa/package/llvm/package.az b/internal/rosa/package/llvm/package.az index 11210563..73b0ed8e 100644 --- a/internal/rosa/package/llvm/package.az +++ b/internal/rosa/package/llvm/package.az @@ -2,11 +2,11 @@ package llvm-project { description = "LLVM monorepo with Rosa OS patches"; anitya = 1830; - version# = "23.1.0"; + version# = "23.1.1"; output = remoteGitHub { suffix = "llvm/llvm-project"; tag = "llvmorg-"+version; - checksum = "wgirRNAhU9451qsZn4FXcaIButgRNZWb4kb8pQwERyF1PGc-iJQVewr6xGk7ctNj"; + checksum = "3PRmlMQcmYffm_uj3DxEeDaukPHBS5fpCsWYLHX-9HZXwlgZQG43li2lJLJ33_SN"; }; patches = [ "increase-stack-size-unconditional.patch", diff --git a/internal/rosa/package/mesa/include.patch b/internal/rosa/package/mesa/include.patch index b1942625..4a8a7fe9 100644 --- a/internal/rosa/package/mesa/include.patch +++ b/internal/rosa/package/mesa/include.patch @@ -1,15 +1,3 @@ -diff --git a/src/amd/compiler/aco_util.h b/src/amd/compiler/aco_util.h -index 82d754f155a..9f20e80a554 100644 ---- a/src/amd/compiler/aco_util.h -+++ b/src/amd/compiler/aco_util.h -@@ -12,6 +12,7 @@ - #include "util/macros.h" - #include "util/u_math.h" - -+#include <algorithm> - #include <array> - #include <cassert> - #include <cstddef> diff --git a/src/freedreno/common/freedreno_common.h b/src/freedreno/common/freedreno_common.h index 36dea4e12b5..cfa243c270f 100644 --- a/src/freedreno/common/freedreno_common.h diff --git a/internal/rosa/package/mesa/package.az b/internal/rosa/package/mesa/package.az index 8db6462e..ec7956fb 100644 --- a/internal/rosa/package/mesa/package.az +++ b/internal/rosa/package/mesa/package.az @@ -4,12 +4,12 @@ package mesa { anitya = 1970; latest = anityaFallback; - version# = "26.2.2"; + version# = "26.2.3"; source = remoteGitLab { domain = "gitlab.freedesktop.org"; suffix = "mesa/mesa"; ref = "mesa-"+version; - checksum = "5mIdojhazcdAgbLW1v4d-7P5pIhu9wnGS3ek1QhJIPMJyFWhfKhiZCsd53WAHt1_"; + checksum = "VAGZWGIjAnBqWi7N_Tye3ihtoc66Gu8AlKGtpmQOfwcwQqhZ6Sxk2Y_IH49jWOrJ"; }; patches = [ "include.patch" ]; diff --git a/internal/rosa/package/nss.az b/internal/rosa/package/nss.az index fb9c1a33..e76be8f2 100644 --- a/internal/rosa/package/nss.az +++ b/internal/rosa/package/nss.az @@ -3,7 +3,7 @@ package nss-cacert { website = "https://firefox-source-docs.mozilla.org/security/nss/index.html"; anitya = 2503; - version# = "3.128"; + version# = "3.129"; source = remoteGitHub { suffix = "nss-dev/nss"; tag = "NSS_"+join { @@ -14,7 +14,7 @@ package nss-cacert { }; sep = "_"; }+"_RTM"; - checksum = "uVP9Tbv17Vo7tUAm1LK16vu-9PA4Mecjc1Kr6y4ptXby9e0zT7I15rzsD2fMApqA"; + checksum = "nrmKcrMZ_Bq5FiWBmJWOPrJvP0IB9jfj4zEm1gzufN4hiuHFlNFjJExBpQVk_l8i"; }; enterSource = true; diff --git a/internal/rosa/package/pipewire.az b/internal/rosa/package/pipewire.az index 06153a9f..30d95de2 100644 --- a/internal/rosa/package/pipewire.az +++ b/internal/rosa/package/pipewire.az @@ -37,12 +37,12 @@ package pipewire { website = "https://pipewire.org"; anitya = 57357; - version# = "1.6.8"; + version# = "1.6.9"; source = remoteGitLab { domain = "gitlab.freedesktop.org"; suffix = "pipewire/pipewire"; ref = version; - checksum = "KPPJDODFi6RpNpoGztQGNTiINRubQ_7WVIngsboHQi0XzEhMAKVp7iaUG74QX3aE"; + checksum = "EtqI-7Gwgp_6rHRqVlhuGAt39vOlX_SAoUWzaeeCaUqX4X6feCQvqmSwQvzR88Dr"; }; exec = meson { diff --git a/internal/rosa/package/pkgconf.az b/internal/rosa/package/pkgconf.az index 7ce1d72c..1ff20388 100644 --- a/internal/rosa/package/pkgconf.az +++ b/internal/rosa/package/pkgconf.az @@ -3,11 +3,11 @@ package pkgconf { website = "https://github.com/pkgconf/pkgconf"; anitya = 12753; - version# = "3.0.6"; + version# = "3.0.7"; source = remoteGitHub { suffix = "pkgconf/pkgconf"; tag = "pkgconf-"+version; - checksum = "2BY20A8o2LTp6qa5MNsH_UPwkN7OGI6DBXGLqpF0g5mOKazYaCVkslFjnI81B2NI"; + checksum = "_IpcXySlbiPfFIS95oAg9C65_wV3BAoLD_QVP2OHx4MNTgdndsgT_WjtJkCbhlEd"; }; exec = meson { diff --git a/internal/rosa/package/python/package.az b/internal/rosa/package/python/package.az index aef3ecda..dfcb6940 100644 --- a/internal/rosa/package/python/package.az +++ b/internal/rosa/package/python/package.az @@ -182,12 +182,13 @@ package python-vcs-versioning { description = "core VCS versioning functionality extracted as a standalone library"; website = "https://setuptools-scm.readthedocs.io/en/latest"; anitya = 389421; + block = "frequent ineffectual updates; questionable maintainer decisions"; - version# = "2.3.4"; + version# = "2.4.0"; source = remoteGitHub { suffix = "pypa/setuptools-scm"; tag = "vcs-versioning-v"+version; - checksum = "TljjSQUxo07jMzfaVyieXD8dS_olgwEA2_RndGeIjlsdKWSa2oYZ5laMRjdgnXJS"; + checksum = "Ziau4BBAwjQVEVe-MlKpA-27nqOm30LlGfHG5SqIrqKbCABWBndCwzpXLxdnZuGn"; }; env = [ @@ -211,12 +212,13 @@ package python-setuptools-scm { description = "extracts Python package versions from Git or Mercurial metadata"; website = "https://setuptools-scm.readthedocs.io/en/latest"; anitya = 7874; + block = "see package python-vcs-versioning"; - version# = "10.2.3"; + version# = "10.3.2"; source = remoteGitHub { suffix = "pypa/setuptools-scm"; tag = "setuptools-scm-v"+version; - checksum = "C76_jiIc_XanEZrpxLb47B3YArtmlt7HcpEOo0wZ5Z4mCFJb2HLIgOSOiRSfttpW"; + checksum = "wnOU9_VeAiNp881loQiJD3KuWgbufNXhQKqHOGBdt9oEjIMXosHjUseE67fW4ips"; }; env = [ @@ -248,11 +250,11 @@ package python-flit-core { website = "https://flit.pypa.io"; anitya = 44841; - version# = "4.0.2"; + version# = "4.1.0"; source = remoteGitHub { suffix = "pypa/flit"; tag = version; - checksum = "LAYWMeQ2wf2fUavUctRHlEVCUUfsVu0so4d0DZh-DAkAvd8kf9ZHQd-o7dXr3tq6"; + checksum = "c-iUN-XyUB-1jF4CYaQaMNa5W0G4c3UcpjQcwSI9KOZFQ_my3ebpPjBvfVchjywC"; }; exec = pip { @@ -354,11 +356,11 @@ package python-poetry-core { website = "https://github.com/python-poetry/poetry-core"; anitya = 71155; - version# = "2.4.1"; + version# = "2.5.0"; source = remoteGitHub { suffix = "python-poetry/poetry-core"; tag = version; - checksum = "tf9OeSUv9TJwKd48fQIU2uGtZ36GN-PDmPDZzjClozzLjv-rQ5nIbOg9gOXpegiH"; + checksum = "FZCJeScQLZBm2W1JiqgPozV2QKxkU0Dr0tQDsFf-H3PNswQwxSLPEGgEl94va7r3"; }; exec = pip { @@ -394,11 +396,11 @@ package python-hatchling { website = "https://hatch.pypa.io"; anitya = 16137; - version# = "1.18.0"; + version# = "1.18.1"; source = remoteGitHub { suffix = "pypa/hatch"; tag = "hatch-v"+version; - checksum = "a_ntndxBlMdqSVW3PkiAY42m-NDgyWJcKLWFIVTB_5PciVeJdYYdbcdF6jsd0U96"; + checksum = "MQHbzLg0Vo9Wp8oNwFqzyr6Z8xIqI8uxp1r_sue5r_QMI6Ryfx4wXJWpQQgdmUdJ"; }; exec = pip { diff --git a/internal/rosa/package/sway/package.az b/internal/rosa/package/sway/package.az index cd7f1f7f..20834397 100644 --- a/internal/rosa/package/sway/package.az +++ b/internal/rosa/package/sway/package.az @@ -11,6 +11,7 @@ package sway { }; patches = [ "remove-unused.patch" ]; + env = [ "CFLAGS=-Wno-switch" ]; exec = meson {}; inputs = [ diff --git a/internal/rosa/package/x.az b/internal/rosa/package/x.az index 73b82981..94c48ac8 100644 --- a/internal/rosa/package/x.az +++ b/internal/rosa/package/x.az @@ -676,12 +676,12 @@ package xserver { website = "https://gitlab.freedesktop.org/xorg/xserver"; anitya = 5250; - version# = "26.0.99.901"; + version# = "26.0.99.902"; source = remoteGitLab { domain = "gitlab.freedesktop.org"; suffix = "xorg/xserver"; ref = "xorg-server-"+version; - checksum = "2Liwqj-tu_NuD8BuWZR0PyYVJ_A0nj_sgx-LZWtdVpKAKQHtN-dSWCl-IPVOlcHG"; + checksum = "lg1TlhQHnQowDeYzJQVoMHZsUSfTLbZVGwMi8afUHCVlVTbCuRRXLtQWoZjkt4QT"; }; exec = meson { @@ -753,12 +753,12 @@ package xwayland { website = "https://gitlab.freedesktop.org/xorg/xserver"; anitya = 180949; - version# = "26.0.99.901"; + version# = "26.0.99.902"; source = remoteGitLab { domain = "gitlab.freedesktop.org"; suffix = "xorg/xserver"; ref = "xwayland-"+version; - checksum = "Vgtnwme2HU3CCeLE_xNScV_uJ55kPMremaOyVWRUFaRpwpaOQxsNB2fde_9Rx5zm"; + checksum = "D60hCizAFqVKBH49_FbHRigeEgzoOUXRgvEncuE6kzdoIUr5iC8RIBncVuTFgY0D"; }; bin = [ "bash" ]; diff --git a/internal/rosa/package/xz.az b/internal/rosa/package/xz.az index 0a186c28..3bb91b5f 100644 --- a/internal/rosa/package/xz.az +++ b/internal/rosa/package/xz.az @@ -3,12 +3,12 @@ package xz { website = "https://tukaani.org/xz"; anitya = 5277; - version# = "5.8.3"; + version# = "5.8.4"; source = remoteGitHubRelease { suffix = "tukaani-project/xz"; tag = "v"+version; name = "xz-"+version+".tar.bz2"; - checksum = "nCdayphPGdIdVoAZ2hR4vYlhDG9LeVKho_i7ealTud4Vxy5o5dWe0VwFlN7utuUL"; + checksum = "sYLUjO5X0QREmCBYceLU3CSj-HUCd3g0kJAHq8F2GO0Y6-LcyKYbESyRq4sr7Bih"; compress = bzip2; }; diff --git a/pkg/archive.go b/pkg/archive.go index ea4017d9..e9f76f5b 100644 --- a/pkg/archive.go +++ b/pkg/archive.go @@ -311,8 +311,16 @@ func (a archiveArtifact) Inputs() []Artifact { // IsExclusive returns false: [Reader] is fully sequential. func (archiveArtifact) IsExclusive() bool { return false } +// Revision satisfies [RevisionArtifact] for status behaviour. +func (archiveArtifact) Revision() uint64 { return 0 } + // Cure cures the [Artifact], producing a directory located at work. func (a archiveArtifact) Cure(t *TContext) (err error) { + var status io.Writer + if status, err = t.GetStatusWriter(); err != nil { + return + } + var r io.ReadCloser if r, err = t.Open(a.f); err != nil { return @@ -347,7 +355,9 @@ func (a archiveArtifact) Cure(t *TContext) (err error) { var header *ArchiveHeader ar := NewReader(r) + msg := t.GetMessage() for header, err = ar.Next(); err == nil; header, err = ar.Next() { + var m string if header.Mode.IsRegular() { var f *os.File if f, err = root.OpenFile( @@ -363,18 +373,33 @@ func (a archiveArtifact) Cure(t *TContext) (err error) { } else if err = f.Close(); err != nil { return } + + m = fmt.Sprintf( + "%s %s (%d bytes)", + header.Mode, + header.Path, + header.Size, + ) } else if header.Mode&fs.ModeSymlink != 0 { var p []byte if p, err = io.ReadAll(ar); err != nil { return } + linkname := unsafe.String(unsafe.SliceData(p), len(p)) if err = root.Symlink( - unsafe.String(unsafe.SliceData(p), len(p)), + linkname, header.Path, ); err != nil { return } + + m = fmt.Sprintf( + "%s %s linkname %s", + header.Mode, + header.Path, + linkname, + ) } else if header.Mode.IsDir() { if header.Path == "." { continue @@ -387,9 +412,24 @@ func (a archiveArtifact) Cure(t *TContext) (err error) { if err = root.Mkdir(header.Path, 0700); err != nil { return } + + m = fmt.Sprintf( + "%s %s", + header.Mode, + header.Path, + ) } else { return InvalidFileModeError(header.Mode) } + + if m != "" { + msg.Verbose(m) + if _, err = io.WriteString(status, m); err != nil { + return + } else if _, err = status.Write([]byte{'\n'}); err != nil { + return + } + } } if errors.Is(err, io.EOF) { err = nil diff --git a/pkg/archive_test.go b/pkg/archive_test.go index 44ea56a7..1ca631ee 100644 --- a/pkg/archive_test.go +++ b/pkg/archive_test.go @@ -202,7 +202,17 @@ func TestArchiveArtifact(t *testing.T) { "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/uevent": {Mode: 0600, Data: []byte("add")}, "identifier": {Mode: fs.ModeDir | 0700}, - "identifier/-zXKfphyWM2Ko7VMVURaEMSuixNokFSe0xFbnwR2RtRtvMrcPGWalV0LIn45PXTY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F")}, + "identifier/iyvWY0irMoW4AVRnG_du07d_nAEUtbHdeiaAYRdp-vf3wstM9u67IokOsPfU9eyM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F")}, + + "status": {Mode: fs.ModeDir | 0711}, + "status/iyvWY0irMoW4AVRnG_du07d_nAEUtbHdeiaAYRdp-vf3wstM9u67IokOsPfU9eyM": {Mode: 0444, Data: []byte(statusHeader + `drwx------ block +-rw------- block/uevent (0 bytes) +drwx------ devices +drwx------ devices/empty +drwx------ devices/sub +-rw------- devices/sub/uevent (3 bytes) +-rw------- devices/uevent (3 bytes) +`)}, "substitute": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, diff --git a/pkg/clean_test.go b/pkg/clean_test.go index e31d52aa..3b5d0b3b 100644 --- a/pkg/clean_test.go +++ b/pkg/clean_test.go @@ -52,7 +52,7 @@ func TestClean(t *testing.T) { "lock": {Mode: 0644}, "variant": {Mode: 0400}, - "status": {Mode: fs.ModeDir | 0700}, + "status": {Mode: fs.ModeDir | 0711}, "substitute": {Mode: fs.ModeDir | 0700}, "fault": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, @@ -73,7 +73,7 @@ func TestClean(t *testing.T) { "lock": {Mode: 0644}, "variant": {Mode: 0400}, - "status": {Mode: fs.ModeDir | 0700}, + "status": {Mode: fs.ModeDir | 0711}, "substitute": {Mode: fs.ModeDir | 0700}, "fault": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, @@ -127,7 +127,7 @@ func TestClean(t *testing.T) { "lock": {Mode: 0644}, "variant": {Mode: 0400}, - "status": {Mode: fs.ModeDir | 0700}, + "status": {Mode: fs.ModeDir | 0711}, "substitute": {Mode: fs.ModeDir | 0700}, "substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")}, @@ -205,9 +205,9 @@ func TestClean(t *testing.T) { "lock": {Mode: 0644}, "variant": {Mode: 0400}, - "status": {Mode: fs.ModeDir | 0700}, - "status/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: 0400, Data: []byte(statusHeader + "kept")}, - "status/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: 0400, Data: []byte(statusHeader + "kept")}, + "status": {Mode: fs.ModeDir | 0711}, + "status/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: 0444, Data: []byte(statusHeader + "kept")}, + "status/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: 0444, Data: []byte(statusHeader + "kept")}, "substitute": {Mode: fs.ModeDir | 0700}, "substitute/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")}, diff --git a/pkg/exec.go b/pkg/exec.go index b40ae84b..fe099ac9 100644 --- a/pkg/exec.go +++ b/pkg/exec.go @@ -601,7 +601,12 @@ func (a *execArtifact) makeContainer( fhs.AbsTmp, std.BindWritable|std.BindEnsure, ) - z.Proc(fhs.AbsProc).Dev(fhs.AbsDev, true) + z. + Proc(fhs.AbsProc). + DevWritable(fhs.AbsDev, true). + Tmpfs(fhs.AbsDevShm, 0, 01777). + Bind(fhs.AbsDevKvm, fhs.AbsDevKvm, std.BindOptional|std.BindDevice). + Remount(fhs.AbsDev, syscall.MS_RDONLY) return } diff --git a/pkg/internal/testtool/main.go b/pkg/internal/testtool/main.go index edffab7e..80f87435 100644 --- a/pkg/internal/testtool/main.go +++ b/pkg/internal/testtool/main.go @@ -259,6 +259,10 @@ func main() { next() } + if m.Next != nil && m.Next.Root == "/kvm" { + next() + } + if m.Next != nil { log.Println("unexpected extra mount entries") for m.Next != nil { @@ -206,7 +206,7 @@ func (t *TContext) prepareStatus(writeHeader bool) error { if t.status, t.statusErr = os.OpenFile( t.statusPath.String(), syscall.O_CREAT|syscall.O_EXCL|syscall.O_WRONLY, - 0400, + 0444, ); t.statusErr != nil { return t.statusErr } @@ -2798,7 +2798,6 @@ func Open( dirSubstitute, dirIdentifier, dirChecksum, - dirStatus, dirFault, dirWork, } { @@ -2810,6 +2809,17 @@ func Open( } } + for _, name := range []string{ + dirStatus, + } { + if err := os.MkdirAll( + base.Append(name).String(), + 0711, + ); err != nil && !errors.Is(err, os.ErrExist) { + return nil, err + } + } + c := Cache{ parent: ctx, diff --git a/pkg/pkg_test.go b/pkg/pkg_test.go index aa5016c1..2d5fdf8e 100644 --- a/pkg/pkg_test.go +++ b/pkg/pkg_test.go @@ -587,7 +587,9 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) { // destroy empty fault directory if err := os.Remove(base.Append("fault").String()); err != nil { - t.Fatal(err) + if !errors.Is(err, syscall.ENOTEMPTY) { + t.Fatal(err) + } } want := tc.want.hash() @@ -1512,10 +1514,10 @@ func TestCache(t *testing.T) { "identifier/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")}, "identifier/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")}, - "status": {Mode: fs.ModeDir | 0700}, + "status": {Mode: fs.ModeDir | 0711}, "status/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x")}, - "status/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: 0400, Data: []byte(statusHeader + "destroyed")}, - "status/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: 0400, Data: []byte(statusHeader + "destroyed")}, + "status/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: 0444, Data: []byte(statusHeader + "destroyed")}, + "status/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: 0444, Data: []byte(statusHeader + "destroyed")}, "substitute": {Mode: fs.ModeDir | 0700}, "substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")}, @@ -1610,14 +1612,16 @@ func TestCache(t *testing.T) { "checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")}, "identifier": {Mode: fs.ModeDir | 0700}, - "identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, - "identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, "identifier/8sInO_dhPW9kweit7jVuH_vtMkRxlZT7XE4_yEKPZmpGkgVxkmxz0OpXgbMsH6ET": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, + "identifier/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, + "identifier/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "identifier/ofaXbB5gIza_7W4Rzo5XDe_8FwlCPKWn3TBcmGgFAkkTWMl5GXGmOzX89Jd2Mk2A": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")}, "identifier/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, - "status": {Mode: fs.ModeDir | 0700}, - "status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0400, Data: []byte("\x00")}, + "status": {Mode: fs.ModeDir | 0711}, + "status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0444, Data: []byte("\x00")}, + "status/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: 0444, Data: []byte(statusHeader + "Lrwxrwxrwx result linkname /proc/nonexistent\n")}, + "status/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {Mode: 0444, Data: []byte(statusHeader)}, "substitute": {Mode: fs.ModeDir | 0700}, "substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, @@ -1756,17 +1760,19 @@ func TestCache(t *testing.T) { "identifier/3fYJjSiWhklt7TK9MPVLGk5_8AIU8ostTcFPXULJf_qeAVG6pmC-Cqqu4ZhEXRxn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, "identifier/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, "identifier/8sInO_dhPW9kweit7jVuH_vtMkRxlZT7XE4_yEKPZmpGkgVxkmxz0OpXgbMsH6ET": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, - "identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, - "identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, + "identifier/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, + "identifier/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "identifier/mXlNz_v77nW7jstn_rJn4RL7dCQlkakM0y-HjO6tkDubtzaj-wCmW1hIr2Gk64_O": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, - "status": {Mode: fs.ModeDir | 0700}, - "status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0400, Data: []byte("\x00")}, + "status": {Mode: fs.ModeDir | 0711}, + "status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0444, Data: []byte("\x00")}, + "status/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: 0444, Data: []byte(statusHeader + "Lrwxrwxrwx result linkname /proc/nonexistent\n")}, + "status/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {Mode: 0444, Data: []byte(statusHeader)}, "substitute": {Mode: fs.ModeDir | 0700}, - "substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "substitute/MccYezQ4pshkeBV4w_aAEIwvZdKHL3OAgAkR3ouZ43EF94Ur1HBHaN7njPfJAj50": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, "substitute/VV5W0_DiA1iylaqbKFThp1ZpV_y1ccVS1XyqDnDaXoHQ-EEyPI4XFrQHcHOF2hWG": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, + "substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "work": {Mode: fs.ModeDir | 0700}, }}, @@ -66,6 +66,9 @@ func (a *tarArtifact) Inputs() []Artifact { // IsExclusive returns false: decompressor and tar reader are fully sequential. func (a *tarArtifact) IsExclusive() bool { return false } +// Revision satisfies [RevisionArtifact] for status behaviour. +func (*tarArtifact) Revision() uint64 { return 0 } + // A DisallowedTypeflagError describes a disallowed typeflag encountered while // unpacking a tarball. type DisallowedTypeflagError byte @@ -76,6 +79,11 @@ func (e DisallowedTypeflagError) Error() string { // Cure cures the [Artifact], producing a directory located at work. func (a *tarArtifact) Cure(t *TContext) (err error) { + var status io.Writer + if status, err = t.GetStatusWriter(); err != nil { + return + } + var r io.ReadCloser if r, err = t.Open(a.f); err != nil { return @@ -110,6 +118,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { var header *tar.Header tr := tar.NewReader(r) + msg := t.GetMessage() for header, err = tr.Next(); err == nil; header, err = tr.Next() { typeflag := header.Typeflag if typeflag == 0 { @@ -126,6 +135,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { } } + var m string switch typeflag { case tar.TypeReg: var f *os.File @@ -142,6 +152,13 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { } else if err = f.Close(); err != nil { return } + + m = fmt.Sprintf( + "%s %s (%d bytes)", + header.FileInfo().Mode(), + header.Name, + header.Size, + ) break case tar.TypeLink: @@ -151,6 +168,13 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { ); err != nil { return } + + m = fmt.Sprintf( + "%s %s linkname %s", + header.FileInfo().Mode(), + header.Name, + header.Linkname, + ) break case tar.TypeSymlink: @@ -160,6 +184,13 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { ); err != nil { return } + + m = fmt.Sprintf( + "%s %s linkname %s", + header.FileInfo().Mode(), + header.Name, + header.Linkname, + ) break case tar.TypeDir: @@ -170,21 +201,37 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { if err = root.MkdirAll(header.Name, 0700); err != nil { return } + + m = fmt.Sprintf( + "%s %s", + header.FileInfo().Mode(), + header.Name, + ) break case tar.TypeChar: - t.GetMessage().Verbosef( - "%sskipping character device %d, %d %q%s", - t.cache.sgrWarn, header.Devmajor, header.Devminor, header.Name, t.cache.sgrRes, + m = fmt.Sprintf( + "skipping character device %d, %d %q", + header.Devmajor, header.Devminor, header.Name, ) - continue + break case tar.TypeXGlobalHeader: - continue // ignore + m = "skipping PAX global key-value record" + break default: return DisallowedTypeflagError(typeflag) } + + if m != "" { + msg.Verbose(m) + if _, err = io.WriteString(status, m); err != nil { + return + } else if _, err = status.Write([]byte{'\n'}); err != nil { + return + } + } } if errors.Is(err, io.EOF) { err = nil diff --git a/pkg/tar_test.go b/pkg/tar_test.go index 5462714f..58ec3aed 100644 --- a/pkg/tar_test.go +++ b/pkg/tar_test.go @@ -44,6 +44,24 @@ func TestTar(t *testing.T) { } wantExpandEncode := pkg.Encode(wantExpand.hash()) + const ( + wantStatus = `drwx------ checksum/ +drwx------ checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/ +-r-------- checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check (2 bytes) +drwx------ checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/ +Lrwxrwxrwx checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so linkname /proc/nonexistent/libedac.so +drwx------ checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig/ +drwx------ identifier/ +Lrwxrwxrwx identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY linkname ../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP +Lrwxrwxrwx identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa linkname ../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP +drwx------ work/ +` + + wantStatusExpand = `drwx------ lib/ +Lrwxrwxrwx lib/libedac.so linkname /proc/nonexistent/libedac.so +` + ) + checkWithCache(t, []cacheTestCase{ {"http", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { checkTarHTTP(t, base, c, fstest.MapFS{ @@ -79,8 +97,12 @@ func TestTar(t *testing.T) { "checksum/" + wantEncode + "/work": {Mode: fs.ModeDir | 0500}, "identifier": {Mode: fs.ModeDir | 0700}, - "identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)}, - "identifier/v9DUj2R4YK_3ae0m9VuUYI-HJysDDCENu1k10thxioycRzFH1Qejw5bBGukm4IdL": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)}, + "identifier/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)}, + "identifier/ld6DxwiP2Gj47Ue2L_pFv6NrOth8nkU5W1voMyivd2aVROrorGqPlpbyHUnU1AvI": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)}, + + "status": {Mode: fs.ModeDir | 0711}, + "status/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: 0444, Data: []byte(statusHeader + wantStatus)}, + "status/ld6DxwiP2Gj47Ue2L_pFv6NrOth8nkU5W1voMyivd2aVROrorGqPlpbyHUnU1AvI": {Mode: 0444, Data: []byte(statusHeader + wantStatus)}, "substitute": {Mode: fs.ModeDir | 0700}, @@ -103,8 +125,12 @@ func TestTar(t *testing.T) { "checksum/" + wantExpandEncode + "/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")}, "identifier": {Mode: fs.ModeDir | 0700}, - "identifier/1SuvgGltcsgqps9tWqjULG8RCdpx_6KVWXdsMd5xPKvdtysOxqpE-3bLu4j0WpGk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)}, - "identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)}, + "identifier/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)}, + "identifier/fsMFOV4_LoYWbC8GNqL2zjbpzNzT80vPWbSw4L47caKVIta333WIW2TZXoSW8ntH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)}, + + "status": {Mode: fs.ModeDir | 0711}, + "status/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: 0444, Data: []byte(statusHeader + wantStatusExpand)}, + "status/fsMFOV4_LoYWbC8GNqL2zjbpzNzT80vPWbSw4L47caKVIta333WIW2TZXoSW8ntH": {Mode: 0444, Data: []byte(statusHeader + wantStatusExpand)}, "substitute": {Mode: fs.ModeDir | 0700}, @@ -206,13 +232,13 @@ func checkTarHTTP( {"directory", pkg.NewTar(&tarDir), ignorePathname, want, pkg.WNew, nil}, - {"multiple entries", pkg.NewTar(&tarDirMulti), nil, nil, pkg.WNew, errors.New( + {"multiple entries", pkg.NewTar(&tarDirMulti), nil, nil, pkg.WNew, errors.Join(errors.New( "input directory does not contain a single regular file", - )}, + ))}, - {"bad type", pkg.NewTar(&tarDirType), nil, nil, pkg.WNew, errors.New( + {"bad type", pkg.NewTar(&tarDirType), nil, nil, pkg.WNew, errors.Join(errors.New( "input directory does not contain a single regular file", - )}, + ))}, {"error passthrough", pkg.NewTar(&stubArtifact{ kind: pkg.KindExec, @@ -220,6 +246,13 @@ func checkTarHTTP( cure: func(t *pkg.TContext) error { return stub.UniqueError(0xcafe) }, - }), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)}, + }), nil, nil, pkg.WNew, errors.Join(stub.UniqueError(0xcafe))}, }) + + fault := base.Append("fault") + if err := os.RemoveAll(fault.String()); err != nil { + t.Fatal(err) + } else if err = os.Mkdir(fault.String(), 0); err != nil { + t.Fatal(err) + } } |
