Add automatic installer and upgrader.
This commit is contained in:
parent
77c2e7f59e
commit
1e17e7fab7
|
@ -185,6 +185,9 @@ set version="$version"
|
||||||
set machine="$machine"
|
set machine="$machine"
|
||||||
set base_menu_title="Sortix \$version for \$machine"
|
set base_menu_title="Sortix \$version for \$machine"
|
||||||
set menu_title="\$base_menu_title"
|
set menu_title="\$base_menu_title"
|
||||||
|
set title_single_user='live environment'
|
||||||
|
set title_sysinstall='new installation'
|
||||||
|
set title_sysupgrade='upgrade existing installation'
|
||||||
set timeout=10
|
set timeout=10
|
||||||
set default="0"
|
set default="0"
|
||||||
if [ -e /boot/random.seed ]; then
|
if [ -e /boot/random.seed ]; then
|
||||||
|
@ -202,6 +205,9 @@ export version
|
||||||
export machine
|
export machine
|
||||||
export base_menu_title
|
export base_menu_title
|
||||||
export menu_title
|
export menu_title
|
||||||
|
export title_single_user
|
||||||
|
export title_sysinstall
|
||||||
|
export title_sysupgrade
|
||||||
export timeout
|
export timeout
|
||||||
export default
|
export default
|
||||||
export no_random_seed
|
export no_random_seed
|
||||||
|
@ -412,9 +418,9 @@ menu_title="\$base_menu_title"
|
||||||
hook_menu_pre
|
hook_menu_pre
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
menuentry "live environment" '-- /sbin/init'
|
menuentry "\$title_single_user" '-- /sbin/init'
|
||||||
menuentry "new installation" '-- /sbin/init --target=sysinstall'
|
menuentry "\$title_sysinstall" '-- /sbin/init --target=sysinstall'
|
||||||
menuentry "upgrade existing installation" '-- /sbin/init --target=sysupgrade'
|
menuentry "\$title_sysupgrade" '-- /sbin/init --target=sysupgrade'
|
||||||
|
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,444 @@
|
||||||
|
.Dd April 23, 2023
|
||||||
|
.Dt AUTOINSTALL.CONF 5
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm autoinstall.conf
|
||||||
|
.Nd automatic installation configuration
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /etc/autoinstall.conf
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
configures
|
||||||
|
.Xr sysinstall 8
|
||||||
|
to do an automatic operating system
|
||||||
|
.Xr installation 7 .
|
||||||
|
.Pp
|
||||||
|
The system administrator can automate operating system installations by
|
||||||
|
following
|
||||||
|
.Xr release-iso-modification 7
|
||||||
|
to embed the
|
||||||
|
.Pa /etc/autoinstall.conf
|
||||||
|
file into the release cdrom filesystem.
|
||||||
|
Existing installations can similarly be automatically upgraded using
|
||||||
|
.Xr autoupgrade.conf 5 .
|
||||||
|
.Pp
|
||||||
|
Each line is formatted as
|
||||||
|
.Ar question Ns = Ns Ar answer
|
||||||
|
which provides an
|
||||||
|
.Ar answer
|
||||||
|
to a
|
||||||
|
.Ar question
|
||||||
|
asked during installation.
|
||||||
|
Alternatively
|
||||||
|
.Ar question Ns += Ns Ar answer
|
||||||
|
appends to an existing answer (if any) separated by a space, and
|
||||||
|
.Ar question Ns ++= Ns Ar answer
|
||||||
|
appends another line to an existing answer (if any).
|
||||||
|
Empty lines and lines starting with
|
||||||
|
.Sq #
|
||||||
|
are comments and are ignored.
|
||||||
|
Otherwise whitespace is significant.
|
||||||
|
The empty answer accepts the default answer (if any) and is different from no
|
||||||
|
answer, which makes
|
||||||
|
.Xr sysinstall 8
|
||||||
|
ask the question normally.
|
||||||
|
Installations can be made fully non-interactive using
|
||||||
|
.Sy accept_defaults .
|
||||||
|
.Pp
|
||||||
|
Each question has a counterpart question suffixed with
|
||||||
|
.Sq "!"
|
||||||
|
which contains a
|
||||||
|
.Xr sh 1
|
||||||
|
script that is executed before the question is asked.
|
||||||
|
If the original question isn't answered, then the script's standard output
|
||||||
|
is used as the answer to the original question.
|
||||||
|
The installation aborts if the script exits unsuccessfully.
|
||||||
|
These scripts are useful to customize the installation with arbitrary code.
|
||||||
|
.Pp
|
||||||
|
The questions in chronological order are as follows:
|
||||||
|
.Bl -tag -width "12345678"
|
||||||
|
.It Sy accept_defaults Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Accept the default answer (if any) to questions that were not
|
||||||
|
configured in
|
||||||
|
.Nm ?
|
||||||
|
This feature makes installations entirely automated even if unexpected questions
|
||||||
|
are asked, although the essential questions must be answered.
|
||||||
|
.It Sy countdown Ns "=" Ns Ar seconds No ( default Li 10 )
|
||||||
|
Count down for this many
|
||||||
|
.Ar seconds
|
||||||
|
with a warning that an automated installation is about to happen?
|
||||||
|
The countdown happens if
|
||||||
|
.Sy accept_defaults=yes
|
||||||
|
or if the
|
||||||
|
.Sy ready
|
||||||
|
question is answered and either the
|
||||||
|
.Sy disked
|
||||||
|
or
|
||||||
|
.Sy confirm_install
|
||||||
|
questions are answered.
|
||||||
|
.It Sy ignore_missing_programs Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Ignore if the installer environment does not have the needed ports installed?
|
||||||
|
This situation ordinarily does not happen.
|
||||||
|
.It Sy ready Ns "=" Ns Ar affirmation
|
||||||
|
Are you ready to begin the installation process?
|
||||||
|
This is a human readable positive affirmation of your choice that you're ready
|
||||||
|
to install, useful for fully automated installations.
|
||||||
|
Not answering this question is useful for semi-automated installations where one
|
||||||
|
would acknowledge the installation before it's begun.
|
||||||
|
It also provides the opportunity to escape to a shell before installing.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sy "ready!"
|
||||||
|
question is convenient for running shell commands before the installation
|
||||||
|
begins.
|
||||||
|
.It Sy kblayout Ns "=" Ns Oo Sy default "|" Ar layout Oc ( default Sy default )
|
||||||
|
Switch to this keyboard
|
||||||
|
.Ar layout
|
||||||
|
using
|
||||||
|
.Xr chkblayout 1 ?
|
||||||
|
The choice is remembered as the
|
||||||
|
.Xr kblayout 5
|
||||||
|
system default.
|
||||||
|
.It Sy videomode Ns "=" Ns Oo Sy no "|" Sy yes "|" Ar WIDTH Ns x Ns Ar HEIGHT Ns x Ns Ar BPP Oc ( default Sy yes )
|
||||||
|
Interactively select a graphics resolution using
|
||||||
|
.Xr chvideomode 1
|
||||||
|
or non-interactively set it to the specified resolution?
|
||||||
|
The choice is remembered as the
|
||||||
|
.Xr videomode 5
|
||||||
|
system default.
|
||||||
|
.Pp
|
||||||
|
If the installation is non-interactive with
|
||||||
|
.Sy accept_defaults=true ,
|
||||||
|
then the default is instead
|
||||||
|
.Sy no .
|
||||||
|
.It Sy grub Ns "=" Ns Oo Sy no "|" Sy yes Oc
|
||||||
|
Install the GRUB bootloader onto the device containing the
|
||||||
|
.Pa /boot
|
||||||
|
filesystem (if it exists, otherwise the root filesystem)?
|
||||||
|
The default is
|
||||||
|
.Sy yes
|
||||||
|
if any existing installations are found with GRUB enabled or if no filesystems
|
||||||
|
were found, otherwise the default is
|
||||||
|
.Sy no .
|
||||||
|
.Pp
|
||||||
|
This is an essential question that must be answered for automatic installations.
|
||||||
|
.It Sy grub_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||||
|
Protect the bootloader with a password to avoid unauthorized root access via the
|
||||||
|
advanced bootloader features?
|
||||||
|
The standard bootloader menu options don't require a password.
|
||||||
|
The password is set in the
|
||||||
|
.Sy grub_password_hash
|
||||||
|
question.
|
||||||
|
.Pp
|
||||||
|
If the installation is non-interactive with
|
||||||
|
.Sy accept_defaults=true ,
|
||||||
|
then the default is instead
|
||||||
|
.Sy no
|
||||||
|
if the
|
||||||
|
.Sy grub_password_hash
|
||||||
|
question is not answered.
|
||||||
|
.It Sy grub_password_hash Ns "=" Ns Ar hash
|
||||||
|
The bootloader password as hashed by the
|
||||||
|
.Xr grub-mkpasswd-pbkdf2 1
|
||||||
|
program?
|
||||||
|
The password is asked interactively if this question is not answered.
|
||||||
|
The choice is remembered in
|
||||||
|
.Xr grubpw 5 .
|
||||||
|
.Pp
|
||||||
|
Although it's discouraged to place unhashed passwords in
|
||||||
|
.Nm ,
|
||||||
|
the
|
||||||
|
.Sy "grub_password!"
|
||||||
|
question could be answered with
|
||||||
|
.Li "grub-mkpasswd-pbkdf2 -p password"
|
||||||
|
to dynamically hash the bootloader password.
|
||||||
|
.It Sy grub_password_empty Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Allow an insecure empty bootloader password typed interactively?
|
||||||
|
.It Sy disked Ns "=" Ns Ar commands
|
||||||
|
Commands to create partitions and filesystems with
|
||||||
|
.Xr disked 8 ?
|
||||||
|
The
|
||||||
|
.Li ++=
|
||||||
|
syntax is useful to append multiple lines to the
|
||||||
|
.Sy disked
|
||||||
|
answer.
|
||||||
|
A root filesystem must be mounted in order to install the operating system.
|
||||||
|
The mountpoints are remembered in
|
||||||
|
.Xr fstab 5 .
|
||||||
|
.Pp
|
||||||
|
This is an essential question that must be answered for automatic installations.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sy "disked!"
|
||||||
|
question is convenient for running shell commands before the partitioning step,
|
||||||
|
or to generate dynamic partitioning commands on the standard output if the
|
||||||
|
original
|
||||||
|
.Sy disked
|
||||||
|
question is unanswered.
|
||||||
|
.It Sy missing_bios_boot_partition Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||||
|
Attempt
|
||||||
|
.Xr disked 8
|
||||||
|
again if the GRUB bootloader is installed but the
|
||||||
|
.Pa /boot
|
||||||
|
directory's filesystem is inside a GPT partition table that doesn't have a
|
||||||
|
biosboot partition?
|
||||||
|
.It Sy confirm_install Ns "=" Ns Oo Sy no "|" Sy yes "|" Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt Oc ( default Sy yes )
|
||||||
|
Install the operating system or abort the installation?
|
||||||
|
This is the final confirmation before the operating system is installed, after
|
||||||
|
the partitioning has taken place.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sy "confirm_install!"
|
||||||
|
question is convenient for running shell commands before the installation step,
|
||||||
|
after partitioning has happened, but before the filesystems are mounted.
|
||||||
|
.It Sy hostname Ns "=" Ns Ar hostname
|
||||||
|
Hostname for the installation?
|
||||||
|
The choice is remembered in
|
||||||
|
.Xr hostname 5 .
|
||||||
|
.Pp
|
||||||
|
This is an essential question that must be answered for automatic installations.
|
||||||
|
If it isn't answered and
|
||||||
|
.Sy accept_defaults=yes ,
|
||||||
|
then the current (and likely default) hostname is used.
|
||||||
|
.It Sy password_hash_root Ns "=" Ns Ar hash
|
||||||
|
Password for the root user as hashed with
|
||||||
|
.Xr crypt_newhash 2 ?
|
||||||
|
The empty string sets the password to the empty string (insecure) and a literal
|
||||||
|
.Sy x
|
||||||
|
disables password login for root.
|
||||||
|
The choice is remembered in
|
||||||
|
.Xr passwd 5 .
|
||||||
|
.Pp
|
||||||
|
This is an essential question that must be answered for automatic installations.
|
||||||
|
If it isn't answered and
|
||||||
|
.Sy accept_defaults=yes ,
|
||||||
|
then password login is disabled for root.
|
||||||
|
.Pp
|
||||||
|
Although it's discouraged to place unhashed passwords in
|
||||||
|
.Nm ,
|
||||||
|
the
|
||||||
|
.Sy "password_hash_root!"
|
||||||
|
question could be answered with
|
||||||
|
.Li "echo password | passwd -H"
|
||||||
|
to dynamically hash the root password.
|
||||||
|
.It Sy password_hash_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Allow an insecure empty root password typed interactively?
|
||||||
|
.It Sy copy_ssh_authorized_keys_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||||
|
Copy the
|
||||||
|
.Pa /root/.ssh/authorized_keys
|
||||||
|
file (if it exists) into the installation?
|
||||||
|
.It Sy copy_ssh_config_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||||
|
Copy the
|
||||||
|
.Pa /root/.ssh/config
|
||||||
|
file (if it exists) into the installation?
|
||||||
|
.It Sy copy_ssh_id_rsa_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||||
|
Copy the
|
||||||
|
.Pa /root/.ssh/id_rsa
|
||||||
|
file (if it exists) into the installation?
|
||||||
|
.It Sy copy_ssh_known_hosts_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||||
|
Copy the
|
||||||
|
.Pa /root/.ssh/known_hosts
|
||||||
|
file (if it exists) into the installation?
|
||||||
|
.It Sy empty_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Allow insecure empty passwords for regular users?
|
||||||
|
.It Sy enable_ntpd Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Automatically get time from the network using
|
||||||
|
.Xr ntpd 8 ?
|
||||||
|
Note this choice has privacy implications as the servers in
|
||||||
|
.Xr ntpd.conf 5
|
||||||
|
file will be contacted in the background.
|
||||||
|
The choice is remembered in
|
||||||
|
.Pa /etc/init/local
|
||||||
|
per
|
||||||
|
.Xr init 5 .
|
||||||
|
.It Sy enable_sshd Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Enable the
|
||||||
|
.Xr sshd 8
|
||||||
|
secure shell server?
|
||||||
|
The choice is remembered in
|
||||||
|
.Pa /etc/init/local
|
||||||
|
per
|
||||||
|
.Xr init 5 .
|
||||||
|
.It Sy copy_sshd_config Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Copy the
|
||||||
|
.Pa /etc/sshd_config
|
||||||
|
file (if it exists) into the installation?
|
||||||
|
.It Sy enable_sshd_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Enable password authentication in the local
|
||||||
|
.Xr sshd 8 ?
|
||||||
|
The choice is remembered in
|
||||||
|
.Xr sshd_config 5 .
|
||||||
|
.Pp
|
||||||
|
It's strongly encouraged to answer
|
||||||
|
.Sy no
|
||||||
|
and instead use public key authentication.
|
||||||
|
The installation environment can be seeded with the ssh keys using the
|
||||||
|
.Xr release-iso-modification 7
|
||||||
|
procedure and the default answers will copy the keys into the installation.
|
||||||
|
.It Sy enable_sshd_root_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||||
|
Enable ssh to the root user with password authentication?
|
||||||
|
.It Sy copy_sshd_private_keys Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||||
|
Copy the sshd private keys (if they exist) into the installation?
|
||||||
|
These are
|
||||||
|
.Pa /etc/ssh_host_ecdsa_key ,
|
||||||
|
.Pa /etc/ssh_host_ed25519_key ,
|
||||||
|
and
|
||||||
|
.Pa /etc/ssh_host_rsa_key .
|
||||||
|
.It Sy finally Ns "=" Ns Oo Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt "|" Sy boot Oc ( default Sy boot )
|
||||||
|
What action should be taken when the installation is finished?
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sy "finally!"
|
||||||
|
question is convenient for running shell commands once the installation is
|
||||||
|
complete to customize the installation.
|
||||||
|
The working directory is the root filesystem of the installation with all
|
||||||
|
filesystems mounted.
|
||||||
|
The
|
||||||
|
.Li "chroot -d ."
|
||||||
|
command is useful to
|
||||||
|
.Xr chroot 8
|
||||||
|
into the new root filesystem to run commands with the
|
||||||
|
.Pa /dev
|
||||||
|
filesystem mounted.
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width "/etc/autoinstall.conf" -compact
|
||||||
|
.It Pa /etc/autoinstall.conf
|
||||||
|
Automatic installation configuration.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLES
|
||||||
|
.Ss Fully automated installation
|
||||||
|
To perform a fully automated installation with root login disabled, create
|
||||||
|
.Pa autoinstall.conf :
|
||||||
|
.Bd -literal -offset indentq
|
||||||
|
accept_defaults=yes
|
||||||
|
grub=yes
|
||||||
|
disked++=mktable mbr
|
||||||
|
disked++=mkpart 1 0% 100% ext2 /
|
||||||
|
hostname=dragon
|
||||||
|
password_hash_root=x
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Then follow
|
||||||
|
.Xr release-iso-modification 7
|
||||||
|
to configure the installation medium:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
tix-iso-liveconfig --autoinstall=autoinstall.conf liveconfig
|
||||||
|
tix-iso-bootconfig \\
|
||||||
|
--liveconfig=liveconfig --default=1 --random-seed \\
|
||||||
|
bootconfig
|
||||||
|
tix-iso-add sortix.iso bootconfig -o autosortix.iso
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The resulting
|
||||||
|
.Pa autosortix.iso
|
||||||
|
image will then automatically format the harddisk and install the operating
|
||||||
|
system on whatever machine it is booted on.
|
||||||
|
Take care.
|
||||||
|
.Ss Setting passwords
|
||||||
|
The
|
||||||
|
.Xr grub-mkpasswd-pbkdf2 1
|
||||||
|
command can be used to hash a GRUB password and
|
||||||
|
.Xr passwd 1
|
||||||
|
can be used to hash a user password:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
grub-mkpasswd-pbkdf2 -p bootloader-password
|
||||||
|
echo root-password | passwd -H
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The hashes can then be inserted in
|
||||||
|
.Nm :
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
grub_password_hash=grub.pbkdf2.sha512.10000.68DA[...]
|
||||||
|
password_hash_root=$2b$10$d/9pP1[...]
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Alternatively the passwords could be embedded in
|
||||||
|
.Nm ,
|
||||||
|
however beware that your
|
||||||
|
.Nm
|
||||||
|
file and the installation medium could leak:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
grub_password_hash!=grub-mkpasswd-pbkdf2 -p bootloader-password
|
||||||
|
password_hash_root!=echo root-password | passwd -H
|
||||||
|
.Ed
|
||||||
|
.Ss Automatically install with sshd
|
||||||
|
To automatically install the operating system with sshd enabled with keys and
|
||||||
|
authorizations set up ahead of time, first create
|
||||||
|
.Pa autoinstall.conf :
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
accept_defaults=yes
|
||||||
|
grub=yes
|
||||||
|
disked++=mktable mbr
|
||||||
|
disked++=mkpart 1 0% 100% ext2 /
|
||||||
|
hostname=example.com
|
||||||
|
password_hash_root=x
|
||||||
|
enable_sshd=yes
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Then follow
|
||||||
|
.Xr release-iso-modification 7
|
||||||
|
to configure the installation medium with automated installation and sshd:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
tix-iso-liveconfig \\
|
||||||
|
--autoinstall=autoinstall.conf \\
|
||||||
|
--root-ssh-authorized-keys="$HOME/.ssh/id_rsa.pub" \\
|
||||||
|
--sshd-keygen \\
|
||||||
|
--sshd-key-known-hosts-file="$HOME/.ssh/known_hosts" \\
|
||||||
|
--sshd-key-known-hosts-hosts="example.com example.com,192.0.2.1 192.0.2.1" \\
|
||||||
|
liveconfig
|
||||||
|
tix-iso-bootconfig \\
|
||||||
|
--liveconfig=liveconfig --default=1 --random-seed \\
|
||||||
|
bootconfig
|
||||||
|
tix-iso-add sortix.iso bootconfig -o autosortix.iso
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
To ssh into the installation after it has finished:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
ssh root@example.com
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The connection will be immediately trusted because the just-generated server
|
||||||
|
keys were associated with the hostname in the
|
||||||
|
.Pa $HOME/.ssh/known_hosts
|
||||||
|
file.
|
||||||
|
This step assumes the hostname (example.com in this example) resolves to the
|
||||||
|
installation's IP address, otherwise the IP address can be used directly.
|
||||||
|
If the IP address is known ahead of time, it should be inserted into the
|
||||||
|
space delimited
|
||||||
|
.Fl \-sshd-key-known-hosts-hosts
|
||||||
|
list of host aliases.
|
||||||
|
.Ss Automatically install into a virtual machine with sshd
|
||||||
|
To automatically install into a qemu virtual machine, follow the above example
|
||||||
|
but instead associate the server keys with your localhost and optionally use a
|
||||||
|
.Pa known_hosts
|
||||||
|
file per virtual machine.
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
...
|
||||||
|
--sshd-key-known-hosts-file="sortix.hdd.known_hosts" \\
|
||||||
|
--sshd-key-known-hosts-hosts=127.0.0.1 \\
|
||||||
|
...
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Create the harddisk and spawn the virtual machine and forward the local port
|
||||||
|
2222 to the virtual machine's port 22.
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
qemu-img create -f qcow2 sortix.hdd 1G
|
||||||
|
qemu-system-x86_64 \\
|
||||||
|
-vga std -m 1024 \\
|
||||||
|
-hda sortix.hdd -cdrom autosortix.iso \\
|
||||||
|
-device e1000,netdev=net0 \\
|
||||||
|
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:2222-:22
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
To ssh into the installation after it has finished:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
ssh -oUserKnownHostsFile=sortix.hdd.known_hosts -p 2222 root@127.0.0.1
|
||||||
|
.Ed
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr autoupgrade.conf 5 ,
|
||||||
|
.Xr upgrade.conf 5 ,
|
||||||
|
.Xr release-iso-modification 7 ,
|
||||||
|
.Xr upgrade 7 ,
|
||||||
|
.Xr sysupgrade 8 ,
|
||||||
|
.Xr tix 8
|
|
@ -0,0 +1,203 @@
|
||||||
|
.Dd April 23, 2023
|
||||||
|
.Dt AUTOUPGRADE.CONF 5
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm autoupgrade.conf
|
||||||
|
.Nd automatic upgrade configuration
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /etc/autoupgrade.conf
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
configures
|
||||||
|
.Xr sysupgrade 8
|
||||||
|
to do an automatic operating system
|
||||||
|
.Xr upgrade 7 .
|
||||||
|
.Pp
|
||||||
|
The system administrator can automate operating system upgrades by
|
||||||
|
following
|
||||||
|
.Xr release-iso-modification 7
|
||||||
|
to embed the
|
||||||
|
.Pa /etc/autoupgrade.conf
|
||||||
|
file into the release cdrom filesystem.
|
||||||
|
New installations can similarly be automatically installed using
|
||||||
|
.Xr autoinstall.conf 5 .
|
||||||
|
.Pp
|
||||||
|
Each line is formatted as
|
||||||
|
.Ar question Ns = Ns Ar answer
|
||||||
|
which provides an
|
||||||
|
.Ar answer
|
||||||
|
to a
|
||||||
|
.Ar question
|
||||||
|
asked during upgrading.
|
||||||
|
Alternatively
|
||||||
|
.Ar question Ns += Ns Ar answer
|
||||||
|
appends to an existing answer (if any) separated by a space, and
|
||||||
|
.Ar question Ns ++= Ns Ar answer
|
||||||
|
appends another line to an existing answer (if any).
|
||||||
|
Empty lines and lines starting with
|
||||||
|
.Sq #
|
||||||
|
are comments and are ignored.
|
||||||
|
Otherwise whitespace is significant.
|
||||||
|
The empty answer accepts the default answer (if any) and is different from no
|
||||||
|
answer, which makes
|
||||||
|
.Xr sysupgrade 8
|
||||||
|
ask the question normally.
|
||||||
|
Upgrades can be made fully non-interactive using
|
||||||
|
.Sy accept_defaults .
|
||||||
|
.Pp
|
||||||
|
Each question has a counterpart question suffixed with
|
||||||
|
.Sq "!"
|
||||||
|
which contains a
|
||||||
|
.Xr sh 1
|
||||||
|
script that is executed before the question is asked.
|
||||||
|
If the original question isn't answered, then the script's standard output
|
||||||
|
is used as the answer to the original question.
|
||||||
|
The upgrade aborts if the script exits unsuccessfully.
|
||||||
|
These scripts are useful to customize the upgrades with arbitrary code.
|
||||||
|
.Pp
|
||||||
|
The questions in chronological order are as follows:
|
||||||
|
.Bl -tag -width "12345678"
|
||||||
|
.It Sy accept_defaults Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Accept the default answer (if any) to questions that were not
|
||||||
|
configured in
|
||||||
|
.Nm ?
|
||||||
|
This feature makes upgrades entirely automated even if unexpected questions
|
||||||
|
are asked, although the essential questions must be answered.
|
||||||
|
.It Sy countdown Ns "=" Ns Ar seconds No ( default Li 10 )
|
||||||
|
Count down for this many
|
||||||
|
.Ar seconds
|
||||||
|
with a warning that an automated upgrade is about to happen?
|
||||||
|
The countdown happens if
|
||||||
|
.Sy accept_defaults=yes
|
||||||
|
or if the
|
||||||
|
.Sy ready
|
||||||
|
and
|
||||||
|
.Sy confirm_upgrrade
|
||||||
|
questions are answered.
|
||||||
|
.It Sy ignore_missing_programs Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Ignore if the upgrader environment does not have the needed ports installed?
|
||||||
|
This situation ordinarily does not happen.
|
||||||
|
.It Sy ready Ns "=" Ns Ar affirmation
|
||||||
|
Are you ready to begin the upgrade process?
|
||||||
|
This is a human readable positive affirmation of your choice that you're ready
|
||||||
|
to upgrade, useful for fully automated upgrades.
|
||||||
|
Not answering this question is useful for semi-automated upgrades where one
|
||||||
|
would acknowledge the upgrades before it's begun.
|
||||||
|
It also provides the opportunity to escape to a shell before upgrading.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sy "ready!"
|
||||||
|
question is convenient for running shell commands before the upgrade begins.
|
||||||
|
.It Sy kblayout Ns "=" Ns Oo Sy default "|" Ar layout Oc ( default Sy default )
|
||||||
|
Switch to this keyboard
|
||||||
|
.Ar layout
|
||||||
|
using
|
||||||
|
.Xr chkblayout 1 ?
|
||||||
|
.It Sy videomode Ns "=" Ns Oo Sy no "|" Sy yes "|" Ar WIDTH Ns x Ns Ar HEIGHT Ns x Ns Ar BPP Oc ( default Sy yes )
|
||||||
|
Interactively select a graphics resolution using
|
||||||
|
.Xr chvideomode 1
|
||||||
|
or non-interactively set it to the specified resolution?
|
||||||
|
.Pp
|
||||||
|
If the upgrade is non-interactive with
|
||||||
|
.Sy accept_defaults=true ,
|
||||||
|
then the default is instead
|
||||||
|
.Sy no .
|
||||||
|
.It Sy run_installer_instead Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy yes )
|
||||||
|
Run the
|
||||||
|
.Xr sysinstall 8
|
||||||
|
installer instead if no installations were found?
|
||||||
|
.Pp
|
||||||
|
This answer is useful combined with
|
||||||
|
.Xr autoinstall.conf 5
|
||||||
|
to either install or upgrade the operating system, regardless of what is already
|
||||||
|
installed on the machine.
|
||||||
|
.It Sy which_installaton Ns "=" Ns Ar block-device
|
||||||
|
The name of the
|
||||||
|
.Ar block-device
|
||||||
|
containing the root filesystem to upgrade?
|
||||||
|
This question is only asked if multiple installations were found.
|
||||||
|
.It Sy switch_architecture Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Switch the installation to another architecture?
|
||||||
|
.Pp
|
||||||
|
Such upgrades are not supported and may corrupt the installation.
|
||||||
|
.It Sy downgrade_release Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Downgrade the installation to an earlier release?
|
||||||
|
.Pp
|
||||||
|
Such upgrades are not supported and may corrupt the installation.
|
||||||
|
.It Sy skip_release Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Skip upgrading to a release that ordinarily must be upgraded to first?
|
||||||
|
.Pp
|
||||||
|
Such upgrades are not supported and may corrupt the installation.
|
||||||
|
.It Sy downgrade_abi Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||||
|
Downgrade the installation to an earlier ABI?
|
||||||
|
.Pp
|
||||||
|
Such upgrades are not supported and may corrupt the installation.
|
||||||
|
.It Sy cancel_pending_sysmerge Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy yes )
|
||||||
|
Cancel an existing pending
|
||||||
|
.Xr sysmerge 8
|
||||||
|
upgrade?
|
||||||
|
.It Sy confirm_upgrade Ns "=" Ns Oo Sy no "|" Sy yes "|" Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt Oc ( default Sy yes )
|
||||||
|
Upgrade the operating system or abort the upgrade?
|
||||||
|
This is the final confirmation before the operating system is upgraded.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sy "confirm_upgrade!"
|
||||||
|
question is convenient for running shell commands before the upgrade step.
|
||||||
|
The working directory is the root filesystem of the installation with all
|
||||||
|
filesystems mounted.
|
||||||
|
Note how
|
||||||
|
.Xr chroot 8
|
||||||
|
command may not work as intended at this point since the ABI may have
|
||||||
|
incompatibly changed.
|
||||||
|
.It Sy finally Ns "=" Ns Oo Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt "|" Sy boot Oc ( default Sy boot )
|
||||||
|
What action should be taken when the upgrade is finished?
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sy "finally!"
|
||||||
|
question is convenient for running shell commands once the upgrade is
|
||||||
|
complete to customize the upgraded installation.
|
||||||
|
The working directory is the root filesystem of the installation with all
|
||||||
|
filesystems mounted.
|
||||||
|
The
|
||||||
|
.Li "chroot -d ."
|
||||||
|
command is useful to
|
||||||
|
.Xr chroot 8
|
||||||
|
into the root filesystem to run commands with the
|
||||||
|
.Pa /dev
|
||||||
|
filesystem mounted.
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width "/etc/autoupgrade.conf" -compact
|
||||||
|
.It Pa /etc/autoupgrade.conf
|
||||||
|
Automatic upgrade configuration.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLES
|
||||||
|
.Ss Fully automated upgrade
|
||||||
|
To perform a fully automated upgrade with, create
|
||||||
|
.Pa autoupgrade.conf :
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
accept_defaults=yes
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Then follow
|
||||||
|
.Xr release-iso-modification 7
|
||||||
|
to configure the upgrade medium:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
tix-iso-liveconfig --autoupgrade=autoupgrade.conf liveconfig
|
||||||
|
tix-iso-bootconfig \\
|
||||||
|
--liveconfig=liveconfig --default=1 --random-seed \\
|
||||||
|
bootconfig
|
||||||
|
tix-iso-add sortix.iso bootconfig -o autosortix.iso
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The resulting
|
||||||
|
.Pa autosortix.iso
|
||||||
|
image will then automatically upgrade the operating system on whatever machine
|
||||||
|
it is booted on.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr autoinstall.conf 5 ,
|
||||||
|
.Xr upgrade.conf 5 ,
|
||||||
|
.Xr release-iso-modification 7 ,
|
||||||
|
.Xr upgrade 7 ,
|
||||||
|
.Xr sysupgrade 8 ,
|
||||||
|
.Xr tix 8
|
|
@ -109,5 +109,7 @@ src = no
|
||||||
grub = yes
|
grub = yes
|
||||||
.Ed
|
.Ed
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
|
.Xr autoinstall.conf 5 ,
|
||||||
|
.Xr autoupgrade.conf 5 ,
|
||||||
.Xr upgrade 7 ,
|
.Xr upgrade 7 ,
|
||||||
.Xr sysupgrade 8
|
.Xr sysupgrade 8
|
||||||
|
|
|
@ -88,7 +88,8 @@ default bootloader menu option and timeout, the default hostname, the default
|
||||||
keyboard layout, the default graphics resolution, adding files of your choice to
|
keyboard layout, the default graphics resolution, adding files of your choice to
|
||||||
the live environment, control which drivers are loaded by default, control which
|
the live environment, control which drivers are loaded by default, control which
|
||||||
live environment daemons are started by default, deploy ssh keys so secure shell
|
live environment daemons are started by default, deploy ssh keys so secure shell
|
||||||
connections are trusted on the first connection, and so on.
|
connections are trusted on the first connection, configure automatic
|
||||||
|
installation and upgrading, and so on.
|
||||||
.Pp
|
.Pp
|
||||||
Warning: The live environment does not come with any random entropy and entropy
|
Warning: The live environment does not come with any random entropy and entropy
|
||||||
gathering is not yet implemented.
|
gathering is not yet implemented.
|
||||||
|
|
|
@ -319,6 +319,15 @@ variable) is automatically selected.
|
||||||
If set to 0, the default menu entry is loaded instantaneously.
|
If set to 0, the default menu entry is loaded instantaneously.
|
||||||
The timeout is disabled if set to -1.
|
The timeout is disabled if set to -1.
|
||||||
(Default: 10)
|
(Default: 10)
|
||||||
|
.It Sy title_single_user
|
||||||
|
The menu title for the single-user selection.
|
||||||
|
(Default: live environment)
|
||||||
|
.It Sy title_sysinstall
|
||||||
|
The menu title for the sysinstall selection.
|
||||||
|
(Default: new installation)
|
||||||
|
.It Sy title_sysupgrade
|
||||||
|
The menu title for the sysupgrade selection.
|
||||||
|
(Default: upgrade existing installation)
|
||||||
.It Sy tix_ Ns Ar $port
|
.It Sy tix_ Ns Ar $port
|
||||||
A copy of the binary package is stored in
|
A copy of the binary package is stored in
|
||||||
.Pa /repository
|
.Pa /repository
|
||||||
|
|
|
@ -18,7 +18,8 @@ default bootloader menu option and timeout, the default hostname, the default
|
||||||
keyboard layout, the default graphics resolution, adding files of your choice to
|
keyboard layout, the default graphics resolution, adding files of your choice to
|
||||||
the live environment, control which drivers are loaded by default, control which
|
the live environment, control which drivers are loaded by default, control which
|
||||||
live environment daemons are started by default, deploy ssh keys so secure shell
|
live environment daemons are started by default, deploy ssh keys so secure shell
|
||||||
connections are trusted on the first connection, and so on.
|
connections are trusted on the first connection, configure automatic
|
||||||
|
installation and upgrading, and so on.
|
||||||
.Ss Prerequisites
|
.Ss Prerequisites
|
||||||
.Bl -bullet -compact
|
.Bl -bullet -compact
|
||||||
.It
|
.It
|
||||||
|
@ -513,6 +514,22 @@ ssh-keygen -t rsa -f liveconfig/root/.ssh/id_rsa -N "" -C "root@$hostname"
|
||||||
Consider omitting the
|
Consider omitting the
|
||||||
.Fl N
|
.Fl N
|
||||||
option and password protect the private key to protect it in the case of a leak.
|
option and password protect the private key to protect it in the case of a leak.
|
||||||
|
.Ss Automatic Installation
|
||||||
|
To customize a release so it automatically installs itself per the
|
||||||
|
.Xr autoinstall.conf 5 :
|
||||||
|
.Bd -literal
|
||||||
|
tix-iso-liveconfig --autoinstall=autoinstall.conf liveconfig
|
||||||
|
tix-iso-bootconfig --liveconfig=liveconfig --default=1 bootconfig
|
||||||
|
tix-iso-add sortix.iso bootconfig
|
||||||
|
.Ed
|
||||||
|
.Ss Automatic Upgrade
|
||||||
|
To customize a release so it automatically upgrades a local installation per the
|
||||||
|
.Xr autoupgrade.conf 5 :
|
||||||
|
.Bd -literal
|
||||||
|
tix-iso-liveconfig --autoinstall=autoupgrade.conf liveconfig
|
||||||
|
tix-iso-bootconfig --liveconfig=liveconfig --default=2 bootconfig
|
||||||
|
tix-iso-add sortix.iso bootconfig
|
||||||
|
.Ed
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr xorriso 1 ,
|
.Xr xorriso 1 ,
|
||||||
.Xr development 7 ,
|
.Xr development 7 ,
|
||||||
|
|
|
@ -31,7 +31,8 @@ default bootloader menu option and timeout, the default hostname, the default
|
||||||
keyboard layout, the default graphics resolution, adding files of your choice to
|
keyboard layout, the default graphics resolution, adding files of your choice to
|
||||||
the live environment, control which drivers are loaded by default, control which
|
the live environment, control which drivers are loaded by default, control which
|
||||||
live environment daemons are started by default, deploy ssh keys so secure shell
|
live environment daemons are started by default, deploy ssh keys so secure shell
|
||||||
connections are trusted on the first connection, and so on.
|
connections are trusted on the first connection, configure automatic
|
||||||
|
installation and upgrading, and so on.
|
||||||
.Pp
|
.Pp
|
||||||
Warning: The live environment does not come with any random entropy and entropy
|
Warning: The live environment does not come with any random entropy and entropy
|
||||||
gathering is not yet implemented.
|
gathering is not yet implemented.
|
||||||
|
|
|
@ -16,6 +16,7 @@ sysmerge.o \
|
||||||
sysupgrade.o \
|
sysupgrade.o \
|
||||||
|
|
||||||
UTIL_OBJS=\
|
UTIL_OBJS=\
|
||||||
|
autoconf.o \
|
||||||
conf.o \
|
conf.o \
|
||||||
devices.o \
|
devices.o \
|
||||||
execute.o \
|
execute.o \
|
||||||
|
@ -28,9 +29,9 @@ string_array.o \
|
||||||
|
|
||||||
OBJS=$(MAIN_OBJS) $(UTIL_OBJS)
|
OBJS=$(MAIN_OBJS) $(UTIL_OBJS)
|
||||||
|
|
||||||
SYSINSTALL_DEPS=conf devices execute fileops interactive manifest release string_array
|
SYSINSTALL_DEPS=autoconf conf devices execute fileops interactive manifest release string_array
|
||||||
SYSMERGE_DEPS=conf fileops execute hooks manifest release string_array
|
SYSMERGE_DEPS=conf fileops execute hooks manifest release string_array
|
||||||
SYSUPGRADE_DEPS=conf devices execute fileops hooks interactive manifest release string_array
|
SYSUPGRADE_DEPS=autoconf conf devices execute fileops hooks interactive manifest release string_array
|
||||||
|
|
||||||
SYSINSTALL_OBJS:=sysinstall.o $(SYSINSTALL_DEPS:=.o)
|
SYSINSTALL_OBJS:=sysinstall.o $(SYSINSTALL_DEPS:=.o)
|
||||||
SYSMERGE_OBJS:=sysmerge.o $(SYSMERGE_DEPS:=.o)
|
SYSMERGE_OBJS:=sysmerge.o $(SYSMERGE_DEPS:=.o)
|
||||||
|
@ -73,13 +74,14 @@ sysupgrade: $(SYSUPGRADE_OBJS)
|
||||||
sysinstall.o: $(SYSINSTALL_DEPS:=.h)
|
sysinstall.o: $(SYSINSTALL_DEPS:=.h)
|
||||||
sysmerge.o: $(SYSMERGE_DEPS:=.h)
|
sysmerge.o: $(SYSMERGE_DEPS:=.h)
|
||||||
sysupgrade.o: $(SYSUPGRADE_DEPS:=.h)
|
sysupgrade.o: $(SYSUPGRADE_DEPS:=.h)
|
||||||
|
autoconf.o: autoconf.h execute.h
|
||||||
conf.o: conf.h
|
conf.o: conf.h
|
||||||
devices.o: devices.h
|
devices.o: devices.h
|
||||||
execute.o: execute.h
|
execute.o: execute.h
|
||||||
fileops.o: fileops.h string_array.h
|
fileops.o: fileops.h string_array.h
|
||||||
string_array.o: string_array.h
|
string_array.o: string_array.h
|
||||||
hooks.o: fileops.h manifest.h release.h string_array.h
|
hooks.o: fileops.h manifest.h release.h string_array.h
|
||||||
interactive.o: interactive.h execute.h
|
interactive.o: interactive.h autoconf.h execute.h
|
||||||
manifest.o: manifest.h fileops.h string_array.h
|
manifest.o: manifest.h fileops.h string_array.h
|
||||||
release.o: release.h
|
release.o: release.h
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,217 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 2023 Jonas 'Sortie' Termansen.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* autoconf.c
|
||||||
|
* Parser for autoinstall.conf(5) and autoupgrade.conf(5).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "autoconf.h"
|
||||||
|
#include "execute.h"
|
||||||
|
|
||||||
|
static char** keyvalues = NULL;
|
||||||
|
static size_t keyvalues_used = 0;
|
||||||
|
static size_t keyvalues_length = 0;
|
||||||
|
|
||||||
|
bool has_autoconf = false;
|
||||||
|
|
||||||
|
bool autoconf_has(const char* name)
|
||||||
|
{
|
||||||
|
if ( !name )
|
||||||
|
return false;
|
||||||
|
size_t len = strlen(name);
|
||||||
|
for ( size_t i = 0; i < keyvalues_used; i++ )
|
||||||
|
{
|
||||||
|
if ( strncmp(keyvalues[i], name, len) )
|
||||||
|
continue;
|
||||||
|
if ( keyvalues[i][len] == '=' )
|
||||||
|
return true;
|
||||||
|
if ( keyvalues[i][len] == '!' && keyvalues[i][len + 1] == '=' )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* autoconf_get(const char* name)
|
||||||
|
{
|
||||||
|
if ( !name )
|
||||||
|
return NULL;
|
||||||
|
size_t len = strlen(name);
|
||||||
|
for ( size_t i = 0; i < keyvalues_used; i++ )
|
||||||
|
if ( !strncmp(keyvalues[i], name, len) && keyvalues[i][len] == '=' )
|
||||||
|
return keyvalues[i] + len + 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* autoconf_eval(const char* name)
|
||||||
|
{
|
||||||
|
if ( !name )
|
||||||
|
return NULL;
|
||||||
|
char* shname;
|
||||||
|
if ( asprintf(&shname, "%s!", name) < 0 )
|
||||||
|
err(1, "malloc");
|
||||||
|
const char* script;
|
||||||
|
char* output = NULL;
|
||||||
|
if ( (script = autoconf_get(shname)) )
|
||||||
|
{
|
||||||
|
char** out_ptr = autoconf_get(name) ? NULL : &output;
|
||||||
|
execute((const char*[]) { "sh", "-c", script, NULL }, "efo", out_ptr);
|
||||||
|
if ( out_ptr )
|
||||||
|
{
|
||||||
|
size_t len = strlen(output);
|
||||||
|
if ( len && output[len - 1] == '\n' )
|
||||||
|
output[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(shname);
|
||||||
|
if ( autoconf_get(name) )
|
||||||
|
{
|
||||||
|
free(output);
|
||||||
|
if ( !(output = strdup(autoconf_get(name))) )
|
||||||
|
err(1, "malloc");
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool autoconf_set(const char* name, const char* value)
|
||||||
|
{
|
||||||
|
char* keyvalue;
|
||||||
|
if ( asprintf(&keyvalue, "%s=%s", name, value) < 0 )
|
||||||
|
return false;
|
||||||
|
size_t len = strlen(name);
|
||||||
|
for ( size_t i = 0; i < keyvalues_used; i++ )
|
||||||
|
{
|
||||||
|
if ( !strncmp(keyvalues[i], name, len) && keyvalues[i][len] == '=' )
|
||||||
|
{
|
||||||
|
free(keyvalues[i]);
|
||||||
|
keyvalues[i] = keyvalue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( keyvalues_used == keyvalues_length )
|
||||||
|
{
|
||||||
|
size_t new_length = keyvalues_length ? 2 * keyvalues_length : 4;
|
||||||
|
char** new_keyvalues =
|
||||||
|
reallocarray(keyvalues, new_length, sizeof(char*));
|
||||||
|
if ( !new_keyvalues )
|
||||||
|
return free(keyvalue), false;
|
||||||
|
keyvalues = new_keyvalues;
|
||||||
|
keyvalues_length = new_length;
|
||||||
|
}
|
||||||
|
keyvalues[keyvalues_used++] = keyvalue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void autoconf_load(const char* path)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(path, "r");
|
||||||
|
if ( !fp )
|
||||||
|
{
|
||||||
|
if ( errno != ENOENT )
|
||||||
|
warn("%s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char* line = NULL;
|
||||||
|
size_t line_size = 0;
|
||||||
|
ssize_t line_length;
|
||||||
|
off_t line_number = 0;
|
||||||
|
while ( 0 < (line_length = getline(&line, &line_size, fp)) )
|
||||||
|
{
|
||||||
|
line_number++;
|
||||||
|
if ( line[line_length - 1] == '\n' )
|
||||||
|
line[--line_length] = '\0';
|
||||||
|
line_length = 0;
|
||||||
|
while ( line[line_length] && line[line_length] != '#' )
|
||||||
|
line_length++;
|
||||||
|
line[line_length] = '\0';
|
||||||
|
char* name = line;
|
||||||
|
if ( !*name || *name == '=' )
|
||||||
|
continue;
|
||||||
|
size_t name_length = 1;
|
||||||
|
while ( name[name_length] &&
|
||||||
|
name[name_length] != '=' &&
|
||||||
|
name[name_length] != '+' )
|
||||||
|
name_length++;
|
||||||
|
if ( name[name_length + 0] == '+' &&
|
||||||
|
name[name_length + 1] == '+' &&
|
||||||
|
name[name_length + 2] == '=' )
|
||||||
|
{
|
||||||
|
name[name_length + 0] = '\0';
|
||||||
|
char* value = name + name_length + 3;
|
||||||
|
const char* existing = autoconf_get(name);
|
||||||
|
if ( existing )
|
||||||
|
{
|
||||||
|
char* full;
|
||||||
|
if ( asprintf(&full, "%s\n%s", existing, value) < 0 )
|
||||||
|
err(2, "%s: malloc", path);
|
||||||
|
if ( !autoconf_set(name, full) )
|
||||||
|
err(2, "%s: malloc", path);
|
||||||
|
free(full);
|
||||||
|
}
|
||||||
|
else if ( !autoconf_set(name, value) )
|
||||||
|
err(2, "%s: malloc", path);
|
||||||
|
}
|
||||||
|
else if ( name[name_length + 0] == '+' &&
|
||||||
|
name[name_length + 1] == '=' )
|
||||||
|
{
|
||||||
|
name[name_length + 0] = '\0';
|
||||||
|
char* value = name + name_length + 2;
|
||||||
|
const char* existing = autoconf_get(name);
|
||||||
|
if ( existing )
|
||||||
|
{
|
||||||
|
char* full;
|
||||||
|
if ( asprintf(&full, "%s %s", existing, value) < 0 )
|
||||||
|
err(2, "%s: malloc", path);
|
||||||
|
if ( !autoconf_set(name, full) )
|
||||||
|
err(2, "%s: malloc", path);
|
||||||
|
free(full);
|
||||||
|
}
|
||||||
|
else if ( !autoconf_set(name, value) )
|
||||||
|
err(2, "%s: malloc", path);
|
||||||
|
}
|
||||||
|
else if ( name[name_length + 0] == '=' )
|
||||||
|
{
|
||||||
|
name[name_length + 0] = '\0';
|
||||||
|
char* value = name + name_length + 1;
|
||||||
|
if ( !autoconf_set(name, value) )
|
||||||
|
err(2, "%s: malloc", path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
errx(2, "%s:%ji: Invalid line: %s",
|
||||||
|
path, (intmax_t) line_number, line);
|
||||||
|
char* value = name + name_length;
|
||||||
|
while ( *value && isblank((unsigned char) *value) )
|
||||||
|
value++;
|
||||||
|
if ( *value != '=' )
|
||||||
|
continue;
|
||||||
|
value++;
|
||||||
|
while ( *value && isblank((unsigned char) *value) )
|
||||||
|
value++;
|
||||||
|
name[name_length] = '\0';
|
||||||
|
}
|
||||||
|
if ( ferror(fp) )
|
||||||
|
err(2, "%s", path);
|
||||||
|
free(line);
|
||||||
|
fclose(fp);
|
||||||
|
has_autoconf = true;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 2023 Jonas 'Sortie' Termansen.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* autoconf.h
|
||||||
|
* Parser for autoinstall.conf(5) and autoupgrade.conf(5).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AUTOCONF_H
|
||||||
|
#define AUTOCONF_H
|
||||||
|
|
||||||
|
extern bool has_autoconf;
|
||||||
|
|
||||||
|
bool autoconf_has(const char* name);
|
||||||
|
const char* autoconf_get(const char* name);
|
||||||
|
char* autoconf_eval(const char* name);
|
||||||
|
bool autoconf_set(const char* name, const char* value);
|
||||||
|
void autoconf_load(const char* path);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2017, 2021, 2023 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -24,6 +24,8 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
|
@ -34,6 +36,8 @@ int execute(const char* const* argv, const char* flags, ...)
|
||||||
bool exit_on_failure = false;
|
bool exit_on_failure = false;
|
||||||
bool foreground = false;
|
bool foreground = false;
|
||||||
bool gid_set = false;
|
bool gid_set = false;
|
||||||
|
const char* input = NULL;
|
||||||
|
char** output = NULL;
|
||||||
bool raw_exit_code = false;
|
bool raw_exit_code = false;
|
||||||
bool uid_set = false;
|
bool uid_set = false;
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
|
@ -50,6 +54,8 @@ int execute(const char* const* argv, const char* flags, ...)
|
||||||
case 'e': exit_on_failure = true; break;
|
case 'e': exit_on_failure = true; break;
|
||||||
case 'f': foreground = true; break;
|
case 'f': foreground = true; break;
|
||||||
case 'g': gid_set = true; gid = va_arg(ap, gid_t); break;
|
case 'g': gid_set = true; gid = va_arg(ap, gid_t); break;
|
||||||
|
case 'i': input = va_arg(ap, const char*); break;
|
||||||
|
case 'o': output = va_arg(ap, char**); break;
|
||||||
case 'r': raw_exit_code = true; break;
|
case 'r': raw_exit_code = true; break;
|
||||||
case 'u': uid_set = true; uid = va_arg(ap, uid_t); break;
|
case 'u': uid_set = true; uid = va_arg(ap, uid_t); break;
|
||||||
case 'q': quiet = true; break;
|
case 'q': quiet = true; break;
|
||||||
|
@ -63,6 +69,15 @@ int execute(const char* const* argv, const char* flags, ...)
|
||||||
sigemptyset(&sigttou);
|
sigemptyset(&sigttou);
|
||||||
sigaddset(&sigttou, SIGTTOU);
|
sigaddset(&sigttou, SIGTTOU);
|
||||||
}
|
}
|
||||||
|
int output_pipes[2] = {-1, -1};
|
||||||
|
if ( output && pipe(output_pipes) < 0 )
|
||||||
|
{
|
||||||
|
if ( !quiet_stderr )
|
||||||
|
warn("pipe: %s", argv[0]);
|
||||||
|
if ( exit_on_failure )
|
||||||
|
(_exit_instead ? _exit : exit)(2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
pid_t child_pid = fork();
|
pid_t child_pid = fork();
|
||||||
if ( child_pid < 0 )
|
if ( child_pid < 0 )
|
||||||
{
|
{
|
||||||
|
@ -90,20 +105,111 @@ int execute(const char* const* argv, const char* flags, ...)
|
||||||
tcsetpgrp(0, getpgid(0));
|
tcsetpgrp(0, getpgid(0));
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
}
|
}
|
||||||
|
if ( input )
|
||||||
|
{
|
||||||
|
int input_pipes[2];
|
||||||
|
if ( pipe(input_pipes) < 0 )
|
||||||
|
{
|
||||||
|
if ( !quiet_stderr )
|
||||||
|
warn("pipe: %s", argv[0]);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
pid_t input_pid = fork();
|
||||||
|
if ( input_pid < 0 )
|
||||||
|
{
|
||||||
|
if ( !quiet_stderr )
|
||||||
|
warn("fork: %s", argv[0]);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
else if ( input_pid == 0 )
|
||||||
|
{
|
||||||
|
close(input_pipes[0]);
|
||||||
|
size_t left = strlen(input);
|
||||||
|
while ( *input )
|
||||||
|
{
|
||||||
|
ssize_t written = write(input_pipes[1], input, left);
|
||||||
|
if ( written <= 0 )
|
||||||
|
break;
|
||||||
|
input += written;
|
||||||
|
left -= written;
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
close(input_pipes[1]);
|
||||||
|
close(0);
|
||||||
|
dup2(input_pipes[0], 0);
|
||||||
|
close(input_pipes[0]);
|
||||||
|
}
|
||||||
|
if ( output )
|
||||||
|
{
|
||||||
|
close(output_pipes[0]);
|
||||||
|
close(1);
|
||||||
|
dup2(output_pipes[1], 1);
|
||||||
|
close(output_pipes[1]);
|
||||||
|
}
|
||||||
if ( quiet )
|
if ( quiet )
|
||||||
{
|
{
|
||||||
close(1);
|
close(1);
|
||||||
open("/dev/null", O_WRONLY);
|
if ( open("/dev/null", O_WRONLY) < 0 )
|
||||||
|
{
|
||||||
|
if ( !quiet_stderr )
|
||||||
|
warn("/dev/null");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( quiet_stderr )
|
if ( quiet_stderr )
|
||||||
{
|
{
|
||||||
close(2);
|
close(2);
|
||||||
open("/dev/null", O_WRONLY);
|
if ( open("/dev/null", O_WRONLY) < 0 )
|
||||||
|
_exit(2);
|
||||||
}
|
}
|
||||||
execvp(argv[0], (char* const*) argv);
|
execvp(argv[0], (char* const*) argv);
|
||||||
warn("%s", argv[0]);
|
warn("%s", argv[0]);
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
|
bool success = true;
|
||||||
|
if ( output )
|
||||||
|
{
|
||||||
|
close(output_pipes[1]);
|
||||||
|
char* out;
|
||||||
|
size_t out_size;
|
||||||
|
FILE* out_fp = open_memstream(&out, &out_size);
|
||||||
|
if ( out_fp )
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t amount = 0;
|
||||||
|
while ( 0 < (amount = read(output_pipes[0], buf, sizeof(buf))) )
|
||||||
|
{
|
||||||
|
if ( fwrite(buf, 1, amount, out_fp) != (size_t) amount )
|
||||||
|
{
|
||||||
|
if ( !quiet_stderr )
|
||||||
|
warn("fwrite to memstream");
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( success && fclose(out_fp) == EOF )
|
||||||
|
{
|
||||||
|
if ( !quiet_stderr )
|
||||||
|
warn("fclose of memstream");
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
close(output_pipes[0]);
|
||||||
|
if ( !success )
|
||||||
|
{
|
||||||
|
free(out);
|
||||||
|
*output = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*output = out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
if ( !quiet_stderr )
|
||||||
|
warn("open_memstream");
|
||||||
|
}
|
||||||
|
}
|
||||||
int code;
|
int code;
|
||||||
waitpid(child_pid, &code, 0);
|
waitpid(child_pid, &code, 0);
|
||||||
if ( foreground )
|
if ( foreground )
|
||||||
|
@ -114,11 +220,13 @@ int execute(const char* const* argv, const char* flags, ...)
|
||||||
}
|
}
|
||||||
if ( exit_on_failure )
|
if ( exit_on_failure )
|
||||||
{
|
{
|
||||||
if ( !WIFEXITED(code) || WEXITSTATUS(code) != 0 )
|
if ( !success || !WIFEXITED(code) || WEXITSTATUS(code) != 0 )
|
||||||
(_exit_instead ? _exit : exit)(2);
|
(_exit_instead ? _exit : exit)(2);
|
||||||
}
|
}
|
||||||
int exit_status;
|
int exit_status;
|
||||||
if ( WIFEXITED(code) )
|
if ( !success )
|
||||||
|
exit_status = 2;
|
||||||
|
else if ( WIFEXITED(code) )
|
||||||
exit_status = WEXITSTATUS(code);
|
exit_status = WEXITSTATUS(code);
|
||||||
else
|
else
|
||||||
exit_status = 128 + WTERMSIG(code);
|
exit_status = 128 + WTERMSIG(code);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include "autoconf.h"
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "interactive.h"
|
#include "interactive.h"
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ void promptx(char* buffer,
|
||||||
const char* answer,
|
const char* answer,
|
||||||
bool catch_if_shell)
|
bool catch_if_shell)
|
||||||
{
|
{
|
||||||
(void) autoconf_name;
|
char* autoconf_answer = autoconf_eval(autoconf_name);
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
printf("\e[1m");
|
printf("\e[1m");
|
||||||
|
@ -169,6 +170,26 @@ void promptx(char* buffer,
|
||||||
else
|
else
|
||||||
printf(" ");
|
printf(" ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
const char* accept_defaults = autoconf_get("accept_defaults");
|
||||||
|
const char* automatic_answer = NULL;
|
||||||
|
if ( autoconf_answer )
|
||||||
|
{
|
||||||
|
automatic_answer = autoconf_answer;
|
||||||
|
if ( !automatic_answer[0] )
|
||||||
|
automatic_answer = answer;
|
||||||
|
}
|
||||||
|
else if ( accept_defaults && !strcasecmp(accept_defaults, "yes") )
|
||||||
|
automatic_answer = answer;
|
||||||
|
if ( automatic_answer )
|
||||||
|
{
|
||||||
|
printf("\e[93m");
|
||||||
|
printf("%s\n", automatic_answer);
|
||||||
|
printf("\e[m");
|
||||||
|
fflush(stdout);
|
||||||
|
strlcpy(buffer, automatic_answer, buffer_size);
|
||||||
|
free(autoconf_answer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
fgets(buffer, buffer_size, stdin);
|
fgets(buffer, buffer_size, stdin);
|
||||||
printf("\e[22m");
|
printf("\e[22m");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -200,6 +221,7 @@ void promptx(char* buffer,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
free(autoconf_answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void password(char* buffer,
|
void password(char* buffer,
|
||||||
|
|
|
@ -20,5 +20,6 @@ must be run as root with stdin, stdout and stderr all pointing to the terminal.
|
||||||
It is intended to be run from a live environment and not from an actual
|
It is intended to be run from a live environment and not from an actual
|
||||||
installation.
|
installation.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
|
.Xr autoinstall.conf 5 ,
|
||||||
.Xr installation 7 ,
|
.Xr installation 7 ,
|
||||||
.Xr sysupgrade 8
|
.Xr sysupgrade 8
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <fstab.h>
|
#include <fstab.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
#include <mount/partition.h>
|
#include <mount/partition.h>
|
||||||
#include <mount/uuid.h>
|
#include <mount/uuid.h>
|
||||||
|
|
||||||
|
#include "autoconf.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "devices.h"
|
#include "devices.h"
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
|
@ -376,6 +378,12 @@ void exit_handler(void)
|
||||||
execute((const char*[]) { "rm", "-rf", etc, NULL }, "");
|
execute((const char*[]) { "rm", "-rf", etc, NULL }, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cancel_on_sigint(int signum)
|
||||||
|
{
|
||||||
|
(void) signum;
|
||||||
|
errx(2, "fatal: Installation canceled");
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
shlvl();
|
shlvl();
|
||||||
|
@ -413,11 +421,54 @@ int main(void)
|
||||||
if ( !conf_load(&conf, "/etc/upgrade.conf") && errno != ENOENT )
|
if ( !conf_load(&conf, "/etc/upgrade.conf") && errno != ENOENT )
|
||||||
warn("/etc/upgrade.conf");
|
warn("/etc/upgrade.conf");
|
||||||
|
|
||||||
|
autoconf_load("/etc/autoinstall.conf");
|
||||||
|
|
||||||
|
char* accepts_defaults = autoconf_eval("accept_defaults");
|
||||||
|
bool non_interactive = accepts_defaults &&
|
||||||
|
!strcasecmp(accepts_defaults, "yes");
|
||||||
|
free(accepts_defaults);
|
||||||
|
|
||||||
static char input[256];
|
static char input[256];
|
||||||
|
|
||||||
textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR ""
|
textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR ""
|
||||||
" installer for %s.\n\n", uts.machine);
|
" installer for %s.\n\n", uts.machine);
|
||||||
|
|
||||||
|
if ( non_interactive ||
|
||||||
|
(autoconf_has("ready") &&
|
||||||
|
(autoconf_has("disked") || autoconf_has("confirm_install"))) )
|
||||||
|
{
|
||||||
|
int countdown = 10;
|
||||||
|
if ( autoconf_has("countdown") )
|
||||||
|
{
|
||||||
|
char* string = autoconf_eval("countdown");
|
||||||
|
countdown = atoi(string);
|
||||||
|
free(string);
|
||||||
|
}
|
||||||
|
sigset_t old_set;
|
||||||
|
sigset_t new_set;
|
||||||
|
sigemptyset(&new_set);
|
||||||
|
sigaddset(&new_set, SIGINT);
|
||||||
|
sigprocmask(SIG_BLOCK, &new_set, &old_set);
|
||||||
|
struct sigaction old_sa;
|
||||||
|
struct sigaction new_sa = { 0 };
|
||||||
|
new_sa.sa_handler = cancel_on_sigint;
|
||||||
|
sigaction(SIGINT, &new_sa, &old_sa);
|
||||||
|
for ( ; 0 < countdown; countdown-- )
|
||||||
|
{
|
||||||
|
textf("Automatically installing " BRAND_DISTRIBUTION_NAME " "
|
||||||
|
VERSIONSTR " in %i %s... (Control-C to cancel)\n", countdown,
|
||||||
|
countdown != 1 ? "seconds" : "second");
|
||||||
|
sigprocmask(SIG_SETMASK, &old_set, NULL);
|
||||||
|
sleep(1);
|
||||||
|
sigprocmask(SIG_BLOCK, &new_set, &old_set);
|
||||||
|
}
|
||||||
|
textf("Automatically installing " BRAND_DISTRIBUTION_NAME " "
|
||||||
|
VERSIONSTR "...\n");
|
||||||
|
text("\n");
|
||||||
|
sigaction(SIGINT, &old_sa, NULL);
|
||||||
|
sigprocmask(SIG_SETMASK, &old_set, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// '|' rather than '||' is to ensure side effects.
|
// '|' rather than '||' is to ensure side effects.
|
||||||
if ( missing_program("cut") |
|
if ( missing_program("cut") |
|
||||||
missing_program("dash") |
|
missing_program("dash") |
|
||||||
|
@ -469,6 +520,12 @@ int main(void)
|
||||||
};
|
};
|
||||||
size_t num_readies = sizeof(readies) / sizeof(readies[0]);
|
size_t num_readies = sizeof(readies) / sizeof(readies[0]);
|
||||||
const char* ready = readies[arc4random_uniform(num_readies)];
|
const char* ready = readies[arc4random_uniform(num_readies)];
|
||||||
|
if ( autoconf_has("disked") )
|
||||||
|
text("Warning: This installer will perform automatic harddisk "
|
||||||
|
"partitioning!\n");
|
||||||
|
if ( autoconf_has("confirm_install") )
|
||||||
|
text("Warning: This installer will automatically install an operating "
|
||||||
|
"system!\n");
|
||||||
prompt(input, sizeof(input), "ready", "Ready?", ready);
|
prompt(input, sizeof(input), "ready", "Ready?", ready);
|
||||||
text("\n");
|
text("\n");
|
||||||
|
|
||||||
|
@ -574,24 +631,26 @@ int main(void)
|
||||||
good = true;
|
good = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const char* def = good ? "no" : "yes";
|
const char* def = non_interactive || good ? "no" : "yes";
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
prompt(input, sizeof(input), "videomode",
|
prompt(input, sizeof(input), "videomode",
|
||||||
"Select a default display resolution? (yes/no)", def);
|
"Select display resolution? "
|
||||||
if ( strcasecmp(input, "no") && strcasecmp(input, "yes") )
|
"(yes/no/WIDTHxHEIGHTxBPP)", def);
|
||||||
|
unsigned int xres, yres, bpp;
|
||||||
|
bool set = sscanf(input, "%ux%ux%u", &xres, &yres, &bpp) == 3;
|
||||||
|
if ( !strcasecmp(input, "no") )
|
||||||
|
{
|
||||||
|
input[0] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char* r = set ? input : NULL;
|
||||||
|
if ( execute((const char*[]) { "chvideomode", r, NULL }, "f") != 0 )
|
||||||
continue;
|
continue;
|
||||||
bool was_no = strcasecmp(input, "no") == 0;
|
|
||||||
input[0] = '\0';
|
input[0] = '\0';
|
||||||
if ( was_no )
|
if ( dispmsg_issue(&get_mode, sizeof(get_mode)) < 0 ||
|
||||||
break;
|
!(get_mode.mode.control & DISPMSG_CONTROL_VALID) ||
|
||||||
if ( execute((const char*[]) { "chvideomode", NULL }, "f") != 0 )
|
get_mode.mode.control & DISPMSG_CONTROL_VGA )
|
||||||
continue;
|
|
||||||
if ( dispmsg_issue(&get_mode, sizeof(get_mode)) < 0 )
|
|
||||||
break;
|
|
||||||
if ( !(get_mode.mode.control & DISPMSG_CONTROL_VALID) )
|
|
||||||
break;
|
|
||||||
if ( get_mode.mode.control & DISPMSG_CONTROL_VGA )
|
|
||||||
break;
|
break;
|
||||||
snprintf(input, sizeof(input), "%ux%ux%u",
|
snprintf(input, sizeof(input), "%ux%ux%u",
|
||||||
get_mode.mode.view_xres,
|
get_mode.mode.view_xres,
|
||||||
|
@ -654,14 +713,23 @@ int main(void)
|
||||||
text("\n");
|
text("\n");
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
|
const char* def =
|
||||||
|
non_interactive &&
|
||||||
|
!autoconf_has("grub_password_hash") ? "no" : "yes";
|
||||||
prompt(accept_grub_password, sizeof(accept_grub_password),
|
prompt(accept_grub_password, sizeof(accept_grub_password),
|
||||||
"grub_password",
|
"grub_password",
|
||||||
"Password protect interactive bootloader? (yes/no)", "yes");
|
"Password protect interactive bootloader? (yes/no)", def);
|
||||||
if ( strcasecmp(accept_grub_password, "no") == 0 ||
|
if ( strcasecmp(accept_grub_password, "no") == 0 ||
|
||||||
strcasecmp(accept_grub_password, "yes") == 0 )
|
strcasecmp(accept_grub_password, "yes") == 0 )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while ( !strcasecmp(accept_grub_password, "yes") )
|
if ( autoconf_has("grub_password_hash") )
|
||||||
|
{
|
||||||
|
char* hash = autoconf_eval("grub_password_hash");
|
||||||
|
install_configurationf("grubpw", "w", "%s\n", hash);
|
||||||
|
free(hash);
|
||||||
|
}
|
||||||
|
else while ( !strcasecmp(accept_grub_password, "yes") )
|
||||||
{
|
{
|
||||||
char first[128];
|
char first[128];
|
||||||
char second[128];
|
char second[128];
|
||||||
|
@ -730,14 +798,17 @@ int main(void)
|
||||||
text("Type man to display the disked(8) man page.\n");
|
text("Type man to display the disked(8) man page.\n");
|
||||||
not_first = true;
|
not_first = true;
|
||||||
const char* argv[] = { "disked", "--fstab=fstab", NULL };
|
const char* argv[] = { "disked", "--fstab=fstab", NULL };
|
||||||
if ( execute(argv, "f") != 0 )
|
char* disked_input = autoconf_eval("disked");
|
||||||
|
if ( execute(argv, "fi", disked_input) != 0 )
|
||||||
{
|
{
|
||||||
|
free(disked_input);
|
||||||
// TODO: We also end up here on SIGINT.
|
// TODO: We also end up here on SIGINT.
|
||||||
// TODO: Offer a shell here instead of failing?
|
// TODO: Offer a shell here instead of failing?
|
||||||
warnx("partitioning failed");
|
warnx("partitioning failed");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
free(disked_input);
|
||||||
free_mountpoints(mountpoints, mountpoints_used);
|
free_mountpoints(mountpoints, mountpoints_used);
|
||||||
mountpoints = NULL;
|
mountpoints = NULL;
|
||||||
mountpoints_used = 0;
|
mountpoints_used = 0;
|
||||||
|
@ -969,6 +1040,8 @@ int main(void)
|
||||||
else while ( true )
|
else while ( true )
|
||||||
{
|
{
|
||||||
char defhost[HOST_NAME_MAX + 1] = "";
|
char defhost[HOST_NAME_MAX + 1] = "";
|
||||||
|
if ( non_interactive )
|
||||||
|
gethostname(defhost, sizeof(defhost));
|
||||||
FILE* defhost_fp = fopen("etc/hostname", "r");
|
FILE* defhost_fp = fopen("etc/hostname", "r");
|
||||||
if ( defhost_fp )
|
if ( defhost_fp )
|
||||||
{
|
{
|
||||||
|
@ -1003,6 +1076,24 @@ int main(void)
|
||||||
{
|
{
|
||||||
textf("Root account already exists, skipping creating it.\n");
|
textf("Root account already exists, skipping creating it.\n");
|
||||||
}
|
}
|
||||||
|
else if ( non_interactive || autoconf_has("password_hash_root") )
|
||||||
|
{
|
||||||
|
char* hash = autoconf_eval("password_hash_root");
|
||||||
|
if ( !hash && !(hash = strdup("x")) )
|
||||||
|
err(2, "malloc");
|
||||||
|
if ( !install_configurationf("etc/passwd", "a",
|
||||||
|
"root:%s:0:0:root:/root:sh\n"
|
||||||
|
"include /etc/default/passwd.d/*\n", hash) )
|
||||||
|
err(2, "etc/passwd");
|
||||||
|
textf("User '%s' added to /etc/passwd\n", "root");
|
||||||
|
if ( !install_configurationf("etc/group", "a",
|
||||||
|
"root::0:root\n"
|
||||||
|
"include /etc/default/group.d/*\n") )
|
||||||
|
err(2, "etc/passwd");
|
||||||
|
install_skel("/root", 0, 0);
|
||||||
|
textf("Group '%s' added to /etc/group.\n", "root");
|
||||||
|
free(hash);
|
||||||
|
}
|
||||||
else while ( true )
|
else while ( true )
|
||||||
{
|
{
|
||||||
char first[128];
|
char first[128];
|
||||||
|
@ -1112,8 +1203,9 @@ int main(void)
|
||||||
text("Congratulations, the system is now functional! This is a good time "
|
text("Congratulations, the system is now functional! This is a good time "
|
||||||
"to do further customization of the system.\n\n");
|
"to do further customization of the system.\n\n");
|
||||||
|
|
||||||
|
// TODO: autoconf users support.
|
||||||
bool made_user = false;
|
bool made_user = false;
|
||||||
for ( uid_t uid = 1000; true; )
|
for ( uid_t uid = 1000; !has_autoconf; )
|
||||||
{
|
{
|
||||||
while ( passwd_has_uid("etc/passwd", uid) )
|
while ( passwd_has_uid("etc/passwd", uid) )
|
||||||
uid++;
|
uid++;
|
||||||
|
@ -1195,7 +1287,9 @@ int main(void)
|
||||||
uid++;
|
uid++;
|
||||||
made_user = true;
|
made_user = true;
|
||||||
}
|
}
|
||||||
text("\n");
|
// TODO: autoconf support.
|
||||||
|
if ( !has_autoconf )
|
||||||
|
text("\n");
|
||||||
|
|
||||||
// TODO: Ask if networking should be disabled / enabled.
|
// TODO: Ask if networking should be disabled / enabled.
|
||||||
|
|
||||||
|
@ -1303,7 +1397,7 @@ int main(void)
|
||||||
!access_or_die("/etc/sshd_config", F_OK);
|
!access_or_die("/etc/sshd_config", F_OK);
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
prompt(input, sizeof(input), "enable_ssh",
|
prompt(input, sizeof(input), "enable_sshd",
|
||||||
"Enable ssh server? (yes/no)",
|
"Enable ssh server? (yes/no)",
|
||||||
might_want_sshd ? "yes" : "no");
|
might_want_sshd ? "yes" : "no");
|
||||||
if ( strcasecmp(input, "no") == 0 )
|
if ( strcasecmp(input, "no") == 0 )
|
||||||
|
@ -1356,7 +1450,7 @@ int main(void)
|
||||||
bool enable_sshd_password = false;
|
bool enable_sshd_password = false;
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
prompt(input, sizeof(input), "enable_ssh_password",
|
prompt(input, sizeof(input), "enable_sshd_password",
|
||||||
"Enable sshd password authentication? (yes/no)", "no");
|
"Enable sshd password authentication? (yes/no)", "no");
|
||||||
if ( strcasecmp(input, "no") == 0 )
|
if ( strcasecmp(input, "no") == 0 )
|
||||||
break;
|
break;
|
||||||
|
@ -1374,7 +1468,7 @@ int main(void)
|
||||||
}
|
}
|
||||||
while ( enable_sshd_password )
|
while ( enable_sshd_password )
|
||||||
{
|
{
|
||||||
prompt(input, sizeof(input), "enable_ssh_root_password",
|
prompt(input, sizeof(input), "enable_sshd_root_password",
|
||||||
"Enable sshd password authentication for root? (yes/no)",
|
"Enable sshd password authentication for root? (yes/no)",
|
||||||
"no");
|
"no");
|
||||||
if ( strcasecmp(input, "no") == 0 )
|
if ( strcasecmp(input, "no") == 0 )
|
||||||
|
|
|
@ -22,5 +22,6 @@ must be run as root with stdin, stdout and stderr all pointing to the terminal.
|
||||||
It is intended to be run from a live environment and not from an actual
|
It is intended to be run from a live environment and not from an actual
|
||||||
installation.
|
installation.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
|
.Xr autoupgrade.conf 5 ,
|
||||||
.Xr upgrade 7 ,
|
.Xr upgrade 7 ,
|
||||||
.Xr sysinstall 8
|
.Xr sysinstall 8
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fstab.h>
|
#include <fstab.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
#include <mount/harddisk.h>
|
#include <mount/harddisk.h>
|
||||||
#include <mount/partition.h>
|
#include <mount/partition.h>
|
||||||
|
|
||||||
|
#include "autoconf.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "devices.h"
|
#include "devices.h"
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
|
@ -329,6 +331,12 @@ void exit_handler(void)
|
||||||
rmdir(fs);
|
rmdir(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cancel_on_sigint(int signum)
|
||||||
|
{
|
||||||
|
(void) signum;
|
||||||
|
errx(2, "fatal: Upgrade canceled");
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
shlvl();
|
shlvl();
|
||||||
|
@ -349,6 +357,13 @@ int main(void)
|
||||||
if ( atexit(exit_handler) != 0 )
|
if ( atexit(exit_handler) != 0 )
|
||||||
err(2, "atexit");
|
err(2, "atexit");
|
||||||
|
|
||||||
|
autoconf_load("/etc/autoupgrade.conf");
|
||||||
|
|
||||||
|
char* accepts_defaults = autoconf_eval("accept_defaults");
|
||||||
|
bool non_interactive = accepts_defaults &&
|
||||||
|
!strcasecmp(accepts_defaults, "yes");
|
||||||
|
free(accepts_defaults);
|
||||||
|
|
||||||
struct utsname uts;
|
struct utsname uts;
|
||||||
uname(&uts);
|
uname(&uts);
|
||||||
|
|
||||||
|
@ -357,6 +372,41 @@ int main(void)
|
||||||
textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR ""
|
textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR ""
|
||||||
" upgrader for %s.\n\n", uts.machine);
|
" upgrader for %s.\n\n", uts.machine);
|
||||||
|
|
||||||
|
if ( autoconf_has("ready") ||
|
||||||
|
autoconf_has("confirm_upgrade") )
|
||||||
|
{
|
||||||
|
int countdown = 10;
|
||||||
|
if ( autoconf_has("countdown") )
|
||||||
|
{
|
||||||
|
char* string = autoconf_eval("countdown");
|
||||||
|
countdown = atoi(string);
|
||||||
|
free(string);
|
||||||
|
}
|
||||||
|
sigset_t old_set;
|
||||||
|
sigset_t new_set;
|
||||||
|
sigemptyset(&new_set);
|
||||||
|
sigaddset(&new_set, SIGINT);
|
||||||
|
sigprocmask(SIG_BLOCK, &new_set, &old_set);
|
||||||
|
struct sigaction old_sa;
|
||||||
|
struct sigaction new_sa = { 0 };
|
||||||
|
new_sa.sa_handler = cancel_on_sigint;
|
||||||
|
sigaction(SIGINT, &new_sa, &old_sa);
|
||||||
|
for ( ; 0 < countdown; countdown-- )
|
||||||
|
{
|
||||||
|
textf("Automatically upgrading to " BRAND_DISTRIBUTION_NAME " "
|
||||||
|
VERSIONSTR " in %i %s... (Control-C to cancel)\n", countdown,
|
||||||
|
countdown != 1 ? "seconds" : "second");
|
||||||
|
sigprocmask(SIG_SETMASK, &old_set, NULL);
|
||||||
|
sleep(1);
|
||||||
|
sigprocmask(SIG_BLOCK, &new_set, &old_set);
|
||||||
|
}
|
||||||
|
textf("Automatically upgrading " BRAND_DISTRIBUTION_NAME " "
|
||||||
|
VERSIONSTR "...\n");
|
||||||
|
text("\n");
|
||||||
|
sigaction(SIGINT, &old_sa, NULL);
|
||||||
|
sigprocmask(SIG_SETMASK, &old_set, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// '|' rather than '||' is to ensure side effects.
|
// '|' rather than '||' is to ensure side effects.
|
||||||
if ( missing_program("cut") |
|
if ( missing_program("cut") |
|
||||||
missing_program("dash") |
|
missing_program("dash") |
|
||||||
|
@ -401,6 +451,9 @@ int main(void)
|
||||||
};
|
};
|
||||||
size_t num_readies = sizeof(readies) / sizeof(readies[0]);
|
size_t num_readies = sizeof(readies) / sizeof(readies[0]);
|
||||||
const char* ready = readies[arc4random_uniform(num_readies)];
|
const char* ready = readies[arc4random_uniform(num_readies)];
|
||||||
|
if ( autoconf_has("confirm_upgrade") )
|
||||||
|
text("Warning: This upgrader will automatically upgrade an operating "
|
||||||
|
"system!\n");
|
||||||
prompt(input, sizeof(input), "ready", "Ready?", ready);
|
prompt(input, sizeof(input), "ready", "Ready?", ready);
|
||||||
text("\n");
|
text("\n");
|
||||||
|
|
||||||
|
@ -479,16 +532,20 @@ int main(void)
|
||||||
good = true;
|
good = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const char* def = good ? "no" : "yes";
|
const char* def = non_interactive || good ? "no" : "yes";
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
prompt(input, sizeof(input), "videomode",
|
prompt(input, sizeof(input), "videomode",
|
||||||
"Select display resolution? (yes/no)", def);
|
"Select display resolution? "
|
||||||
if ( strcasecmp(input, "no") && strcasecmp(input, "yes") )
|
"(yes/no/WIDTHxHEIGHTxBPP)", def);
|
||||||
|
unsigned int xres, yres, bpp;
|
||||||
|
bool set = sscanf(input, "%ux%ux%u", &xres, &yres, &bpp) == 3;
|
||||||
|
if ( !set && strcasecmp(input, "no") && strcasecmp(input, "yes") )
|
||||||
continue;
|
continue;
|
||||||
if ( strcasecmp(input, "no") == 0 )
|
if ( strcasecmp(input, "no") == 0 )
|
||||||
break;
|
break;
|
||||||
if ( execute((const char*[]) { "chvideomode", NULL }, "f") != 0 )
|
const char* r = set ? input : NULL;
|
||||||
|
if ( execute((const char*[]) { "chvideomode", r, NULL }, "f") != 0 )
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -535,7 +592,7 @@ int main(void)
|
||||||
execlp("sysinstall", "sysinstall", (const char*) NULL);
|
execlp("sysinstall", "sysinstall", (const char*) NULL);
|
||||||
err(2, "sysinstall");
|
err(2, "sysinstall");
|
||||||
}
|
}
|
||||||
continue;
|
errx(2, "Upgrade aborted since no installations were found");
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( true )
|
while ( true )
|
||||||
|
|
|
@ -130,7 +130,15 @@ if $random_seed; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
has_autoinstall=false
|
||||||
|
has_autoupgrade=false
|
||||||
if [ -n "$liveconfig" ]; then
|
if [ -n "$liveconfig" ]; then
|
||||||
|
if [ -e "$liveconfig/etc/autoinstall.conf" ]; then
|
||||||
|
has_autoinstall=true
|
||||||
|
fi
|
||||||
|
if [ -e "$liveconfig/etc/autoupgrade.conf" ]; then
|
||||||
|
has_autoupgrade=true
|
||||||
|
fi
|
||||||
mkdir -p -- "$directory/boot"
|
mkdir -p -- "$directory/boot"
|
||||||
(cd "$liveconfig" && tar -c -f- -- *) > "$directory/boot/liveconfig.tar"
|
(cd "$liveconfig" && tar -c -f- -- *) > "$directory/boot/liveconfig.tar"
|
||||||
rm -f -- "$directory/boot/liveconfig.tar.xz"
|
rm -f -- "$directory/boot/liveconfig.tar.xz"
|
||||||
|
@ -147,6 +155,12 @@ mkdir -p -- "$directory/boot/grub"
|
||||||
if [ -n "$timeout" ]; then
|
if [ -n "$timeout" ]; then
|
||||||
printf 'timeout="%s"\n' "$timeout"
|
printf 'timeout="%s"\n' "$timeout"
|
||||||
fi
|
fi
|
||||||
|
if $has_autoinstall; then
|
||||||
|
echo "title_sysinstall='***AUTOMATIC INSTALLATION***'"
|
||||||
|
fi
|
||||||
|
if $has_autoupgrade; then
|
||||||
|
echo "title_sysupgrade='***AUTOMATIC UPGRADE***'"
|
||||||
|
fi
|
||||||
print_enable_default_bool "$enable_dhclient" dhclient dhclient
|
print_enable_default_bool "$enable_dhclient" dhclient dhclient
|
||||||
print_enable_default "$enable_network_drivers" network_drivers network-drivers
|
print_enable_default "$enable_network_drivers" network_drivers network-drivers
|
||||||
print_enable_default_bool "$enable_src" src src
|
print_enable_default_bool "$enable_src" src src
|
||||||
|
|
|
@ -216,6 +216,13 @@ GRUB module is loaded and an
|
||||||
hook is emitted that loads
|
hook is emitted that loads
|
||||||
.Pa output-directory/boot/liveconfig.tar.xz
|
.Pa output-directory/boot/liveconfig.tar.xz
|
||||||
as a multiboot module.
|
as a multiboot module.
|
||||||
|
.Pp
|
||||||
|
If the liveconfig contains
|
||||||
|
.Xr autoinstall.conf 5
|
||||||
|
or
|
||||||
|
.Xr autoupgrade.conf 5 ,
|
||||||
|
the menu titles are modified to loudly warn they will automatically
|
||||||
|
install/upgrade the operating system.
|
||||||
.It Fl \-random-seed
|
.It Fl \-random-seed
|
||||||
Copy 256 bytes of randomness from
|
Copy 256 bytes of randomness from
|
||||||
.Pa /dev/urandom
|
.Pa /dev/urandom
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
autoinstall=
|
||||||
|
autoupgrade=
|
||||||
daemons=
|
daemons=
|
||||||
directory=
|
directory=
|
||||||
hostname=
|
hostname=
|
||||||
|
@ -51,6 +53,10 @@ for argument do
|
||||||
|
|
||||||
case $dashdash$argument in
|
case $dashdash$argument in
|
||||||
--) dashdash=yes ;;
|
--) dashdash=yes ;;
|
||||||
|
--autoinstall=*) autoinstall=$parameter ;;
|
||||||
|
--autoinstall) previous_option=autoinstall ;;
|
||||||
|
--autoupgrade=*) autoupgrade=$parameter ;;
|
||||||
|
--autoupgrade) previous_option=autoupgrade ;;
|
||||||
--daemons=*) daemons=$parameter ;;
|
--daemons=*) daemons=$parameter ;;
|
||||||
--daemons) previous_option=daemons ;;
|
--daemons) previous_option=daemons ;;
|
||||||
--hostname=*) hostname=$parameter ;;
|
--hostname=*) hostname=$parameter ;;
|
||||||
|
@ -101,6 +107,15 @@ fi
|
||||||
|
|
||||||
mkdir -p "$directory"
|
mkdir -p "$directory"
|
||||||
|
|
||||||
|
if [ -n "$autoinstall" ]; then
|
||||||
|
mkdir -p -- "$directory/etc"
|
||||||
|
cp -- "$autoinstall" "$directory/etc/autoinstall.conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$autoupgrade" ]; then
|
||||||
|
mkdir -p -- "$directory/etc"
|
||||||
|
cp -- "$autoupgrade" "$directory/etc/autoupgrade.conf"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "$daemons" ]; then
|
if [ -n "$daemons" ]; then
|
||||||
mkdir -p -- "$directory/etc/init"
|
mkdir -p -- "$directory/etc/init"
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
.Nd generate additional live environment configuration for Sortix .iso releases
|
.Nd generate additional live environment configuration for Sortix .iso releases
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
|
.Op Fl \-autoinstall Ns = Ns Ar file
|
||||||
|
.Op Fl \-autoupgrade Ns = Ns Ar file
|
||||||
.Op Fl \-daemons Ns = Ns Ar daemons
|
.Op Fl \-daemons Ns = Ns Ar daemons
|
||||||
.Op Fl \-hostname Ns = Ns Ar hostname
|
.Op Fl \-hostname Ns = Ns Ar hostname
|
||||||
.Op Fl \-kblayout Ns = Ns Ar kblayout
|
.Op Fl \-kblayout Ns = Ns Ar kblayout
|
||||||
|
@ -53,6 +55,20 @@ installations made from inside it.
|
||||||
.Pp
|
.Pp
|
||||||
The options are as follows:
|
The options are as follows:
|
||||||
.Bl -tag -width "12345678"
|
.Bl -tag -width "12345678"
|
||||||
|
.It Fl \-autoinstall Ns = Ns Ar file
|
||||||
|
Copy
|
||||||
|
.Ar file
|
||||||
|
to
|
||||||
|
.Pa output-directory/etc/autoinstall.conf .
|
||||||
|
(See
|
||||||
|
.Xr autoinstall.conf 5 )
|
||||||
|
.It Fl \-autoupgrade Ns = Ns Ar file
|
||||||
|
Copy
|
||||||
|
.Ar file
|
||||||
|
to
|
||||||
|
.Pa output-directory/etc/autoupgrade.conf .
|
||||||
|
(See
|
||||||
|
.Xr autoupgrade.conf 5 )
|
||||||
.It Fl \-daemons Ns = Ns Ar daemons
|
.It Fl \-daemons Ns = Ns Ar daemons
|
||||||
Configures the
|
Configures the
|
||||||
.Sy local
|
.Sy local
|
||||||
|
@ -286,9 +302,32 @@ rm -f bootconfig/boot/liveconfig.xz # When no longer useful.
|
||||||
rm -f sortix.iso # When no longer useful.
|
rm -f sortix.iso # When no longer useful.
|
||||||
# And erase any media made from sortix.iso when no longer useful.
|
# And erase any media made from sortix.iso when no longer useful.
|
||||||
.Ed
|
.Ed
|
||||||
|
.Ss Automatic Installation
|
||||||
|
To customize a release so it automatically installs itself according to
|
||||||
|
.Pa autoinstall.conf
|
||||||
|
(see
|
||||||
|
.Xr autoinstall.conf 5 ) :
|
||||||
|
.Bd -literal
|
||||||
|
tix-iso-liveconfig --autoinstall=autoinstall.conf liveconfig
|
||||||
|
tix-iso-bootconfig --liveconfig=liveconfig --default=1 bootconfig
|
||||||
|
tix-iso-add sortix.iso bootconfig
|
||||||
|
.Ed
|
||||||
|
.Ss Automatic Upgrade
|
||||||
|
To customize a release so it automatically upgrades a local installation
|
||||||
|
according to
|
||||||
|
.Pa autoupgrade.conf
|
||||||
|
(see
|
||||||
|
.Xr autoupgrade.conf 5 ) :
|
||||||
|
.Bd -literal
|
||||||
|
tix-iso-liveconfig --autoinstall=autoupgrade.conf liveconfig
|
||||||
|
tix-iso-bootconfig --liveconfig=liveconfig --default=2 bootconfig
|
||||||
|
tix-iso-add sortix.iso bootconfig
|
||||||
|
.Ed
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr ssh-keygen 1 ,
|
.Xr ssh-keygen 1 ,
|
||||||
.Xr xorriso 1 ,
|
.Xr xorriso 1 ,
|
||||||
|
.Xr autoinstall.conf 5 ,
|
||||||
|
.Xr autoupgrade.conf 5 ,
|
||||||
.Xr hostname 5 ,
|
.Xr hostname 5 ,
|
||||||
.Xr kblayout 5 ,
|
.Xr kblayout 5 ,
|
||||||
.Xr ssh_config 5 ,
|
.Xr ssh_config 5 ,
|
||||||
|
|
Loading…
Reference in New Issue