--- /dev/null
+/fai/config/class/51-multi-boot
+/fai/config/files/root/.ssh/authorized_keys
+/fai/config/files/root/.ssh/authorized_keys2
+/fai/config/files/usr/local
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+PXE install w multi-boot, btrfs & Libreboot support
+
+Some things are specific to my home network, and uses files with secrets
+that are not in this repo. I use this for bare metal and vms, and two
+scripts which can run post boot so I use them on vps distributed image
+as well.
+
+Features people may find useful: installs encrypted trisquel, debian,
+ubuntu, arch, and parabola (archlike install is likely broken, I've only
+done pxe boots recently), in a multi-boot setup using multiple
+subvolumes of a single btrfs filesystem. Utilizes multiple disks, with
+scripts to automatically decrypt on intentional reboots, but not after
+shutdown or power loss.
+
+Normal install mode for fai is using pxe, but on a libreboot system,
+there is no pxe. The pxe in a normal computer is nonfree
+firmware. Alternatives to normal pxe that I've tried:
+
+* libreboot + seabios + ipxe
+
+* Use a live cd to call pxe-kexec, this is described later in this file.
+
+* Use the fai autodiscover iso. This is more automated, so nicer.
+
+* Use an install method above to setup a gnu/linux disk partition that
+ coordinates with libreboot grub to acts like a pxe boot using
+ kexec. The boot process takes a bit longer than normal pxe. This is
+ the bootstrap partition in my scripts.
+
+Things I haven't tried:
+
+* The bios chip has enough room for an initrd. This could be setup to
+ work like the partition I use to kexec, but it would be faster, and
+ not require installing to disk.
+
+The partititioning and filesystem script is at
+fai/config/hooks/partition.DEFAULT. Disks are grouped as ssd or hdd and
+raided in raid 1 or raid 0 per configuration. The base partitions are
+divided into boot, swap, and root, (only boot is unencrypted). There are
+scripts to resize those partitions post-provision and while the system
+is running.
+
+People who use fai may find these things as useful examples: it uses
+dnsmasq (on a openwrt machine) for dhcp instead of the isc
+dhcp. fai-wrapper is a small script to use basic fai classes outside of
+fai. It does not use the fai partitioning tool, but the script is
+inspired from it and works outside of fai. It supports running a fai
+server on debian within android via Maru.
+
+It also automates configuration of an openwrt router after manual
+initial installation.
+
+After provisionining is done, I sync files using btrfs, or unison for
+vps, then automate further setup using a different set of scripts,
+https://iankelling.org/git/?p=distro-setup;a=tree.
+
+My network is a wndr3700v2 router with openwrt on it and a few pcs/laptops.
+
+Since fai requires a debian server as the fai server, there are also
+scripts to automate a debian install using pxe and preseeding, which can
+be done from any distro.
+
+Some of the scripts have dependencies for some simple obvious utility
+scripts from https://iankelling.org/git, and of course there are some
+hostnames that are specific to my network.
+
+
+# Per-host/install configuration
+
+Before doing a fai install, you will need to populate a class file. I
+use one called 51-multi-boot, which you can see example of in
+fai/config/class/50-host-classes.
+
+Before doing a fai install, you will need to populate /q/root/luks and
+/q/root/shadow, see their references. You might also want to copy
+existing /etc/ssh/*host* to
+/p/c/machine_specific/HOST/filesystem/etc/ssh
+
+host-* luks keyfiles generated like:
+h=demohost; head -c 2048 /dev/urandom | od | se dd of=/q/root/luks/host-$h
+
+Configuration of which luks key to use is in
+fai/config/hooks/partition.DEFAULT
+
+Configuration of which (if any) shadow file to use is in
+fai/config/distro-install-common/end
+and which shadow file / luks file(s) to copy into the new machine depends
+on fai-redep arguments.
+
+Also, setup dns in /p/c/host-info and firewall redirects in wrt-setup-local.
+
+After install, btrbk to setup data, and then distro-begin && distro end.
+See notes in distro-begin for other configuration.
+
+# Scripts (meant to be used directly):
+
+
+# Setup the environment for the install
+
+# create tiny autodiscover cd
+# todo: with fai-revm at least, this complains about missing vmlinuz. need to fix this.
+fai-redep && sudo fai-cd -g $PWD/grub.cfg.autodiscover -f -A $BASEFILE_DIR/autodiscover.iso
+# create normal fai cd (replace TARGET_HOSTNAME)
+fai-redep -t TARGET_HOSTNAME && sudo fai-cd -M -g $PWD/grub.cfg.netinst-noreboot -f $BASEFILE_DIR/netinst.iso
+# note, may need to set hostname, depending on config,
+# and some other things for environment not on your lan
+# for example see fai/config/class/LINODE.var. See linode notes below.
+
+mymk-basefile # Create basefiles for various distros
+archlike-pxe # Setup pxe boot server from an archlike base image
+fai-redep # Deploy fai configuration to host "faiserver"
+faiserver-uninstall # uninstall fai-server
+faiserver-setup # install fai-server on the current machine
+myfai-chboot # setup fai tftp and nfs. useful for doing pxe-kexec or booting from a fai-cd.
+pxe-server # disable/enable pxe dhcp, tfp, and nfs. calls myfai-chboot
+wrt-setup # setup my router in general: dhcp, dns, etc.
+
+
+# Script to do a distro install
+
+faiserver-revm # using pxe & preseed, create a vm which is a fai server
+dsfull # install & post-install a new fai distro
+arch-init-remote # install arch after it's been booted into it's setup env
+live-kexec # Kexec this or a remote machine using host faiserver. also
+ useful to run as curl live-kexec|bash
+
+
+# Test scripts
+
+arch-revm # test arch install on a fresh vm
+fai-revm # test fai install on a fresh vm
+
+
+# Scripts to call after a distro install for various reasons
+
+chboot # Set grub to boot into a different distro (installed earlier)
+install-chboot # reinstall chboot to /boot subvols, for chboot updates.
+eboot # reboot without automatic disk decryption
+fai-wrapper # use fai classes outside of fai. sourced, not called.
+faiserver-disable # Disable the fai nfs server exports
+fresize # resize swap or boot partitions in a host
+
+
+# NAT/forward/vpn tftp
+
+I tried to get this working, but failed.
+
+tftp server in theory can be forwarded over a vpn, eg on a wireguard tunnel.
+
+However, I found that when actually pxe booting, it wouldn't work, only
+the 1st filename would be requested, eg, in the logs:
+
+Jun 20 23:51:02 kd in.tftpd[4021350]: RRQ from 10.2.0.12 filename pxelinux.0
+
+
+To get that far, nating tftp requires some special attention in iptables, like so:
+
+https://unix.stackexchange.com/questions/579508/iptables-rules-to-forward-tftp-via-nat
+iptables -t raw -A PREROUTING -p udp --dport 69 -s 209.51.188.0/24 -j CT --helper tftp
+modprobe nf_nat_tftp
+
+to test tftp from a client machine:
+
+tftp SERVER_IP -c get pxelinux.0
+rm -fv pxelinux.0
+
+
+# Common problems
+
+## kernel mismatch very early error, no remote logs:
+
+ERROR: the running kernel does not match the kernel modules inside the nfsroot.
+ERROR: Kernel modules directory /lib/modules/5.10.0-8-amd not available. Only found /lib/modules/5.10.0-15-amd64
+
+solution: if running from fai-cd, recreate autodiscover cd as noted above in setup.
+
+## Weird package dependency errors
+
+for example: in fai.log, within instsoft.DEBIAN
+```
+The following packages have unmet dependencies:
+ libc6 : Breaks: locales (< 2.36) but 2.35-0ubuntu3.7+11.0trisquel1 is to be installed
+```
+
+In this case, it was because the basefile was missing, and so instead
+fai decided to use the wrong basefile.
+
+for example: in fai.log, within instsoft.DEBIAN
+
+```
+ftar: No matching class found in /var/lib/fai/config/basefiles//
+ftar: extracting /var/tmp/base.tar.zst to /target/
+```
+
+# What good logs look like:
+
+logging nfs traffic from server
+
+s rpcdebug -m nfsd -s all
+
+
+normal nfs mount & umount logs look like:
+
+journalctl -ef | gr nfs
+
+Jun 20 22:15:36 kd rpc.mountd[2025725]: authenticated mount request from 10.32.2.1:865 for /srv/fai/nfsroot (/srv/fai/nfsroot)
+Jun 20 22:15:36 kd kernel: nfsd: exp_rootfh(/srv/fai/nfsroot [00000000e8c53e54] *:dm-0/5521225)
+Jun 20 22:15:36 kd kernel: nfsd: fh_compose(exp 00:1b/5521225 fai/nfsroot, ino=5521225)
+Jun 20 22:15:36 kd kernel: nfsd: FSINFO(3) 28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000
+Jun 20 22:15:36 kd kernel: nfsd: fh_verify(28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000)
+Jun 20 22:15:36 kd kernel: nfsd: PATHCONF(3) 28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000
+Jun 20 22:15:36 kd kernel: nfsd: fh_verify(28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000)
+Jun 20 22:15:36 kd kernel: nfsd: GETATTR(3) 28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000
+Jun 20 22:15:36 kd kernel: nfsd: fh_verify(28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000)
+Jun 20 22:15:36 kd kernel: nfsd: FSINFO(3) 28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000
+Jun 20 22:15:36 kd kernel: nfsd: fh_verify(28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000)
+Jun 20 22:15:36 kd kernel: nfsd: GETATTR(3) 28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000
+Jun 20 22:15:36 kd kernel: nfsd: fh_verify(28: 00070001 00543f49 00000000 d185f7b0 58d1a3c6 00000000)
+Jun 20 22:15:45 kd rpc.mountd[2025725]: authenticated unmount request from 10.32.2.1:986 for /srv/fai/nfsroot (/srv/fai/nfsroot)
+
+normal tftpd logs from:
+
+after setting -vv in TFTP_OPTIONS in /etc/default/tftpd-hpa
+
+journalctl -u tftpd-hpa
+
+Jun 20 23:51:02 kd in.tftpd[4021350]: RRQ from 10.2.0.12 filename pxelinux.0
+Jun 20 23:51:02 kd in.tftpd[4021351]: RRQ from 10.2.0.12 filename ldlinux.c32
+Jun 20 23:51:02 kd in.tftpd[4021352]: RRQ from 10.2.0.12 filename pxelinux.cfg/a913a477-fca6-234d-a928-6bb011decd05
+Jun 20 23:51:02 kd in.tftpd[4021352]: sending NAK (1, File not found) to 10.2.0.12
+Jun 20 23:51:02 kd in.tftpd[4021353]: RRQ from 10.2.0.12 filename pxelinux.cfg/01-52-54-00-9c-ef-ad
+Jun 20 23:51:02 kd in.tftpd[4021353]: sending NAK (1, File not found) to 10.2.0.12
+Jun 20 23:51:02 kd in.tftpd[4021354]: RRQ from 10.2.0.12 filename pxelinux.cfg/0A02000C
+Jun 20 23:51:02 kd in.tftpd[4021355]: RRQ from 10.2.0.12 filename vmlinuz-5.10.0-15-amd64
+Jun 20 23:51:03 kd in.tftpd[4021356]: RRQ from 10.2.0.12 filename initrd.img-5.10.0-15-amd64
+
+
+
+# Replacing a raid 10 disk
+
+pxe-server -S HOST fai
+
+# btrfs replace or delete. prefer replace. to setup partitions on replacement drive:
+scp fai-wrapper HOST:
+ssh root@HOST
+. fai-wrapper
+export SPECIAL_DISK=/dev/REPLACEMENT_DEV
+/var/lib/fai/config/hooks/partition.DEFAULT
+
+
+ssh root@HOST
+for x in /target/* /target; do umount $x; done
+cat >p
+PASSWORD HERE(ctrl-d ctrl-d)
+cd /dev/disk/by-id/
+for d in ata*part1; do cryptsetup luksOpen -d /root/p $d crypt_dev_$d; done
+x=(/dev/mapper/*part1); mount -o subvol=root_trisquelflidas $x /mnt
+# btrfs fi show /mnt
+# btrfs replace start -f /dev/mapper/OLD_DEV /dev/mapper/NEW_DEV /mnt
+# btrfs replace status /mnt
+# nohup btrfs dev delete /dev/sde1 /mnt
+mount -o subvol=boot_trisquelflidas /dev/sda3 /mnt/boot
+# also replace or delete disk for boot
+for x in dev proc sys; do mount -o bind /$x /mnt/$x; done
+chroot /mnt /bin/bash
+# replace disk in fstab
+# replace disk in /etc/crypttab
+update-grub
+update-initramfs -u
+mount /a
+/a/exe/keyscript-on
+exit
+reboot
+
+
+# Expected output in fai logs
+
+
+## On focal:
+
+fai.log:updatebase.UBUNTU FAILED with exit code 1.
+the real error is dpkg-reconfigure locales, seems to be related
+to a workaround for < 20.04, relevant comment:
+# in case the locales are already included inside the base file (Ubuntu)
+in config/hooks/instsoft.DEBIAN
+
+
+## For flidas,
+
+when installing systemd, this error happens, and it's
+a superflous upstream bug based on reading the post install script:
+
+addgroup: The group `systemd-journal' already exists as a system group. Exiting.
+Operation failed: No such file or directory
+
+## On nabia/newer,
+
+python is removed, now its python3,
+and its easier to just let the package get removed than
+do host class package config.
+fai.log:WARNING: These unknown packages are removed from the installation list: python python-minimal
+
+Similar to python, linux-image-amd64 is the debian package name
+for the kernel, linux-image-generic is for ubuntu, but the
+DEBIAN class is defined on ubuntu and its easier to just let
+the package get removed with this warning:
+fai.log:WARNING: These unknown packages are removed from the installation list: linux-image-amd64
+Also, cryptsetup-initramfs is new to buster/nabia, it gets removed
+on earlier versions.
+
+## parted error
+fai.log:Error: /dev/vda: unrecognised disk label
+This is from parted -m $d unit MiB print.
+It happens when there are no partitions yet.
+
+
+######## notes on creating a lan with just 2 computers ########
+
+
+## below assumes eth0 is the ethernet device used to connect to the target computer.
+
+
+# this is not strictly needed. I had my connection die at some point,
+# and I suspected this might help.
+# based on
+# https://support.qacafe.com/knowledge-base/how-do-i-prevent-network-manager-from-controlling-an-interface/
+cat > /etc/NetworkManager/conf.d/99-fai-tmp.conf <<'EOF'
+[main]
+plugins=keyfile
+
+[keyfile]
+unmanaged-devices=interface-name:eth0
+EOF
+ser restart NetworkManager
+
+
+cat >> /etc/network/interfaces <<'EOF'
+iface eth0 inet static
+address 10.0.44.1/24
+EOF
+
+ifup eth0
+
+# note turn off fsf vpn, so route to coresite is the normal route.
+echo 1 > /proc/sys/net/ipv4/ip_forward
+m s iptables -t nat -A POSTROUTING -o $(ip -4 route get 8.8.8.8 | sed -nr 's,^.* dev\s+(\S+).*,\1,p') -j MASQUERADE
+
+
+change /p/c/machine_specific/vps/bind-initial/db.b8.nz
+faiserver 10.0.44.1
+TARGET_HOSTNAME 10.0.44.2
+
+apt install isc-dhcp-server
+
+cat >> /etc/default/isc-dhcp-server <<'EOF'
+INTERFACESv4="eth0"
+EOF
+
+edit ./dhcpd.conf to change mac address and target host name.
+
+s cp /b/fai/dhcpd.conf /etc/dhcp/
+ser restart isc-dhcp-server
+
+edit /a/bin/fai/fai/config/class/51-multi-boot
+
+pxe-server -d TARGET fai
+
+Then do a pxe boot on the target host
+
+
+
+##### linode notes ######
+
+* create 2 disks, installer (3000 mb, raw), boot (remaining, raw)
+* create 2 profiles w direct boot, no helpers:
+ * installer (sda=boot, sdb=installer, boot dev=sdb)
+ * boot (sda=boot)
+* Boot into rescue mode, ssh in with lish,
+ curl url_to_some_fai_cd_created_image | dd of=/dev/sda
+ poweroff
+* boot into installer.
+* Lish shows console, at the end of install, it gives prompt because
+ logs failed to save remotely, check the logs, then reboot into boot
+ profile if all is well. If that doesn't happen, turn off lassie in
+ settings.
+
+
+
+###### ubuntu notes ######
+
+For someone who really needed ubuntu on host tp, otherwise they would
+end up on a non-gnu os, and I didn't want to figure out how to get all
+the default software installed, I did the following:
+
+# On remote host:
+# install etiona
+cd /b/fai
+# set 51-multi-boot to set classes outside of fai-wrapper conditional, including NOWIPE
+. fai-wrapper
+./fai/config/hooks/partition.DEFAULT
+
+# on remote host
+# install ubuntu 20.04 using virt-install
+sudo -i
+virt-install --os-variant=ubuntu16.04 --cdrom ubuntu-20.04-desktop-amd64.iso --disk path=u2004.qcow2 -r 2048 --vcpus 1 -n u2004
+qemu-img create -o preallocation=metadata -f qcow2 u2004.qcow2 15G
+# alternatively, also tried a physical install, because I know the virtual install ends up
+# with some differen things, like some spice service. then pulled the data out with
+rsync -ahSAX --numeric-ids --exclude=proc --exclude=sys --exclude=dev --exclude=tmp --exclude=run root@tp:/ .; mkdir proc sys dev tmp
+
+modprobe nbd
+qemu-nbd --connect=/dev/nbd0 u1804.qcow2 -f qcow2
+qemu-nbd --connect=/dev/nbd0 u2004.qcow2 -f qcow2
+mount /dev/nbd0p1 /mnt/1 # bionic
+mount /dev/nbd0p5 /mnt/1 # focal
+mount -o bind /mnt/root/root_ubuntubionic /mnt/2
+mount -o bind /mnt/root/root_ubuntufocal /mnt/2
+mkdir -p /mnt/2/boot
+mount -o bind /mnt/boot/boot_ubuntubionic /mnt/2/boot
+mount -o bind /mnt/boot/boot_ubuntufocal /mnt/2/boot
+# S = sparse, A = acls, X = xattrs
+rsync -ahSAX --numeric-ids /mnt/1/ /mnt/2
+
+cd /mnt/2
+cp /tmp/fai/crypttab etc
+sed -i "s#/root/keyscript,#decrypt_keyctl,#" etc/crypttab
+cp /tmp/fai/fstab etc
+echo "tmpfs /tmp tmpfs nodev,nosuid,size=50%,mode=1777 0 0" >> etc/fstab
+chrbind
+chroot .
+mv /etc/resolv.conf /etc/resolv.conf.old
+echo nameserver 1.1.1.1 >/etc/resolv.conf
+# install programs from /a/bin/fai/fai/config/package_config/STANDARD:
+apt install -y openssh-client openssh-server cryptsetup keyutils btrfs-progs console-setup kbd pciutils usbutils unattended-upgrades initramfs-tools-core dropbear-initramfs
+mv /etc/resolv.conf.old /etc/resolv.conf
+exit
+d=etc/initramfs-tools
+mkdir -p $d/root/.ssh etc/dropbear-initramfs root/.ssh
+chmod 700 $d/root $d/root/.ssh root/.ssh
+cp -p /root/.ssh/authorized_keys $d/root/.ssh/authorized_keys
+cp -p /root/.ssh/authorized_keys etc/dropbear-initramfs
+cp -p /root/.ssh/authorized_keys root/.ssh/authorized_keys
+chroot .
+sed -ri 's/^ *GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="rd.luks.crypttab=no"/' /etc/default/grub
+grub-install --no-floppy $(grub-probe -tdrive -d /dev/sda)
+update-grub
+grub-bios-setup -d /boot/grub/i386-pc -s /dev/sda
+exit
+umount proc
+umount dev
+umount sys
+reboot
+
+# for switching the boot to root2
+zboot
+# for switching back, efibootmgr, if there is a problem with the root filesystem detection,
+# boot into the debian bootstrap distro, run partition.DEFAULT using comments for mktab arg.
+# then manually run iboot and then reboot.
+
+
+# pine rock64 notes
+# the only useful image is ubuntu 18.04 ayafun or something.
+# using emmc usb:
+s mount /dev/sdb7 /mnt/1
+s cp `which qemu-arm-static` /mnt/1/usr/bin
+s chroot /mnt/1 qemu-arm-static /bin/bash
+usermod --login iank --move-home --home /home/iank rock46
+groupmod --new-name iank rock64
+passwd iank
+# boot it
+s apt-get update
+s apt dist-upgrade
+
+
+### How to merge upstream fai-config
+
+git checkout upstream
+cd path-to-fai-config
+git pull --stat
+# the following needs modification if there was deletions or renames
+rsync --exclude /.git -rlpgoDcvi . /b/fai/fai/config/
+cd /b/fai/fai/config/
+# where XXXXX is the git commit hash
+# note, several files which just had trailing space changes will get ignored.
+git commit -am "update upstream to XXXXX"
+git checkout master
+git merge upstream
+# fix conflicts
+git commit
+
+
+# TODO
+Change arch to archlike and to support arch and parabola
+
+
+# License
+
+The license for the project is GPLv2 or later, mostly because fai is and
+I periodically merge the upstream example config, which contains small
+scripts. Also, there is a modified encrypt.upstream, which is from the
+cryptsetup package in arch, which is under the same license.
--- /dev/null
+#!/bin/bash -x
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+cd ${x%/*}
+
+export HOSTNAME="$1"
+mirror=$2
+
+(( $# >= 1 )) || { echo "$0: error: need 1 or 2 arguments"; exit 1; }
+
+rm -f /etc/pacman.d/mirrorlist
+# https://wiki.archlinux.org/index.php/Mirrors#Sorting_mirrors
+
+if [[ $mirror ]]; then
+ echo "Server = $mirror" >> /etc/pacman.d/mirrorlist
+fi
+curl -s 'https://www.archlinux.org/mirrorlist/?country=US&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on' |
+ sed -r 's/^[ #]*(Server *=)/\1/' >> /etc/pacman.d/mirrorlist
+
+. /a/bin/fai/fai-wrapper
+export LUKS_DIR=/root/luks
+export DISTRO=arch
+partition_script=/a/bin/fai/fai/config/hooks/partition.DEFAULT
+chmod +x $partition_script
+
+export PARTITION_PROMPT=true
+
+# to be idempotent if we fail after partitioning
+already_partitioned=true
+mount_out=$(mount)
+for dir in /mnt{,/home,/boot,/a}; do
+ regex=" on $dir "
+ if [[ ! $mount_out =~ $regex ]]; then
+ already_partitioned=false
+ break
+ fi
+done
+
+if ! $already_partitioned; then
+ /a/bin/fai/fai/config/hooks/partition.DEFAULT
+fi
+
+. /tmp/fai/disk_var.sh
+
+
+# arch doesn't need crypttab entries for initramfs crypt partititions
+export rootn=1
+export bootn=3
+export swapn=2
+export BOOT_DEVICE
+export ROOT_PARTITIONS
+sed -ri --follow-symlinks "/^crypt_dev_\S+$rootn /d" /tmp/fai/crypttab
+
+if ! $already_partitioned; then
+ mount -o subvol=root_$DISTRO $ROOT_PARTITION /mnt
+ mkdir -p /mnt/boot
+ mount -o subvol=boot_$DISTRO $BOOT_PARTITION /mnt/boot
+fi
+
+# https://wiki.archlinux.org/index.php/Dm-crypt/Device_encryption#Keyfiles
+cp /root/luks/host-$HOSTNAME /mnt/crypto_keyfile.bin
+chmod 600 /mnt/crypto_keyfile.bin
+
+
+if [[ $mirror ]]; then
+ echo "$0: 404 errors about core.db etc are normal,
+they will succeed using the secodary mirror"
+fi
+pacstrap /mnt base
+cp /tmp/fai/{fstab,crypttab} /mnt/etc
+cp /a/bin/fai/encrypt /mnt/usr/lib/initcpio/hooks
+
+cp -r /root/.ssh /mnt/root
+
+bindmount() {
+ local mountpoint=$2
+ local source=$1
+ mkdir -p $mountpoint
+ mount -o bind $source $mountpoint
+}
+bindmount /root/shadow /mnt/q/root/shadow
+bindmount /a /mnt/a
+
+mkdir -p /mnt/etc/ssh
+cp /etc/ssh/ssh_host_* /mnt/etc/ssh
+
+cp /a/bin/fai/arch-init-chroot /mnt/root
+# for manual commands, arch-chroot /mnt bash
+arch-chroot /mnt /root/arch-init-chroot
+
+# this gets mounted in chroot so we have to do it outside
+rm -f /mnt/etc/resolv.conf
+ln -s /run/systemd/resolve/resolv.conf /mnt/etc/resolv.conf
+
+# not necsesary, but makes reboot go fast.
+umount -R /mnt; sleep 1
+
+# causes 255 exit code, so doing this from the caller script.
+# reboot now
--- /dev/null
+#!/bin/bash -x
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+# note, when I did genfstab, i
+# neeeded to to do for x in mv /etc/*.pacorig; do mv $x ${x%.pacorig}; done
+
+pacman -Syu
+
+[[ -L /etc/localtime ]] || ln -s /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
+l=en_US.UTF-8
+echo "$l UTF-8" > /etc/locale.gen
+locale-gen
+echo "LANG=$l" > /etc/locale.conf
+# if coming from windows, and you had to set the time, do this
+# hwclock --systohc --utc
+
+# A password is required to access the volume:
+# Command requires device and ampped name as arguments
+
+# If we were using btrfs raid, we supposedly would need this.
+# # add btrfs as module instead of hook due to
+# # https://wiki.archlinux.org/index.php/Btrfs,
+# # https://bugs.archlinux.org/task/42884
+# # disabled, as with just the module, startup spammed something about
+# # command takes a device name and something else.
+# sed -ri --follow-symlinks '/^ *MODULES *=.*btrfs/!s/^( *MODULES *=.*)"/\1 btrfs"/' /etc/mkinitcpio.conf
+# # remove extra space
+# sed -ri --follow-symlinks 's/^( *MODULES *=[^"]*)" */\1"/' /etc/mkinitcpio.conf
+
+
+
+
+# for desktop without full fs encryption, use this:
+#cat > /etc/crypttab <<'EOF'
+#tmp /dev/lvm/tmp /dev/urandom tmp,cipher=aes-xts-plain64,size=256
+
+# otgherwise ERROR: file not found: `fsck.btrfs'
+pacman -S --noconfirm btrfs-progs
+
+pacman -S --noconfirm grub gptfdisk
+
+
+shopt -s extglob
+echo "$0: fstab:"
+cat /etc/fstab
+# https://wiki.archlinux.org/index.php/Dm-crypt/System_configuration#Boot_loader
+# if cryptdevice was lvm, it woulde be in this format,
+# where x2-vg is from lvdisplay, VG Name field.
+# cryptdevice=/dev/disk/by-uuid/585dff23-136f-446f-815f-01053b70c957:x2-vg
+# but, if you are using your own fstab, it seems you just give it a name,
+# which will be the crypt device name under /dev/mapper/
+# https://wiki.archlinux.org/index.php/GRUB#Additional_arguments
+
+
+root_devs=( ${ROOT_PARTITIONS} )
+first_root_dev=${root_devs[0]}
+
+
+k_args=(
+ cryptdevices=${ROOT_PARTITIONS// /,}
+ root=/dev/mapper/crypt_dev_${first_root_dev##*/}
+ resume=${first_root_dev%[0-9]}$swapn
+)
+
+
+# If we have more than 1 to decrypt, arch wiki lead me onto
+# a sort of hacky way run the encrypt hook multiple times.
+
+# https://wiki.archlinux.org/index.php/Dm-crypt/Encrypting_an_entire_system#Configuring_mkinitcpio_2
+# used to have lvm2 after encrypt for lvm, but not using lvm anymore
+for x in encrypt btrfs; do
+ sed -ri --follow-symlinks -f - /etc/mkinitcpio.conf <<EOF
+/^ *HOOKS.*\b$x\b/!s/^( *HOOKS=.*)filesystems/\1$x filesystems/
+EOF
+done
+
+# this is the default file, otherwise you use cryptkey=device:fstype:path
+sed -ri --follow-symlinks -f - /etc/mkinitcpio.conf <<EOF
+s#^\s*FILES=.*#FILES="/crypto_keyfile.bin"#
+EOF
+echo "$0: FILES:"
+grep FILES /etc/mkinitcpio.conf
+echo "$0: grub cmdline additions: ${k_args[*]}"
+sed -ri --follow-symlinks -f - /etc/default/grub <<EOF
+\%${k_args[*]}%!s%^ *GRUB_CMDLINE_LINUX_DEFAULT *= *"%\0${k_args[*]} %
+EOF
+
+mkinitcpio -p linux
+
+
+# remove the default quiet arg.
+# this doesn't seem to affect anything, so leave it alone.
+#sed -ri --follow-symlinks 's/^( *GRUB_CMDLINE_LINUX_DEFAULT *= *.*) ?\bquiet\b(.*)/\1\2/' /etc/default/grub
+
+# https://wiki.archlinux.org/index.php/GRUB#Install_to_disk
+for dev in $BOOT_DEVICE; do
+ grub-install --recheck $dev
+done
+grub-mkconfig -o /boot/grub/grub.cfg
+# gtk2 is an optional dependency of unison.
+# I know Im gonna want the gui, so just doing it now.
+pacman -S --noconfirm openssh rsync
+
+
+pacman -S --noconfirm sudo
+
+. /a/bin/fai/fai-wrapper
+/a/bin/fai/fai/config/distro-install-common/end
+systemctl enable sshd
+
+rm -rf /home/iank/.ssh
+cp -r /root/.ssh /home/iank
+chown -R iank:iank /home/iank/.ssh
+# the groups recommended by
+# https://wiki.archlinux.org/index.php/Users_and_groups#Group_list
+usermod -aG games,rfkill,users,uucp,wheel iank
+
+
+pacman -S --noconfirm net-tools # for route
+# get the mac of the interface used by the broadcast route.
+mac=$(cat /sys/class/net/$(route -n | sed -rn 's/^0\.0\.0\.0.*[[:space:]]([^[:space:]]+)[[:space:]]*$/\1/p')/address)
+
+
+# simple bridge.
+cat > /etc/systemd/network/wired.network <<EOF
+[Match]
+Name=en*
+
+[Network]
+Bridge=br0
+EOF
+
+cat > /etc/systemd/network/br0.network <<EOF
+[Match]
+Name=br0
+
+[Network]
+DHCP=ipv4
+EOF
+
+cat > /etc/systemd/network/br0.netdev <<EOF
+[NetDev]
+Name=br0
+Kind=bridge
+# use the same mac as the physical port,
+# which is mapped to a static ip in our dhcp server.
+MACAddress=$mac
+EOF
+
+
+
+
+for x in networkd resolved; do systemctl enable systemd-$x; done
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2019 Ian Kelling
+# SPDX-License-Identifier: AGPL-3.0-or-later
+if [[ -s ~/.bashrc ]];then . ~/.bashrc;fi
+
+set -x
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [-h|--help] HOSTNAME
+install arch after it's been booted into it's setup env
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+esac
+
+if [[ ! $1 ]]; then
+ echo "error: expect a hostname in \$1 "
+ usage 1
+fi
+host=$1
+
+
+scp -o StrictHostKeyChecking=false -o UserKnownHostsFile=/dev/null \
+ /p/c/machine_specific/$host/filesystem/etc/ssh/* root@$host:/etc/ssh
+
+if [[ -e /var/cache/pacman/pkg ]]; then
+ darkhttpd /var/cache/pacman/pkg &
+ mirror=http://$HOSTNAME:8080
+fi
+
+rsync -rlpthvi --relative /a/bin/fai/ root@$host:/
+rsync /a/bin/fai/ root@$host:/a/bin/fai/
+sudo scp -r /q/root/luks /q/root/shadow root@$host:
+# creating shadow file string:
+# on debian, you can use mkpasswd -m sha-512 to generate a pass.
+# arch doesn't have this program. instead, you can do passwd,
+# and extract it from the shadow file.
+ssh root@$host bash -x /a/bin/fai/arch-init $host $mirror
+
+ssh root@$host reboot || [[ $? == 255 ]]
+
+# next up is sync data, then
+# ssh $host /a/bin/distro-begin
+
+if [[ -e /var/cache/pacman/pkg ]]; then
+ killall darkhttpd
+fi
+# todo: this doesn't work. figure out why.
+#kill $!
--- /dev/null
+fai-revm
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+echo $(date) > /tmp/myarchlikeinit.log
+if ! ip a | grep '^ *inet ' | grep -vF 127.0.0.1; then
+ cat <<'eof'
+We don't have an ipv4 address. Maybe arch doesn't do that for us,
+or we are probably using an ethernet port
+which is not the 1st one, so we haven't automatically done dhcpcd,
+so let's do it on whatever interface has a carrier
+eof
+ for f in /sys/class/net/*; do
+ if [[ `cat $f/carrier` == 1 ]]; then
+ echo $0: running: dhcpcd ${f##*/}
+ dhcpcd ${f##*/}
+ break
+ fi
+ done
+fi
+systemctl start sshd
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Setup arch pxe boot server from the base image.
+#
+if [[ -s ~/.bashrc ]];then . ~/.bashrc;fi
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/}
+Setup arch pxe boot server from the base image
+
+Requires manually downloading image. Image path is hardcoded below to
+/a/opt/image_name without .iso on the end. adjust the code for a new image. After this, run pxe-server.
+HOST|default arch to enable it.
+
+-h|--help Print help and exit.
+EOF
+ exit $1
+}
+
+case $1 in
+ -h|--help) usage ;;
+esac
+
+
+x="$(readlink -f "$BASH_SOURCE")"
+script_dir="${x%/*}"
+cd /a/opt/roms
+iso="parabola-systemd-cli-x86_64-netinstall-2018.06.02.iso"
+idir=${iso%.iso}
+rm -rf $idir
+ex $iso
+# should be parabola or arch
+n=${iso%%-*}
+sfs=$idir/$n/x86_64/*.sfs
+
+sed -i --follow-symlinks -f - $idir/$n/boot/syslinux/${n}iso_pxe64.cfg <<EOF
+1itotaltimeout 1
+/^LABEL arch64_nfs/a menu default
+s/^APPEND .*/\0 script=archlike-iso-init/
+EOF
+# based on https://blog.chendry.org/2015/02/06/automating-arch-linux-installation.html
+# and https://wiki.archlinux.org/index.php/Remastering_the_Install_ISO
+
+sudo rm -rf squashfs-root # remove any existing folder
+sudo unsquashfs $sfs
+sudo mkdir -p squashfs-root/root/.ssh
+sudo chmod 755 squashfs-root/root/.ssh
+sudo cp ~/.ssh/home.pub squashfs-root/root/.ssh/authorized_keys
+
+sudo cp $script_dir/archlike-iso-init squashfs-root/root
+sudo rm $sfs
+sudo mksquashfs squashfs-root $sfs -comp xz
+# file transfer to wrt is slow, so remove some useless files
+rm -f $idir/$n/i686/airootfs.sfs $idir/$n/boot/i686/${n}iso.img
+pushd $(dirname $sfs); md5sum ${sfs##*/} > airootfs.md5; popd
+
+# seems if you've done a pxe boot, mounted the nfs,
+# then shutdown, it's still busy.
+ssh cmc "/etc/init.d/nfsd stop; \
+umount /run/archiso/bootmnt; \
+umount /run/parabolaiso/bootmnt; \
+rm -rf /mnt/usb/$idir"
+
+scp -r $idir wrt:/mnt/usb
+ssh wrt "cd /mnt/usb && rm -f tftpboot && ln -s $idir tftpboot"
+
+# The default settings in the installer expect to find the NFS at /run/archiso/bootmnt
+
+# background: great documentation at
+# https://wiki.archlinux.org/index.php/PXE
+# arch can do netboot like ubuntu etc, but the docs look a little
+# complicated, so fuck it, we use nfs cuz it's easy
+
+rm -rf $idir
+sudo rm -rf squashfs-root
--- /dev/null
+fai/config/files/boot/bash-trace/DEFAULT
\ No newline at end of file
--- /dev/null
+; -*- zone -*-
+$TTL 30
+@ IN SOA cmc.b8.nz. postmaster.iankelling.org. (
+ 2021030716 ; serial
+ 1d 1d 4w 1M ; refresh retry expire minimum
+ )
+@ NS cmc.b8.nz.
+;; systemd overrides 1 with _gateway, when its the gateway. laaame.
+1 PTR cmc.b8.nz.
+2 PTR kd.b8.nz.
+3 PTR sy.b8.nz.
+4 PTR wrt2.b8.nz.
+5 PTR x2.b8.nz.
+6 PTR x2w.b8.nz.
+7 PTR syw.b8.nz.
+8 PTR amy.b8.nz.
+9 PTR bb8.b8.nz.
+12 PTR demohost.b8.nz.
+14 PTR wrt3.b8.nz.
+19 PTR brother.b8.nz.
+23 PTR amyw.b8.nz.
+25 PTR hp.b8.nz.
+;; todo: add transmission
--- /dev/null
+// This is the primary configuration file for the BIND DNS server named.
+
+// deploy with:
+// named-checkconf named.conf && named-checkzone 0.2.10.in-addr db.0.2.10.in-addr.arpa && scp named.conf db.0.2.10.in-addr.arpa 10.2.0.1:/etc/bind; ssh 10.2.0.1 /etc/init.d/named restart
+
+
+options {
+
+ listen-on { localnets; localhost; };
+ listen-on-v6 { localnets; localhost; };
+ directory "/tmp";
+
+ // If your ISP provided one or more IP addresses for stable
+ // nameservers, you probably want to use them as forwarders.
+ // Uncomment the following block, and insert the addresses replacing
+ // the all-0's placeholder.
+
+
+ auth-nxdomain no; # conform to RFC1035
+};
+
+#acl trusted { 10.2.0.7; 10.2.0.3; 10.2.0.2; };
+acl "trusted" { 10.2.0.7; };
+view "trusted" {
+ match-clients { "trusted"; };
+ forwarders {
+ 1.1.1.1 ;
+ 1.0.0.1 ;
+ 2606:4700:4700::1111 ;
+ 2606:4700:4700::1001 ;
+ };
+ forward only ;
+
+ // prime the server with knowledge of the root servers
+ zone "." {
+ type hint;
+ file "/etc/bind/db.root";
+ };
+
+ // be authoritative for the localhost forward and reverse zones, and for
+ // broadcast zones as per RFC 1912
+
+ zone "localhost" {
+ type master;
+ file "/etc/bind/db.local";
+ };
+
+ zone "127.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.127";
+ };
+
+ zone "0.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.0";
+ };
+
+ zone "255.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.255";
+ };
+
+ zone "0.2.10.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.0.2.10.in-addr.arpa";
+ };
+};
+
+
+acl "guest" { localnets; localhost; };
+view "guest" {
+ match-clients { "guest"; };
+
+ forwarders {
+ 1.1.1.3 ;
+ 1.0.0.3 ;
+ 2606:4700:4700::1113 ;
+ 2606:4700:4700::1003 ;
+ };
+ forward only ;
+ // prime the server with knowledge of the root servers
+ zone "." {
+ type hint;
+ file "/etc/bind/db.root";
+ };
+
+ // be authoritative for the localhost forward and reverse zones, and for
+ // broadcast zones as per RFC 1912
+
+ zone "localhost" {
+ type master;
+ file "/etc/bind/db.local";
+ };
+
+ zone "127.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.127";
+ };
+
+ zone "0.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.0";
+ };
+
+ zone "255.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.255";
+ };
+
+ zone "0.2.10.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.0.2.10.in-addr.arpa";
+ };
+};
--- /dev/null
+// This is the primary configuration file for the BIND DNS server named.
+
+options {
+ directory "/tmp";
+
+ // If your ISP provided one or more IP addresses for stable
+ // nameservers, you probably want to use them as forwarders.
+ // Uncomment the following block, and insert the addresses replacing
+ // the all-0's placeholder.
+
+ // forwarders {
+ // 0.0.0.0;
+ // };
+
+ auth-nxdomain no; # conform to RFC1035
+};
+
+// prime the server with knowledge of the root servers
+zone "." {
+ type hint;
+ file "/etc/bind/db.root";
+};
+
+// be authoritative for the localhost forward and reverse zones, and for
+// broadcast zones as per RFC 1912
+
+zone "localhost" {
+ type master;
+ file "/etc/bind/db.local";
+};
+
+zone "127.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.127";
+};
+
+zone "0.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.0";
+};
+
+zone "255.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.255";
+};
--- /dev/null
+fai/config/files/boot/chboot/DEFAULT
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# chost: get canonical hostname
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+host=$1
+# ||: because if we are using 2+ resolvers, 1 may fail, causing error, but we still get
+# a valid address and we just use that
+addr=$(host $host | sed -rn 's/^\S+ has address //p;T;q' ||:)
+h=$(host $addr)
+case $h in
+ *"no PTR record")
+ echo "error: chost: $h" >&2
+ exit 1
+ ;;
+esac
+h=${h##* }
+# trailing dot in a hostname will mess up rsync
+h=${h%.}
+echo $h
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} OPTIONS
+
+Given a tftproot, setup a preseed in it.
+
+-c Disable ssh network console. ssh user = installer. pw = test.
+-d Do debian ubuntu 14.04, default is jessie.
+-g GRUB_DISK Default is sda. Not used in interactive partitioning.
+-h|--help Print this help
+-i TFTP_IP Ip of tftp server. this is required.
+-p Stop for interactive partitioning.
+-t DIR Tftp root. Default is current dir.
+-u USER Username for the os install. Default is ${SUDO_USER:-$USER}
+
+EOF
+ exit $1
+}
+
+interactive_partition=false
+user=${SUDO_USER:-$USER}
+distro=debian-jessie
+net_console=false
+grub_disk=sda
+while [[ $1 == -* ]]; do
+ case $1 in
+ -c) net_console=false; shift ;;
+ -d) distro=ubuntu-14.04; shift ;;
+ -g) grub_disk=$2; shift 2 ;;
+ -i) ip=$2; shift 2 ;;
+ -p) interactive_partition=true; shift ;;
+ -t) cd $2; shift 2;;
+ -u) user=$2; shift 2;;
+ --) shift; break ;;
+ -*|-h|--help) usage ;;
+ esac
+done
+
+
+shopt -s extglob
+rm -rf !(netboot.tar.gz)
+preseed=example-preseed.txt
+neboot_path=main/installer-amd64/current/images/netboot/netboot.tar.gz
+case $distro in
+ ubuntu-14.04)
+ wget -q https://help.ubuntu.com/lts/installation-guide/$preseed
+ wget -qN http://archive.ubuntu.com/ubuntu/dists/trusty/$neboot_path
+ sed -ri --follow-symlinks 's!^tasksel tasksel/first multiselect .*!#\0!' $preseed
+ echo 'tasksel tasksel/first multiselect ubuntu-server, openssh-server' >>$preseed
+ ;;
+ debian-jessie)
+ wget -q https://www.debian.org/releases/jessie/$preseed
+ wget -qN http://ftp.nl.debian.org/debian/dists/jessie/$neboot_path
+ cat >>$preseed <<'EOF'
+tasksel tasksel/first multiselect ssh-server
+EOF
+ if ! $interactive_partition; then
+ cat >>$preseed <<EOF
+d-i grub-installer/bootdev string /dev/$grub_disk
+EOF
+ fi
+ ;;
+esac
+tar xzf netboot.tar.gz
+
+
+# if you set priority=critical, you can avoid a few of these questions. but
+# then you need to set the hostname in dhcp options
+# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=755848
+# questions you can avoid setting in boot parameters:
+# console-setup/ask_detect=false keyboard-configuration/layoutcode=us
+# hostname=$hostname
+# also, it asks about partition size. I don't know the preseeded answer,
+# as it just says "2.0 TB" in get-selections. I would need to figure out
+# how to accept the default.
+#
+# you can also see what got configured on a system with this command:
+# sudo apt-get install debconf-utils
+# debconf-get-selections --installer
+#
+
+# keymap=us is only needed for debian.
+pxe_cfg=${distro%-*}-installer/amd64/boot-screens/txt.cfg
+sed="sed -ri --follow-symlinks"
+$sed "s#^[[:space:]]*append[[:space:]]#\0auto priority=critical locale=en_US.UTF-8 netcfg/choose_interface=auto url=tftp://$ip/example-preseed.txt keymap=us#" $pxe_cfg
+# various google results say timeout x will result in doing the default thing,
+# but that doesn't happen. no idea why. Maybe it needed to be part of the label.
+echo 'totaltimeout 1' | tee -a $pxe_cfg
+
+if $interactive_partition; then
+ $sed 's/^d-i[[:space:]]partman.*/#\0/' $preseed
+ # at least in ubuntu, this does automatic selection of boot device,
+ # and on a server where we setup raid, it choose sda, and failed
+ # and the whole installation could not be salvaged.
+ $sed 's/^d-i[[:space:]]grub-installer.*/#\0/' $preseed
+fi
+
+$sed "s#(^d-i time/zone string US/).*#\1Pacific#" $preseed
+$sed '/^xserver-xorg/,/[^\\$]/ s/.*/#\0/' $preseed
+# we set the locale in kernel args. maybe we don't need to. this overrides it.
+$sed 's!^d-i[[:space:]]debian-installer/locale[[:space:]].*!#\0!' $preseed
+
+# for secure pass, set the shadow option with mkpasswd -s -m sha-512 < passfile
+
+# the example config says this option shoudl work, but it doesn't. tried it with http too,
+# and tried naming it authorized_keys.
+#d-i network-console/authorized_keys_url tftp://tftp@10.0.0.107/id_rsa.pub
+
+if $net_console; then
+ cat >> $preseed <<EOF
+d-i anna/choose_modules string network-console
+# this doesn't work. todo: ask debian about it
+#d-i network-console/authorized_keys_url http://10.0.0.2/authorized_keys
+d-i network-console/password password test
+d-i network-console/password-again password test
+EOF
+fi
+
+cat >> $preseed <<EOF
+d-i hw-detect/load_firmware boolean true
+d-i partman/default_filesystem string ext4
+d-i passwd/user-fullname string $user
+d-i passwd/username string $user
+# cleartext password for testing.
+d-i passwd/user-password password $user
+d-i passwd/user-password-again password $user
+d-i passwd/root-password password $user
+d-i passwd/root-password-again password $user
+d-i pkgsel/update-policy select unattended-upgrades
+d-i preseed/late_command string \
+in-target sed -i 's/^%sudo.*$/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' /etc/sudoers; \
+in-target mkdir -p /home/$user/.ssh; \
+in-target /bin/sh -c "echo '$(cat ~/.ssh/home.pub)' >> /home/$user/.ssh/authorized_keys"; \
+in-target chown -R $user:$user /home/$user; \
+in-target chmod -R go-rwx /home/$user/.ssh/authorized_keys; \
+in-target cp -r /home/$user/.ssh /root; \
+in-target usermod -a -G sudo $user;
+EOF
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# WARNING: outdated! needs docs and update to debian-stretch
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+
+[[ $EUID == 0 ]] || exec sudo "$BASH_SOURCE" "$@"
+
+src=$(readlink -f "${BASH_SOURCE%/*}")
+
+e() { echo "$*"; "$@"; }
+
+mount_dir=$(mktemp -d)
+
+err-cleanup() { cd; umount -f $mount_dir; }
+e mount -o users cmc:/mnt/usb $mount_dir
+
+
+cd $mount_dir
+e rm -rf debian-wheezy
+mkdir debian-wheezy
+cd debian-wheezy
+e $src/debian-preseed "$@" # my script
+cd ..
+e rm -f tftpboot
+e ln -s debian-wheezy tftpboot
+
+cd /
+e umount $mount_dir
+e $src/pxe-server default plain # my script
--- /dev/null
+fai/config/distro-install-common/devbyid
\ No newline at end of file
--- /dev/null
+#
+
+# iank: just guessing here.
+authoritative;
+
+
+deny unknown-clients;
+option dhcp-max-message-size 2048;
+use-host-decl-names on;
+
+subnet 10.0.44.0 netmask 255.255.255.0 {
+option routers 10.0.44.1;
+option domain-name "b8.nz";
+option domain-search "b8.nz";
+option domain-name-servers 8.8.8.8;
+option ntp-servers 0.ubuntu.pool.ntp.org, 1.ubuntu.pool.ntp.org, ntp.ubuntu.com;
+# iank: not sure why this is here, but not in
+#server-name faiserver;
+option time-offset -18000; # Eastern Standard Time
+}
+
+host community0p {
+next-server faiserver.b8.nz;
+filename "pxelinux.0";
+
+hardware ethernet 00:1f:16:14:01:d8;
+# 1st mobo, mostly fails to boot
+#hardware ethernet 08:60:6e:10:f0:fe;
+fixed-address 10.0.44.2;
+option host-name "x3";
+}
+
+
+default-lease-time 600;
+max-lease-time 7200;
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [[ -s ~/.bashrc ]];then . ~/.bashrc;fi
+
+reboot=true
+if [[ $1 == -r ]]; then
+ reboot=false
+ shift
+fi
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [OPTIONS] HOST
+"distro setup full" using fai.
+
+Note: relies on other repos and paths specific to Ian's system.
+Note: disables btrbk.timer. If it was active before, it should
+be manual reenabled after completion.
+
+-k ssh to host and kexec, don't use pxe. implies --no-r
+--no-r Don't ssh to host and reboot. Use this for when you are
+ booting or rebooting from some other means.
+-h|--help Print help and exit.
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+##### begin command line parsing ########
+
+reboot=true
+kexec=false
+temp=$(getopt -l help,no-r hk "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ --no-r) reboot=false; shift ;;
+ -k) kexec=true; reboot=false; shift ;;
+ -h|--help) usage ;;
+ --) shift; break ;;
+ *) echo "$0: Internal error!" ; exit 1 ;;
+ esac
+done
+host=$1
+
+##### end command line parsing ########
+
+ser stop btrbk.timer
+if [[ ! $host ]]; then
+ echo "$0: error: expected 1 arg of hostname"
+ exit 1
+fi
+
+if $kexec; then
+ fai-redep
+ myfai-chboot $host
+ live-kexec $host ||:
+else
+ err-cleanup() { pxe-server; }
+ pxe-server $host fai
+
+ if $reboot; then
+ # untested, this caused hang using here doc.
+ ssh root@$host "touch /tmp/keyscript-off; reboot" ||: &
+ fi
+
+ pxe-server -a
+ unset err-cleanup
+fi
+
+error=true
+for ((i=0; i<240; i++)); do
+ if timeout -s 9 10 ssh $host :; then
+ error=false
+ break
+ fi
+ sleep 5
+done
+faiserver-disable
+if $error; then
+ echo "$0: error: timeout"
+ exit 1
+fi
+while [[ $(ser is-active btrbk.service) == active ]]; do
+ sleep 5
+done
+# if we partitioned, we do this:
+#btrbk-run -t $host archive
+btrbk-run -t $host
+dsremote $host
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2017 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [-h|--help]
+reboot and keep disks encrypted
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+esac
+
+touch /tmp/keyscript-off
+[[ $EUID == 0 ]] || s=sudo
+$s reboot "$@"
--- /dev/null
+#!/usr/bin/ash
+
+# This file is a modification of the file encrypt in cryptsetup package
+# in arch. The original version is encrypt.upstream in the repo at
+# https://iankelling.org/git/?p=automated-distro-installer. It did not
+# come with a license notice in the file, but I remember that it is
+# GPLv2-or-later.
+
+run_hook() {
+ set -x
+ echo $0
+ modprobe -a -q dm-crypt >/dev/null 2>&1
+ [ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
+
+ # Get keyfile if specified
+ ckeyfile="/crypto_keyfile.bin"
+ if [ -n "$cryptkey" ]; then
+ IFS=: read ckdev ckarg1 ckarg2 <<EOF
+$cryptkey
+EOF
+
+ if [ "$ckdev" = "rootfs" ]; then
+ ckeyfile=$ckarg1
+ elif resolved=$(resolve_device "${ckdev}" ${rootdelay}); then
+ case ${ckarg1} in
+ *[!0-9]*)
+ # Use a file on the device
+ # ckarg1 is not numeric: ckarg1=filesystem, ckarg2=path
+ mkdir /ckey
+ mount -r -t "$ckarg1" "$resolved" /ckey
+ dd if="/ckey/$ckarg2" of="$ckeyfile" >/dev/null 2>&1
+ umount /ckey
+ ;;
+ *)
+ # Read raw data from the block device
+ # ckarg1 is numeric: ckarg1=offset, ckarg2=length
+ dd if="$resolved" of="$ckeyfile" bs=1 skip="$ckarg1" count="$ckarg2" >/dev/null 2>&1
+ ;;
+ esac
+ fi
+ [ ! -f ${ckeyfile} ] && echo "Keyfile could not be opened. Reverting to passphrase."
+ fi
+
+ for cryptdev in ${cryptdevices//,/ }; do
+ cryptname=crypt_dev_${cryptdev##*/}
+
+ if [ -n "${cryptoptions}" ]; then
+ cryptargs="${cryptargs} --allow-discards"
+ fi
+ for cryptopt in ${cryptoptions//,/ }; do
+ case ${cryptopt} in
+ no-allow-discards)
+ cryptargs=""
+ ;;
+ *)
+ echo "Encryption option '${cryptopt}' not known, ignoring." >&2
+ ;;
+ esac
+ done
+
+ if resolved=$(resolve_device "${cryptdev}" ${rootdelay}); then
+ if cryptsetup isLuks ${resolved} >/dev/null 2>&1; then
+ dopassphrase=1
+ # If keyfile exists, try to use that
+ if [ -f ${ckeyfile} ]; then
+ if eval cryptsetup --key-file ${ckeyfile} open --type luks ${resolved} ${cryptname} ${cryptargs} ${CSQUIET}; then
+ dopassphrase=0
+ else
+ echo "Invalid keyfile. Reverting to passphrase."
+ fi
+ fi
+ # Ask for a passphrase
+ if [ ${dopassphrase} -gt 0 ]; then
+ echo ""
+ echo "A password is required to access the ${cryptname} volume:"
+
+ #loop until we get a real password
+ while ! eval cryptsetup open --type luks ${resolved} ${cryptname} ${cryptargs} ${CSQUIET}; do
+ sleep 2;
+ done
+ fi
+ if [ -e "/dev/mapper/${cryptname}" ]; then
+ if [ ${DEPRECATED_CRYPT} -eq 1 ]; then
+ export root="/dev/mapper/root"
+ fi
+ else
+ err "Password succeeded, but ${cryptname} creation failed, aborting..."
+ exit 1
+ fi
+ elif [ -n "${crypto}" ]; then
+ msg "Non-LUKS encrypted device found..."
+ if echo "$crypto" | awk -F: '{ exit(NF == 5) }'; then
+ err "Verify parameter format: crypto=hash:cipher:keysize:offset:skip"
+ err "Non-LUKS decryption not attempted..."
+ return 1
+ fi
+ exe="cryptsetup open --type plain $resolved $cryptname $cryptargs"
+ IFS=: read c_hash c_cipher c_keysize c_offset c_skip <<EOF
+$crypto
+EOF
+ [ -n "$c_hash" ] && exe="$exe --hash '$c_hash'"
+ [ -n "$c_cipher" ] && exe="$exe --cipher '$c_cipher'"
+ [ -n "$c_keysize" ] && exe="$exe --key-size '$c_keysize'"
+ [ -n "$c_offset" ] && exe="$exe --offset '$c_offset'"
+ [ -n "$c_skip" ] && exe="$exe --skip '$c_skip'"
+ if [ -f "$ckeyfile" ]; then
+ exe="$exe --key-file $ckeyfile"
+ else
+ exe="$exe --verify-passphrase"
+ echo ""
+ echo "A password is required to access the ${cryptname} volume:"
+ fi
+ eval "$exe $CSQUIET"
+
+ if [ $? -ne 0 ]; then
+ err "Non-LUKS device decryption failed. verify format: "
+ err " crypto=hash:cipher:keysize:offset:skip"
+ exit 1
+ fi
+ if [ -e "/dev/mapper/${cryptname}" ]; then
+ if [ ${DEPRECATED_CRYPT} -eq 1 ]; then
+ export root="/dev/mapper/root"
+ fi
+ else
+ err "Password succeeded, but ${cryptname} creation failed, aborting..."
+ exit 1
+ fi
+ else
+ err "Failed to open encryption mapping: The device ${cryptdev} is not a LUKS volume and the crypto= paramater was not specified."
+ fi
+ fi
+ done
+ rm -f ${ckeyfile}
+}
+
+# vim: set ft=sh ts=4 sw=4 et:
--- /dev/null
+#!/usr/bin/ash
+
+# This file is from the cryptsetup package in arch. The only
+# modification is this comment. It did not come with a license notice in
+# the file, but I remember that it is GPLv2-or-later.
+
+run_hook() {
+ modprobe -a -q dm-crypt >/dev/null 2>&1
+ [ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
+
+ # Get keyfile if specified
+ ckeyfile="/crypto_keyfile.bin"
+ if [ -n "$cryptkey" ]; then
+ IFS=: read ckdev ckarg1 ckarg2 <<EOF
+$cryptkey
+EOF
+
+ if [ "$ckdev" = "rootfs" ]; then
+ ckeyfile=$ckarg1
+ elif resolved=$(resolve_device "${ckdev}" ${rootdelay}); then
+ case ${ckarg1} in
+ *[!0-9]*)
+ # Use a file on the device
+ # ckarg1 is not numeric: ckarg1=filesystem, ckarg2=path
+ mkdir /ckey
+ mount -r -t "$ckarg1" "$resolved" /ckey
+ dd if="/ckey/$ckarg2" of="$ckeyfile" >/dev/null 2>&1
+ umount /ckey
+ ;;
+ *)
+ # Read raw data from the block device
+ # ckarg1 is numeric: ckarg1=offset, ckarg2=length
+ dd if="$resolved" of="$ckeyfile" bs=1 skip="$ckarg1" count="$ckarg2" >/dev/null 2>&1
+ ;;
+ esac
+ fi
+ [ ! -f ${ckeyfile} ] && echo "Keyfile could not be opened. Reverting to passphrase."
+ fi
+
+ if [ -n "${cryptdevice}" ]; then
+ DEPRECATED_CRYPT=0
+ IFS=: read cryptdev cryptname cryptoptions <<EOF
+$cryptdevice
+EOF
+ else
+ DEPRECATED_CRYPT=1
+ cryptdev="${root}"
+ cryptname="root"
+ fi
+
+ warn_deprecated() {
+ echo "The syntax 'root=${root}' where '${root}' is an encrypted volume is deprecated"
+ echo "Use 'cryptdevice=${root}:root root=/dev/mapper/root' instead."
+ }
+
+ for cryptopt in ${cryptoptions//,/ }; do
+ case ${cryptopt} in
+ allow-discards)
+ cryptargs="${cryptargs} --allow-discards"
+ ;;
+ *)
+ echo "Encryption option '${cryptopt}' not known, ignoring." >&2
+ ;;
+ esac
+ done
+
+ if resolved=$(resolve_device "${cryptdev}" ${rootdelay}); then
+ if cryptsetup isLuks ${resolved} >/dev/null 2>&1; then
+ [ ${DEPRECATED_CRYPT} -eq 1 ] && warn_deprecated
+ dopassphrase=1
+ # If keyfile exists, try to use that
+ if [ -f ${ckeyfile} ]; then
+ if eval cryptsetup --key-file ${ckeyfile} open --type luks ${resolved} ${cryptname} ${cryptargs} ${CSQUIET}; then
+ dopassphrase=0
+ else
+ echo "Invalid keyfile. Reverting to passphrase."
+ fi
+ fi
+ # Ask for a passphrase
+ if [ ${dopassphrase} -gt 0 ]; then
+ echo ""
+ echo "A password is required to access the ${cryptname} volume:"
+
+ #loop until we get a real password
+ while ! eval cryptsetup open --type luks ${resolved} ${cryptname} ${cryptargs} ${CSQUIET}; do
+ sleep 2;
+ done
+ fi
+ if [ -e "/dev/mapper/${cryptname}" ]; then
+ if [ ${DEPRECATED_CRYPT} -eq 1 ]; then
+ export root="/dev/mapper/root"
+ fi
+ else
+ err "Password succeeded, but ${cryptname} creation failed, aborting..."
+ exit 1
+ fi
+ elif [ -n "${crypto}" ]; then
+ [ ${DEPRECATED_CRYPT} -eq 1 ] && warn_deprecated
+ msg "Non-LUKS encrypted device found..."
+ if echo "$crypto" | awk -F: '{ exit(NF == 5) }'; then
+ err "Verify parameter format: crypto=hash:cipher:keysize:offset:skip"
+ err "Non-LUKS decryption not attempted..."
+ return 1
+ fi
+ exe="cryptsetup open --type plain $resolved $cryptname $cryptargs"
+ IFS=: read c_hash c_cipher c_keysize c_offset c_skip <<EOF
+$crypto
+EOF
+ [ -n "$c_hash" ] && exe="$exe --hash '$c_hash'"
+ [ -n "$c_cipher" ] && exe="$exe --cipher '$c_cipher'"
+ [ -n "$c_keysize" ] && exe="$exe --key-size '$c_keysize'"
+ [ -n "$c_offset" ] && exe="$exe --offset '$c_offset'"
+ [ -n "$c_skip" ] && exe="$exe --skip '$c_skip'"
+ if [ -f "$ckeyfile" ]; then
+ exe="$exe --key-file $ckeyfile"
+ else
+ exe="$exe --verify-passphrase"
+ echo ""
+ echo "A password is required to access the ${cryptname} volume:"
+ fi
+ eval "$exe $CSQUIET"
+
+ if [ $? -ne 0 ]; then
+ err "Non-LUKS device decryption failed. verify format: "
+ err " crypto=hash:cipher:keysize:offset:skip"
+ exit 1
+ fi
+ if [ -e "/dev/mapper/${cryptname}" ]; then
+ if [ ${DEPRECATED_CRYPT} -eq 1 ]; then
+ export root="/dev/mapper/root"
+ fi
+ else
+ err "Password succeeded, but ${cryptname} creation failed, aborting..."
+ exit 1
+ fi
+ else
+ err "Failed to open encryption mapping: The device ${cryptdev} is not a LUKS volume and the crypto= paramater was not specified."
+ fi
+ fi
+ rm -f ${ckeyfile}
+}
+
+# vim: set ft=sh ts=4 sw=4 et:
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2019 Ian Kelling
+# SPDX-License-Identifier: AGPL-3.0-or-later
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+readonly this_file="$(readlink -f -- "${BASH_SOURCE[0]}")"; cd "${this_file%/*}"
+
+source bash-trace
+
+usage() {
+ cat <<EOF
+usage: ${0##*/} [OPTIONS] [HOST]
+Deploy fai config (the one in nfs) to HOST or default faiserver
+
+Note, for booting from fai-cd, this needs to be called from myfai-chboot or that via pxe-server,
+due to setting
+echo FAI_ACTION=$fai_action >> /srv/fai/config/class/LAST.var
+note FAI_ACTION might be able to be set elsewhere, like in grub for this case
+
+-d DISTRO DISTRO for setting up fai class DESKTOP packages, for preinstalling stuff.
+-t TARGET_HOST Copy only secrets for TARGET_HOST into the config space. Useful for virtual server
+ on hardware we don't control.
+-h|--help Print help and exit
+
+Note: uses paths specific to authors machine.
+EOF
+ exit $1
+}
+
+##### begin command line parsing ########
+
+# ensure we can handle args with spaces or empty.
+ret=0; getopt -T || ret=$?
+[[ $ret == 4 ]] || { echo "Install util-linux for enhanced getopt" >&2; exit 1; }
+
+temp=$(getopt -l help hd:t: "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ -d) distro=$2; shift ;;
+ -t) target=$2; shift ;;
+ -h|--help) usage ;;
+ --) shift; break ;;
+ *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;;
+ esac
+ shift
+done
+host=${1:-faiserver}
+
+readonly host distro target
+
+##### end command line parsing ########
+
+m() { printf "$pre %s\n" "$*"; "$@"; }
+
+# i use faiserver as a dns alias, but ssh key is associated with
+# a canonical hostname and we will have ssh warning spam unless we
+# use it, so look it up just to avoid the warning spam.
+faiserver_host=$(/a/exe/chost $host)
+# faiserver_host=$host
+
+faiserver_addr=$(host $host | sed -rn 's/^\S+ has address //p;T;q' ||:)
+if ! ip a | grep "^ *inet.\? $faiserver_addr" &>/dev/null; then
+ rpre=(-e "ssh -F $HOME/.ssh/confighome" root@$faiserver_host:)
+ faiserver_shell="ssh -F $HOME/.ssh/confighome root@$faiserver_host"
+fi
+
+# these are gitignored.
+rsync -atL /home/iank/.ssh/authorized_keys fai/config/files/root/.ssh/authorized_keys/STANDARD
+# we hssh and ssh_filter_btrbk for the initial btrbk (alternatively, I could open up the
+# permissions in authorized_keys, but that just seems lazy)
+install --owner=iank --group=iank -d fai/config/files/usr/local/bin/hssh
+install --owner=iank --group=iank -d fai/config/files/usr/local/bin/ssh_filter_btrbk.sh
+rsync -atL /a/opt/btrbk/ssh_filter_btrbk.sh fai/config/files/usr/local/bin/ssh_filter_btrbk.sh/STANDARD
+m rsync -rlpt --delete --relative --exclude /fai/config/basefiles/ fai/config "${rpre[@]}"/srv
+
+# todo: automatically disable faiserver after a period so
+# these files are not available.
+
+
+if [[ $target ]]; then
+ secret_files=(luks/$target luks/host-$target shadow/$target)
+ exists=false
+ secret_exists=()
+ for f in ${secret_files[@]}; do
+ if [[ -e /q/root/$f ]]; then
+ exists=true
+ secrets_to_send+=("$f")
+ fi
+ done
+ if $exists; then
+ {
+ for f in ${secrets_to_send[@]}; do
+ echo $f
+ done
+ } | rsync -lpt --files-from=- /q/root "${rpre[@]}"/srv/fai/config/distro-install-common
+ fi
+else
+ rsync -rlpt /q/root/shadow /q/root/luks "${rpre[@]}"/srv/fai/config/distro-install-common
+fi
+
+rsync -rlpt --delete /a/opt/btrfs-progs-release \
+ filesystem/usr/local/bin/ethusb-nm \
+ filesystem/usr/local/bin/ethusb-static \
+ "${rpre[@]}"/srv/fai/config/distro-install-common
+
+dirs=(/p/c/machine_specific/${target:-*}/filesystem/etc/ssh)
+if [[ -e ${dirs[0]} ]]; then
+ rsync -rlpt --delete --relative ${dirs[@]} "${rpre[@]}"/srv/fai/config/distro-install-common
+fi
+
+. /a/bin/distro-setup/pkgs
+pall+=($(/a/bin/buildscripts/emacs -p; /a/bin/distro-setup/distro-pkgs $distro))
+
+printf "%s\n%s\n" "PACKAGES install" ${pall[*]} | \
+ $faiserver_shell dd of=/srv/fai/config/package_config/DESKTOP status=none ||: # broken pipe
+
+
+m rsync -rplt --include '/*.zst' --exclude '/**' --delete-excluded $BASEFILE_DIR/ "${rpre[@]}"/srv/fai/config/basefiles/
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+
+readonly this_file="$(readlink -f -- "${BASH_SOURCE[0]}")"
+script_dir="${this_file%/*}"
+# shellcheck source=./bash-trace
+source "${script_dir}/bash-trace"
+cd $script_dir
+PATH="$PATH:$PWD"
+
+e() { echo "$*"; "$@"; }
+
+
+usage() {
+ cat <<EOF
+# Usage: ${0##*/} [OPTIONS]
+Setup fai or arch pxe (depending on $0 name)
+then start a virtual machine to test the config
+
+todo: make it so this can run this on a network we dont control, the 2
+ways I know which could work are either running in libvirt's the nated
+network, and altering the dnsmasq options for the dnsmasq that runs in
+that, or giving the vm a static ip and for resolving faiserver, and then
+for resolving "faiserver", either setup some static resolution in the
+vm, or give it the host machine's ip as a dns server, or in general
+change references of faiserver to faiserver.b8.nz (I like this idea
+because it helps in other cases too).
+
+Note, sometimes shutting down the existing demohost vm
+fails. Just run again if that happens.
+
+-d When doing pxe with -p, don't do dhcp setup. Good for when we
+ aren't on Ian's home network.
+-n Create new qcow2(s) for vm. Good for testing partitioning
+ script, to ensure a blank disk.
+-p Use pxe instead of autodiscover iso with fai.
+-c Use normal fai-cd iso is instead of autodiscover iso.
+-r Do not boot after install is complete
+-h|--help Print help and exit.
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+orig_args=("$@")
+new_disk=false
+pxe=false
+iso=autodiscover.iso
+temp=$(getopt -l help dnpcrh "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ -d) dhcp_arg=-d; shift ;;
+ -n) new_disk=true; shift ;;
+ -p) pxe=true; shift ;;
+ -c) iso=netinst.iso; shift ;;
+ -r) reboot_arg=--noreboot; shift ;;
+ -h|--help) usage ;;
+ --) shift; break ;;
+ *) echo "$0: Internal error!" ; exit 1 ;;
+ esac
+done
+
+
+# change this to test different disk counts.
+disk_count=3
+disk_count=1
+
+
+rm -f /tmp/fai-revm-did-pxe
+
+if ! ip l show br0 &>/dev/null; then
+ cat <<'EOF'
+fai-rvm error: no bridge detected. add one to interfaces like this:
+iface eth0 inet manual
+iface br0 inet dhcp
+ bridge_ports eth0
+ bridge_stp off
+ bridge_maxwait 0
+EOF
+ exit 1
+fi
+
+if [[ $script_dir == /a/bin/* ]]; then
+ # Copy our script elsewhere so we can develop it
+ # and save it at the same time it's running
+ rm -rf /tmp/faifreeze
+ cp -ar /a/bin/fai /tmp/faifreeze
+ exec /tmp/faifreeze/${BASH_SOURCE##*/} "${orig_args[@]}"
+fi
+
+
+is_arch_revm() {
+ [[ ${0##*/} == arch-revm ]]
+}
+
+err-cleanup() {
+ echo "doing cleanup"
+ if [[ -e /tmp/fai-revm-did-pxe ]]; then
+ e ./pxe-server $dhcp_arg
+ fi
+ ./faiserver-disable
+}
+
+boot_arg=--pxe
+if is_arch_revm; then
+ e ./pxe-server $dhcp_arg demohost arch
+ touch /tmp/fai-revm-did-pxe
+ sleep 2
+ # via osinfo-query os. guessing arch is closest to latest fedora.
+ variant=fedora22
+else
+ if $pxe; then
+ e ./pxe-server $dhcp_arg demohost fai
+ touch /tmp/fai-revm-did-pxe
+ sleep 2
+ else
+ killall fai-monitor &>/dev/null ||:
+ fai-monitor &
+ if [[ ! $BASEFILE_DIR ]]; then
+ BASEFILE_DIR=/tmp
+ fi
+ isopath=$BASEFILE_DIR/$iso
+ isosrc=$BASEFILE_DIR/BOOKWORM64.tar.zst
+ if [[ ! -e $isopath || $(stat -c %Y $isopath) -lt $(stat -c %Y $isosrc) ]]; then
+ e fai-cd -g $(readlink -f grub.cfg.${iso%%.*}) -f -A $isopath
+ fi
+ boot_arg="--cdrom $isopath"
+ e fai-redep
+ cat ~/.ssh/demo.pub | /a/exe/cedit -s /srv/fai/nfsroot/root/.ssh/authorized_keys
+ e myfai-chboot default
+ fi
+ # I don't think these variants actually make a diff for us, but I
+ # use the appropriate one when trying a new distro just in case.
+ #variant=ubuntu14.04
+ #variant=ubuntu16.04
+ #variant=debian8
+ variant=ubuntu20.04
+fi
+
+name=demohost
+
+e virsh destroy $name ||:
+sleep 1
+e virsh destroy $name ||:
+e virsh undefine $name ||:
+sleep 1
+
+
+disk_arg=()
+for ((i=1; i <= disk_count; i++)); do
+ f=/var/lib/libvirt/images/${name}$i
+ disk_arg+=("--disk path=$f")
+ if $new_disk || [[ ! -e $f ]]; then
+ rm -f $f
+ # https://btrfs.wiki.kernel.org/index.php/FAQ
+ touch $f
+ chattr +C $f
+ e qemu-img create -o preallocation=metadata -f qcow2 $f 50G
+ fi
+done
+
+if [[ $SSH_CLIENT ]]; then
+ console_arg=--noautoconsole
+fi
+
+# docker makes forward default to drop, which blocks the vm pxe on flidas. easiest solution:
+e iptables -P FORWARD ACCEPT
+
+# --cpu host: this causes mkfs.btrfs to fail with a stack trace which began
+# something like:
+# init_module+0x108/0x1000 [raid6_pq]
+#
+# uniq is to stop gtk-warning spam
+# e virt-install --os-variant $variant -n $name --pxe -r 2048 --vcpus 1 \
+ # ${disk_arg[*]} -w bridge=br0,mac=52:54:00:9c:ef:ad $reboot_arg \
+ # --graphics spice,listen=0.0.0.0 $console_arg |& grep -v '^ *$' | uniq &
+
+cpus=1
+if (( $(nproc) > 2 )); then
+ cpus=2
+fi
+
+e systemctl start libvirtd
+e virt-install --rng /dev/urandom --os-variant $variant -n $name $boot_arg -r 2048 --vcpus $cpus \
+ ${disk_arg[*]} -w bridge=br0,mac=52:54:00:9c:ef:ad $reboot_arg \
+ --graphics spice,listen=0.0.0.0 $console_arg |& grep -v '^ *$' | uniq &
+
+
+if [[ $SSH_CLIENT ]]; then
+ fg
+fi
+
+sleep 90
+while ! timeout -s 9 10 ssh -oBatchMode=yes root@$name true; do
+ e sleep 5
+done
+unset -f err-cleanup
+if $pxe; then
+ rm -f /tmp/fai-revm-did-pxe
+ e ./pxe-server $dhcp_arg
+fi
+
+# this tends to remove it too soon
+#echo | /a/exe/cedit -s /srv/fai/nfsroot/root/.ssh/authorized_keys
+
+if is_arch_revm; then
+ ./arch-init-remote $name
+fi
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2019 Ian Kelling
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+# For using some fai commands outside of fai.
+# Usually this is sourced from another script. Note this has
+# paths specific to Ian's machine.
+# to set fai classes, export CLASS_CLASSNAME=true
+# This wrapper can be detected by using this var:
+export FAI_WRAPPER=true
+
+ifclass() {
+ local var=${1/#/CLASS_}
+ [[ $HOSTNAME == $1 || ${!var} ]]
+}
+fai-setclass() {
+ for class in "$@"; do
+ # export class vars with CLASS_ in front to avoid name collisions.
+ classes+=" $class"
+ export CLASS_$class=true
+ done
+ classes="${classes# }"
+ export classes
+}
+eval-fai-classfile() {
+ file=$1
+ if [[ ! -s $file ]]; then
+ echo "$0: probably an error: eval-fai-classfile no such file: $file"
+ return 0
+ fi
+ fai-setclass $(bash $file)
+}
+export -f ifclass
+# DEFAULT is used by fcopy
+classes="DEFAULT $(hostname)"
+export CLASS_DEFAULT=true
+if [[ ! -d $FAI_ROOT ]]; then
+ export FAI_ROOT=/
+fi
+if [[ ! -d $FAI ]]; then
+ if [[ -d /a/bin/fai/fai/config ]]; then
+ export FAI=/a/bin/fai/fai/config
+ else
+ echo "$0: error: could not find directory to set for FAI. currently FAI=$FAI"
+ return 1
+ fi
+fi
+
+eval-fai-classfile $FAI/class/50-host-classes
+eval-fai-classfile $FAI/class/51-multi-boot
#! /bin/bash
-
# mk-basefile, create basefiles for some distributions
#
# Thomas Lange, Uni Koeln, 2011-2024
# For the first stage, set the CentOS/SLC mirror in /etc/rinse/rinse.conf
MIRROR_DEBIAN=http://deb.debian.org/debian/
MIRROR_UBUNTU=http://mirror.netcologne.de/ubuntu/
+MIRROR_TRISQUEL=http://mirror.fsf.org/trisquel/
MIRROR_CENTOS=http://mirror.netcologne.de/
EXCLUDE_SQUEEZE=isc-dhcp-client,isc-dhcp-common,info
EXCLUDE_FORKY=
EXCLUDE_SID=
+EXCLUDE_BELENOS=dhcp3-client,dhcp3-common,info
EXCLUDE_TRUSTY=dhcp3-client,dhcp3-common,info
EXCLUDE_XENIAL=udhcpc,dibbler-client,info
+EXCLUDE_FLIDAS=udhcpc,dibbler-client,info
EXCLUDE_BIONIC=udhcpc,dibbler-client,info
+EXCLUDE_ETIONA=udhcpc,dibbler-client,info
EXCLUDE_FOCAL=udhcpc,dibbler-client,info
+EXCLUDE_NABIA=udhcpc,dibbler-client,info
EXCLUDE_JAMMY=udhcpc,dibbler-client,info
+EXCLUDE_ARAMO=udhcpc,dibbler-client,info
EXCLUDE_NOBLE=udhcpc,dibbler-client,info
# here you can add packages, that are needed very early
INCLUDE_DEBIAN=
-
+INCLUDE_ETIONA=ifupdown
+INCLUDE_NABIA=ifupdown
+INCLUDE_ARAMO=ifupdown
setarch() {
cleanup-deb() {
+ if [[ $cmd ]]; then
+ if [[ -e $cmd ]]; then
+ cp "$cmd" $xtmp/tmp
+ chroot $xtmp "/tmp/$cmd"
+ else
+ chroot $xtmp $cmd
+ fi
+ fi
chroot $xtmp apt-get clean
rm -f $xtmp/etc/hostname $xtmp/etc/resolv.conf \
$xtmp/var/lib/apt/lists/*_* $xtmp/usr/bin/qemu-*-static \
dist=${DIST%%[0-9][0-9]}
local exc="EXCLUDE_$dist"
[ -n "${!exc}" ] && exc="--exclude=${!exc}" || unset exc
+ local inc="INCLUDE_$dist"
+ [ -n "${!inc}" ] && inc="--include=${!inc}" || unset inc
dist=${dist,,}
check
- if [ -n "$INCLUDE_DEBIAN" ]; then
- local inc="--include=$INCLUDE_DEBIAN"
- fi
if [ -n "$arch" ]; then
qemu-debootstrap --arch $arch ${exc} $inc $dist $xtmp $mirror
SLC7_64
TRUSTY32 TRUSTY64
XENIAL32 XENIAL64
+ FLIDAS64
BIONIC64
+ ETIONA64
FOCAL64
+ NABIA64
JAMMY64
+ ARAMO64
NOBLE64
SQUEEZE32 SQUEEZE64
WHEEZY32 WHEEZY64
-z Use zstd for compressing the tar file.
-J Use xz for compressing the tar file.
-k Keep the temporary subtree structure, do not remove it.
+ -x CMD Run CMD in chroot. If CMD exists as a file, copy it and run it.
+ Debian based only
-h Print help.
Usage example: mk-basefile -J STRETCH64
cleanup=1
attributes="--xattrs --selinux --acls"
-while getopts ashzJd:kf: opt ; do
+while getopts ashzJd:kf:x: opt ; do
case "$opt" in
a) echo "$0: Warning. -a is ignored, because xtattrs, acls and selinux are always added." ;;
d) export TMPDIR=$OPTARG ;;
k) cleanup=0 ;;
h) usage ;;
s) prtdists ; exit 0;;
+ x) cmd="$OPTARG" ;;
?) exit 3 ;; # error in option parsing
esac
done
SLC6_32) slc i386 6 ;;
SLC6_64) slc amd64 6 ;;
SLC7_64) slc amd64 7 ;;
+ BELENOS*|FLIDAS*|ETIONA*|NABIA*|ARAMO*)
+ debgeneric $target $MIRROR_TRISQUEL ;;
TRUSTY*|XENIAL*|BIONIC*|FOCAL*|JAMMY*|NOBLE*)
debgeneric $target $MIRROR_UBUNTU ;;
SQUEEZE*|WHEEZY*|JESSIE*|STRETCH*|BUSTER*|BULLSEYE*|BOOKWORM*|TRIXIE*|FORKY*|SID*)
-#! /bin/bash
+#!/bin/bash
# assign classes to hosts based on their hostname
# do not use this if a menu will be presented
[ "$flag_menu" ] && exit 0
-# use a list of classes for our demo machine
-case $HOSTNAME in
- faiserver)
- echo "FAIBASE DEBIAN DEMO FAISERVER" ;;
- demohost|client*)
- echo "FAIBASE DEBIAN DEMO" ;;
- xfcehost)
- echo "FAIBASE DEBIAN DEMO XORG XFCE LVM";;
- gnomehost)
- echo "FAIBASE DEBIAN DEMO XORG GNOME";;
- ubuntuhost)
- echo "FAIBASE DEBIAN DEMO UBUNTU JAMMY JAMMY64 XORG";;
- rocky)
- echo "FAIBASE ROCKY" # you may want to add class XORG here
- ifclass AMD64 && echo ROCKY9_64
- ;;
- *)
- echo "FAIBASE DEBIAN DEMO" ;;
-esac
+# set these early so they are lowest priority.
+echo FAIBASE STANDARD DEBIAN
+
+# note, this is where this file comes from:
+# cp /usr/share/keyrings/freesh-archive-keyring.gpg STANDARD.gpg
+
+
+# For multi-boot system.
+# We check that we aren't in a pxe boot environment.
+# There is probably a better way to do this.
+# We check the reverse condition in 51-multi-boot,
+# and set what os we are installing, but don't check it
+# into git since it changes regularly.
+
+#
+#
+# Each host defines following:
+# The base distro:
+# UBUNTU or nothing. DEBIAN is always defined as a base.
+#
+# The base disto version, only use so far is the basefile name if it exists.
+# Debian stable basefile gets built by faisetup and gets used otherwise.
+# With X suffix, means it has gone through the dirinstall process and has eXtra
+# things installed, to speed up installation.
+#
+# STRETCH64, BUSTER64, BULLSEYE64, BOOKWORM64
+# FLIDAS64, FLIDAS64BIG, ETIONA64, NABIA64, ARAMO64
+# XENIAL64, BIONIC64, FOCAL64,
+#
+# The distro subvol name, we can add as many of these as we want:
+# VOL_TESTING, VOL_STRETCH, VOL_BUSTER, VOL_BULLSEYE, VOL_BOOKWORM
+# VOL_FLIDAS, VOL_ETIONA, VOL_NABIA, VOL_ARAMO
+# VOL_XENIAL, VOL_BIONIC VOL_FOCAL
+# VOL_BUSTER_BOOTSTRAP.
+# Using VOL_BUSTER_BOOTSTRAP sets up the install to act like a pxe rom if
+# grub sets a specific var.
+#
+# The apt sources files we want,
+# STRETCH_FREE, STRETCH_NONFREE, STRETCH_LINODE
+# BUSTER_FREE, BUSTER_NONFREE,
+# BULLSEYE_FREE, BULLSEYE_NONFREE
+# BOOKWORM_FREE, BOOKWORM_NONFREE
+# TESTING_FREE, TESTING_NONFREE,
+# XENIAL_FREE, BIONIC, FOCAL, FLIDAS, ETIONA, NABIA, ARAMO.
+#
+# It's all a little redundant in some cases, but it keeps things
+# simpler.
+#
+#
+# Other notable classes:
+#
+# INSTALL: for autodiscover iso, this is needed. We could also add it to
+# the autodiscover grub, but then we have to burn a new iso if we want a
+# non-install one. It sets the class for the corresponding INSTALL.var,
+# which sets FAI_ACTION=INSTALL. I'm not sure if this variable overrides
+# FAI_ACTION outside of autodiscover, todo: test it out, if it doesn't,
+# make install be default in 51-multi-boot, and disable it if needed.
+#
+# DESKTOP: install a bunch of extra packages. For creating X suffix
+# basefiles. See README.
+#
+# LINODE: For running a vm on linode, especially one created with fai-cd.
+#
+# IANK / FSF: general setup of my machine vs FSF machines
+# NABIA_EXTRA: extra repos for NABIA from other distros
+# ARAMO_EXTRA: extra repos for ARAMO from other distros
+#
+# UBUNTU_UP: for trisquel, we want to inherit ubuntu things, except for
+# some ubuntu things which go in this class. UP = upstream.
+#
+# D16: for kgpe-d16 specific settings.
+#
+# JAMMY_FIRMWARE: for trisquel install to get nonfree firmware from
+# ubuntu jammy. The linux-firmware-free package in trisquel conflicts
+# with the linux-firmware package in ubuntu, but you only find out after
+# installing due to an error.
+#
+# For filesystem/partitioning related classes, see comments at the top of
+# fai/config/hooks/partition.DEFAULT
+
+if [[ -e /a/bin/fai/fai-wrapper ]]; then
+ source /a/bin/distro-functions/src/identify-distros
+ if isdeb; then
+ codename=$(debian-codename)
+ echo ${codename^^}
+ distro=$(distro-name)
+ case $distro in
+ debian)
+ echo ${distro^^}
+ # nonfree repo is not going away any time soon due to
+ # gcc-doc being in nonfree
+ echo ${codename^^}_NONFREE
+ ;;
+ trisquel)
+ # easier to stay with fai example config if we just call it ubuntu
+ echo UBUNTU
+ ;;
+ esac
+ fi
+ case $HOSTNAME in
+ li|lj) echo "LINODE" ;;
+ bk|je) echo "NOCRYPT" ;;
+ esac
+fi
+
+
+#echo "PARTITION_PROMPT"
+#echo REPARTITION
+
+
+if grep ^52:54:00: /sys/class/net/eth0/address &>/dev/null; then
+ # if our eth0 mac is in the kvm range, we are a vm.
+ echo "VM"
+fi
+
+exit 0
+### Below here is a comment of code, exit above is so it does not get executed ###
+
+###### begin Template for 51-multi-boot ######
+#
+# It has reasonable combinations of above classes.
+# We must first replace _ with host name(s).
+
+#!/bin/bash
+
+# pick one of these:
+#echo IANK
+#echo FSF
+if [[ ! -e /a/bin/fai/fai-wrapper || $FAI_ACTION == dirinstall ]]; then
+ case $HOSTNAME in
+ # bullseye based minimal recovery / bootstraping os:
+ _) echo BULLSEYE64 VOL_BULLSEYE_BOOTSTRAP BULLSEYE_FREE ;;
+ # flidas
+ _) echo UBUNTU FLIDAS64 VOL_FLIDAS FLIDAS ;;
+ # etiona
+ _) echo UBUNTU ETIONA64 VOL_ETIONA ETIONA ;;
+ # nabia
+ _) echo UBUNTU NABIA64 VOL_NABIA NABIA NABIA_EXTRA ;;
+ # aramo
+ _) echo UBUNTU ARAMO64 VOL_ARAMO ARAMO ARAMO_EXTRA ;;
+ # stretch
+ _) echo STRETCH64 VOL_STRETCH STRETCH_NONFREE ;;
+ # buster
+ _) echo BUSTER64 VOL_BUSTER BUSTER_NONFREE ;;
+ # bullseye
+ _) echo BULLSEYE64 VOL_BULLSEYE BULLSEYE_NONFREE ;;
+ # bookworm
+ _) echo BOOKWORM64 VOL_BOOKWORM BOOKWORM_NONFREE ;;
+ # testing
+ _) echo BOOKWORM64 VOL_TESTING TESTING_NONFREE ;;
+ # xenial
+ _) echo UBUNTU XENIAL64 VOL_XENIAL XENIAL_FREE ;;
+ # bionic
+ _) echo UBUNTU BIONIC64 VOL_BIONIC BIONIC ;;
+ # focal
+ _) echo UBUNTU FOCAL64 VOL_FOCAL FOCAL ;;
+ # jammy
+ _) echo UBUNTU JAMMY64 VOL_JAMMY JAMMY ;;
+ esac
+fi
+###### end Template for 51-multi-boot ######
--- /dev/null
+# /a/opt/linux/Documentation/admin-guide/serial-console.rst
+# https://libreboot.org/docs/hardware/kgpe-d16.html
+
+
+# pci=realloc=off = per rubens suggestion to make a d16 more stable
+
+# we make tty0 the last one so that it gets /dev/console and then
+# debian's cryptsetup addition askpass prompts there in the initramfs.
+# todo: file a bug to make it prompt on both.
+d16_cmdline="pci=realloc=off console=ttyS0,115200n8 console=tty0"
-release=bookworm
-apt_cdn=http://deb.debian.org
-security_cdn=http://security.debian.org
+# ian, commented, sources are set with fcopy
+# release=bookworm
+# apt_cdn=http://deb.debian.org
+# security_cdn=http://security.debian.org
# since bullseye Debian changed the suite name for security
if [ $release = buster ]; then
# if you have enough RAM (>2GB) you may want to enable this line. It
# also puts /var/cache into a ramdisk.
-#FAI_RAMDISKS="$target/var/lib/dpkg $target/var/cache"
+# ian: uncommented
+FAI_RAMDISKS="$target/var/lib/dpkg $target/var/cache"
# if you want to use the faiserver as APT proxy
#APTPROXY=http://faiserver:3142
--- /dev/null
+# according to fai-guide, required to enable saving logs
+# remotely.
+
+LOGUSER=fai
+
+# when downloading from https intead of nfs, this is not set,
+# it is used as the default for LOGSERVER, and for calling chboot.
+# My faiserver's hostname is always faiserver, so just hardcoding it.
+SERVER=faiserver
+
+# busted for debian, no time to troubleshoot atm
+#APTPROXY=http://faiserver:3142
+#### from upstream example config, except where noted
+
# default values for installation. You can override them in your *.var files
# allow installation of packages from unsigned repositories
# Set UTC=yes if your system clock is set to UTC (GMT), and UTC=no if not.
UTC=yes
-TIMEZONE=Europe/Berlin
-
-# the hash of the root password for the new installed linux system
-# pw is "fai"
-ROOTPW='$1$kBnWcO.E$djxB128U7dMkrltJHPf6d1'
+## changed from upstream. found in /usr/share/zoneinfo/, via fai-guide
+TIMEZONE=US/Eastern
# errors in tasks greater than this value will cause the installation to stop
STOP_ON_ERROR=700
#LOGUSER=fai
# a user account will be created
-username=demo
-USERPW='$1$kBnWcO.E$djxB128U7dMkrltJHPf6d1'
+#username=demo
+#USERPW='$1$kBnWcO.E$djxB128U7dMkrltJHPf6d1'
# set a default
FAI_DEBOOTSTRAP="bookworm http://deb.debian.org/debian"
--- /dev/null
+fsf_cmdline_extra="elevator=deadline transparent_hugepage=always numa=off"
--- /dev/null
+APTPROXY=
+linode_ip=172.105.84.95
+linode_gw=172.105.84.1
+# this is the same at least in 2 regions
+linode_if=enp0s3
+LOGSERVER=b8.nz
+HOSTNAME=l2
+cmdline_extra=console=ttyS0,19200n8
--- /dev/null
+CONSOLEFONT=lat9v-16
+KEYMAP=us
+DEFAULTLOCALE=en_US.UTF-8
+SUPPORTEDLOCALE=en_US.UTF-8:en_US:en
+
+# if you install much software and have only few RAM, use the RAM disk
+# not for var/cache/yum
+#FAI_RAMDISKS="$target/var/lib/rpm $target/var/cache/yum"
+FAI_RAMDISKS="$target/var/lib/rpm"
-ubuntumirror=http://archive.ubuntu.com
-ubuntudist=jammy
+#iank, i define these by classes. commenting
+# to make sure these arent used
+#ubuntumirror=http://archive.ubuntu.com
+#ubuntudist=jammy
--- /dev/null
+# config for a disk image for a VM
+#
+# p=<partlabel> <mountpoint> <size> <fs type> <mount options> <misc options>
+
+disk_config disk1 disklabel:gpt bootable:1 fstabkey:uuid align-at:1M
+
+p=efi /boot/efi 64M vfat defaults createopts="-F 32"
+p=root / 300- ext4 rw,discard,barrier=0,noatime,errors=remount-ro tuneopts="-c 0 -i 0"
--- /dev/null
+# example of new config file for setup-storage
+#
+# <type> <mountpoint> <size> <fs type> <mount options> <misc options>
+
+# you may want to add "-O ^metadata_csum_seed" to createopts if the target
+# system is older than bullseye. See #866603, #1031415, #1031416 for more info.
+
+disk_config disk1 disklabel:msdos bootable:1 fstabkey:label
+
+primary / 4G-50G ext4 rw,noatime,errors=remount-ro createopts="-L ROOT"
+
+logical swap 200-10G swap sw createopts="-L SWAP"
+logical /home 100- ext4 rw,noatime,nosuid,nodev createopts="-L HOME -m 1" tuneopts="-c 0 -i 0"
--- /dev/null
+disk_config disk1 disklabel:gpt-bios bootable:1 fstabkey:uuid
+primary / 100% ext4 noatime,errors=remount-ro
--- /dev/null
+#!/bin/bash
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# input eg: /dev/sda1 or /dev/sda
+# output: /dev/disk/by-id/model+serial, or if no link exists, the same as input
+
+short_dev=$1
+if [[ ! -e $short_dev ]]; then
+ echo "devbyid: error: argument=$short_dev does not exist"
+ exit 1
+fi
+
+# devices are identified by model+serial num
+# and for ssd/hdd: wwn, and for nvme: eui.
+# model+serial gives me more info, so use that.
+shopt -s extglob
+for id in /dev/disk/by-id/!(nvme-eui*|wwn*); do
+ [[ -e $id ]] || break # if we matched nothing
+ if [[ $(readlink -f $id) == "$short_dev" ]]; then
+ printf '%s\n' "$id"
+ exit
+ fi
+done
+# a vm may not have a by-id link.
+printf '%s\n' "$short_dev"
--- /dev/null
+#!/bin/bash -x
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: expected to be root."
+ exit 1
+fi
+
+# ssh host keys
+# note, $BASH_SOURCE is not defined here under fai.
+
+src=$(dirname "$0")/p/c/machine_specific/$HOSTNAME/filesystem/etc/ssh
+dst=$target/etc/ssh
+if [[ -e $src && -e $dst ]]; then
+ # outside of fai context or setting up a brand new host, we skip this
+ cp -rT $src $dst
+fi
+
+root_pw_f=/q/root/shadow/standard
+if [[ ! -e $root_pw_f ]]; then
+ root_pw_f=/q/root/shadow/$HOSTNAME
+fi
+
+au() { # add user. i don't use adduser for portability
+ local user=${@: -1}
+ if ! $ROOTCMD getent passwd $user; then
+ $ROOTCMD useradd -c $user -Um -s /bin/bash $@
+ fi
+}
+
+
+# only setup root pass for bootstrap vol
+# for bootstrap vol, we only use root user
+if ifclass VOL_BULLSEYE_BOOTSTRAP || ifclass VOL_BOOKWORM_BOOTSTRAP; then
+ sed 's/^/root:/' $root_pw_f | $ROOTCMD chpasswd -e
+ exit 0
+fi
+
+
+# return of 9 = user already exists. so we are idempotent.
+au iank
+# generating a hashed password:
+# under debian, you can do
+# mkpasswd -m sha-512 -s >/q/root/shadow/standard
+# On arch, best seems to be copy your shadow file to a temp location,
+# then passwd, get out the new pass, then copy the shadow file back.
+if [[ -e $root_pw_f ]]; then
+ sed 's/^/root:/' $root_pw_f | $ROOTCMD chpasswd -e
+ sed 's/^/iank:/' $root_pw_f | $ROOTCMD chpasswd -e
+fi
+
+au user2
+if ifclass frodo; then
+ sed 's/^/user2:/' /q/root/shadow/user2 | $ROOTCMD chpasswd -e
+fi
+# comparing iank's groups to user2, I see none she should join on arch
+$ROOTCMD usermod -a -G user2 iank
+
+
+$ROOTCMD getent group docker &>/dev/null || $ROOTCMD groupadd -r docker
+$ROOTCMD usermod -a -G docker iank
+
+# based on unison error, with 8192 from
+# sysctl -a | grep fs.inotify.max_user_watches
+#http://stackoverflow.com/questions/535768/what-is-a-reasonable-amount-of-inotify-watches-with-linux
+f=$target/etc/sysctl.d/99-sysctl.conf
+key=fs.inotify.max_user_watches
+if [[ -e $f ]]; then sed -ri --follow-symlinks "/^\s*$key\s*=/d" $f; fi
+echo "fs.inotify.max_user_watches = 50000" >> $f
+# applies it. it would be also be applied after a reboot
+$ROOTCMD sysctl --system
+
+if getent group sudo >/dev/null; then
+ $ROOTCMD usermod -aG sudo iank
+fi
+
+mkdir -p $target/etc/sudoers.d
+cat >$target/etc/sudoers.d/ianksudoers <<'EOF'
+Defaults timestamp_timeout=1440
+# used in bashrc
+Defaults env_keep += SUDOD
+# always_set_home
+# makes ubuntu be like debian
+# https://unix.stackexchange.com/a/91572
+Defaults always_set_home
+# umask: default setting is to have minimum umask of 0022
+# This lets us have user-specific umasks which are more permissive.
+# I did this for transmission and set it's umask gecos on install,
+# see there for more info.
+Defaults !umask
+# i use sudo in cronjobs, it spams the logs rather uselessly
+# https://stackoverflow.com/questions/14277116/suppress-log-entry-for-single-sudo-commands
+Defaults:root,iank !log_allowed, !pam_session
+# for just the root user, set some env vars
+Defaults>root env_file=/etc/rootsudoenv
+
+# a few commands we should be able to run with no password
+iank ALL = (root) NOPASSWD: /usr/local/bin/spend,/usr/local/bin/us,/usr/local/bin/off,/usr/bin/nmtui-connect,/usr/local/bin/bitcoinoff,/usr/local/bin/bitcoinon
+
+EOF
+
+case $HOSTNAME in
+ li|bk|je)
+ cat >>$target/etc/sudoers.d/ianksudoers <<'EOF'
+iank ALL=(ALL) NOPASSWD: ALL
+EOF
+ ;;
+esac
+
+# remove old config line. can be removed eventually.
+f=$target/etc/sudoers
+line='iank ALL=(ALL) NOPASSWD: ALL'
+if grep -qxF "$line" $f; then
+ sed -i "/^$line/d" $f
+fi
+
+
+au --system -s /bin/false --home-dir /var/lib/bitcoind bitcoin
--- /dev/null
+#!/bin/bash
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+set -x
+
+prereqs=()
+for p in wget curl; do
+ if ! type -p $p &>/dev/null; then
+ prereqs+=($p)
+ fi
+done
+if (( ${#prereqs[@]} >= 1 )); then
+ apt-get -y install ${prereqs[@]}
+fi
+
+
+tmpdir=$($ROOTCMD mktemp -d) || exit
+outertmp=$target/$tmpdir
+trap 'cd; rm -rf "$outertmp"' EXIT
+cd $outertmp
+
+# update stable_ver when we are ready to jump to a new stable kernel.
+# Stable kernels are listed here: https://www.kernel.org/category/releases.html
+stable_ver='6\.6'
+# Actually, I dont want stable right now. comment this out to get stable
+# version.
+stable_ver='[1-9]'
+va=$(curl -s https://kernel.ubuntu.com/mainline/ | \
+ sed -rn 's,.*alt="\[DIR\]".*href="([^/]+).*,\1,p' | \
+ grep -v -- -rc | sed 's/^v//' | grep "^$stable_ver" | sort -V | tail -n1)
+
+# note the wiki page about these says to install linux-headers.*generic.*amd64, but
+# as of 2024, they have a requirement of a very new glibc, and people report
+# that installing it is not needed.
+tmpstr=$(curl -s https://kernel.ubuntu.com/mainline/v$va/amd64/CHECKSUMS | awk '$2 ~ /^linux-/ { print $2 }' | sort -u | grep -iv 'linux-headers.*generic.*amd64' )
+mapfile -t pkgs <<<"$tmpstr"
+
+if (( ${#pkgs[@]} != 3 )); then
+ echo "$0: error. expected to find 3 kernel packages, got: ${pkgs[*]}" >&2
+ exit 1
+fi
+
+urls=()
+for p in ${pkgs[@]}; do
+ if ! $ROOTCMD dpkg -s -- "${p%%_*}" 2>&1 | grep -Fx "Status: install ok installed" &>/dev/null; then
+ urls+=(https://kernel.ubuntu.com/mainline/v$va/amd64/$p)
+ fi
+done
+if (( ${#urls[@]} >= 1 )); then
+ wget -nv "${urls[@]}"
+ $ROOTCMD dpkg -i ${pkgs[@]/#/$tmpdir/}
+fi
--- /dev/null
+#!/bin/sh
+# shebang is for editor file mode detection only
+
+function save_vars {
+ if [ -s $envfile ]; then
+ for var in $@; do
+ save_env --file $envfile $var
+ done
+ fi
+}
+
+function save_chosen {
+ save_vars did_fai_check last_boot
+}
+
+# fai_check is so we can act like a pxe boot, but just for fai, and by
+# using /bookworm_bootstrap to do it. We toggle on and off the grub var
+# did_fai_check so we can do the check every other boot. Then
+# /debian_bootstrap checks for that var on boot and if we want to do a
+# fai check, it does it, then reboots. But fai-check also sets
+# did_fai_check to a 3rd state os_true which means we did the fai check,
+# and we don't want to do it again. This is useful for systems without
+# libreboot.
+
+# We don't set this to fai check so we can't get into
+# an infinite reboot cycle. We depend on the os to
+# create the initial grubenv file.
+set default=/debianbookworm_bootstrap # could use 0 here.
+set timeout=1
+
+# grub_extn
+for part in (ahci*4) (ata*4); do
+ envfile=$part/grubenv
+ if [ -s $envfile ]; then
+ load_env --file $envfile
+ if [ x$did_fai_check == xfalse -a x$last_boot != x$default ]; then
+ set default=fai-check
+ elif [ ! -z $last_boot ]; then
+ set default=$last_boot
+ fi
+ break
+ fi
+done
+
+did_fai_check=false
+
+bs_dir=/debianbookworm_bootstrap
+menuentry $bs_dir --id=$bs_dir {
+ # note, we might be able to use $chosen and avoid setting this here,
+ # and set it inside save_chosen. but I haven't tested it,
+ # it's just one less line of repitition.
+ last_boot=$1
+ save_chosen
+ configfile $bs_dir/boot/grub/grub.cfg
+}
+
+for dir in /boot_*; do
+ if [ $dir == '/boot_*' ]; then
+ break
+ fi
+ menuentry $dir --id=$dir {
+ last_boot=$1
+ save_chosen
+ configfile $1/grub/grub.cfg
+ }
+done
+
+menuentry fai-check --id=fai-check {
+ did_fai_check=true
+ save_vars did_fai_check
+ configfile $bs_dir/boot/grub/grub.cfg
+}
--- /dev/null
+#!/bin/bash
+# Bash Error Handler
+# Copyright (C) 2020 Ian Kelling <ian@iankelling.org>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+# This is a single file library, just source this file. When an error
+# happens, we print a stack trace then exit. In an interactive shell, we
+# return from functions instead of exiting. If err-cleanup is a command,
+# it runs before the stack trace. Functions are documented inline below
+# for additional use cases.
+#
+# Note: occasionally the line numbers are off a bit (at least in Bash
+# 5.0). This appears to be a bash bug. I plan to report it next time it
+# happens to me.
+#
+# Please email me if you use this or have anything to contribute. I'm
+# not aware of any users yet Ian Kelling <ian@iankelling.org>.
+#
+# Tested on bash 4.4.20(1)-release (x86_64-pc-linux-gnu) and
+# 5.0.17(1)-release (x86_64-pc-linux-gnu).
+#
+# Related: see my bash script template repo at https://iankelling.org/git.
+
+
+# TODO: investigate to see if we can format output betting in case of
+# subshell failure. Right now, we get independent trace from inside and
+# outside of the subshell. Note, errexit + inherit_errexit doesn't have
+# any smarts around this either.
+
+if ! test "$BASH_VERSION"; then echo "error: shell is not bash" >&2; exit 1; fi
+
+#######################################
+# err-catch: Setup trap on ERR to print stack trace and exit (or return
+# if the shell is interactive). This is the most common use case so we
+# run it after defining it, you can call err-allow to undo that.
+#
+# This also sets pipefail because it's a good practice to catch more
+# errors.
+#
+# Note: In interactive shell, stack calling line number is not
+# available, so we print function definition lines.
+#
+# Note: This works like set -e, which has one unintuitive feature: If
+# you use a function as part of a conditional, eg: func && come_cmd, a
+# failed command within func won't trigger an error.
+#
+# Globals
+#
+# err_catch_ignore Array containing glob patterns to test against
+# filenames to ignore errors from in interactive
+# shell. Initialized to ignore bash-completion
+# scripts on debian based systems.
+#
+# err-cleanup If set, this command will run just before exiting.
+#
+# _err_func_last Used internally in err-bash-trace-interactive
+#
+#######################################
+err-catch() {
+ set -E;
+ if [[ $- == *i* ]]; then
+ if ! test ${err_catch_ignore+defined}; then
+ err_catch_ignore=(
+ '/etc/bash_completion.d/*'
+ '*/bash-completion/*'
+ )
+ fi
+ declare -i _err_func_last=0
+ if [[ $- != *c* ]]; then
+ shopt -s extdebug
+ fi
+ # shellcheck disable=SC2154
+ trap '_err-bash-trace-interactive $? "${PIPESTATUS[*]}" "$BASH_COMMAND" ${BASH_ARGC[0]} "${BASH_ARGV[@]}" || return $?' ERR
+ else
+ # Man bash on exdebug: "If set at shell invocation, arrange to
+ # execute the debugger". We want to avoid that, but I want this file
+ # to be sourceable from bash startup files. noninteractive ssh and
+ # sources .bashrc on invocation. login_shell sources things on
+ # invocation.
+ #
+ # extdebug allows us to print function arguments in our stack trace.
+ if ! shopt login_shell >/dev/null && [[ ! $SSH_CONNECTION ]]; then
+ shopt -s extdebug
+ fi
+ trap err-exit ERR
+ fi
+ set -o pipefail
+}
+# This is the most common use case so run it now.
+err-catch
+
+#######################################
+# Undo err-catch/err-catch-interactive
+#######################################
+err-allow() {
+ shopt -u extdebug
+ set +E +o pipefail
+ trap ERR
+}
+
+#######################################
+# err-exit: Print stack trace and exit
+#
+# Use this instead of the exit command to be more informative.
+#
+# usage: err-exit [-EXIT_CODE] [MESSAGE]
+#
+# EXIT_CODE Default: $? if it is nonzero, otherwise 1.
+# MESSAGE Print MESSAGE to stderr. Default:
+# ${BASH_SOURCE[1]}:${BASH_LINENO[0]}: `$BASH_COMMAND' returned $?
+#
+# Globals
+#
+# err-cleanup If set, this command will run just before exiting.
+#
+#######################################
+err-exit() {
+ # vars have _ prefix so that we can inspect existing set vars without
+ # too much overwriting of them.
+ local _err=$? _pipestatus="${_pipestatus[*]}"
+
+ # This has to come before most things or vars get changed
+ local _msg="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $_err"
+ local _cmdr="$BASH_COMMAND" # command right. we chop of the left, keep the right.
+
+ if [[ $_pipestatus != "$_err" ]]; then
+ _msg+=", PIPESTATUS: $_pipestatus"
+ fi
+ set +x
+ if [[ $1 == -* ]]; then
+ _err=${1#-}
+ shift
+ elif (( ! _err )); then
+ _err=1
+ fi
+ if [[ $1 ]]; then
+ _msg="$1"
+ fi
+
+ ## Begin printing vars from within BASH_COMMAND ##
+ local _var _chars _l
+ local -A _vars
+ while [[ $_cmdr ]]; do
+ _chars="${#_cmdr}"
+ _cmdr="${_cmdr#*$}"
+ _cmdr="${_cmdr#{}"
+ if (( _chars == ${#_cmdr} )); then
+ break
+ fi
+ _var="${_cmdr%%[^a-zA-Z0-9_]*}"
+ if [[ ! $_var || $_var == [0-9]* ]]; then
+ continue
+ fi
+ _vars[${_var}]=t
+ done
+ #echo "iank ${_vars[*]}"
+ #set |& grep ^password
+ # in my small test, this took 50% longer than piping to grep.
+ # That seems a small enough penalty to stay in bash here.
+ if (( ${#_vars[@]} )); then
+ set |& while read -r _l; do
+ for _var in "${!_vars[@]}"; do
+ case $_l in
+ ${_var}=*) printf "%s\n" "$_l" >&2 ;;
+ esac
+ done
+ done
+ fi
+ ## End printing vars from within BASH_COMMAND ##
+
+ printf "%s\n" "$_msg" >&2
+ err-bash-trace 2
+ set -e # err trap does not work within an error trap
+ if type -t err-cleanup >/dev/null; then
+ err-cleanup
+ fi
+ printf "%s: exiting with status %s\n" "$0" "$_err" >&2
+ exit $_err
+}
+
+#######################################
+# Print stack trace
+#
+# usage: err-bash-trace [FRAME_START]
+#
+# This function is called by the other functions which print stack
+# traces.
+#
+# It does not show function args unless you first run:
+# shopt -s extdebug
+# which err-catch does for you.
+#
+# FRAME_START Optional variable to set before calling. The frame to
+# start printing on. default=1. If ${#FUNCNAME[@]} <=
+# FRAME_START + 1, don't print anything because we are at
+# the top level of the script and better off printing a
+# general message, for example see what our callers print.
+#
+#######################################
+err-bash-trace() {
+ local -i argc_index=0 frame i frame_start=${1:-1}
+ local source_loc
+ if (( ${#FUNCNAME[@]} <= frame_start + 1 )); then
+ return 0
+ fi
+ for ((frame=0; frame < ${#FUNCNAME[@]}; frame++)); do
+ argc=${BASH_ARGC[frame]}
+ argc_index+=$argc
+ if ((frame < frame_start)); then continue; fi
+ if (( ${#BASH_SOURCE[@]} > 1 )); then
+ source_loc="${BASH_SOURCE[frame]}:${BASH_LINENO[frame-1]}:"
+ fi
+ printf " from %sin \`%s" "$source_loc" "${FUNCNAME[frame]}" >&2
+ if shopt extdebug >/dev/null; then
+ for ((i=argc_index-1; i >= argc_index-argc; i--)); do
+ printf " %s" "${BASH_ARGV[i]}" >&2
+ done
+ fi
+ echo \' >&2
+ done
+ return 0
+}
+
+#######################################
+# Internal function for err-catch. Prints stack trace from interactive
+# shell trap.
+#
+# Usage: see err-catch-interactive
+#######################################
+_err-bash-trace-interactive() {
+ if (( ${#FUNCNAME[@]} <= 1 )); then
+ return 0
+ fi
+
+ for pattern in "${err_catch_ignore[@]}"; do
+ # shellcheck disable=SC2053
+ if [[ ${BASH_SOURCE[1]} == $pattern ]]; then
+ return 0
+ fi
+ done
+
+ local ret bash_command argc pattern i last
+ last=$_err_func_last
+ _err_func_last=${#FUNCNAME[@]}
+ # We have these passed to us because they are lost inside the
+ # function.
+ ret=$1
+ pipestatus="$2"
+ bash_command="$3"
+ argc=$(( $4 - 1 ))
+ shift 4
+ argv=("$@")
+ # The trap returns a nonzero, then gets called again. This condition
+ # tells us if is that has happened by checking if we've gone down a
+ # stack level.
+ if (( _err_func_last >= last )); then
+ printf "ERR: \`%s\' returned %s" "$bash_command" $ret >&2
+ if [[ $pipestatus != "$ret" ]]; then
+ printf ", PIPESTATUS: %s" "$pipestatus" >&2
+ fi
+ echo >&2
+ fi
+ printf " from \`%s" "${FUNCNAME[1]}" >&2
+ if shopt extdebug >/dev/null; then
+ for ((i=argc; i >= 0; i--)); do
+ printf " %s" "${argv[i]}" >&2
+ done
+ fi
+ printf "\' defined at %s:%s\n" "${BASH_SOURCE[1]}" "$(declare -F "${FUNCNAME[1]}"|awk "{print \$2}")" >&2
+ if [[ -t 1 ]]; then
+ return $ret
+ else
+ # Part of an outgoing pipe, avoid getting get us stuck in a weird
+ # subshell if we returned nonzero, which would happen in a situation
+ # like this:
+ #
+ # tf() { while read -r line; do :; done < <(asdf); };
+ # tf
+ #
+ # Note: exit $ret also avoids the stuck subshell problem, and I
+ # can't notice any difference, but this seems more proper.
+ return 0
+ fi
+}
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+[[ $EUID == 0 ]] || exec sudo "$BASH_SOURCE" "$@"
+
+
+x="$(readlink -f "$BASH_SOURCE")"
+f="${x%/*}/bash-trace"
+if [[ -e $f ]]; then
+ source $f
+else
+ source ${x%/*}/../bash-trace/DEFAULT
+fi
+
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [OPTIONS] DISTRO_NAME
+Set grub to boot into a different distro, and reboot unless -r
+
+With no argument, print available distros
+DISTRO_NAME is based on the partition names in /boot.
+For example, boot_debianjessie.
+
+For a system without libreboot, which is failing completely to
+boot on one distro, here is how I did a chboot for it:
+# arch-pxe had been run previously
+pxe-server some_hostname arch
+# reboot some_hostname into arch live env
+pxe-server # disable pxe server
+ssh root@some_hostname
+lsblk # identify boot dev. if boot dev is a raid, this could be repeated on all boot devs.
+mount /dev/sdd3 /mnt
+mp=/mnt/boot_debiantesting # the subvol i want to chboot to
+boot_disk=/dev/sdd
+grub-bios-setup -d $mp/grub/i386-pc -s -m $mp/grub/device.map $boot_disk
+reboot
+
+todo: figure out if it's possible to make a multi-distro grub like I have with libreboot
+for non-libreboot systems
+
+-r Do not reboot.
+-d Enable debug output.
+-h|--help Print help and exit.
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+
+
+###### begin command line parsing #####
+reboot=true
+temp=$(getopt -l help hdr "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ -d) set -x; shift ;;
+ -r) reboot=false; shift ;;
+ -h|--help) usage ;;
+ --) shift; break ;;
+ *) echo "$0: Internal error!" ; exit 1 ;;
+ esac
+done
+
+
+distro=$1
+
+mnt=/boot
+if ! mountpoint $mnt &>/dev/null; then
+ mnt=/
+fi
+
+if [[ ! $distro ]]; then
+ echo "available distros:"
+ cur=$(btrfs subvol show $mnt| sed -rn 's/^.*Name:\s*(\S*).*/\1/p')
+ btrfs subvolume list $mnt | awk '{print $9}' | sed "s/$cur/$cur (current)/"
+ exit 0
+fi
+
+###### end command line parsing #####
+
+
+#### begin initial error checking #####
+
+if ! btrfs subvolume list $mnt | grep "$distro$" &>/dev/null; then
+ echo "$0: error: $distro not found in btrfs subvolume list $mnt:"
+ btrfs subvolume list $mnt
+ exit 1
+fi
+
+#### end initial error checking #####
+
+e() { echo "$@"; "$@"; }
+
+for boot_dev in $(btrfs fil show $mnt | sed -nr 's#.*path\s+(\S+)$#\1#p'); do
+
+ mount_point=$(mktemp -d)
+
+ e mount -o subvol=$distro $boot_dev $mount_point
+
+ boot_disk=${boot_dev%%[0-9]*}
+
+ # arch doesn't have $mount_point/grub/device.map, accoring to the grub manual,
+ # it just generates one if the file doesn't exist.
+ # https://www.gnu.org/software/grub/manual/html_node/Device-map.html
+ e grub-bios-setup -d $mount_point/grub/i386-pc -s -m $mount_point/grub/device.map $boot_disk
+ e umount $mount_point
+done
+
+if [[ $(blockdev --getsize64 ${boot_disk}4) == 8388608 ]]; then
+ # old partition scheme
+ grub_dev=${boot_disk}4
+elif [[ $(blockdev --getsize64 ${boot_disk}5) == 8388608 ]]; then
+ grub_dev=${boot_disk}5
+else
+ grub_dev=${boot_disk}7
+fi
+
+e mount $grub_dev $mount_point
+e grub-editenv $mount_point/grubenv set last_boot=/$distro
+e grub-editenv $mount_point/grubenv set did_fai_check=true
+e umount $mount_point
+if $reboot; then
+ touch /tmp/keyscript-off
+ reboot now
+fi
--- /dev/null
+Package: *
+Pin: release n=jammy,o=Ubuntu
+Pin-Priority: -100
--- /dev/null
+Package: *
+Pin: release a=belenos-backports
+Pin-Priority: 500
--- /dev/null
+Package: *
+Pin: release n=bionic,o=Ubuntu
+Pin-Priority: -100
--- /dev/null
+Package: *
+Pin: release a=flidas
+Pin-Priority: -100
+
+Package: *
+Pin: release a=flidas-updates
+Pin-Priority: -100
+
+Package: *
+Pin: release a=flidas-security
+Pin-Priority: -100
--- /dev/null
+Package: *
+Pin: release n=focal,o=Ubuntu
+Pin-Priority: -100
--- /dev/null
+Package: *
+Pin: release a=etiona-backports
+Pin-Priority: 500
--- /dev/null
+Package: *
+Pin: release a=flidas-backports
+Pin-Priority: 500
--- /dev/null
+Package: linux-image-generic linux-firmware intel-microcode amd64-microcode
+Pin: release n=jammy,o=Ubuntu
+Pin-Priority: 1001
--- /dev/null
+Package: *
+Pin: release n=focal,o=Ubuntu
+Pin-Priority: -100
--- /dev/null
+Package: *
+Pin: release n=jammy,o=Ubuntu
+Pin-Priority: -100
--- /dev/null
+Explanation: tar, cuz https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=819978
+Explanation: kernel & btrfs-progs, because btrfs is getting a lot of active
+Explanation: dev, and their mailing list says better to use recent version
+Explanation: to avoid bugs. linux-base is needed for the kernel,
+Explanation: which you can find out by failing
+Explanation: apt-get install linux-image-amd64/stretch-backports
+Explanation: And then trying aptitude -s install, or
+Explanation: apt-get -t stretch-backports install linux-image-amd64
+Explanation:
+Explanation:
+Package: tar linux-image-amd64 linux-base btrfs-progs
+Pin: release a=stretch-backports
+Pin-Priority: 500
+
+Package: *
+Pin: release a=buster
+Pin-Priority: -10
+
+Package: *
+Pin: release a=buster-updates
+Pin-Priority: -10
--- /dev/null
+Explanation: https://debian-handbook.info/browse/stable/sect.apt-get.html#sect.apt.priorities
+Explanation: And man apt_preferences
+Explanation: Installed packages get 100 priority, so this won't upgrade testing
+Explanation: packages unless explicitly asked to.
+Explanation: Less than 0 won't install package unless you specify the archive.
+Explanation: This is good, so you never just search for a package and install
+Explanation: it without knowing it's from a different archive.
+Explanation: Install with apt-get install package/testing. But if dependencies are
+Explanation: needed, or need upgrading,
+Explanation: apt-get -t testing package, setting testing to priority
+Explanation: 990 just for that command.
+Explanation: Use apt-cache policy to verify these settings.
+Package: *
+Pin: release a=unstable
+Pin-Priority: -20
+
+Package: *
+Pin: release a=unstable-updates
+Pin-Priority: -20
+
+Package: *
+Pin: release a=experimental
+Pin-Priority: -40
--- /dev/null
+deb http://archive.trisquel.org/trisquel/ aramo main
+deb-src http://archive.trisquel.org/trisquel/ aramo main
+
+deb http://archive.trisquel.org/trisquel/ aramo-updates main
+deb-src http://archive.trisquel.org/trisquel/ aramo-updates main
+
+deb http://archive.trisquel.info/trisquel/ aramo-security main
+deb-src http://archive.trisquel.info/trisquel/ aramo-security main
+
+deb http://archive.trisquel.org/trisquel/ aramo-backports main
+deb-src http://archive.trisquel.org/trisquel/ aramo-backports main
--- /dev/null
+deb http://mirror.fsf.org/trisquel/ etiona main
+deb-src http://mirror.fsf.org/trisquel/ etiona main
+
+deb http://mirror.fsf.org/trisquel/ etiona-updates main
+deb-src http://mirror.fsf.org/trisquel/ etiona-updates main
+
+deb http://archive.trisquel.info/trisquel/ etiona-security main
+deb-src http://archive.trisquel.info/trisquel/ etiona-security main
+
+# Uncomment this lines to enable the backports optional repository
+deb http://mirror.fsf.org/trisquel/ etiona-backports main
+deb-src http://mirror.fsf.org/trisquel/ etiona-backports main
--- /dev/null
+deb http://archive.trisquel.org/trisquel/ nabia main
+deb-src http://archive.trisquel.org/trisquel/ nabia main
+
+deb http://archive.trisquel.org/trisquel/ nabia-updates main
+deb-src http://archive.trisquel.org/trisquel/ nabia-updates main
+
+deb http://archive.trisquel.info/trisquel/ nabia-security main
+deb-src http://archive.trisquel.info/trisquel/ nabia-security main
+
+deb http://archive.trisquel.org/trisquel/ nabia-backports main
+deb-src http://archive.trisquel.org/trisquel/ nabia-backports main
--- /dev/null
+deb http://mirror.fsf.org/trisquel/ belenos main
+deb-src http://mirror.fsf.org/trisquel/ belenos main
+
+deb http://mirror.fsf.org/trisquel/ belenos-updates main
+deb-src http://mirror.fsf.org/trisquel/ belenos-updates main
+
+deb http://mirror.fsf.org/trisquel/ belenos-security main
+deb-src http://mirror.fsf.org/trisquel/ belenos-security main
+
+# Uncomment this lines to enable the backports optional repository
+deb http://mirror.fsf.org/trisquel/ belenos-backports main
+deb-src http://mirror.fsf.org/trisquel/ belenos-backports main
--- /dev/null
+deb http://us.archive.ubuntu.com/ubuntu/ bionic main universe multiverse
+deb http://us.archive.ubuntu.com/ubuntu/ bionic-updates main universe multiverse
+deb http://us.archive.ubuntu.com/ubuntu/ bionic-security main universe multiverse
+deb-src http://us.archive.ubuntu.com/ubuntu/ bionic main universe multiverse
+deb-src http://us.archive.ubuntu.com/ubuntu/ bionic-updates main universe multiverse
+deb-src http://us.archive.ubuntu.com/ubuntu/ bionic-security main universe multiverse
--- /dev/null
+deb http://deb.debian.org/debian bookworm main
+deb-src http://deb.debian.org/debian bookworm main
+
+deb http://security.debian.org/ bookworm-security main
+deb-src http://security.debian.org/ bookworm-security main
+
+deb http://deb.debian.org/debian bookworm-updates main
+deb-src http://deb.debian.org/debian bookworm-updates main
+
+deb http://http.debian.net/debian bookworm-backports main
+deb-src http://http.debian.net/debian bookworm-backports main
--- /dev/null
+deb http://http.us.debian.org/debian bookworm main contrib non-free
+deb-src http://http.us.debian.org/debian bookworm main contrib non-free
+
+deb http://security.debian.org/ bookworm-security main contrib non-free
+deb-src http://security.debian.org/ bookworm-security main contrib non-free
+
+deb http://http.us.debian.org/debian bookworm-updates main contrib non-free
+deb-src http://http.us.debian.org/debian bookworm-updates main contrib non-free
+
+deb http://http.debian.net/debian bookworm-backports main contrib non-free
+deb-src http://http.debian.net/debian bookworm-backports main contrib non-free
+
+deb http://http.us.debian.org/debian unstable main contrib non-free
+deb-src http://http.us.debian.org/debian unstable main contrib non-free
+
+deb http://http.us.debian.org/debian experimental main
+deb-src http://http.us.debian.org/debian experimental main
--- /dev/null
+deb http://deb.debian.org/debian bullseye main
+deb-src http://deb.debian.org/debian bullseye main
+
+deb http://security.debian.org/ bullseye-security main
+deb-src http://security.debian.org/ bullseye-security main
+
+deb http://deb.debian.org/debian bullseye-updates main
+deb-src http://deb.debian.org/debian bullseye-updates main
+
+deb http://http.debian.net/debian bullseye-backports main
+deb-src http://http.debian.net/debian bullseye-backports main
--- /dev/null
+deb http://http.us.debian.org/debian bullseye main contrib non-free
+deb-src http://http.us.debian.org/debian bullseye main contrib non-free
+
+deb http://security.debian.org/ bullseye-security main contrib non-free
+deb-src http://security.debian.org/ bullseye-security main contrib non-free
+
+deb http://http.us.debian.org/debian bullseye-updates main contrib non-free
+deb-src http://http.us.debian.org/debian bullseye-updates main contrib non-free
+
+deb http://http.debian.net/debian bullseye-backports main contrib non-free
+deb-src http://http.debian.net/debian bullseye-backports main contrib non-free
+
+deb http://http.us.debian.org/debian unstable main contrib non-free
+deb-src http://http.us.debian.org/debian unstable main contrib non-free
+
+deb http://http.us.debian.org/debian experimental main
+deb-src http://http.us.debian.org/debian experimental main
--- /dev/null
+deb http://http.us.debian.org/debian buster main
+deb-src http://http.us.debian.org/debian buster main
+
+deb http://security.debian.org/ buster/updates main
+deb-src http://security.debian.org/ buster/updates main
+
+deb http://http.us.debian.org/debian buster-updates main
+deb-src http://http.us.debian.org/debian buster-updates main
+
+deb http://http.debian.net/debian buster-backports main
+deb-src http://http.debian.net/debian buster-backports main
--- /dev/null
+deb http://http.us.debian.org/debian buster main contrib non-free
+deb-src http://http.us.debian.org/debian buster main contrib non-free
+
+deb http://security.debian.org/ buster/updates main contrib non-free
+deb-src http://security.debian.org/ buster/updates main contrib non-free
+
+deb http://http.us.debian.org/debian buster-updates main contrib non-free
+deb-src http://http.us.debian.org/debian buster-updates main contrib non-free
+
+deb http://http.debian.net/debian buster-backports main contrib non-free
+deb-src http://http.debian.net/debian buster-backports main contrib non-free
+
+deb http://http.us.debian.org/debian unstable main contrib non-free
+deb-src http://http.us.debian.org/debian unstable main contrib non-free
+
+deb http://http.us.debian.org/debian experimental main
+deb-src http://http.us.debian.org/debian experimental main
--- /dev/null
+deb http://mirror.fsf.org/trisquel/ flidas main
+deb-src http://mirror.fsf.org/trisquel/ flidas main
+
+deb http://mirror.fsf.org/trisquel/ flidas-updates main
+deb-src http://mirror.fsf.org/trisquel/ flidas-updates main
+
+deb http://mirror.fsf.org/trisquel/ flidas-security main
+deb-src http://mirror.fsf.org/trisquel/ flidas-security main
+
+# Uncomment this lines to enable the backports optional repository
+deb http://mirror.fsf.org/trisquel/ flidas-backports main
+deb-src http://mirror.fsf.org/trisquel/ flidas-backports main
--- /dev/null
+FOCAL
\ No newline at end of file
--- /dev/null
+# multiverse needed for libfdk-aac1, which is actually free
+# https://www.gnu.org/licenses/license-list.html#fdk
+
+###### Ubuntu Main Repos
+deb http://archive.ubuntu.com/ubuntu/ focal main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ focal main universe multiverse
+
+###### Ubuntu Update Repos
+deb http://archive.ubuntu.com/ubuntu/ focal-security main universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-updates main universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-backports main universe
+deb-src http://archive.ubuntu.com/ubuntu/ focal-security main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ focal-updates main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ focal-backports main universe
--- /dev/null
+FOCAL
\ No newline at end of file
--- /dev/null
+# multiverse needed for libfdk-aac1, which is actually free
+# https://www.gnu.org/licenses/license-list.html#fdk
+
+###### Ubuntu Main Repos
+deb http://archive.ubuntu.com/ubuntu/ impish main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ impish main universe multiverse
+
+###### Ubuntu Update Repos
+deb http://archive.ubuntu.com/ubuntu/ impish-security main universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ impish-updates main universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ impish-backports main universe
+deb-src http://archive.ubuntu.com/ubuntu/ impish-security main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ impish-updates main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ impish-backports main universe
--- /dev/null
+JAMMY
\ No newline at end of file
--- /dev/null
+# multiverse needed for libfdk-aac1, which is actually free
+# https://www.gnu.org/licenses/license-list.html#fdk
+
+###### Ubuntu Main Repos
+deb http://archive.ubuntu.com/ubuntu/ jammy main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ jammy main universe multiverse
+
+###### Ubuntu Update Repos
+deb http://archive.ubuntu.com/ubuntu/ jammy-security main universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ jammy-updates main universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ jammy-backports main universe
+deb-src http://archive.ubuntu.com/ubuntu/ jammy-security main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ jammy-updates main universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ jammy-backports main universe
--- /dev/null
+JAMMY
\ No newline at end of file
--- /dev/null
+deb http://http.us.debian.org/debian stretch main
+deb-src http://http.us.debian.org/debian stretch main
+
+deb http://security.debian.org/ stretch/updates main
+deb-src http://security.debian.org/ stretch/updates main
+
+deb http://http.us.debian.org/debian stretch-updates main
+deb-src http://http.us.debian.org/debian stretch-updates main
+
+deb http://http.debian.net/debian stretch-backports main
+deb-src http://http.debian.net/debian stretch-backports main
--- /dev/null
+deb http://http.us.debian.org/debian stretch main contrib non-free
+deb-src http://http.us.debian.org/debian stretch main contrib non-free
+
+deb http://security.debian.org/ stretch/updates main contrib non-free
+deb-src http://security.debian.org/ stretch/updates main contrib non-free
+
+deb http://http.us.debian.org/debian stretch-updates main contrib non-free
+deb-src http://http.us.debian.org/debian stretch-updates main contrib non-free
+
+deb http://http.debian.net/debian stretch-backports main contrib non-free
+deb-src http://http.debian.net/debian stretch-backports main contrib non-free
--- /dev/null
+deb http://deb.debian.org/debian testing main
+deb-src http://deb.debian.org/debian testing main
+
+deb http://deb.debian.org/debian-security/ testing-security main
+deb-src http://deb.debian.org/debian-security/ testing-security main
+
+deb http://deb.debian.org/debian testing-updates main
+deb-src http://deb.debian.org/debian testing-updates main
+
+deb http://http.us.debian.org/debian unstable main
+deb-src http://http.us.debian.org/debian unstable main
--- /dev/null
+deb http://http.us.debian.org/debian testing main contrib non-free
+deb-src http://http.us.debian.org/debian testing main contrib non-free
+
+deb http://security.debian.org/ testing-security main contrib non-free
+deb-src http://security.debian.org/ testing-security main contrib non-free
+
+deb http://http.us.debian.org/debian testing-updates main contrib non-free
+deb-src http://http.us.debian.org/debian testing-updates main contrib non-free
+
+deb http://http.us.debian.org/debian unstable main contrib non-free
+deb-src http://http.us.debian.org/debian unstable main contrib non-free
--- /dev/null
+###### Ubuntu Main Repos
+deb http://us.archive.ubuntu.com/ubuntu/ xenial main universe
+deb-src http://us.archive.ubuntu.com/ubuntu/ xenial main universe
+
+###### Ubuntu Update Repos
+deb http://us.archive.ubuntu.com/ubuntu/ xenial-security main universe
+deb http://us.archive.ubuntu.com/ubuntu/ xenial-updates main universe
+deb http://us.archive.ubuntu.com/ubuntu/ xenial-backports main universe
+deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-security main universe
+deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-updates main universe
+deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-backports main universe
--- /dev/null
+deb {%apt_cdn%}/debian {%release%} main contrib non-free non-free-firmware
+deb {%security_cdn%}/debian-security {%secsuite%} main contrib non-free non-free-firmware
+deb {%apt_cdn%}/debian {%release%}-updates main contrib non-free non-free-firmware
--- /dev/null
+# intentionaly left empty. only using sources.list.d
+++ /dev/null
-deb {%apt_cdn%}/debian {%release%} main
-deb {%security_cdn%}/debian-security {%secsuite%} main
-deb {%apt_cdn%}/debian {%release%}-updates main
+++ /dev/null
-
-
-Plan your installation, and FAI installs your plan.
--- /dev/null
+CLOUD
\ No newline at end of file
--- /dev/null
+# This file controls the state of SELinux on the system.
+# SELINUX= can take one of these three values:
+# enforcing - SELinux security policy is enforced.
+# permissive - SELinux prints warnings instead of enforcing.
+# disabled - No SELinux policy is loaded.
+SELINUX=disabled
+# SELINUXTYPE= can take one of these two values:
+# targeted - Only targeted network daemons are protected.
+# strict - Full SELinux protection.
+# mls - Multi Level Security protection.
+SELINUXTYPE=targeted
+# SETLOCALDEFS= Check local definition changes
--- /dev/null
+# See logind.conf(5) for details.
+[Login]
+HandleLidSwitch=ignore
+# seemed like a good idea when i was using psd
+# https://wiki.archlinux.org/index.php/profile-sync-daemon#I_need_more_memory_to_accommodate_my_profile/profiles_in_/run/user/xxxx._How_can_I_allocate_more?
+#RuntimeDirectorySize=50%
--- /dev/null
+VOL_BULLSEYE_BOOTSTRAP
\ No newline at end of file
--- /dev/null
+[Unit]
+Description=check whether to kexec to fai, reboot, or do nothing
+After=syslog.target network-online.target
+
+[Service]
+Type=oneshot
+ExecStart=/root/fai-check
+TimeoutStartSec=60
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+# empty directory
+*
+!.gitignore
--- /dev/null
+#!/bin/bash
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+#set -x
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [OPTION] [HOST]
+If grub var set, act like pxe rom and pxe-kexec to faiserver
+
+-f|--force do kexec if we can reach faiserver
+-h|--help Print help and exit.
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+
+
+# Keep it short so we don't delay too much wnen we don't have networking.
+# In practice, on my home network, on an x200, it took 15 seconds, so
+# give it an extra 10 seconds, which seems fairly short as I write this.
+NETWORK_TIMOUT_SECS=25
+did_fai_check=false
+
+m() { printf "%s\n" "$*"; "$@"; }
+
+try-kexec() {
+ deadline=$(( `date +%s` + NETWORK_TIMOUT_SECS ))
+ while ! timeout -s 9 3 nc -zu $faiserver 69; do
+ if (( `date +%s` > deadline )); then
+ echo "fai-check: hit $NETWORK_TIMOUT_SECS s tftp server timeout"
+ return 0
+ fi
+ sleep 1
+ done
+ m pxe-kexec -n --ignore-whitelist -l fai-generated $faiserver ||:
+}
+
+force=false
+case $1 in
+ -h|--help)
+ usage
+ ;;
+ -f|--force)
+ force=true
+ shift
+ ;;
+esac
+
+faiserver=${1:-faiserver.b8.nz}
+
+
+if $force; then
+ try-kexec
+ exit
+fi
+
+# on one machine, I could do this:
+# dmidecode -t system | grep -F "Version: ThinkPad X200"
+# however, on another, the version field just says invalid data.
+# todo: figure out some better way to check if we are on
+# an x200.
+
+if ! dmidecode | grep -i thinkpad &>/dev/null; then
+ echo "not x200, exiting"
+ exit 0
+fi
+
+first=true
+for dev in $(btrfs fi show / | sed -rn 's#^\s*devid\s.*\s([^0-9 ]+)\S+$#\1#p' \
+ |sort); do
+ echo dev=$dev
+ found=false
+ # Decide which is my grub_ext partition. see partition.DEFAULT file
+ # for details. currently it is 4
+ for (( i=4; i<=7; i++ )); do
+ if [[ $(blockdev --getsize64 ${dev}$i) == 8388608 ]]; then
+ grub_extn=${dev}$i
+ found=true
+ echo grub_extn=$grub_extn
+ break
+ fi
+ done
+ if ! $found; then
+ echo "$0: error: failed to find grub_ext partition."
+ exit 1
+ fi
+ m mount $grub_extn /mnt
+ if $first; then
+ if [[ -e /mnt/grubenv ]]; then
+ m grub-editenv /mnt/grubenv list
+ source <(grub-editenv /mnt/grubenv list)
+ fi
+ first=false
+ # we could just as well check if last_boot != /debianbullseye_bootstrap
+ # the intent with this one is just a little clearer.
+ if [[ $did_fai_check == true ]]; then
+ m grub-editenv /mnt/grubenv set did_fai_check=os_true
+ # our service does not wait for network-online.target,
+ # because it will wait for too long when we don't have a network
+ # connection. So, we wait for 10 seconds.
+ # ref: https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
+ try-kexec ||:
+ fi
+ else
+ # we make sure there is only 1 grubenv,
+ # so grub can just find the first one, in whatever order
+ # if looks at them, which may not be the same as us.
+ # If the disk dies, we just lose the default boot option,
+ # we will have to do manual steps to replace it anyways.
+ m rm -f /mnt/gruvenv
+ fi
+ m umount /mnt
+done
+
+# the check for last_boot is not needed afaik, just sanity check.
+case $did_fai_check in
+ true|os_true)
+ if [[ $last_boot != /debian*_bootstrap ]]; then
+ # no need to reboot if we actually want to boot into this os.
+ echo "last_boot=$last_boot not debian*_bootstrap, rebooting"
+ reboot
+ fi
+esac
--- /dev/null
+VOL_BOOKWORM_BOOTSTRAP
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+
+if ! test "$BASH_VERSION"; then echo "error: shell is not bash" >&2; exit 1; fi
+shopt -s inherit_errexit 2>/dev/null ||: # ignore fail in bash < 4.4
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" exit status: $?, PIPESTATUS: ${PIPESTATUS[*]}" >&2' ERR
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+
+# todo: we should make this be a service which sets the /sys/ value
+# before the mount target or something like that, because if you hot
+# plug a drive in, its ata number will change on reboot, meaning you
+# have to remember to run this again and then reboot again.
+
+# example from t8 kernel
+# Sep 01 14:35:01 watson kernel: ata7.00: status: { DRDY }
+# Sep 01 14:35:01 watson kernel: ata7.00: failed command: WRITE FPDMA QUEUED
+# Sep 01 14:35:01 watson kernel: ata7.00: cmd 61/08:c0:b8:bf:ff/00:00:01:00:00/40 tag 24 ncq 4096 out
+
+
+# https://wiki.archlinux.org/index.php/Solid_state_drive#Resolving_NCQ_errors
+# evo-870 doesnt get along well with d16.
+# Dmesg gives us an ata number we could disable specifically on the command line, but I've had that number change on me between oses, so reenabling ncq
+
+debug=false
+if [[ $1 == debug ]]; then
+ debug=true
+fi
+
+upgrub=true
+if [[ $1 == no-upgrub ]]; then
+ upgrub=false
+fi
+
+regex='^.*-part[0-9]*$'
+for path in /dev/disk/by-id/ata-Samsung_SSD_870*; do
+ if [[ ! $path =~ $regex ]]; then
+ byid=$path
+ break
+ fi
+done
+
+if [[ ! -e $byid ]]; then
+ if $debug; then echo "samsung 870 not plugged in or not found"; fi
+ exit 0
+fi
+
+dev=$(readlink $byid)
+if [[ ! $dev ]]; then
+ exit 1
+fi
+
+dev=${dev##*/}
+
+depth=$(cat /sys/block/$dev/device/queue_depth)
+if [[ $depth != 0 ]]; then
+ if grep -qF libata.force=noncq /proc/cmdline; then
+ echo $0: warning, cant change queue_depth due to globally disabled ncq
+ else
+ if $debug; then
+ echo "updating to 1 if not: cat /sys/block/$dev/device/queue_depth"
+ cat /sys/block/$dev/device/queue_depth
+ fi
+ echo 1 >/sys/block/$dev/device/queue_depth
+ fi
+fi
+
+sys=$(readlink /sys/block/$dev)
+ata=${sys#*/*/*/*/ata}
+ata=${ata%%/*}
+
+arg=libata.force=${ata}.00:noncq
+
+if ! grep "^GRUB_CMDLINE_LINUX_DEFAULT=.*[\" ]${arg//./\\.}[\" ]" /etc/default/grub; then
+ sed -ri "s/([\" ])libata.force=[^ ]+ */\1/g;s/^GRUB_CMDLINE_LINUX_DEFAULT=\"(.*)/GRUB_CMDLINE_LINUX_DEFAULT=\"$arg \1/" /etc/default/grub
+ if $upgrub; then
+ echo "$0: warning: grub updated. you may want to reboot"
+ if type -P update-grub2 &>/dev/null; then
+ update-grub2
+ else
+ update-grub
+ fi
+ fi
+fi
--- /dev/null
+#! /bin/bash
+
+skiptask debconf
--- /dev/null
+#!/bin/bash
+
+# exit for any vm which is not our test vm
+if ifclass VM && ! ifclass demohost; then
+ exit 0
+fi
+
#! /bin/bash
+set -x
# if package locales will be installed, then install it early, before
# other packages
if [ $FAI_ACTION != "install" -a $FAI_ACTION != "dirinstall" ]; then
fi
fcopy -Bi /etc/apt/apt.conf.d/force_confdef
-ainsl -a /etc/ucf.conf "^conf_force_conffold=YES"
# in case the locales are already included inside the base file (Ubuntu)
if [ -f $target/usr/sbin/locale-gen ]; then
--- /dev/null
+#!/bin/bash
+
+# These are things we can do before package_config packages get installed.
+
+# exit for any vm except demohost, or if we are doing a dirinstall
+if ifclass VM && ! ifclass demohost || ifclass VOL_BULLSEYE_BOOTSTRAP || ifclass VOL_BOOKWORM_BOOTSTRAP || [[ ! $FAI_ACTION || $FAI_ACTION = dirinstall ]]; then
+ exit 0
+fi
+
+if ifclass FSF; then
+ exit 0
+fi
+
+fcopy -riB /etc/apt/preferences.d
+# ian: i'm guessing fai does this already
+#fcopy -riB /etc/apt/sources.list.d
+
+
+keyfile=/var/lib/fai/config/distro-install-common/luks/host-$HOSTNAME
+f=$target/root/keyscript
+cat > $f <<EOFOUTER
+#!/bin/sh
+cat <<'EOF'
+$(cat $keyfile)
+EOF
+EOFOUTER
+chmod 700 $f
+
+
+# for hosts which don't have these data volumes, copy the specific
+# files we need.
+if ifclass demohost; then
+ files=(/var/lib/fai/config/distro-install-common/luks/host-demohost)
+elif ifclass tp; then
+ files=(/var/lib/fai/config/distro-install-common/luks/host-tp)
+fi
+if [[ ${files[0]} ]]; then
+ d=$target/q/root/luks
+ mkdir -p $d
+ chmod 700 $d
+ cp -p ${files[@]} $d
+fi
+
+
+#### This bit is duplicated in rootsshsync, except we skip
+#### update-initramfs and add $target
+####
+# We generally shouldn't need this, because we don't ssh in on the 1st
+# reboot since we initially embed the luks key, and with distro-begin,
+# we run rootsshsync around the same time as we remove it. However, it
+# could be helpful in case of problems.
+
+auth_dir=$target/etc/dropbear/initramfs/
+candidate=$(apt-cache policy dropbear-initramfs | awk '$1 == "Candidate:" { print $2 }' | head -n1 ||:)
+if [[ $candidate ]] && dpkg --compare-versions "$candidate" lt 2020.81-4; then
+ auth_dir=$target/etc/dropbear-initramfs
+fi
+auth_file=$auth_dir/authorized_keys
+mkdir -p $auth_dir
+if [[ ! -e $auth_file ]] || ! diff -q /root/.ssh/authorized_keys $auth_file; then
+ cp -p /root/.ssh/authorized_keys $auth_file
+fi
--- /dev/null
+#!/bin/bash -x
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# todo /boot/chboot needs update for lvm i think?
+
+PS4='+ $LINENO '
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: need to run as root" >&2
+ exit 1
+fi
+
+# for calling outside of FAI without args:
+#
+# source /b/fai/fai-wrapper
+# - set any appropriate classes with: fai-setclass OPT1... which sets CLASS_OPT1=true...
+# or run eval-fai-classfile FILE.
+# - Set a VOL_DISTROVER (if not doing mkroot2) eg:
+# fai-setclass VOL_NABIA
+#
+# ARGS (only 1 is valid):
+#
+# mkroot2: for running outside of fai and setting up the root2/boot2 luks and btrfs and tab files
+#
+# mkroot2tab: for running outside of fai and setting up the root2/boot2 tab files, in case luks and btrfs
+# happen to already be setup.
+#
+# mktab: for running outside of fai and generating a crypttab for
+# the main root fs in /tmp/fai. Must run with env var, eg export DISTRO=trisquelaramo.
+#
+# Example use in a bootstrap distro:
+# scp /a/bin/fai/fai/config/{distro-install-common/devbyid,hooks/partition.DEFAULT} root@HOST:
+# sl HOST
+# export DISTRO=trisquelnabia; ./partition.DEFAULT mktab
+# ## cryptsetup wont take within a pipeline
+# mapfile -t lines < <(awk '! /swap/ {print $2,$1}' /tmp/fai/crypttab )
+# for l in "${lines[@]}"; do cryptsetup luksOpen $l; done
+#
+# # or alternatively, to avoid typing it many times:
+# read -r lukspw; for l in "${lines[@]}"; do yes "$lukspw" | cryptsetup luksOpen $l; done
+
+## potentially useful later:
+# sed 's#/root/keyscript,#decrypt_keyctl,#;s/$/,noauto/' /tmp/fai/crypttab >/etc/crypttab
+#
+# environment variables:
+#
+# HOSTNAME: if demohost, we set the luks password to just
+# 'x'. Used in various other ways too.
+#
+# SPECIAL_DISK: For use outside of fai. A base disk name like
+# /dev/sdk. If set, we just cryptsetup and partition this one disk then
+# exit. This is useful for partitioning a disk in preparation to replace
+# a failed or failing disk from a raid10 array.
+#
+# classes:
+#
+# REPARTITION: forces repartitioning even if we detect the proper amount
+# of partitions already exist.
+#
+# NOWIPE: use existing subvolumes if they exist
+#
+# REROOTFS: Don't reuse the root filesystem, even if we normally would
+#
+# ROTATIONAL: forces to install onto hdds instead of sdds. normally sdds
+# are chosen if they exist.
+#
+# PARTITION_PROMPT: command line prompt before partitioning. This is good
+# to set if we don't expect repartitioning to happen.
+#
+# ROTATIONAL: in a system with ssd and hdd, install to the hdd
+# instead of the default ssd.
+#
+# RAID0: forces raid0 filesystem. Normally with 4+ devices, we use
+# raid10.
+# RAID1: forces raid1 filesystem.
+# RAID1c3: forces raid1c3 filesystem (btrfs raid 1, 3 copies).
+
+mkroot2tab=false
+mkroot2=false
+mktab=false
+if [[ $1 ]]; then
+ ## duplicates fai-wrapper, for convenience of not needing it
+ if ! type -t ifclass &>/dev/null; then
+ ifclass() {
+ local var=${1/#/CLASS_}
+ [[ $HOSTNAME == "$1" || ${!var} ]]
+ }
+ fi
+
+ case $1 in
+ mkroot2)
+ mkroot2=true
+ ;;
+ mkroot2tab)
+ mkroot2tab=true
+ ;;
+ mktab)
+ mktab=true
+ ;;
+ *)
+ echo "$0: error: unsupported arg: $1" >&2
+ exit 1
+ ;;
+ esac
+fi
+
+if [[ ! $SPECIAL_DISK ]] && ! $mkroot2 && ! $mkroot2tab && ! $mktab \
+ && ! ifclass IANK && ! ifclass FSF; then
+ echo $0: error: need class IANK or FSF or SPECIAL_DISK for running in fai
+fi
+
+
+if [[ $SPECIAL_DISK ]]; then
+ export CLASS_REPARTITION=true
+fi
+
+# # fai's setup-storage won't do btrfs on luks,
+# # so we do it ourself :)
+# inspiration taken from files in fai-setup-storage package
+
+# if we are not running in fai, skiptask won't be defined, so carry on.
+skiptask partition || ! type skiptask
+
+if ! type -p devbyid; then
+ for d in $FAI/distro-install-common \
+ /a/bin/fai/fai/config/distro-install-common $FAI $PWD; do
+ [[ -d $d ]] || continue
+ if [[ -e $d/devbyid ]]; then
+ devbyid=$d/devbyid
+ devbyid() { $devbyid "$@"; }
+ break
+ fi
+ done
+ if [[ ! $devbyid ]]; then
+ echo "$0: error: failed to find devbyid script" >&2
+ exit 1
+ fi
+fi
+
+#### begin configuration
+
+# this is the ordering of the /dev/sdaX, but
+# the ordering of the partition layout goes like this:
+# bios_grub
+# grub_ext
+# efi
+# lvm
+# root
+# swap
+# boot
+
+
+##### end configuration
+
+##### begin function defs
+
+bpart() { # btrfs a partition
+ case $raid_level in
+ 0) mkfs.btrfs -f $@ ;;
+ *) mkfs.btrfs -f -m raid$raid_level -d raid$raid_level $@ ;;
+ esac
+}
+
+
+zilap() {
+ case $HOSTNAME in
+ sy|bo|so)
+ return 0
+ ;;
+ esac
+ return 1
+}
+
+getluks() {
+ if [[ ! $luks_dir ]]; then
+ # see README for docs about how to create these
+ luks_dir=$FAI/distro-install-common/luks
+ if [[ ! -d $luks_dir ]]; then
+ luks_dir=/q/root/luks
+ fi
+ if [[ ! -d $luks_dir ]]; then
+ echo "$0: error: no luks_dir found" >&2
+ exit 1
+ fi
+ fi
+
+ luks_file=$luks_dir/host-$HOSTNAME
+ if [[ ! -e $luks_file ]]; then
+ # shellcheck disable=SC2206 # globbing is intended
+ hostkeys=($luks_dir/host-*)
+ # if there is only one key, we might be deploying somewhere
+ # where dhcp doesnt give us a proper hostname, so use that.
+ if [[ ${#hostkeys[@]} == 1 && -e ${hostkeys[0]} ]]; then
+ luks_file=${hostkeys[0]}
+ else
+ echo "$0: error: no key for hostname at $luks_file" >&2
+ exit 1
+ fi
+ fi
+
+ # # note, corresponding changes in /b/ds/keyscript-{on,off}
+ if ifclass demohost; then
+ lukspw=x
+ elif [[ -e $luks_dir/$HOSTNAME ]]; then
+ lukspw=$(cat $luks_dir/$HOSTNAME)
+ else
+ lukspw=$(cat $luks_dir/iank)
+ fi
+
+ if $mkroot2; then
+ luks_file=$luks_dir/host-amy
+ lukspw=$(cat $luks_dir/amy)
+ fi
+}
+
+
+fsf() {
+ ifclass FSF
+}
+
+
+dev-mib() {
+ local d=${1:-$dev}
+ echo $(( $(parted -m $d unit MiB print | \
+ sed -nr "s#^/dev/[^:]+:([0-9]+).*#\1#p") - 1))
+}
+
+luks-setup() {
+ local luksdev="$1"
+ local cryptname="$2"
+ # when we move to newer than trisquel 9, we can remove
+ # --type luks1. We can also check on cryptsetup --help | less /compil
+ # to see about the other settings. Default in debian 9 is luks2.
+ # You can convert from luks2 to luks 1 by adding a temporary key:
+ # cryptsetup luksAddKey --pbkdf pbkdf2
+ # then remove the new format keys with cryptsetup luksRemoveKey
+ # then cryptsetup convert DEV --type luks1, then readd old keys and remove temp.
+ yes YES | cryptsetup luksFormat $luksdev $luks_file || [[ $? == 141 ]]
+ yes "$lukspw" | \
+ cryptsetup luksAddKey --key-file $luks_file \
+ $luksdev || [[ $? == 141 ]]
+ # background: Keyfile and password are treated just
+ # like 2 ways to input a passphrase, so we don't actually need to have
+ # different contents of keyfile and passphrase, but it makes some
+ # security sense to a really big randomly generated passphrase
+ # as much as possible, so we have both.
+ #
+ # This would remove the keyfile.
+ # yes 'test' | cryptsetup luksRemoveKey /dev/... \
+ # /key/file || [[ $? == 141 ]]
+ cryptsetup luksOpen $luksdev $cryptname --key-file $luks_file
+}
+
+mktab() {
+ mkdir -p /tmp/fai
+ dev=${boot_devs[0]}
+ fstabstd="x-systemd.device-timeout=30s,x-systemd.mount-timeout=30s"
+
+ if [[ $DISTRO == *_bootstrap ]]; then
+ cat > /tmp/fai/fstab <<EOF
+$first_boot_dev / btrfs noatime,subvol=$boot_vol 0 0
+$first_efi /boot/efi vfat nofail,$fstabstd 0 0
+EOF
+ cat >/tmp/fai/disk_var.sh <<EOF
+BOOT_DEVICE="${short_devs[@]}"
+ROOT_PARTITION=$first_boot_dev
+EOF
+ else
+ # note, fai creates the mountpoints listed here
+ cat > /tmp/fai/fstab <<EOF
+$first_root_dev / btrfs $fstabstd,noatime,subvol=root_$DISTRO$mopts 0 0
+$first_root_dev /mnt/root btrfs nofail,$fstabstd,noatime,subvolid=0$mopts 0 0
+$first_boot_dev /boot btrfs nofail,$fstabstd,noatime,subvol=$boot_vol 0 0
+$first_efi /boot/efi vfat nofail,$fstabstd 0 0
+$first_boot_dev /mnt/boot btrfs nofail,$fstabstd,noatime,subvolid=0 0 0
+EOF
+ if ! fsf; then
+ cat >> /tmp/fai/fstab <<EOF
+/dev/mapper/crypt-${vgs[0]}-o /mnt/o btrfs nofail,$fstabstd,noatime,subvolid=0$mopts 0 0
+EOF
+ fi
+ rm -f /tmp/fai/crypttab
+ for vg in ${vgs[@]}; do
+ if ! fsf; then
+ cat >>/tmp/fai/crypttab <<EOF
+crypt-$vg-root /dev/$vg/root none keyscript=/root/keyscript,discard,luks,initramfs
+crypt-$vg-o /dev/$vg/o none keyscript=/root/keyscript,discard,luks,initramfs
+crypt-$vg-swap /dev/$vg/swap /dev/urandom swap,cipher=aes-xts-plain64,size=256,hash=ripemd160
+EOF
+ fi
+ if fsf; then
+ cat >> /tmp/fai/fstab <<EOF
+/dev/$vg/swap none swap nofail,$fstabstd,sw 0 0
+EOF
+ else
+ cat >> /tmp/fai/fstab <<EOF
+/dev/mapper/crypt-$vg-swap none swap nofail,$fstabstd,sw 0 0
+EOF
+ fi
+ done
+
+ # fai would do this:
+ #BOOT_DEVICE=\${BOOT_DEVICE:-"${devs[0]}"}
+
+ # note: swaplist seems to do nothing.
+ cat >/tmp/fai/disk_var.sh <<EOF
+BOOT_DEVICE="${short_devs[@]}"
+BOOT_PARTITION=\${BOOT_PARTITION:-$first_boot_dev}
+# ROOT_PARTITIONS is added by me, used in arch setup.
+ROOT_PARTITIONS="${root_devs[@]}"
+ROOT_PARTITION=\${ROOT_PARTITION:-$first_root_dev}
+SWAPLIST=\${SWAPLIST:-"${swap_devs[@]}"}
+EOF
+
+ if [[ $HOSTNAME == frodo ]]; then
+ big_disks=(
+ ata-Hitachi_HDS722020ALA330_JK1121YAG7SXWS-part1
+ ata-Hitachi_HDS722020ALA330_JK1121YAG7SY4S-part1
+ ata-Hitachi_HDS723030ALA640_MK0311YHG2WUSA-part1
+ ata-ST4000DM000-1F2168_Z300AZ6K-part1
+ ata-ST6000DM001-1XY17Z_Z4D2WMZK-part1
+ ata-TOSHIBA_MD04ACA500_8539K4TQFS9A-part1
+ ata-TOSHIBA_MD04ACA500_85NAK4T2FS9A-part1
+ ata-TOSHIBA_MD04ACA500_9551K615FS9A-part1
+ ata-TOSHIBA_MD04ACA500_Y5IFK6IJFS9A-part1
+ )
+ for d in ${big_disks[@]}; do
+ cat >>/tmp/fai/crypttab <<EOF
+crypt_dev_$d /dev/disk/by-id/$d /mnt/root/q/root/luks/iank discard,luks
+EOF
+ done
+ cat >> /tmp/fai/fstab <<EOF
+/dev/mapper/crypt_dev_${big_disks[0]} /mnt/i btrfs nofail,$fstabstd,noatime,subvolid=0 0 0
+EOF
+ fi
+ if [[ $HOSTNAME == kd ]]; then
+ # note, having these with keyscript and initramfs causes a luks error in fai.log,
+ # but it is safely ignorable and gets us the ability to just type our password
+ # in once at boot. A downside is that they are probably needed to be plugged in to boot.
+ cat >>/tmp/fai/crypttab <<EOF
+crypt_dev_ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V${even_bigsuf} /dev/disk/by-id/ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V${even_bigsuf} /mnt/root/q/root/luks/iank discard,luks
+crypt_dev_ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1 /dev/disk/by-id/ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1 /mnt/root/q/root/luks/iank discard,luks
+crypt_dev_ata-ST6000DM001-1XY17Z_Z4D29EBL-part1 /dev/disk/by-id/ata-ST6000DM001-1XY17Z_Z4D29EBL-part1 /mnt/root/q/root/luks/iank discard,luks
+EOF
+ cat >> /tmp/fai/fstab <<EOF
+# r7 = root partition7. it isnt actually #7 anymore, not a great name, but whatever
+/dev/mapper/crypt_dev_ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V${even_bigsuf} /mnt/r7 btrfs nofail,$fstabstd,noatime,compress=zstd,subvolid=0 0 0
+/dev/mapper/crypt_dev_ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1 /mnt/rust1 btrfs nofail,$fstabstd,noatime,compress=zstd,subvolid=0 0 0
+/dev/mapper/crypt_dev_ata-ST6000DM001-1XY17Z_Z4D29EBL-part1 /mnt/rust2 btrfs nofail,$fstabstd,noatime,compress=zstd,subvolid=0 0 0
+EOF
+ fi
+ fi
+}
+
+
+
+#### root2 non-fai run
+
+# todo: update for lvm
+doroot2() {
+
+
+ # We write to these files instead of just /etc/fstab, /etc/crypttab,
+ # because these are filesystems created after our current root, and so
+ # this allows us to update other root filesystems too.
+ rm -f /mnt/root/root2-{fs,crypt}tab
+ if $partition; then
+ echo $0: error: found partition=true but have mkroot2 arg
+ exit 1
+ fi
+
+
+ root2_devs=()
+ for vg in ${vgs[@]}; do
+
+
+ root2_devs+=(/dev/mapper/crypt-$vg-root2)
+ if $mkroot2; then
+ lvcreate -y -L $root2_part_mib $vg -n root2
+ lvcreate -y -L $boot2_part_mib $vg -n boot2
+ luks-setup /dev/$vg/root2 crypt-$vg-root2
+ fi
+ cat >>/mnt/root/root2-crypttab <<EOF
+crypt-$vg-root2 /dev/$vg/root2 $luks_file discard,luks,initramfs
+EOF
+ done
+ if $mkroot2; then
+ bpart ${root2_devs[@]}
+ bpart ${boot2_devs[@]}
+ fi
+ mkdir -p /mnt/root2 /mnt/boot2
+ cat >>/mnt/root/root2-fstab <<EOF
+${root2_devs[0]} /mnt/root2 btrfs nofail,x-systemd.device-timeout=30s,x-systemd.mount-timeout=30s,noatime,subvolid=0$mopts 0 0
+${boot2_devs[0]} /mnt/boot2 btrfs nofail,x-systemd.device-timeout=30s,x-systemd.mount-timeout=30s,noatime,subvolid=0 0 0
+EOF
+ exit 0
+}
+
+
+##### end function defs
+
+
+##### begin variable setup
+
+
+partition=false
+if ifclass REPARTITION; then
+ partition=true # force a full wipe
+fi
+wipe=true
+if ifclass NOWIPE; then
+ wipe=false
+fi
+
+rerootfs=false
+if ifclass REROOTFS; then
+ rerootfs=true
+fi
+
+if (($(nproc) > 2)); then
+ mopts=,compress=zstd
+fi
+
+declare -A disk_excludes
+if ! $mkroot2 && ! $mkroot2tab && ! $mktab ! ifclass USE_MOUNTED; then
+ ## ignore disks that are mounted, eg when running from fai-cd
+ while read -r l; do
+ eval "$l"
+ if [[ ! $PKNAME ]]; then
+ # shellcheck disable=SC2153 # not a misspelling
+ PKNAME="$KNAME"
+ fi
+ if [[ $MOUNTPOINT ]]; then
+ disk_excludes[$PKNAME]=true
+ fi
+ done < <(lsblk -nP -o KNAME,MOUNTPOINT,PKNAME)
+fi
+
+hdds=()
+ssds=()
+# this excludes "usb". vda disk has empty tran (transport). This may need adjustment
+# for some new type we come across. cdrom has type "rom"
+for disk in $(lsblk -ndo name,type,tran | awk '$3 ~ "^(sata|nvme|)$" && $2 == "disk" { print $1 }'); do
+ if [[ ${disk_excludes[$disk]} ]]; then
+ continue
+ fi
+ case $disk in
+ # cdrom
+ sr*) continue ;;
+ esac
+ case $(cat /sys/block/$disk/queue/rotational) in
+ 0)
+ ssds+=("/dev/$disk")
+ echo $0: found ssd /dev/$disk
+ ;;
+ 1)
+ hdds+=("/dev/$disk")
+ echo $0: found hdd /dev/$disk
+ ;;
+ *) echo "$0: error: unknown /sys/block/$disk/queue/rotational: \
+$(cat $disk/queue/rotational)"; exit 1 ;;
+ esac
+done
+
+# install all ssds, or if there are none, all hdds.
+# Note, usb flash disks are seen as rotational, which is
+# very odd, but convenient for ignoring them here.
+if ! ifclass ROTATIONAL && (( ${#ssds[@]} > 0 )); then
+ read -ra short_devs<<<"${ssds[@]}"
+else
+ read -ra short_devs<<<"${hdds[@]}"
+fi
+
+pvn=1
+
+bootn=2
+
+# rootn=1
+# root2n=2
+# swapn=3
+# bootn=4
+# boot2n=5
+
+efin=3
+# ext partition so grub can write persistent variables,
+# so it can do a one time boot. grub can't write to
+# btrfs or any cow fs because it's more
+# more complicated to do and they don't want to.
+grub_extn=4
+# bios boot partition,
+# https://wiki.archlinux.org/index.php/GRUB
+bios_grubn=5
+# for an even raid (raid 1), when one disk is bigger, this partition goes on the big disk
+even_bign=6
+# even_bign only exists in some cases
+lastn=$bios_grubn
+# check if the partitions exist have the right filesystems
+#blkid="$(blkid -s TYPE)"
+for dev in ${short_devs[@]}; do
+ if $partition; then break; fi
+ y=$(readlink -f $dev)
+ # shellcheck disable=SC2206 # globbing is intended
+ arr=($y?*)
+ if (( ${#arr[@]} < lastn )); then
+ partition=true
+ fi
+ # On one system, blkid is missing some partitions.
+ # maybe we need a flag, like FUZZY_BLKID or something, so we
+ # can check that at least some exist.
+ # for x in "`rootdev`: TYPE=\"crypto_LUKS\"" "`bootdev`: TYPE=\"btrfs\""; do
+ # echo "$blkid" | grep -Fx "$x" &>/dev/null || partition=true
+ # done
+done
+
+if $partition && ifclass PARTITION_PROMPT; then
+ echo "Press any key except ctrl-c to continue and partition these drives:"
+ if [[ $SPECIAL_DISK ]]; then
+ echo $SPECIAL_DISK
+ else
+ echo " ${short_devs[*]}"
+ fi
+ read -r
+fi
+
+devs=()
+vgs=()
+root_devs=()
+o_devs=()
+swap_devs=()
+shopt -s extglob
+partsuffix=-part
+for short_dev in ${short_devs[@]}; do
+ dev="$(devbyid $short_dev)"
+ if [[ $dev != */by-id/* ]]; then
+ # no by-id link, assume we are in a vm and this is true for all devs.
+ partsuffix=
+ fi
+ # for vms, cant name a vg the same as the short device name, they
+ # conflict: /dev/$vg is already taken
+
+ dname=${dev##*/}
+ vg=vg$dname
+ vg=${vg//:/}
+ vgs+=("$vg")
+ devs+=("$dev")
+ if fsf; then
+ root_devs+=(/dev/$vg/root)
+ swap_devs+=(/dev/$vg/swap)
+ else
+ o_devs+=(/dev/mapper/crypt-$vg-o)
+ root_devs+=(/dev/mapper/crypt-$vg-root)
+ swap_devs+=(/dev/mapper/crypt-$vg-swap)
+ fi
+done
+first_root_dev=${root_devs[0]}
+if [[ ! $SPECIAL_DISK && ! ${devs[0]} ]]; then
+ echo "$0: error: failed to detect devs" >&2
+ exit 1
+fi
+
+
+pvsuf=$partsuffix$pvn
+bootsuf=$partsuffix$bootn
+efisuf=$partsuffix$efin
+grub_extsuf=$partsuffix$grub_extn
+# We dont do anything with this partition here, so this
+# is be unused, but left as a comment for completing the pattern
+# of all the suffixes.
+#bios_grubsuf=$partsuffix$bios_grubn
+even_bigsuf=$partsuffix$even_bign
+
+
+boot_space=0
+first=true
+boot_devs=()
+boot2_devs=()
+for dev in ${devs[@]}; do
+ vg=vg${dev##*/}
+ vg=${vg//:/}
+ # I ran into a machine (frodo) where the bios doesn't know about some disks,
+ # so 1st stage of grub also doesn't know about them.
+ # Also, grub does not support mounting degraded btrfs as far as
+ # I can tell with some googling.
+ # From within an arch install env, I could detect them by noting
+ # their partitions were mixed with the next disk in /dev/disk/by-path,
+ # and I have mixed model disks, and I could see the 8 models which showed
+ # up in the bios, and thus see which 2 models were missing.
+ # hdparm -I /dev/sdh will give model info in linux.
+ # However, in fai on jessie, /dev/disk/by-path dir doesn't exist,
+ # and I don't see another way, so I'm hardcoding them.
+ # We still put grub on them and partition them the same, for uniformity
+ # and in case they get moved to a system that can recognize them,
+ # we just exclude them from the boot filesystem.
+ cd /dev/disk/by-id/
+ bad_disk=false
+ for id in ata-TOSHIBA_MD04ACA500_8539K4TQFS9A \
+ ata-TOSHIBA_MD04ACA500_Y5IFK6IJFS9A; do
+ if [[ $(readlink -f $id) == "$(readlink -f $dev)" ]]; then
+ bad_disk=true
+ break
+ fi
+ done
+ if $bad_disk; then
+ continue
+ fi
+ boot_devs+=($dev$bootsuf)
+ boot2_devs+=(/dev/$vg/boot2)
+ boot_space=$(( boot_space + $(parted -m $dev unit MiB print | \
+ sed -nr "s#^/dev/[^:]+:([0-9]+).*#\1#p") - 1))
+ if $first; then
+ first_efi=$dev$efisuf
+ first_grub_extdev=$dev$grub_extsuf
+ first=false
+ fi
+done
+first_boot_dev=${boot_devs[0]}
+
+even_raid=false
+if ifclass RAID0 || (( ${#boot_devs[@]} == 1 )); then
+ raid_level=0
+ raid_duplication=1
+elif ifclass RAID1 || (( ${#boot_devs[@]} == 2 )); then
+ if (( ${#boot_devs[@]} == 2 )); then
+ even_raid=true
+ fi
+ raid_level=1
+ raid_duplication=2
+elif ifclass RAID1c3 || (( ${#boot_devs[@]} == 3 )); then
+ raid_level=1c3
+ raid_duplication=3
+else
+ raid_level=10
+ raid_duplication=2
+fi
+
+
+
+### Begin calculate boot partition space
+# due to raid duplication
+case $raid_level in
+ 1|10) boot_space=$(( boot_space / 2 )) ;;
+ 1c3) boot_space=$(( boot_space / 3 )) ;;
+esac
+if fsf; then
+ boot_mib=6000
+elif (( boot_space > 900000 )); then
+ # this is larger than needed for several /boot subvols,
+ # becuase I keep a minimal debian install on it for
+ # recovery needs and for doing pxe-kexec.
+ boot_mib=10000
+ root2_mib=500000
+ boot2_mib=5000
+elif (( boot_space > 30000 )); then
+ boot_mib=$(( 5000 + (boot_space - 30000) / 2 ))
+ root2_mib=100
+ boot2_mib=100
+else
+ # Small vms don't have room for /boot recovery. With 3 kernels
+ # installed, i'm using 132M on t8, so this seems like plenty of
+ # room. note: rhel 8 recomments 1g for /boot. u20.04 with 3 kernels =
+ # 308 mb, so things have grown significantly
+ boot_mib=1000
+ root2_mib=100
+ boot2_mib=100
+fi
+boot_part_mib=$(( boot_mib * raid_duplication / ${#boot_devs[@]} ))
+
+if zilap; then
+ boot2_part_mib=$(( boot2_mib * raid_duplication / ${#boot_devs[@]} ))
+ root2_part_mib=$(( root2_mib * raid_duplication / ${#root_devs[@]} ))
+else
+ boot2_part_mib=0
+ root2_part_mib=0
+fi
+### end calculate boot partition space
+
+
+if [[ ! $DISTRO ]]; then
+ if ifclass VOL_BOOKWORM_BOOTSTRAP; then
+ DISTRO=debianbookworm_bootstrap
+ elif ifclass VOL_BULLSEYE_BOOTSTRAP; then
+ DISTRO=debianbullseye_bootstrap
+ elif ifclass VOL_STRETCH; then
+ DISTRO=debianstretch
+ elif ifclass VOL_BUSTER; then
+ DISTRO=debianbuster
+ elif ifclass VOL_BULLSEYE; then
+ DISTRO=debianbullseye
+ elif ifclass VOL_BOOKWORM; then
+ DISTRO=debianbookworm
+ elif ifclass VOL_TESTING; then
+ DISTRO=debiantesting
+ elif ifclass VOL_XENIAL; then
+ DISTRO=ubuntuxenial
+ elif ifclass VOL_BIONIC; then
+ DISTRO=ubuntubionic
+ elif ifclass VOL_FOCAL; then
+ DISTRO=ubuntufocal
+ elif ifclass VOL_JAMMY; then
+ DISTRO=ubuntujammy
+ elif ifclass VOL_FLIDAS; then
+ DISTRO=trisquelflidas
+ elif ifclass VOL_ETIONA; then
+ DISTRO=trisqueletiona
+ elif ifclass VOL_NABIA; then
+ DISTRO=trisquelnabia
+ elif ifclass VOL_ARAMO; then
+ DISTRO=trisquelaramo
+ elif $mkroot2 || $mkroot2tab; then
+ :
+ else
+ echo "PARTITIONER ERROR: no distro class/var set" >&2
+ exit 1
+ fi
+fi
+
+if [[ $DISTRO == *_bootstrap ]]; then
+ # this is just convenience for the libreboot_grub config
+ # so we can glob the other ones easier.
+ boot_vol=$DISTRO
+else
+ boot_vol=boot_$DISTRO
+fi
+
+
+# 1.5 x based on https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide/sect-disk-partitioning-setup-x86.html#sect-custom-partitioning-x86
+swap_mib=$(( $(grep ^MemTotal: /proc/meminfo | \
+ awk '{print $2}') * 3/(${#devs[@]} * 2 ) / 1024 ))
+
+shopt -s nullglob
+##### end variable setup
+
+
+
+
+if $mkroot2 || $mkroot2tab; then
+ getluks
+ doroot2
+elif $mktab; then
+ mktab
+ exit 0
+else
+ mktab
+ if ! fsf; then
+ getluks
+ fi
+fi
+
+
+if $partition; then
+ ### begin wipefs
+ if [[ ! $SPECIAL_DISK ]]; then
+
+ # we do lvm removals just for the disks we are using
+ pv_wipes=()
+ vg_wipes=()
+ declare -A vg_map
+ pv_devs=$(pvs --noheadings -o pvname)
+ for pv_dev in $pv_devs; do
+ for short_dev in ${short_devs[@]}; do
+ if [[ $pv_dev == $short_dev* ]]; then
+ pv_wipes+=($pv_dev)
+ vgs_of_pv=$(pvs --noheadings -o vgname $pv_dev)
+ for vg in $vgs_of_pv; do
+ if [[ ${vg_map[$vg]} ]]; then
+ continue
+ fi
+ vg_map[$vg]=t
+ vg_wipes+=($vg)
+ lvs=$(vgs --noheadings -o lv_path $vg)
+ for lv in $lvs; do
+ wipefs -a $lv
+ done
+ done
+ fi
+ done
+ done
+
+ for vg in ${vg_wipes[@]}; do
+ vgchange -an $vg
+ vgremove -ff $vg
+ done
+
+ for pv in ${pv_wipes[@]}; do
+ pvremove -ff $pv
+ done
+
+ for dev in ${devs[@]}; do
+ # if we repartition to the same as an old partition,
+ # we don't want any old fses hanging around.
+ count_down=10
+ # wipefs has failed, manual run works, google suggests timing issue
+ while ! wipefs -a $dev; do
+ sleep 2
+ count_down=$((count_down - 1))
+ if (( count_down <= 0 )); then
+ echo "$0: wipefs failed 10 times. exiting" >&2
+ exit 1
+ fi
+ done
+ done
+ fi
+ ### end wipefs
+
+
+ # When we have 2 disks of at least 100g difference in size,
+ # make an extra partition on the end of the bigger one.
+ even_big_part=false
+ even_diff_min=100000
+ if $even_raid; then
+ smalli=0
+ bigi=1
+ if (( $(dev-mib ${devs[0]}) >= $(dev-mib ${devs[1]}) )); then
+ smalli=1
+ bigi=0
+ fi
+ disk_mib=$(dev-mib ${devs[smalli]})
+ even_big_dev=${devs[bigi]}
+ even_big_mib=$(dev-mib $even_big_dev)
+ if (( even_big_mib - disk_mib > even_diff_min )); then
+ even_big_part=true
+ fi
+ fi
+
+ if [[ $SPECIAL_DISK ]]; then
+ devs=($(devbyid $SPECIAL_DISK))
+ fi
+ for dev in ${devs[@]}; do
+ vg=vg${dev##*/}
+ vg=${vg//:/}
+
+ # parted will round up the disk size. Do -1 so we can have
+ # fully 1MiB unit partitions for easy resizing of the last partition.
+ # Otherwise we would pass in -0 for the end argument for the last partition.
+ #
+ # Note: parted print error output is expected. example:
+ # Error: /dev/vda: unrecognised disk label
+ if ! $even_raid; then
+ disk_mib=$(dev-mib)
+ fi
+
+
+ parted -s $dev mklabel gpt
+ # MiB because parted complains about alignment otherwise.
+ pcmd="parted -a optimal -s -- $dev"
+ # main lvm partition
+
+ pv_end=$(( disk_mib - boot_part_mib ))
+ $pcmd mkpart primary ext3 524MiB ${pv_end}MiB
+ $pcmd name $pvn pv
+
+ # + 794 pvcreate -y /dev/disk/by-id/ata-ST4000DM000-1F2168_Z3028BKA-part1
+ # WARNING: Device /dev/sde1 not initialized in udev database even after waiting 10000000 microseconds.
+ # No device found for /dev/disk/by-id/ata-ST4000DM000-1F2168_Z3028BKA-part1.
+ # sleep 10 was not enough.
+ secs=0
+ while [[ ! -e $dev$pvsuf ]] && (( secs < 40 )); do
+ sleep 1
+ secs=$((secs +1))
+ done
+ sleep 3
+ pvcreate -y -ff $dev$pvsuf
+ vgcreate -y -ff $vg $dev$pvsuf
+
+ if fsf; then
+ root_mib=40000
+ else
+ # This would maximize it, but we are going for a separate filesystem in /o,
+ # so use fixed sizes to allow both to grow
+ # 600 = uefi 512 + grubext 8 + bios grub 3 + some extra cuz this is lvm
+ #root_mib=$(( disk_mib - root2_part_mib - swap_mib - boot_part_mib - boot2_part_mib - 600 ))
+ o_mib=$(( 180 * 1000 ))
+ # max minus o, minus a gig just for some extra space
+ max_root_mib=$(( disk_mib - root2_part_mib - swap_mib - boot_part_mib - boot2_part_mib - 600 - o_mib - 1000 ))
+ root_mib=$(( 1700 * 1000 )) # * 1000 to make it in gb.
+ if (( max_root_mib < root_mib )); then
+ root_mib=$max_root_mib
+ fi
+ fi
+
+ if [[ $SPECIAL_DISK ]]; then
+ lvcreate -y -L $max_root_mib $vg -n data
+ else
+ # -L unit default mebibyte
+ lvcreate -y -L $root_mib $vg -n root
+ if ! fsf; then
+ lvcreate -y -L $o_mib $vg -n o
+ fi
+ lvcreate -y -L $swap_mib $vg -n swap
+ # unencrypted swap needs mkswap
+ if fsf; then
+ mkswap /dev/$vg/swap
+ fi
+ fi
+
+ $pcmd mkpart primary "" ${pv_end}MiB ${disk_mib}MiB
+ $pcmd name $bootn boot
+ $pcmd set $bootn boot on
+
+ # uefi partition, for normal bios systems, its just in case.
+ $pcmd mkpart primary "fat32" 12MiB 524MiB
+ $pcmd name $efin efi
+ # note, this is shown here: https://support.system76.com/articles/bootloader/
+ # but not mentioned https://wiki.archlinux.org/index.php/EFI_system_partition
+ # might not be needed
+ $pcmd set $efin esp on
+
+ # i only need a few k, but googling min size,
+ # I found someone saying that gparted required
+ # required at least 8 because of their hard drive cylinder size.
+ # And 8 is still very tiny.
+ # grub_ext partition
+ $pcmd mkpart primary "ext2" 4MiB 12MiB
+ $pcmd name $grub_extn grubext
+ # gpt ubuntu cloud image uses ~4 mb for this partition. fai uses 1 MiB.
+ # so, I use 3, whatever.
+ # note: parted manual saying cheap flash media
+ # should to start at 4.
+ # biols grub partition
+ $pcmd mkpart primary "" 1MiB 4MiB
+ $pcmd name $bios_grubn biosgrub
+ $pcmd set $bios_grubn bios_grub on
+ if $even_big_part && [[ $dev == "$even_big_dev" ]]; then
+ $pcmd mkpart primary ext3 ${disk_mib}MiB ${even_big_mib}MiB
+ $pcmd name $even_bign even_big
+ fi
+
+ # the mkfs failed before on a vm, which prompted me to add
+ # sleep .1
+ # then it failed again on a physical machine
+ # with:
+ # Device /dev/disk/by-id/foo doesn't exist or access denied,
+ # so I added a wait until it existed.
+ # Then I added the mkfs.ext2, which claimed to succeed,
+ # but then couldn't be found upon reboot. In that case we didn't
+ # wait at all. So I've added a 3 second minimum wait.
+ secs=0
+ while [[ ! -e $dev$efisuf ]] && (( secs < 40 )); do
+ sleep 1
+ secs=$((secs +1))
+ done
+ sleep 3
+
+ mkfs.fat -F32 $dev$efisuf
+
+ if ! fsf && $even_big_part && [[ $dev == "$even_big_dev" ]]; then
+ luks-setup $even_big_dev$even_bigsuf ${even_big_dev##*/}$even_bigsuf
+ mkfs.btrfs -f /dev/mapper/${even_big_dev##*/}$even_bigsuf
+ fi
+
+ # Holds just a single file, rarely written, so
+ # use ext2, like was often used for the /boot partition.
+ # This exists because grub can only persist data to a non-cow fs.
+ # And we use persisting a var in grub to do a one time boot.
+ # We could pass the data on the kernel command line and persist it
+ # to grubenv after booting, but that relies on the boot always succeeding.
+ # This is just a bit more robust, and it could work for booting
+ # into ipxe which can't persist data, if we ever got that working.
+ mkfs.ext2 $dev$grub_extsuf
+
+ if [[ $SPECIAL_DISK ]]; then
+ luks-setup /dev/$vg/data crypt-$vg-data
+ exit 0
+ fi
+
+ # for fsf, no encryption of root because root will not contain any
+ # sensitive data.
+ if ! fsf; then
+ luks-setup /dev/$vg/root crypt-$vg-root
+ luks-setup /dev/$vg/o crypt-$vg-o
+ fi
+
+ done
+ ls -la /dev/btrfs-control # this was probably for debugging...
+ sleep 1
+
+ bpart ${root_devs[@]}
+ if ! fsf; then
+ bpart ${o_devs[@]}
+ fi
+ bpart ${boot_devs[@]}
+
+else ## end if $partition ##
+
+ if ! fsf; then
+ for vg in ${vgs[@]}; do
+ if [[ -e /dev/mapper/crypt-$vg-root ]]; then
+ continue
+ fi
+ if $rerootfs; then
+ luks-setup /dev/$vg/root crypt-$vg-root
+ else
+ cryptsetup luksOpen /dev/$vg/root crypt-$vg-root \
+ --key-file $luks_file
+ cryptsetup luksOpen /dev/$vg/o crypt-$vg-o \
+ --key-file $luks_file
+ fi
+ done
+ fi
+
+ if $rerootfs; then
+ sleep 1
+ bpart ${root_devs[@]}
+ fi
+ sleep 1
+fi
+
+
+if $wipe && [[ $DISTRO != *_bootstrap ]]; then
+ # bootstrap distro doesn't use separate encrypted root.
+ mount -o subvolid=0 ${root_devs[0]} /mnt
+ # systemd creates subvolumes we want to delete.
+ mapfile -t s < <(btrfs subvolume list --sort=-path /mnt |
+ sed -rn "s#^.*path\s*(root_$DISTRO/\S+)\s*\$#\1#p")
+ for subvol in ${s[@]}; do btrfs subvolume delete /mnt/$subvol; done
+ btrfs subvolume set-default 0 /mnt
+ [[ ! -e /mnt/root_$DISTRO ]] || btrfs subvolume delete /mnt/root_$DISTRO
+
+ ## create subvols ##
+ cd /mnt
+
+ btrfs subvolume create root_$DISTRO
+
+ # could set default subvol like this, but no reason to.
+ # btrfs subvolume set-default \
+ # $(btrfs subvolume list . | grep "root_$DISTRO$" | awk '{print $2}') .
+
+ # For raid systems, cow allows for error correction, for non-raid systems,
+ # protects root fs from having the plug pulled. Reprovisioning a root
+ # subvol is not my favorite thing to do.
+ # # no cow on the root filesystem. it's setup is fully scripted,
+ # # if it's messed up, we will just recreated it,
+ # # and we can get better perf with this.
+ # # I can't remember exactly why, but this is preferable to mounting with
+ # # -o nodatacow, I think because subvolumes inherit that.
+ # chattr -Rf +C root_$DISTRO
+ cd /
+ umount /mnt
+fi
+
+mount -o subvolid=0 $first_boot_dev /mnt
+cd /mnt
+btrfs subvolume set-default 0 /mnt # already default, just ensuring it.
+
+# for libreboot systems. grub2 only reads from subvolid=0
+mkdir -p /mnt/grub2
+# todo: this would need some rework if we moved boot into
+# lvm.
+cp $FAI/distro-install-common/libreboot_grub.cfg /mnt/grub2
+
+if $wipe && [[ -e /mnt/$boot_vol ]]; then
+ btrfs subvolume delete /mnt/$boot_vol
+fi
+if [[ ! -e /mnt/$boot_vol ]]; then
+ btrfs subvolume create $boot_vol
+fi
+cd /
+umount /mnt
+## end create subvols ##
+
+mount $first_grub_extdev /mnt
+grub-editenv /mnt/grubenv set did_fai_check=true
+grub-editenv /mnt/grubenv set last_boot=/$boot_vol
+umount /mnt
+
+
+# initial setup of extra data fs, mounted,
+# btrfs subvol create nocow
+# chattr +C nocow
+# chown iank.iank nocow
+
--- /dev/null
+#! /bin/bash
+
+# (c) Michael Goetze, 2010-2011, mgoetze@mgoetze.net
+
+error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
+
+if [ $FAI_ACTION = "install" ]; then
+ ctam
+ [ -L $target/etc/mtab ] || cp /etc/mtab $target/etc/mtab
+
+ cat > $target/etc/sysconfig/network <<-EOF
+ NETWORKING=yes
+ HOSTNAME=$HOSTNAME.$DOMAIN
+ EOF
+ echo "127.0.0.1 localhost" > $target/etc/hosts
+ ifclass DHCPC || ainsl -s /etc/hosts "$IPADDR $HOSTNAME.$DOMAIN $HOSTNAME"
+ cp /etc/resolv.conf $target/etc
+fi
+
+fcopy -riv /etc/yum.repos.d/
+
+# disable the fastestmirror plugin
+#fai-sed 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
+
+skiptask repository
+
+exit $error
--- /dev/null
+#! /bin/bash
+
+# This file is sourced during task_setup
+# you can define your own functions and use them later, for e.g.
+# in scripts/...
+
+
+cleanup_base() {
+
+ rm -f $target/etc/mailname \
+ $target/etc/machine-id \
+ $target/var/lib/dbus/machine-id \
+ $target/var/log/install_packages.list
+
+ > $target/etc/machine-id
+ shred --remove $target/etc/ssh/ssh_host_*
+}
+
+
+cleanup_dpkg_apt() {
+
+ rm -f $target/var/log/alternatives.log \
+ $target/var/log/apt/* \
+ $target/var/log/bootstrap.log \
+ $target/var/log/dpkg.log
+
+ rm -rf $target/var/cache/apt/*
+ rm -rf $target/var/lib/apt/lists/*
+ rm -f $target/var/lib/dpkg/available*
+ rm -f -- $target/var/lib/dpkg/*-old
+}
--- /dev/null
+#! /bin/bash
+
+if [ ! -f $target/etc/resolv.conf ]; then
+ cp /etc/resolv.conf $target/etc
+fi
+
+if [ X$verbose = X1 ]; then
+ echo "Updating base"
+ $ROOTCMD yum -y update |& tee -a $LOGDIR/software.log
+else
+ $ROOTCMD yum -y update >> $LOGDIR/software.log
+fi
+
+$ROOTCMD systemd-machine-id-setup
+
+cat > $target/etc/sysconfig/kernel <<EOF
+# UPDATEDEFAULT specifies if new-kernel-pkg should make
+# new kernels the default
+UPDATEDEFAULT=yes
+
+# DEFAULTKERNEL specifies the default kernel package type
+DEFAULTKERNEL=kernel-core
+EOF
+
+skiptask updatebase
#! /bin/bash
-# use external mirror, remove this script when using a mirror from CD
-
-cat <<EOM > $target/etc/apt/sources.list
-# external mirror
-deb $ubuntumirror/ubuntu $ubuntudist main restricted universe multiverse
-deb $ubuntumirror/ubuntu $ubuntudist-updates main restricted universe multiverse
-deb $ubuntumirror/ubuntu $ubuntudist-security main restricted universe multiverse
-EOM
+# mk-basefile doesn't use the -updates suite, then we unpack it, then we
+# install sources.list that has -updates and we install random
+# packages. It might avoid a problem if we a dist-upgrade first.
+$ROOTCMD apt-get update
+$ROOTCMD apt-get -y dist-upgrade --purge --auto-remove
# https://lists.uni-koeln.de/pipermail/linux-fai/2016-July/011398.html
# In Ubuntu 16.04 (but not 14.04), the locales configuration mechanism has
# hook applies the debconf setting. It must run after FAI's debconf task
# but before dpkg gets a chance to clobber debconf with an empty setting.
+
if [ ! -f "$target/var/lib/locales/supported.d/local" ]; then
- $ROOTCMD debconf --owner=locales sh -c '
+ $ROOTCMD debconf --owner=locales sh -c '
. /usr/share/debconf/confmodule
db_version 2.0
db_get locales/locales_to_be_generated &&
--- /dev/null
+UBUNTU_UP.gpg
\ No newline at end of file
-PACKAGES install-norec
-#cryptsetup-initramfs # needed if you use an encrypted partition
-bash-completion
-debconf-utils
-file
-zstd
-less
-linuxlogo
-rsync
-openssh-client openssh-server
-time
-procinfo
-nullmailer
-sudo
-locales
-console-setup kbd
-pciutils usbutils
-unattended-upgrades
+# otherwise sshd takes like 10 seconds to start.
+# not sure if this applies to bullseye or just buster, installing it so i dun have to worry.
+PACKAGES install BUSTER BULLSEYE BOOKWORM
+haveged
PACKAGES install NONFREE
# you may want these non-free kernel drivers
PACKAGES install-norec CHROOT
linux-image-686-pae-
linux-image-amd64-
+initramfs-tools-core-
+dropbear-initramfs-
PACKAGES install-norec AMD64
${kernelname} # see class/DEBIAN.var
${kernelname} # see class/DEBIAN.var
grub-efi-arm64
-PACKAGES install-norec GRUB_PC
-grub-pc
+# iank this is duplicate with STANDARD.
+#PACKAGES install-norec GRUB_PC
+#grub-pc
-PACKAGES install-norec GRUB_EFI
-grub-efi dosfstools
+#PACKAGES install-norec GRUB_EFI
+#grub-efi dosfstools
PACKAGES install LVM
lvm2
--- /dev/null
+PACKAGES install
+# resolvconf because if we don't install it now we have to reboot for it to
+# take effect. This is explained when you do dpkg-reconfigure resolvconf,
+# and may be fixed in future releases. in newer than flidas, we use
+# systemd-resolved, so this is not needed.
+resolvconf
--- /dev/null
+PACKAGES install
+# needed for bonding
+ifenslave
+# generating luks passwords
+apg
--- /dev/null
+ARAMO.gpg
\ No newline at end of file
--- /dev/null
+UBUNTU_UP.gpg
\ No newline at end of file
--- /dev/null
+PACKAGES dnfgroup
+core
+minimal-environment
+#server-product-environment
+#headless-management
+
+PACKAGES dnfgroup XORG
+graphical-server-environment
+workstation-product-environment
+
+PACKAGES dnfi
+NetworkManager
+dbus-broker # needed by systemd
+chrony
+kernel
+dracut
+less
+openssh
+openssh-clients
+openssh-server
+vim-enhanced
+man
+curl
+unzip
+which
+ncurses ncurses-base
+coreutils-common
+libibverbs # needed for nc, but missing dependency
+
+PACKAGES dnfi GRUB_PC
+grub2-pc
+
+PACKAGES dnfi GRUB_EFI
+grub2-efi
+
+
+PACKAGES dnfi LVM
+lvm2
manpages
mime-support
ncurses-term
-netcat-traditional
openssh-client
pciutils
perl
+python3
+python3-minimal
reportbug
telnet
traceroute
ucf
xz-utils
-python3
-python3-minimal
+# ian standard packages
+# lsof is used in my btrfs util scritps.
+# netcat is used for proxy.
+lvm2
+keyutils
+cryptsetup
+btrfs-progs
+sudo
+bridge-utils
+netcat-openbsd
+lsof
+debconf-utils
+file
+less
+rsync
+openssh-client openssh-server
+time
+procinfo
+console-setup kbd
+pciutils usbutils
+unattended-upgrades
+initramfs-tools-core
+dropbear-initramfs
+apt-transport-https
+# ifupdown because etiona doesnt have it by default
+# and fai scripts want to call ifquery.
+ifupdown
+netplan.io-
+libnss-resolve
+publicsuffix
+iso-codes
+# new package buster/nabia+
+cryptsetup-initramfs
+# for btrbk
+zstd
+# for detecting wireless
+iw
+
+# iank, copied from DEBIAN so it goes into ubuntu too
+PACKAGES install GRUB_PC
+grub-pc
+
+PACKAGES install GRUB_EFI
+# normally would have just grub-efi
+# but theres a dependency problem with it in nabia: for some reason it depends on
+# a version in security, but theres a later version in updates that the system
+# really wants to install.
+grub-efi-amd64 dosfstools
-# the kernel is now defined in DEBIAN
+PACKAGES install I386
+linux-image-generic
+memtest86+
-PACKAGES install
-ubuntu-minimal
-ubuntu-server
+PACKAGES install CHROOT
+linux-image-generic-
+
+PACKAGES install AMD64
+linux-image-generic
+memtest86+
+
+PACKAGES install FLIDAS64 XENIAL64
+linux-image-generic-hwe-8.0
+
+PACKAGES install NABIA64 FOCAL64
+linux-image-generic-
+linux-image-generic-hwe-20.04
PACKAGES install XORG
ubuntu-server-
--- /dev/null
+ian: Ya, for each trisquel release, we need a new key symlink link, or
+new file if the key has changed.
--- /dev/null
+#!/bin/bash -x
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: expected to be root."
+ exit 1
+fi
+
+exit 0
+
+cat >$FAI_ROOT/etc/grub.d/40_custom <<EOF
+#!/bin/sh
+exec tail -n +3 \$0
+# This file provides an easy way to add custom menu entries. Simply type the
+# menu entries you want to add after this comment. Be careful not to change
+# the 'exec tail' line above.
+
+# https://www.coreboot.org/Serial_console # tty
+# but removed unneeded stuff
+
+serial --speed=115200
+terminal_input --append serial
+terminal_output --append serial
+EOF
$ROOTCMD chpasswd --encrypted <<< "root:${ROOTPW}"
elif [ -n "$username" ]; then
$ROOTCMD usermod -L root
- # enable sudo for user
- ainsl /etc/sudoers "$username ALL = ALL"
- if [ ! -f $target/usr/bin/sudo ]; then
- echo "WARNING. Package sudo is not installed"
- fi
fi
exit $error
--- /dev/null
+#!/bin/bash -x
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: expected to be root."
+ exit 1
+fi
+
+m() { printf "%s\n" "$*"; "$@"; }
+
+
+fcopy -riB /root
+
+# in bullseye, installing systemd-resolved says: Converting
+# /etc/resolv.conf to a symlink to
+# /run/systemd/resolve/stub-resolv.conf... which breaks
+# resolution. This happens to be the first script we install a package
+# after that. This should do nothing in a fai-wrapper situation.
+if [[ ! -s $target/etc/resolv.conf ]]; then
+ m ls -la $target/etc/resolv.conf ||:
+ # Keep the symlink in place, systemd-resolved should change the file
+ # when it runs.
+ mkdir -p $target/run/systemd/resolve
+ if [[ ! -s /etc/resolv.conf ]] && ! host google.com; then
+ echo "ERROR: empty resolv.conf & failed dns resolution. exiting 1" >&2
+ exit 1
+ fi
+ cat /etc/resolv.conf >$target/etc/resolv.conf
+fi
+
+
+
+#### misc configurations
+chroot $FAI_ROOT bash <<'EOFOUTER'
+set -xe
+if getent group systemd-journal >/dev/null; then
+ # makes the journal be saved to disk.
+ mkdir -p /var/log/journal
+ chmod 755 /var/log/journal
+fi
+debconf-set-selections <<EOF
+kexec-tools kexec-tools/load_kexec boolean false
+EOF
+
+# This used to be pxe-kexec. For some reason pxe-kexec is not in
+# bookworm. kexec-tools is
+# something pxe-kexec depended on and might be useful.
+# todo: figure out why and get it installed.
+apt-get install -y kexec-tools
+
+# this is usefull. Only thing reason I see this being disabled by default is
+# that a non-root user can disrupt the system, eg cause a reboot.
+sed -i '$a kernel.sysrq=1
+/^kernel.sysrq=/d' /etc/sysctl.conf
+
+EOFOUTER
+
+cmdline_extra="$d16_cmdline $fsf_cmdline_extra"
+
+# luks options, see man systemd-cryptsetup-generator
+# all i know is that with luks.crypttab=no, swap still timed out on boot.
+# and with rd.luks.crypttab=no, it works.
+cmdline="rd.luks.crypttab=no net.ifnames=0 $cmdline_extra"
+
+chroot $FAI_ROOT bash <<EOF
+set -x
+set -eE -o pipefail
+# https://askubuntu.com/questions/33416/how-do-i-disable-the-boot-splash-screen-and-only-show-kernel-and-boot-text-inst
+
+sed -ri 's/(^GRUB_CMDLINE_LINUX_DEFAULT=")quiet/\1/;s/^(GRUB_CMDLINE_LINUX_DEFAULT=".*) quiet([ "])/\1\2/' /etc/default/grub
+sed -ri 's/(^GRUB_CMDLINE_LINUX_DEFAULT=")splash/\1/;s/^(GRUB_CMDLINE_LINUX_DEFAULT=".*) splash([ "])/\1\2/' /etc/default/grub
+
+for arg in $cmdline; do
+ if ! grep "^GRUB_CMDLINE_LINUX_DEFAULT=.*[\" ]\${arg//./\\.}[\" ]" /etc/default/grub; then
+ sed -ri "s/^GRUB_CMDLINE_LINUX_DEFAULT=\"(.*)/GRUB_CMDLINE_LINUX_DEFAULT=\"\$arg \1/" /etc/default/grub
+ fi
+done
+
+if grep -qF "$cmdline" /etc/default/grub; then
+ # already set things, exit
+ exit 0
+fi
+
+# required to show vga grub on d16, at least for t11
+echo GRUB_TERMINAL=console >>/etc/default/grub
+
+
+sed -ri 's/^ *GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="$cmdline"/' /etc/default/grub
+sed -ri 's/^ *GRUB_TIMEOUT_STYLE=.*/GRUB_TIMEOUT_STYLE=menu/' /etc/default/grub
+sed -ri 's/^ *GRUB_TIMEOUT=.*/GRUB_TIMEOUT=6/' /etc/default/grub
+# on xenial, no grub is displayed at all. fix that.
+# found just by noticing this in the config file, and a
+# warning about it in error.log
+sed -i '/^ *GRUB_HIDDEN_TIMEOUT/d' /etc/default/grub
+
+if type -P update-grub2 &>/dev/null; then
+ update-grub2
+else
+ update-grub
+fi
+
+EOF
+
+
+# I prefer to stick with ifup/down or networkmanager: networkd is not in its
+# own package, so cant use in other init systems. b. it works fine.
+chroot $FAI_ROOT bash <<EOF
+systemctl disable systemd-networkd.socket systemd-networkd networkd-dispatcher systemd-networkd-wait-online
+systemctl mask systemd-networkd.socket systemd-networkd networkd-dispatcher systemd-networkd-wait-online
+EOF
# Restore them here.
#
+# note on an ubuntu 16.04 system, these caps were set without this script
+# running. I wonder if it is actually needed on a debian 8 system.
+
set -e
if [ ! -x $target/sbin/setcap ] ; then
+++ /dev/null
-#! /bin/bash
-
-netplan_yaml() {
- # network configuration using ubuntu's netplan.io
- local IFNAME="$1"
- local METHOD="$2"
- echo "Generating netplan configuration for $IFNAME ($METHOD)" >&2
- echo "# generated by FAI"
- echo "network:"
- echo " version: 2"
- echo " renderer: $RENDERER"
- case "$RENDERER" in
- networkd)
- echo " ethernets:"
- echo " $IFNAME:"
- case "$METHOD" in
- dhcp)
- echo " dhcp4: true"
- ;;
- static)
- echo " addresses: [$CIDR]"
- echo " gateway4: $GATEWAYS_1"
- echo " nameservers:"
- echo " search: [$DOMAIN]"
- echo " addresses: [${DNSSRVS// /, }]"
- ;;
- esac
- esac
-}
-
-iface_stanza() {
- # classic network configuration using /etc/network/interfaces
- local IFNAME="$1"
- local METHOD="$2"
- echo "Generating interface configuration for $IFNAME ($METHOD)" >&2
- echo "# generated by FAI"
- echo "auto $IFNAME"
- echo "iface $IFNAME inet $METHOD"
- case "$METHOD" in
- static)
- echo " address $CIDR"
- echo " gateway $GATEWAYS"
- ;;
- esac
-}
-
-newnicnames() {
-
- local name
-
- [ $do_init_tasks -eq 0 ] && return
- [ -z "$NIC1" ] && return
-
- fields="ID_NET_NAME_FROM_DATABASE ID_NET_NAME_ONBOARD ID_NET_NAME_SLOT ID_NET_NAME_PATH"
- for field in $fields; do
- name=$(udevadm info /sys/class/net/$NIC1 | sed -rn "s/^E: $field=(.+)/\1/p")
- if [[ $name ]]; then
- NIC1=$name
- return
- fi
- done
-
- # try to get altname net dev
- name=$(ip link show $NIC1 | awk '/altname / { print $2 }')
- if [[ $name ]]; then
- NIC1=$name
- return
- else
- echo "$0: error: could not find systemd predictable network name. Using $NIC1."
- fi
-}
-
-if [ -z "$NIC1" ]; then
- echo "WARNING: \$NIC1 is not defined. Cannot add ethernet to /etc/network/interfaces."
-fi
-CIDR=$(ip --br ad sh $NIC1|awk '{print $3}')
-newnicnames
-
-case "$FAI_ACTION" in
- install|dirinstall)
- ifclass DHCPC && METHOD=dhcp || METHOD=static
- ifclass XORG && RENDERER=NetworkManager || RENDERER=networkd
-
- if [ -d $target/etc/netplan ]; then
- # Ubuntu >= 17.10 with netplan.io
- if [ -n "$NIC1" ]; then
- netplan_yaml $NIC1 $METHOD > $target/etc/netplan/01-${NIC1}.yaml
- fi
- elif [ -d $target/etc/network/interfaces.d ]; then
- # ifupdown >= 0.7.41 (Debian >= 8, Ubuntu >= 14.04)
- iface_stanza lo loopback > $target/etc/network/interfaces.d/lo
-
- if [ -n "$NIC1" -a ! -f $target/etc/NetworkManager/NetworkManager.conf ]; then
- iface_stanza $NIC1 $METHOD > $target/etc/network/interfaces.d/$NIC1
- fi
- else
- (
- iface_stanza lo loopback
- iface_stanza $NIC1 $METHOD
- ) > $target/etc/network/interfaces
- fi
-
- if ! ifclass DHCPC ; then
- [ -n "$NETWORK" ] && echo "localnet $NETWORK" > $target/etc/networks
- if [ ! -L $target/etc/resolv.conf -a -e /etc/resolv.conf ]; then
- cp -p /etc/resolv.conf $target/etc
- fi
- fi
- ;;
-esac
-
-# here fcopy is mostly used, when installing a client for running in a
-# different subnet than during the installation
-fcopy -iM /etc/resolv.conf
-fcopy -iM /etc/network/interfaces /etc/networks
-
-exit $error
# (c) Thomas Lange, 2001-2016, lange@debian.org
# (c) Michael Goetze, 2010-2011, mgoetze@mgoetze.net
+
+# on ubuntu 16.04 which didn't run this script, some things which didn't
+# apply:
+# /etc/dpkg/dpkg.cfg.d/fai didn't exist,
+# machine-id was already setup.
+
+# on that system and a debian stretch system, after reboot,
+# some things done here don't seem to persist:
+# some thin/etc/mtab is symlink somewhere else,
+# and mailname is $HOSTNAME.lan
+
+# the adjtime thing is to support changing the system clock
+# from representing UTC (the default) to localtime (windows default).
+
+# afaik, the only useful thing here for me is setting /etc/hostname
+
error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
# a list of modules which are loaded at boot time
+++ /dev/null
-#! /bin/bash
-
-# (c) Thomas Lange, 2001-2017, lange@debian.org
-
-error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
-
-ifclass XORG && {
- fcopy -M /etc/X11/xorg.conf
-}
-
-if ifclass UBUNTU; then
- groups="adm cdrom sudo dip plugdev lpadmin sambashare"
- $ROOTCMD addgroup --system lpadmin || true
- $ROOTCMD addgroup --system sambashare || true
-fi
-
-# add additional user account
-if [ -n "$username" ]; then
- if ! $ROOTCMD getent passwd $username ; then
- $ROOTCMD adduser --disabled-password --gecos "$username user" $username
- $ROOTCMD usermod -p "$USERPW" $username
- userdir=$($ROOTCMD getent passwd "$username" | cut -d: -f6 )
-
- # disable xfce question about default or empty panel
- if [ -f $target/etc/xdg/xfce4/panel/default.xml ]; then
- xfdir=$userdir/.config/xfce4/xfconf/xfce-perchannel-xml
- if [ ! -d $target/$xfdir ]; then
- $ROOTCMD mkdir -p $xfdir
- $ROOTCMD cp /etc/xdg/xfce4/panel/default.xml $xfdir/xfce4-panel.xml
- # group name is the same as user name
- $ROOTCMD chown -R $username:$username $userdir/.config
- fi
- fi
-
- for g in $groups; do
- $ROOTCMD adduser $username $g
- done
- fi
-fi
--- /dev/null
+#! /bin/bash
+
+# (c) Thomas Lange, 2022, lange@debian.org
+#
+# Add public ssh key for user root to get login access
+
+error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
+
+SSHDIR=$target/root/.ssh
+AUKEY=$SSHDIR/authorized_keys
+
+# reverse order of classes
+for c in $classes; do
+ revclasses="$c $revclasses"
+done
+
+for c in $revclasses; do
+ if [ -f $FAI/files/root-ssh-key/$c ]; then
+ if [ -f $AUKEY ]; then
+ cmp -s $FAI/files/root-ssh-key/$c $AUKEY
+ if [ $? -eq 0 ]; then
+ exit
+ fi
+ fi
+ if [ ! -d $SSHDIR ]; then
+ mkdir -m 700 $SSHDIR
+ fi
+ cp -v $FAI/files/root-ssh-key/$c $AUKEY
+ chown root:root $AUKEY
+ chmod 700 $AUKEY
+ break
+ fi
+done
+
+exit $error
--- /dev/null
+#!/bin/bash -x
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: expected to be root."
+ exit 1
+fi
+
+
+# this is needed to enable resolvconf, making /etc/resolv.conf be a symlink.
+# why? i dun know, it\'s really dumb.
+dpkg-reconfigure -fnoninteractive resolvconf
--- /dev/null
+#!/bin/bash -x
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: expected to be root."
+ exit 1
+fi
+
+
+sed 's/^/root:/' $FAI/distro-install-common/shadow/community0p | $ROOTCMD chpasswd -e
+
+# todo, need to set static ip here
+if ifclass demohost; then
+ cat > $target/etc/network/interfaces <<EOF
+# generated by FAI
+auto lo eth0
+iface lo inet loopback
+iface eth0 inet dhcp
+iface eth0 inet6 auto
+
+source-directory /etc/network/interfaces.d
+EOF
+else
+ ip6=$(getent ahosts $HOSTNAME |grep ^2001.*RAW| sed 's/ .*//' ||:)
+ gateway6=2001:470:142::1
+
+ # todo: this needs adjustment per machine
+ internal_ip=10.0.0.25/16
+
+ if ip l show dev bond0 &>/dev/null; then
+ cat >$target/etc/network/interfaces <<EOF
+auto lo
+iface lo inet loopback
+
+auto eth0
+allow-bond eth0
+iface eth0 inet manual
+ bond-master bond0
+
+auto eth1
+allow-bond eth1
+iface eth1 inet manual
+ bond-master bond0
+
+auto bond0
+iface bond0 inet static
+ bond-slaves none
+ bond-mode 0
+ bond-miimon 100
+ address $internal_ip
+ pre-up ip link add link bond0 name macvtap-bond0 type macvtap mode bridge
+# no iptables files exist yet
+# post-up iptables-restore < /etc/default/iptables ; ip6tables-restore < /etc/default/ip6tables || :
+
+auto macvtap-bond0
+iface macvtap-bond0 inet static
+ address $CIDR
+ gateway $GATEWAYS
+ post-up ip a add $internal_ip broadcast 10.0.255.255 dev macvtap-bond0
+
+EOF
+
+ # I'm not sure ipv6 works well with the macvtap stuff. todo: research.
+ # anyways, other kvm hosts dont have it enabled.
+ if false && [[ $ip6 ]]; then
+ cat >>$target/etc/network/interfaces <<EOF
+iface bond0 inet6 static
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/bond0/accept_dad
+ address $ip6
+ netmask 48
+ gateway $gateway6
+EOF
+ fi
+
+ else
+ cat > $target/etc/network/interfaces <<EOF
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet static
+address $CIDR
+gateway $GATEWAYS
+EOF
+
+ if [[ $ip6 ]]; then
+ cat >>$target/etc/network/interfaces <<EOF
+iface eth0 inet6 static
+pre-up echo 0 > /proc/sys/net/ipv6/conf/eth0/accept_dad
+address $ip6
+netmask 48
+gateway $gateway6
+EOF
+ fi
+ fi
+fi
+
+# previously had an else condition after
+#elif ifclass VM || ifclass LINODE; then
+# iface $NIC1 inet manual
+# iface br0 inet dhcp
+# bridge_ports $NIC1
+# bridge_stp off
+# bridge_maxwait 0
+# however, on t9, on startup, br0, became
+# rename1 and didn't come up. i dunno why,
+# but the bridge is for vms that I rarely use,
+# so not bothering to figure it out.
+
+
+##### end network setup #####
+
+# note: systemd-resolved + ifupdown causes networking.service to fail in t11,
+# https://bugs.launchpad.net/ubuntu/+source/ifupdown/+bug/1907878
+systemctl disable systemd-resolved
+# rm first to remove any symlink
+rm -f $target/etc/resolv.conf
+
+if ifclass demohost || [[ $GATEWAYS != 209.51.188.* ]]; then
+ cat >$target/etc/resolv.conf <<'EOF'
+nameserver 8.8.8.8
+EOF
+else
+ cat >$target/etc/resolv.conf <<'EOF'
+domain fsf.org
+search fsf.org
+nameserver 209.51.188.16
+nameserver 209.51.188.27
+EOF
+fi
error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
+set -x
# do only execute for Debian and similar distros
if ! ifclass DEBIAN ; then
exit 0
# Check if RAID is used for the boot device
if [[ $BOOT_DEVICE =~ '/dev/md' ]]; then
+ GROOT=$($ROOTCMD grub-probe -tdrive -d $BOOT_DEVICE)
raiddev=${BOOT_DEVICE#/dev/}
# install grub on all members of RAID
for device in $(LC_ALL=C perl -ne 'if(/^'$raiddev'\s.+raid\d+\s(.+)/){ $_=$1; s/\d+\[\d+\]//g; s/(nvme.+?)p/$1/g; print }' /proc/mdstat); do
# remove last ,
mbrdevices=${mbrdevices%, }
else
- mbrdevices=$(get_stable_devname $BOOT_DEVICE)
+ for dev in $BOOT_DEVICE; do
+ mbrdev=$(get_stable_devname $dev)
if [ -z "$mbrdevices" ]; then
- # if we cannot find a persistent name (for e.g. in a VM) use old name
- mbrdevices=$BOOT_DEVICE
+ # if we cannot find a persistent name (for e.g. in a VM) use old name
+ mbrdevices+="$dev, "
fi
- echo "Installing grub on $BOOT_DEVICE = $mbrdevices"
- $ROOTCMD grub-install --no-floppy "$mbrdevices"
+ echo "Installing grub on $dev = $mbrdev"
+ $ROOTCMD grub-install --no-floppy "$mbrdev"
+ done
+ # remove trailing ,
+ mbrdevices=${mbrdevices%, }
fi
echo "grub-pc grub-pc/install_devices multiselect $mbrdevices" | $ROOTCMD debconf-set-selections
--- /dev/null
+#!/bin/bash -x
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: expected to be root."
+ exit 1
+fi
+
+if ! type -t fcopy &>/dev/null; then
+ sudo apt-get -y install fai-client
+fi
+
+# -r = recursive
+# -i = ignore non-matching class warnings, always exit 0
+# -B = no backup files
+fcopy -riB /boot
+# this is also done by FAIBASE/10-misc by default (without B)
+fcopy -riB /usr/local/bin
+
+fcopy -riB /etc/apt/logind.conf.d
+
+# this gets done by fai, but just happens too often that
+# I add sources due to new distros, whatever.
+fcopy -riB /etc/apt/preferences.d
+fcopy -riB /etc/apt/sources.list.d
+
+
+src=$FAI/distro-install-common/shadow
+dst=/q/root/shadow
+if [[ ! -e $dst && -e $src ]]; then
+ # outside of fai context, we skip this
+ mkdir -p $dst
+ mount -o bind $src $dst
+fi
+
+
+
+$FAI/distro-install-common/end
+
+
+
+### begin sources install + updates
+# these get copied in an earlier stage by fai, but leaving it here since
+# I run this as a single post-fai script to update things that have changed.
+tmpfile1=$(mktemp)
+# this can fail if we need an apt update
+$ROOTCMD /usr/bin/apt-cache policy >$tmpfile1 ||:
+fcopy -riB /etc/apt
+
+tmpfile2=$(mktemp)
+$ROOTCMD /usr/bin/apt-cache policy >$tmpfile2
+if ! diff -q $tmpfile1 $tmpfile2; then
+ $ROOTCMD /usr/bin/apt update
+fi
+# outside of fai, this seems to regularly lead to
+# E: Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable)
+# so add a sleep. 1 sec is probably way more than needed.
+sleep 1
+f=$FAI_ROOT/var/cache/apt/pkgcache.bin
+if [[ ! -r $f ]] || (( $(( $(date +%s) - $(stat -c %Y $f ) )) > 60*60*2 )); then
+ i=0
+ while fuser $FAI_ROOT/var/lib/dpkg/lock &>/dev/null; do
+ sleep 1
+ i=$(( i+1 ))
+ if (( i > 300 )); then
+ echo "error: timed out waiting for /var/lib/dpkg/lock" >&2
+ exit 1
+ fi
+ $ROOTCMD apt-get update
+ done
+fi
+### end sources install + updates
+
+
+#### misc configurations
+
+if [[ $FAI_ACTION != dirinstall ]] && ! ifclass NOCRYPT; then
+ if ifclass LINODE; then
+ speed=19200
+ cmdline="rd.luks.crypttab=no net.ifnames=0 console=ttyS0,${speed}n8"
+ else
+ speed=115200
+ cmdline="rd.luks.crypttab=no net.ifnames=0 console=ttyS0,${speed}n8 console=tty0"
+ case $HOSTNAME in
+ kd)
+ fcopy -v /usr/bin/myncq
+
+ cat >$target/etc/systemd/system/myncq.service <<'EOF'
+[Unit]
+Description=fix ncq errors
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/myncq
+TimeoutStartSec=20
+
+[Install]
+# https://www.enricozini.org/blog/2017/debian/systemd-07-devices/
+WantedBy=dev-disk-by\x2did-ata\x2dSamsung_SSD_870_QVO_8TB_S5VUNG0N900656V.device
+EOF
+
+ $ROOTCMD bash <<'EOFOUTER'
+systemctl enable myncq.service
+/usr/bin/myncq no-upgrub
+EOFOUTER
+
+ ;;&
+ # per rubens suggestion to make a d16 more stable
+ kd|kw) cmdline+=" pci=realloc=off" ;;
+ esac
+ fi
+
+fi ##### end != dirinstall && != NOCRYPT
+
+
+###### begin network setup ####
+
+# use old names. the idea of them changing between boots has never
+# happened to me and I usually only have 1 wired or other type.
+# If I ever do need to care about it, I will.
+# Strangely this didn't work on kw, so I added kernel cmdline parameter.
+# https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/
+ln -sf /dev/null $target/etc/systemd/network/99-default.link
+
+
+# bitfolk installer handles the rest
+case $HOSTNAME in
+ bk|je) exit 0 ;;
+esac
+
+
+# bug fix, somewhere between t9's xorg 1.19.6
+# and 1.20.1-3ubuntu2
+# xserver-xorg-video-nouveau 1:1.0.15-3
+# xorg stopped load nouveau
+# https://www.linuxquestions.org/questions/slackware-14/kernel-modules-conflicting-with-nouveau-driver-4175623867/
+# https://nouveau.freedesktop.org/InstallNouveau.html
+# And now in t11, things got worse with a newer card also not loading
+# nouveau when it did in t10.
+if lspci|grep -q 'VGA compatible controller: NVIDIA'; then
+ mkdir -p $target/etc/X11/xorg.conf.d/
+ cat >$target/etc/X11/xorg.conf.d/10-nouveau.conf <<'EOF'
+Section "Device"
+Identifier "Device0"
+Driver "nouveau"
+EndSection
+EOF
+fi
+
+# use networkmanager if this host has wireless.
+if [[ $(iw dev) ]]; then
+ $ROOTCMD bash -xe <<EOF
+apt-get -y install network-manager
+EOF
+
+ # allow networkmanager to manage interfaces
+ #https://bugs.launchpad.net/ubuntu/+source/network-manager/+bug/1638842
+ touch $target/etc/NetworkManager/conf.d/10-globally-managed-devices.conf
+ # in a default desktop install, it looks like netplan creates this file under
+ # run/NetworkManager/conf.d in early boot.
+
+ # By default, dns=default is set in etiona, and dns is just broken.
+ # Maybe with resolvconf it would work, but theres no need for that.
+ # https://wiki.gnome.org/Projects/NetworkManager/DNS
+ cat >$target/etc/NetworkManager/conf.d/99-iank.conf <<'EOF'
+[main]
+dns=systemd-resolved
+EOF
+
+ $FAI/distro-install-common/ethusb-static
+ if [[ $(dig +short @10.2.0.1 -x 10.2.0.2 2>&1 ||:) == kd.b8.nz. ]] \
+ && ip n show 10.2.0.1 | grep . &>/dev/null; then
+ : # we are at home. note: logic duplicated in btrbk-run
+ else
+ $FAI/distro-install-common/ethusb-nm
+ fi
+
+
+else
+ cat > $target/etc/network/interfaces <<-EOF
+# generated by FAI
+auto lo eth0
+iface lo inet loopback
+iface eth0 inet dhcp
+iface eth0 inet6 auto
+
+source-directory /etc/network/interfaces.d
+EOF
+
+ # previously had an else condition after
+ #elif ifclass VM || ifclass LINODE; then
+ # iface $NIC1 inet manual
+ # iface br0 inet dhcp
+ # bridge_ports $NIC1
+ # bridge_stp off
+ # bridge_maxwait 0
+ # however, on t9, on startup, br0, became
+ # rename1 and didn't come up. i dunno why,
+ # but the bridge is for vms that I rarely use,
+ # so not bothering to figure it out.
+
+
+fi
+
+if ifclass LINODE; then
+ mkdir -p $target/etc/initramfs-tools/conf.d
+ cat >$target/etc/initramfs-tools/conf.d/mine <<EOF
+# dhcp in initramfs doesn't work on linode. i dunno why, whatever.
+# man 5 initramfs.conf
+# /usr/share/doc/klibc-utils/README.ipconfig.gz
+# /usr/share/initramfs-tools/scripts/functions
+IP=$linode_ip::$linode_gw:255.255.255.0::eth0:off
+EOF
+
+
+ if [[ $HOSTNAME == li ]]; then
+ cat > $target/etc/network/interfaces <<-EOF
+# generated by FAI
+auto lo eth0
+iface lo inet loopback
+iface eth0 inet dhcp
+# for the standard network config, uncomment this and comment the lines after it.
+#iface eth0 inet6 auto
+
+iface eth0 inet6 static
+# this is really a /128. it seems like we need to assign it for ipv6 to work.
+address 2600:3c00::f03c:91ff:fe6d:baf8/64
+gateway fe80::1
+
+iface eth0 inet6 static
+# from a requested /64 pool
+address 2600:3c00:e000:280::2/64
+
+source-directory /etc/network/interfaces.d
+EOF
+ fi
+fi
+
+
+##### end network setup #####
+
+
+if ifclass VOL_BULLSEYE_BOOTSTRAP || ifclass VOL_BOOKWORM_BOOTSTRAP; then
+ fcopy /etc/systemd/system/faicheck.service
+ $ROOTCMD bash <<'EOFOUTER'
+systemctl enable faicheck.service
+EOFOUTER
+ exit 0 # avoid unnecessary stuff in bootstrap vol
+fi
+
+
+## misc settings
+$ROOTCMD bash <<'EOFOUTER'
+#### begin .ssh setup ###
+set -x
+set -eE -o pipefail
+if ! [[ -s /home/iank/.ssh/authorized_keys ]]; then
+ mkdir -p /home/iank/.ssh
+ f=/root/.ssh/authorized_keys
+ if [[ -e $f ]]; then
+ cp $f /home/iank/.ssh
+ fi
+ chown -R 1000:1000 /home/iank/.ssh
+ chmod -R u=Xrw,og= /home/iank/.ssh
+ rm -rf /root/.ssh
+ # remove broken symlinks or the following cp will fail
+ find /home/iank/.ssh -xtype l -exec rm '{}' \;
+ cp -rL /home/iank/.ssh /root
+ chown -R root:root /root/.ssh
+ chmod 700 /root/.ssh
+fi
+
+# old link from
+# # https://ticktockhouse.svbtle.com/my-obligatory-ubuntu-ssh-agent-post
+# but that made a service that started too soon and didn't pick up our
+# x env vars. instead, copy from the root ssh-agent just the
+# appropriate things into a new service.
+
+rm -f /home/iank/.local/share/systemd/user/sshaiank.service \
+ /home/iank/.config/systemd/user/default.target.wants/sshaiank.service
+
+#### end .ssh setup ###
+
+## duplicated in ssh-emacs-setup
+# done here so its setup earlier for convenience
+line='AcceptEnv INSIDE_EMACS BRC COLUMNS'
+f=/etc/ssh/sshd_config
+grep -xFq "$line" $f || tee -a $f <<<"$line"
+
+
+# default debian groups (jessie through buster) + adm, root, admin
+for g in cdrom floppy audio dip video plugdev netdev adm sudo admin; do
+ if getent group $g >/dev/null; then
+ usermod -aG $g iank
+ fi
+done
+
+if getent group systemd-journal >/dev/null; then
+ usermod -aG systemd-journal iank
+fi
+EOFOUTER
+
+rm -f $target/etc/resolv.conf
+ln -s ../run/systemd/resolve/stub-resolv.conf $target/etc/resolv.conf
+# needed for bitfolk image
+if [[ -e /a/bin/fai/fai-wrapper ]]; then
+ systemctl enable systemd-resolved
+ systemctl start systemd-resolved
+fi
+
+
+
+# reading through the groups that iank is in but user2 isn't,
+for g in plugdev audio video cdrom; do
+ $ROOTCMD usermod -a -G $g user2
+done
+
+
+## begin get new kernel and btrfs-progs ##
+case $HOSTNAME in
+ sy|so)
+ $FAI/distro-install-common/install-stable-kernel-debs
+ ;;
+ *)
+ $ROOTCMD apt-get -y install linux-libre
+ ;;
+esac
+
+pre=https://mirrors.edge.kernel.org/pub/linux/kernel/people/kdave/btrfs-progs
+tarball=$(curl -s $pre/sha256sums.asc \
+ | awk '$2 ~ /^btrfs-progs-v/ { print $2 }' | grep -v -- -rc | grep "^btrfs-progs-v.*gz\$" | sort -V | tail -n1)
+url="$pre/$tarball"
+dir=${tarball%.tar.gz}
+ver=${dir#btrfs-progs-}
+cur_ver=$($ROOTCMD btrfs --version 2>/dev/null | awk '{print $2}') ||:
+
+if [[ $FAI_ROOT == / ]]; then
+ bp_dir=/a/opt/btrfs-progs-release
+else
+ bp_dir=$FAI/distro-install-common/btrfs-progs-release
+fi
+if [[ $ver != "$cur_ver" ]]; then
+ if [[ $ver != "$($bp_dir/btrfs --version 2>/dev/null | awk '{print $2}')" ]]; then
+ cd $target/tmp
+ wget $url
+ tar xzf $tarball
+ $ROOTCMD apt-get -y build-dep btrfs-progs
+ # no docs cuz I didn't want to bother fixing error of missing docs dependencies
+ $ROOTCMD bash -xe <<EOF
+cd /tmp/${tarball%.tar.gz}
+./configure --disable-documentation
+make
+make install
+EOF
+ # If our desktop is HOST2, will we btrbk this latest bprogs to other
+ # machines.
+ if [[ -s /a/bin/bash_unpublished/source-state ]]; then
+ source /a/bin/bash_unpublished/source-state
+ fi
+ if [[ $HOST2 == "$HOSTNAME" && $FAI_ROOT != / ]]; then
+ rm -rf $bp_dir
+ chown -R iank:iank $target/tmp/${tarball%.tar.gz}
+ mv $target/tmp/${tarball%.tar.gz} $bp_dir
+ fi
+ else
+ if ! $ROOTCMD dpkg -s -- build-essential 2>&1 | grep -Fx "Status: install ok installed" &>/dev/null; then
+ $ROOTCMD apt-get -y install build-essential
+ fi
+
+ if [[ $FAI_ROOT == / ]]; then
+ cd /a/opt/btrfs-progs-release
+ make install
+ else
+ mkdir -p $target/tmp/bprogs
+ mount -o bind $bp_dir $target/tmp/bprogs
+ $ROOTCMD bash -xe <<EOF
+cd /tmp/bprogs
+make install
+EOF
+ fi
+ fi
+fi
+## end get new kernel and btrfs-progs ##
echo ERROR: You want to add cryptsetup-initramfs or dracut to some package_config file.
fi
+ # note, if we used dm for crypt, not lvm, so would givee false positive. todo, send patch to fix
usedm=$(dmsetup ls 2>/dev/null | egrep -v '^live-rw|^live-base|^No devices found' | wc -l)
if [ $usedm -ne 0 ]; then
if [ ! -d $target/etc/lvm ]; then
fi
# Make sure everything is configured properly
-if ifclass DEBIAN ; then
+if ifclass DEBIAN || ifclass UBUNTU; then
$ROOTCMD apt-get -f install -y
fi
return
fi
- dists="jessie stretch buster bullseye bookworm trixie forky noble jammy focal bionic xenial trusty"
+ dists="jessie stretch buster bullseye bookworm trixie forky noble jammy focal bionic xenial trusty aramo nabia etiona"
for d in $dists; do
if grep -iq $d $target/etc/os-release; then
release=$d
--- /dev/null
+#! /bin/bash
+
+# create an initrd for booting from ISO
+
+# get highest kernel version
+ver=$(ls -r1 $target/boot/initrd.img-*|tail -1| sed 's/.\+initrd.img-//')
+if [ -z "$ver" ]; then
+ echo "ERROR: no initrd found in $0"
+ exit 9
+fi
+
+rm $target/boot/initrd.img-$ver
+$ROOTCMD dracut -N --zstd --filesystems ext4 -a "dmsquash-live " -o"btrfs crypt dash lvm resume usrmount modsign mdraid shutdown virtfs" /boot/initrd.img-$ver $ver
+
+echo ISO initrd was created
--- /dev/null
+#! /bin/bash
+
+# this is defined in hooks/subroutines
+cleanup_dpkg_apt
+cleanup_base
+
+echo cleanup for live ISO done
--- /dev/null
+#! /bin/bash
+
+# (c) Michael Goetze, 2010-11, mgoetze@mgoetze.net
+# Thomas Lange, 2015-2020
+
+error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
+
+$ROOTCMD usermod -p $ROOTPW root
+
+fcopy -v /etc/selinux/config
+$ROOTCMD fixfiles onboot # this fixes the SELinux security contexts during the first boot
+chmod a+rx $target
+
+exit $error
--- /dev/null
+#! /bin/bash
+
+# (c) Michael Goetze, 2010-2011, mgoetze@mgoetze.net
+# (c) Thomas Lange, 2011, Uni Koeln
+
+error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
+
+ainsl -v /etc/fstab "proc /proc proc defaults 0 0"
+ainsl -v /etc/fstab "sysfs /sys sysfs auto 0 0"
+
+version=$($ROOTCMD rpm -qv kernel | cut -d- -f2-)
+
+
+if [ -f $target/etc/lvm/lvm.conf ]; then
+ fai-sed 's/use_lvmetad = 1/use_lvmetad = 0/' /etc/lvm/lvm.conf
+ ainsl -av /etc/dracut.conf.d/fai.conf 'add_dracutmodules+=" lvm "'
+fi
+
+
+# add filesystem driver into initrd
+ainsl -av /etc/dracut.conf.d/fai.conf 'filesystems+=" ext4 "'
+$ROOTCMD dracut -v --kver $version --force
+
+
+exit $error
--- /dev/null
+#! /bin/bash
+
+# (c) Michael Goetze, 2011, mgoetze@mgoetze.net
+# (c) Thomas Lange 2014
+
+error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
+
+if [ -r $LOGDIR/disk_var.sh ] ; then
+ . $LOGDIR/disk_var.sh
+else
+ echo "disk_var.sh not found!"
+ exit 1
+fi
+
+
+# CentOS 7 does not have a device.map file, so generate one
+if [ -d $target/boot/grub2 -a ! -f $target/boot/grub2/device.map ]; then
+ echo "# Generated by FAI" >> $target/boot/grub2/device.map
+ centosdisks=$(awk '/[sv]d.$/ {print $4}' /proc/partitions | sort)
+ dcount=0
+ for d in $centosdisks; do
+ echo "(hd$dcount) /dev/$d" >> $target/boot/grub2/device.map
+ dcount=$((dcount + 1))
+ done
+fi
+
+bootdev=$(device2grub $BOOT_DEVICE)
+bootpart=$(device2grub $BOOT_PARTITION)
+version=$($ROOTCMD rpm -qv kernel | cut -d- -f2-)
+
+if grep '[[:space:]]/boot[[:space:]]' $LOGDIR/fstab; then
+ bootdir=''
+else
+ bootdir='/boot'
+fi
+
+mount -o bind /dev $target/dev
+
+if [ -f $target/usr/sbin/grub2-install ]; then
+
+ # CentOS 7
+ $ROOTCMD grub2-install --no-floppy "$BOOT_DEVICE"
+ $ROOTCMD grub2-mkconfig --output=/boot/grub2/grub.cfg
+else
+
+$ROOTCMD grub-install --just-copy
+
+$ROOTCMD grub --device-map=/dev/null --no-floppy --batch <<-EOF
+ device $bootdev $BOOT_DEVICE
+ root $bootpart
+ setup $bootdev
+ quit
+ EOF
+
+ln -s ./menu.lst $target/boot/grub/grub.conf
+
+if [ -f $target/boot/grub/splash.xpm.gz ]; then
+ pretty="splashimage=$bootpart$bootdir/grub/splash.xpm.gz"
+else
+ pretty="color cyan/blue white/blue"
+fi
+
+title=$(head -1 $target/etc/redhat-release)
+
+cat > $target/boot/grub/grub.conf <<-EOF
+ timeout 5
+ default 0
+ $pretty
+ hiddenmenu
+
+ title $title
+ root $bootpart
+ kernel $bootdir/vmlinuz-$version root=$ROOT_PARTITION ro
+ initrd $bootdir/initramfs-$version.img
+ EOF
+
+fi
+
+umount $target/dev
+
+echo ""
+echo "Grub installed on $BOOT_DEVICE = $bootdev"
+echo "Grub boot partition is $BOOT_PARTITION = $bootpart"
+echo "Root partition is $ROOT_PARTITION"
+echo "Boot kernel: $version"
+
+exit $error
--- /dev/null
+#! /bin/bash
+
+# (c) Michael Goetze, 2011, mgoetze@mgoetze.net
+
+error=0 ; trap "error=$((error|1))" ERR
+
+cat > $target/etc/sysconfig/clock <<-EOF
+ UTC=$UTC
+ ZONE=$TIMEZONE
+ EOF
+cat > $target/etc/sysconfig/i18n <<-EOF
+ LANG="$DEFAULTLOCALE"
+ SUPPORTED="$SUPPORTEDLOCALE"
+ SYSFONT="$CONSOLEFONT"
+ EOF
+cat > $target/etc/sysconfig/keyboard <<-EOF
+ KEYBOARDTYPE="pc"
+ KEYTABLE="$KEYMAP"
+ EOF
+
+# can not be used, because we still not use systemd in FAI
+# $ROOTCMD localectl set-locale LANG=$DEFAULTLOCALE
+
+cat > $target/etc/locale.conf <<-EOF
+ LANG="$DEFAULTLOCALE"
+ EOF
+if [ -f $target/usr/lib/locale/locale-archive.tmpl \
+ -a ! -s $target/usr/lib/locale/locale-archive ]; then
+ mv $target/usr/lib/locale/locale-archive.tmpl $target/usr/lib/locale/locale-archive
+fi
+
+fcopy -iv /etc/sysconfig/i18n /etc/sysconfig/keyboard
+
+exit $error
+
--- /dev/null
+#! /bin/bash
+
+error=0 ; trap "error=$((error|1))" ERR
+
+ifcfg_config() {
+
+ cat > $target/etc/sysconfig/network-scripts/ifcfg-$NIC1 <<-EOF
+ # generated by FAI
+ TYPE=Ethernet
+ PROXY_METHOD=none
+ BOOTPROTO=dhcp
+ DEFROUTE=yes
+ BROWSER_ONLY=no
+ IP4_FAILURE_FATAL=no
+ IPV6INIT=no
+ IPV6_AUTOCONF=no
+ NAME=$NIC1
+ DEVICE=$NIC1
+ ONBOOT=yes
+ EOF
+}
+
+nm_config() {
+
+ uuid=$(uuidgen)
+
+ cat > $target/etc/NetworkManager/system-connections/${NIC1}.nmconnection << EOF
+
+# generated by FAI
+[connection]
+id=$NIC1
+uuid=$uuid
+type=ethernet
+autoconnect-priority=-999
+interface-name=$NIC1
+
+[ethernet]
+
+[ipv4]
+method=auto
+
+[ipv6]
+addr-gen-mode=eui64
+method=auto
+
+[proxy]
+EOF
+
+ chmod 600 $target/etc/NetworkManager/system-connections/${NIC1}.nmconnection
+}
+
+
+
+# determine predictable network names
+fields="ID_NET_NAME_FROM_DATABASE ID_NET_NAME_ONBOARD ID_NET_NAME_SLOT ID_NET_NAME_PATH"
+for field in $fields; do
+ name=$(udevadm info /sys/class/net/$NIC1 | sed -rn "s/^E: $field=(.+)/\1/p")
+ if [[ $name ]]; then
+ NIC1=$name
+ break
+ fi
+done
+if [[ ! $name ]]; then
+ echo "$0: error: could not find systemd predictable network name. Using $NIC1."
+fi
+
+if [ $FAI_ACTION != "softupdate" ] && ifclass DHCPC; then
+ . $target/etc/os-release
+ major=$(echo ${VERSION_ID} | awk -F '.' '{ print $1 }')
+
+ if [ $major -lt 9 ]; then
+ ifcfg_config
+ else
+ nm_config
+ fi
+fi
+
+fcopy -iv /etc/sysconfig/network /etc/resolv.conf /etc/networks
+fcopy -ivr /etc/sysconfig/network-scripts
+
+exit $error
--- /dev/null
+#! /bin/bash
+
+error=0 ; trap "error=$((error|1))" ERR
+
+# add a $username user account
+if [ -n "$username" ]; then
+ if ! $ROOTCMD getent passwd $username ; then
+ $ROOTCMD adduser -c "$username user" $username
+ $ROOTCMD usermod -p "$USERPW" $username
+ fi
+fi
+
+# enable graphical login screen, make run level 5 as default
+if [ -f $target/usr/sbin/gdm ]; then
+ fai-sed 's/id:3:initdefault:/id:5:initdefault:/' /etc/inittab
+ # do not run this tool
+ echo "RUN_FIRSTBOOT=NO" > $target/etc/sysconfig/firstboot
+fi
+
+exit $error
+
--- /dev/null
+#! /bin/bash
+
+$ROOTCMD yum clean all
#! /bin/bash
+# iank: we already set mirrors, i dont want to have to add "external mirror"
+# to every sources.list. Leaving the rest of this file so future merges will flag up
+# changes easier
+exit 0
+
# check if we already use an external mirror
grep -q "external mirror" $target/etc/apt/sources.list && exit 0
cat <<EOM > $target/etc/apt/sources.list
# external mirror
-deb $ubuntumirror/ubuntu $ubuntudist main restricted universe multiverse
-deb $ubuntumirror/ubuntu $ubuntudist-updates main restricted universe multiverse
-deb $ubuntumirror/ubuntu $ubuntudist-security main restricted universe multiverse
+deb $ubuntumirror/ubuntu $ubuntudist main universe
+deb $ubuntumirror/ubuntu $ubuntudist-updates main universe
+deb $ubuntumirror/ubuntu $ubuntudist-security main universe
EOM
--- /dev/null
+#!/bin/bash
+
+readonly this_file="$(readlink -f -- "${BASH_SOURCE[0]}")"
+script_dir="${this_file%/*}"
+# shellcheck source=./bash-trace
+source "${script_dir}/bash-trace"
+cd $script_dir
+source "${script_dir}/bash-trace"
+
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/}
+Disable the fai nfs server exports
+EOF
+ exit $1
+}
+
+if [[ $1 ]]; then
+ usage 1
+fi
+
+
+
+faiserver_addr=$(host faiserver | sed -rn 's/^\S+ has address //p;T;q' ||:)
+if ip a | grep "^ *inet.\? $faiserver_addr" &>/dev/null; then
+ echo "$0: disabling fai nfs exports or apache site"
+ ./faiserver-disable-local
+else
+ echo "$0: sshing to $(chost faiserver) to disable fai nfs exports or apache site"
+ ssh root@$(chost faiserver) bash <faiserver-disable-local
+fi
--- /dev/null
+#!/bin/bash
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/}
+Disable the fai nfs server exports
+EOF
+ exit $1
+}
+
+if [[ $1 ]]; then
+ usage 1
+fi
+
+
+if modprobe nfsd &>/dev/null; then
+ sed -ri --follow-symlinks '\%^/srv/fai/%d' /etc/exports
+ exportfs -ra
+else
+ rm -f /etc/apache2/sites-enabled/faiserver.conf
+ systemctl reload apache2
+fi
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2019 Ian Kelling
+# SPDX-License-Identifier: AGPL-3.0-or-later
+set -x
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+cd ${x%/*}
+
+usage() {
+ cat <<EOF
+usage: ${0##*/} [-h|--help]
+Create a vm which is a fai server.
+
+This assumes you've set the dhcp server to make 52:54:00:56:09:f9 be
+faiserver. That mac is a randomly generated one in the libvirt range.
+
+WARNING: has hardcoded IP and name for for my local lan
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+esac
+
+err-cleanup() { pxe-server :; }
+./debian-pxe-preseed -i 10.0.0.1 -u iank -g vda
+
+name=faiserver
+s virshrm $name ||:
+
+f=/var/lib/libvirt/images/${name}
+s qemu-img create -o preallocation=metadata -f qcow2 $f 30G
+
+# uniq because virt-viewer spams me with pointless gtk warnings
+s virt-install --os-variant debian8 --cpu host -n $name --pxe -r 1024 --vcpus 1 \
+ --disk $f -w bridge=br0,mac=52:54:00:56:09:f9 |& sed "/^ *$/d" | uniq &
+
+sleep $((60*6)) # takes like 10x as long as a fai install!
+
+opts="-oStrictHostKeyChecking=false -oUserKnownHostsFile=/dev/null"
+while ! scp $opts faiserver-setup root@faiserver:; do
+ sleep 5
+done
+
+# note: with a vm, pxe boot is turned off in the bios after it's first reboot.
+err-cleanup() { :; }
+./pxe-server
+
+ssh $opts root@faiserver ./faiserver-setup
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2018 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+
+usage() {
+ cat <<'EOF'
+usage: ${0##*/} [-h|--help] [BASE_CODENAME] [ARCH]
+install fai-server on the current machine
+
+Initial setup of a fai server. works on localhost. Set's the current ip
+as the tftp server. I vaguely remember that using a hostname does not
+work. Separate from running this, faiserver needs to be setup in dns to
+point to whatever host this is run on.
+
+Default BASE_CODENAME is bookworm. Default ARCH is 64. The script expects corresponding
+$BASEFILE_DIR/${UPCASED_BASE_CODENAME}${ARCH}.tar.(zst|xz) to exist, and it must have been
+generated around the same time as the nfsroot, at least so it has the
+same kernel version.
+
+for copying and running this on a remote server,
+scp -tPrl fai SERVER:
+scp $(readlink -f ~/.ssh/home.pub) SERVER:.ssh
+scp /a/bin/cedit/cedit SERVER:/usr/local/bin
+# todo: make the above key be an option
+
+
+Note: there is a bug in 5.9.4, fixed by adding
+ sleep 2
+
+Note: in t9, there is a bug in recent fai packages (eg 2021+), where
+ unshare uses a too new argument. I was able to fix it by
+ just going to the site of the error and changing unshare to
+ chroot like it used to be, but I'm not bothering to make
+ any persistent fix, since I'm now on t10. If it ever came
+ up again, using an old fai package would also work.
+ /usr/sbin/fai-make-nfsroot:503, before apt-get update
+
+
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+esac
+
+
+e() { echo "+ $@"; "$@"; }
+
+
+base=${1:-bookworm}
+arch=${2:-64}
+
+if [[ $base == [[:upper:]] ]]; then
+ echo $0: error: use lowercase base
+ exit 1
+fi
+
+basefile=($BASEFILE_DIR/${base^^}${arch^^}.tar.zst)
+sed="sed -ri --follow-symlinks"
+
+if [[ ! -e $basefile ]]; then
+ printf "%s\n" "$0: error basefile=$basefile does not exist" >&2
+ exit 1
+fi
+
+if [[ ! -d $BASEFILE_DIR ]]; then
+ printf "%s\n" "$0: error BASEFILE_DIR=$BASEFILE_DIR does not exist" >&2
+ exit 1
+fi
+
+
+if ! type -p wget &>/dev/null; then
+ apt-get install -y wget
+fi
+
+armhf() {
+ [[ $(dpkg --print-architecture) == armhf ]]
+}
+
+# fai on ubuntu only has official support using the universe repo, but newer
+# tends to have less bugs.
+wget -O - https://fai-project.org/download/fai-project.gpg | sudo dd of=/etc/apt/trusted.gpg.d/fai-project.gpg
+
+update=false
+case $base in
+ stretch|buster|bullseye|bookworm)
+ if ! grep -qFx "deb https://fai-project.org/download $base koeln" /etc/apt/sources.list.d/fai.list; then
+ update=true
+ fi
+ cat >/etc/apt/sources.list.d/fai.list <<EOF
+deb https://fai-project.org/download $base koeln
+EOF
+ ;;
+ *)
+ echo "$0: error: script needs updating for new base" >&2
+ exit 1
+ ;;
+esac
+
+f=/var/cache/apt/pkgcache.bin;
+if [[ -r $f ]]; then
+ cachetime=$(stat -c %Y $f );
+ now=$(date +%s)
+ limittime=$(( now - 60*60*2 ))
+ if (( cachetime > limittime )); then
+ update=true
+ fi
+fi
+
+if $update; then
+ apt-get update
+fi
+
+# Relevant packages from fai-quickstart depends and fai-server recommends.
+# I especially do not wait isc-dhcp-server or an inetd. Also excludes
+# nfs-kernel-server. On an android chroot, we don\'t have nfs in the
+# kernel, or the ability to install it.
+# xorriso is for running fai-cd -a, not strictly need for fai-server
+# perl-tk is for fai-monitor-gui
+# mtools is for fai-cd
+pkgs=(fai-doc tftpd-hpa tar reprepro squashfs-tools binutils xorriso perl-tk mtools)
+if modprobe nfsd &>/dev/null; then
+ pkgs+=(nfs-kernel-server)
+else
+ pkgs+=(apache2)
+fi
+
+
+e apt-get install -y ${pkgs[@]}
+# confnew since we edit /etc/fai/NFSROOT in an automated way
+# fai-client is already a fai-server dependency, but make sure it gets upgraded
+e apt-get install --no-install-recommends -y -o Dpkg::Options::=--no-force-confdef -o Dpkg::Options::=--force-confnew fai-server fai-client
+
+r=http://http.us.debian.org/debian
+# like default, but scrap httpredir, and nonfree.
+# All my systems should be able to get along without nonfree
+# for a base working system afaik.
+
+cat >/etc/fai/apt/sources.list <<EOF
+deb $r $base main contrib
+EOF
+
+### begin setup security repo ###
+case $base in
+ stretch|buster)
+ cat >>/etc/fai/apt/sources.list <<EOF
+deb http://security.debian.org/debian-security $base/updates main contrib
+EOF
+ ;;
+ *)
+ # new naming convention
+ cat >>/etc/fai/apt/sources.list <<EOF
+deb http://security.debian.org/debian-security $base-security main contrib
+EOF
+esac
+### end setup security repo ###
+
+
+cat >>/etc/fai/apt/sources.list <<EOF
+# use fai repo. it's commented in the defaults. it's got bug fixes.
+# and may contain newer packages.
+deb http://fai-project.org/download $base koeln
+EOF
+
+## Get latest kernel and btrfs for dealing with btrfs issues.
+# if [[ $base == buster ]]; then
+# cat >>/etc/fai/apt/sources.list <<'EOF'
+# deb http://ftp.debian.org/debian buster-backports main
+# EOF
+# # note, fai doesn\'t look at /etc/fai/apt/preferences.d
+# cat >/etc/fai/apt/preferences <<'EOF'
+# Package: linux-* firmware-linux-free btrfs-progs
+# Pin: release a=buster-backports
+# Pin-Priority: 500
+# EOF
+# fi
+
+
+if [[ -s /q/root/shadow/standard ]]; then
+ $sed -f - /etc/fai/nfsroot.conf <<EOF
+$ a FAI_ROOTPW='$(</q/root/shadow/standard)'
+/^\s*FAI_ROOTPW/d
+EOF
+fi
+
+$sed -f - /etc/fai/nfsroot.conf <<EOF
+$ a SSH_IDENTITY=/root/.ssh/home.pub
+/^\s*SSH_IDENTITY/d
+s,^( *FAI_DEBOOTSTRAP=).*,\1"$base $r",
+# add --arch amd64. this is needed on arm system which is
+# used to install amd64 clients. On amd64 servers, it's redundant.
+# disabled for now, since creating fai nfsroot on my arm machine
+# is not working
+#/--arch amd64/!s/^(\s*FAI_DEBOOTSTRAP_OPTS=")/\1--arch amd64 /
+EOF
+
+$sed 's/#LOGUSER/LOGUSER/' /etc/fai/fai.conf
+$sed -i '/^LOGUSER=/d' /etc/fai/fai.conf
+$sed -i '/^FAI_FLAGS=/d' /etc/fai/fai.conf
+echo "FAI_FLAGS=verbose" >>/etc/fai/fai.conf
+# note if this isnt set, the user isnt created
+echo "LOGUSER=fai" >>/etc/fai/fai.conf
+
+# from man fai-make-nfsroot,
+# figured out after partitioning ignored my crypt partition
+
+
+cedit /etc/fai/NFSROOT <<'EOF' || [[ $? == 1 ]]
+# inserted by faserver-setup
+PACKAGES install
+cryptsetup
+# default one is linux-image-server, doesnt exist anymore
+linux-image-amd64
+# default is btrfs-tools which doesnt exist anymore
+btrfs-progs
+iw
+# got an error in error.log about not having gpg.
+# system seemed to still install ok, so i havent tested if this fixes it.
+gpg
+EOF
+
+if armhf; then
+ cd /srv/fai
+ e rm -rf nfsroot
+ e tar Jxf $basefile
+ # background: Can't build the nfsroot on my arm system now. First,
+ # fai-make-nfsroot won't work out of the box. One idea to make it work
+ # is by installing qemu-user-static, then copying qemu-x86_64-static
+ # into the nfsroot, and prepending it to chroot commands in
+ # fai-make-nfsroot, but that fails in odd ways. ls has permissions
+ # problems on reading directories, various programs segfault
+ # immediately, cat can't open a file, etc.
+
+ NFSROOT=/srv/fai/nfsroot
+ TFTPROOT=/srv/tftp/fai
+
+ # test if our copy of setup_tftp has changed in fai-make-nfsroot,
+ # and if not, run it.
+ setup_tftp(){
+
+ # tftp environment
+ local pxebin
+
+ # jessie+ path
+ pxebin=$NFSROOT/usr/lib/syslinux/pxelinux.0
+
+ rm -f $NFSROOT/boot/*.bak
+ mkdir -p $TFTPROOT/pxelinux.cfg
+ if ! chmod a+r $NFSROOT/boot/initrd.img-*; then
+ echo "$0: error: No initrd was created. Check the package name of the linux-image package in /etc/fai/NFSROOT."
+ exit 1
+ fi
+ cp -p $v $NFSROOT/boot/vmlinu?-* $NFSROOT/boot/initrd.img-* $TFTPROOT
+ cp -u $pxebin $TFTPROOT
+ if [ -f $NFSROOT/usr/lib/syslinux/modules/bios/ldlinux.c32 ]; then
+ cp -u $NFSROOT/usr/lib/syslinux/modules/bios/ldlinux.c32 $TFTPROOT
+ fi
+ if [ X$verbose = X1 ]; then
+ echo "TFTP environment prepared. Enable DHCP and start the TFTP daemon on root $TFTPROOT."
+ fi
+ }
+ diff -u <(type setup_tftp) <(cat <(sed -n '/^setup_tftp(){/,/^}/p' $(which fai-make-nfsroot) ) - <<'EOF' |bash
+type setup_tftp
+EOF
+ )
+ e setup_tftp
+
+ # -g causes skipping set_root_pw() in fai-make-nfsroot, -ag
+ # is the only way to make it run without chrooting. the options
+ # seem contradictory, but it works.
+ e fai-setup -evag
+
+else # not armhf
+ # note, this copies the -B arg to
+ # /srv/fai/nfsroot/var/tmp/base.tar.xz
+ e fai-setup -evf -B $basefile
+ # fai-setup expert mode avoids writing to /var/log/fai/variables
+ # at least config_src is needed for autodiscover
+
+
+ # lld /var/log/fai/remote-logs:
+ # d 750 fai nogroup 100 08-07 08:51 pm /var/log/fai/remote-logs
+ # We could change the group or something, but why not just give me more permissions :)
+ e usermod -a -G nogroup iank
+ $sed '/^FAI_CONFIGDIR|^FAI_CONFIG_SRC|^LOGUSER/d' /var/log/fai/variables
+ tee -a /var/log/fai/variables <<'EOF'
+LOGUSER=fai
+FAI_CONFIGDIR=/srv/fai/config
+FAI_CONFIG_SRC=nfs://faiserver/srv/fai/config
+EOF
+ # make the faiserver also the apt proxy server
+ # apt-get -y install apt-cacher-ng
+fi
+
+rm -f /srv/fai/nfsroot/root/.ssh/known_hosts
+if [[ $HOSTNAME == kd ]]; then
+ keyscan_arg="-p 8989"
+fi
+key=$(ssh-keyscan $keyscan_arg localhost |& grep -o "ecdsa-sha2-nistp256.*")
+for ip in faiserver $(ip addr show up| grep -w '^ *inet' | awk '{print $2}'| cut -d / -f 1 | grep -vF 127.0.0.1); do
+ echo "$ip $key" >>/srv/fai/nfsroot/root/.ssh/known_hosts
+done
+
+# make it the root because pxe-kexec only looks there.
+# It wouldn't be too hard to change if we needed.
+# We could also just dump things in /srv/tftp, but fai
+# has some defaults, which I don't even use, which expect
+# the other directory, so it's kind of a tossup, whatever.
+# This means fai's example isc-dhcp-server filename directory should remove the fai/ prefix.
+sed -ri 's,^ *(TFTP_DIRECTORY=).*,\1"/srv/tftp/fai",' /etc/default/tftpd-hpa
+systemctl restart tftpd-hpa
+
+
+# serial console
+# mainly from
+# https://wiki.archlinux.org/index.php/working_with_the_serial_console
+# at runtime, running this from ssh worked:
+# https://unix.stackexchange.com/questions/242778/what-is-the-easiest-way-to-configure-serial-port-on-linux
+# stty -F /dev/ttyS0 115200 cs8 -cstopb -parenb
+# /sbin/agetty 115200 ttyS0 linux
+# dated info, but validation that this might work on debian:
+# https://help.ubuntu.com/community/SerialConsoleHowto
+# note in the nfsroot, systemd is not running.
+echo "c0:2345:respawn:/sbin/agetty 115200 ttyS0 linux" >>/srv/fai/nfsroot/etc/inittab
+
+# initially did the basic fai-chboot -Iv $std_arg default
+# but found in console that it wanted to mount nfsroot
+# to be the same as my dhcp server.
+# Figured out to change the root= parameter from googling,
+# and seeing fai-chboot -L
+# using hostname failed.
+# for -f, combined the 2 defaults so it will reboot and print to screen.
+
+# Add debug to -f flag for more verbose output.
+
+
+# background on choosing apt-cacher-ng:
+# googling around a bit finds 2 main solutions:
+# http://askubuntu.com/questions/3503/best-way-to-cache-apt-downloads-on-a-lan
+# apt-cacher-ng doesn\'t have zeroconf.
+# It touts having minimal dependencies, but I don\'t care.
+# The downside to squid-deb-proxy is that it\'s config is for specific repos,
+# you have to add all the repos you use.
+# That is the main reason I use apt-cacher-ng.
+# It has a web portal, at http://faiserver:3142/acng-report.html
+
+
+# random fai note: as far as I can tell, profiles are just for putting
+# in a selectable boot menu, which I don\'t want.
+
+# the logsave prompted because the hostname faiserver was uknown.
+# Here it was faiserver.lan when running from a faiserver vm.
+# When running from a normal host with faiserver alias, it was the normal hosts name.
+$sed 's/(^[^,]+,)\S+/\1faiserver/' /srv/fai/nfsroot/root/.ssh/known_hosts
+# ditch the logo banner up top which screws with less.
+touch /srv/fai/nfsroot/.nocolorlogo
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+[[ $EUID == 0 ]] || exec sudo "${BASH_SOURCE}" "$@"
+
+usage() {
+ cat <<EOF
+usage: ${0##*/} [-h|--help]
+uninstall fai-server
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+esac
+
+
+apt-get -y remove --purge --auto-remove fai-doc nfs-kernel-server \
+ tftpd-hpa tar reprepro squashfs-tools binutils fai-server
--- /dev/null
+#!/bin/bash
+
+[[ $EUID == 0 ]] || exec sudo "$BASH_SOURCE" "$@"
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [OPTIONS] -- +/-SIZE[g] swap|boot
+
+Assuming Ian Kelling's partition scheme and we are currently into one of
+it's encrypted oses (we it's btrfs filesystem to be mounted), resize
+swap or boot, expanding or shrinking the root fs and partition to
+compensate. If it changes the partition tables incorrectly, the
+originals are stored in /root/backup_partition_table_<device_names>.
+
+TODO: only tested on stretch. deactivation of swap on reboot
+probably needs to be fixed on other oses. Even on stretch,
+we get 1.5 minutes of waiting for the crypt_dev and normal
+boot .device units.
+
+Warning!!! Backup your data. This script could have bugs in it.
+
+-n Dry run. Note, this likely won't be the exact commands,
+ for example, if you are running outside a vm, there will
+ probably be a reboot required in the middle so the kernel
+ can know about partition changes.
+-r Reboot right away if it's needed.
+-f Force running on a distro that has not been tested.
+-h|--help Print help and exit.
+
+SIZE is MiB, or if g is specified, GiB.
+
+If using multiple devices, SIZE is applied to each device, so total change is
+SIZE * devices.
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+reboot_not=false
+dry_run=false
+force=false
+
+temp=$(getopt -l help rnfh "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ -r) reboot_now=true; shift ;;
+ -n) dry_run=true; shift ;;
+ -f) force=true; shift ;;
+ -h|--help) usage ;;
+ --) shift; break ;;
+ *) echo "$0: Internal error!" ; exit 1 ;;
+ esac
+done
+
+#### begin arg error checking ####
+
+if [[ $# != 2 ]]; then
+ echo "$0: error: expected 2 arguments"
+ usage 1
+fi
+
+if [[ $1 != [+-][0-9]* ]]; then
+ echo "$0: error: bad 1st arg: $1"
+ usage 1
+fi
+
+if ! which parted &>/dev/null; then
+ echo "$0: error: install parted"
+ exit 1
+fi
+
+case $2 in swap|boot) : ;; *) echo "$0: error: bad 2nd arg"; usage 1 ;; esac
+
+if ! $force && ! grep -q 'VERSION=.*stretch' /etc/os-release; then
+ echo "$0: error: This distro is untested. Only tested version atm is Stretch."
+ exit 1
+fi
+
+#### end arg error checking ####
+
+
+boot=true
+[[ $2 == boot ]] || boot=false
+
+op_size=$1 # operator plus size
+if [[ $op_size == *g ]]; then
+ op_size=${op_size%g}
+ size=${op_size#?}
+ op=${op_size%$size}
+ size=$(( $size * 1024 ))
+ op_size=$op$size
+else
+ size=${op_size#?}
+fi
+
+if [[ $op_size == +* ]]; then
+ op_size_rev=-$size # rev = reverse
+ grow=true
+else
+ op_size_rev=+$size
+ grow=false
+fi
+
+##### end command line parsing ########
+
+rootn=1
+swapn=2
+bootn=3
+needs_reboot=false
+reboot_script_initialized=false
+
+pmk() { # partition make
+ part=$1
+ start_op=$2
+ end_op=$3
+ fs_type="$4"
+
+ # This fails outside a vm, but actually succeeds. also prints this
+ # message:
+ # Error: Partition(s) 2 on /dev/sda have been written, but
+ # we have been unable to inform the kernel of the change, probably
+ # because it/they are in use. As a result, the old partition(s)
+ # will remain in use. You should reboot now before making further
+ # changes.
+
+ if ! p mkpart primary "$fs_type" \
+ $((${ptable[start$part]} $start_op)) $((${ptable[end$part]} $end_op)); then
+ echo "$0: warning: ignoring failure return of mkpart"
+ fi
+}
+
+def-e() {
+ if $dry_run; then
+ e() { echo "+ $@"; }
+ else
+ e() { echo "+ $@"; "$@"; }
+ fi
+}
+
+def-e
+
+
+while read devid dev; do
+ case $dev in
+ /dev/dm-[0-9])
+ # older oses, it points to /dev/dm-x
+ dev=$(dmsetup info $dev | sed -rn 's/^\s*Name:\s*(\S*)/\1/p')
+ ;;
+ /dev/mapper/*)
+ dev=${dev#/dev/mapper/}
+ ;;
+ *)
+ echo "$0: error: could not find devicemapper root dev,
+make sure you are running from a encrypted root this script is resizing"
+ exit 1
+ ;;
+ esac
+ if [[ $dev != crypt_dev_*-part$rootn ]]; then
+ echo "$0: error: unexpected root device name,
+make sure you are running from a encrypted root this script is resizing"
+ exit 1
+ fi
+ dev=${dev#crypt_dev_}
+ dev=${dev%-part$rootn}
+ devpath=/dev/disk/by-id/$dev
+ echo skip=$size
+ def-e
+ declare -A ptable
+ while IFS=: read id start end psize _; do
+ [[ $id == [0-9] ]] || continue
+ ptable[start$id]=start=${start%%[^0-9]*}
+ ptable[end$id]=${end%%[^0-9]*}
+ ptable[size$id]=${psize%%[^0-9]*}
+ done < <(parted -m $devpath unit MiB print)
+ parted $devpath unit MiB print | tee /root/backup_partition_table_$dev
+ p() { e parted -a optimal -s -- $devpath unit MiB "$@"; }
+ unit=systemd-cryptsetup@crypt_dev_$dev-part$swapn
+ # note systemctl show can test if a unit exists.
+ if ! e systemctl stop $unit; then
+ e swapoff -a
+ fi
+ # there is a bug in jessie. this and the .swap unit are
+ # generated from /etc/fstab, and it escapes - to x2d, then doesn't escape it
+ # when looking for the file to use as swap. so, no swap is working on jessie
+ # right now.
+ sleep 1 # dunno if this is needed,
+ # but systemd likes to do these kind of things in the background.
+
+ # These partition comments seems a little verbose now, but I bet they
+ # will be helpfull if I read this in more than a week from now.
+ # <> = deleted partition, () = partition
+ p rm $swapn # ( root )< swap >( boot )
+
+ root_resize_cmd="e btrfs fi resize $devid:${op_size_rev}M /"
+ if $grow; then $root_resize_cmd; fi
+ # if $grow; then
+ # < root >< swap >( boot )
+ # ( root ) >< swap >( boot )
+ # else
+ # < root >< swap >( boot )
+ # ( root >< ) swap >( boot )
+
+ out=$(p rm $rootn 2>&1)
+ echo "$out"
+
+ pmk $rootn "" $op_size_rev
+
+ if echo "$out" | \
+ grep "but we have been unable to inform the kernel" &>/dev/null; then
+ needs_reboot=true
+ fi
+ if $needs_reboot; then
+ # note: even if these units don't exist, this will succeed.
+ e systemctl mask dev-mapper-crypt_swap_$dev$swapn.swap
+ e systemctl mask systemd-cryptsetup@crypt_swap_$dev$swapn.service
+ e() { echo "$@" >> /root/finish-resize; }
+ if ! $reboot_script_initialized; then
+ reboot_script_initialized=true
+ rm -rf /root/finish-resize
+ cat >/root/finish-resize <<'EOF'
+#!/bin/bash -x
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+EOF
+ chmod +x /root/finish-resize
+ fi
+ e swapoff -a
+ e systemctl unmask systemd-cryptsetup@crypt_swap_$dev$swapn.service
+ e systemctl unmask dev-mapper-crypt_swap_$dev$swapn.swap
+ fi
+ if ! $grow; then
+ $root_resize_cmd
+ fi
+ if $boot; then
+ # non by-id path, to match what btrfs fi show will tell us
+ boot_dev_path=$(readlink -f $devpath-part$bootn)
+ boot_devid=$(btrfs fi show /boot | \
+ sed -rn "s#^\s*devid\s+(\S+)\s.*$boot_dev_path#\1#p")
+
+ if ! $grow; then
+ # shrink boot, move it to a temp file
+ e btrfs fi resize $boot_devid:${op_size}M /boot
+ e umount /boot
+ temp_boot=/root/temp_boot_$dev
+ e dd bs=1M if=$boot_dev_path of=$temp_boot \
+ count=$((${ptable[size$bootn]} $op_size))
+ else
+ e umount /boot
+ fi
+ # if $grow; then
+ # ( root ) >< swap >< boot >
+ # ( root )( >< swap ) >< boot >
+ # ( root )( >< swap )( >< boot )
+ # else
+ # ( root >< ) swap >< boot >
+ # ( root >< )( swap >< ) boot >
+ # ( root >< )( swap >< )( boot )
+ p rm $bootn
+ pmk $swapn $op_size_rev $op_size_rev "linux-swap"
+ pmk $bootn $op_size_rev ""
+
+ if $grow; then
+ e dd bs=1M if=$boot_dev_path of=$boot_dev_path skip=$size
+ e mount /boot
+ e btrfs fi resize $boot_devid:${op_size}M /boot
+ else
+ e dd bs=1M if=$temp_boot of=$boot_dev_path
+ e mount /boot
+ fi
+ else
+ # if $grow; then ( root )( >< swap )( boot )
+ # else ( root >< )( swap )( boot )
+ pmk $swapn $op_size_rev "" "linux-swap"
+ e systemctl start systemd-cryptsetup@crypt_swap_$dev$swapn
+ fi
+done < <(btrfs fi show / | sed -nr 's#^\s*devid\s*(\S+).* path (.*)$#\1 \2#p')
+
+
+if $boot; then
+ e rm -rf "/root/temp_boot_*"
+ e rm -f /root/finish-resize
+fi
+
+if $needs_reboot; then
+ echo "$0: Reboot, run /root/finish-resize. It's contents:"
+ cat /root/finish-resize
+ if $reboot_now; then
+ echo "$0: rebooting now"
+ reboot now
+ exit
+ fi
+fi
--- /dev/null
+#
+
+# iank: just guessing here.
+authoritative;
+
+
+deny unknown-clients;
+option dhcp-max-message-size 2048;
+use-host-decl-names on;
+
+subnet 209.51.188.0 netmask 255.255.255.0 {
+option routers 209.51.188.1;
+option domain-name "fsf.org";
+option domain-search "fsf.org";
+option domain-name-servers 209.51.188.16;
+option ntp-servers 0.ubuntu.pool.ntp.org, 1.ubuntu.pool.ntp.org, ntp.ubuntu.com;
+# iank: not sure why this is here, but not in
+#server-name faiserver;
+option time-offset -18000; # Eastern Standard Time
+}
+
+host community0p {
+next-server faiserver.fsf.org;
+filename "pxelinux.0";
+
+hardware ethernet ac:22:0b:1d:11:f9;
+# 1st mobo, mostly fails to boot
+#hardware ethernet 08:60:6e:10:f0:fe;
+fixed-address 209.51.188.193;
+option host-name "community0p";
+}
+
+
+default-lease-time 600;
+max-lease-time 7200;
--- /dev/null
+## grub2 configuration
+set default="FAI server via dns"
+set timeout=20
+
+# make sure we can access partitions
+insmod part_msdos
+insmod part_gpt
+insmod all_video
+insmod gfxterm
+
+set gfxmode=auto
+set color_normal=white/black
+set color_highlight=red/black
+set menu_color_normal=white/black
+set menu_color_highlight=black/yellow
+
+
+# ian: Added this from fai
+# note, we could replace faiserver with an ip if we didn't want to mess with dns.
+# args are copied from myfai-chboot-local.
+# Note, for a real cd or usb flash, if it is the default boot device, we would need to remove the disk
+# after install is done very quickly, or else remove the reboot arg here
+menuentry "FAI server via dns" {
+ set gfxpayload=$resolution
+ search --set=root --file /FAI-CD
+ linux /boot/vmlinuz libata.force=noncq FAI_FLAGS=verbose,sshd,createvt,reboot FAI_CONFIG_SRC=nfs://faiserver/srv/fai/config root=/dev/nfs nfsroot=faiserver:/srv/fai/nfsroot,vers=3,nolock rootovl ip=dhcp
+ initrd /boot/initrd.img
+}
+
+menuentry "FAI server via dns, no reboot" {
+ set gfxpayload=$resolution
+ search --set=root --file /FAI-CD
+ linux /boot/vmlinuz libata.force=noncq FAI_FLAGS=verbose,sshd,createvt FAI_CONFIG_SRC=nfs://faiserver/srv/fai/config root=/dev/nfs nfsroot=faiserver:/srv/fai/nfsroot,vers=3,nolock rootovl ip=dhcp
+ initrd /boot/initrd.img
+}
+
+# ro,noatime,vers=3,rsize=1048576,wsize=same,namelen=255,hard,nolock,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=10.2.0.2,nountvers=3,mountport=49179,mountproto=udp,lock_lock=all,addr=10.2.0.2
+menuentry "Autodiscover the FAI server" {
+ search --set=root --file /FAI-CD
+ linux /boot/vmlinuz libata.force=noncq FAI_FLAGS="menu,verbose,createvt" fai.discover rootovl root=/dev/nfs ip=dhcp quiet
+ initrd /boot/initrd.img
+}
+
+menuentry "Boot OS from first partition on first disk" {
+ if [ "$grub_platform" = "efi" ]; then
+ if [ -f (hd0,gpt1)/efi/debian/grub.cfg ]; then
+ configfile (hd0,gpt1)/efi/debian/grub.cfg
+ elif [ -f (hd1,gpt1)/efi/debian/grub.cfg ]; then
+ configfile (hd1,gpt1)/efi/debian/grub.cfg
+ elif [ -f (hd0,gpt2)/boot/grub/grub.cfg ]; then
+ configfile (hd0,gpt2)/boot/grub/grub.cfg
+ elif [ -f (hd1,gpt2)/boot/grub/grub.cfg ]; then
+ configfile (hd1,gpt2)/boot/grub/grub.cfg
+ else
+ echo "cannot find grub.cfg"
+ sleep 7
+ fi
+ # legacy BIOS booting
+ elif [ -d (cd) ]; then
+ set root=(hd0)
+ chainloader +1
+ else
+ set root=(hd1)
+ chainloader +1
+ fi
+}
--- /dev/null
+## grub2 configuration
+set default="Netinstall"
+set timeout=2
+set resolution=1024x768
+
+if loadfont /boot/grub/unicode.pf2 ; then
+ insmod png
+ set gfxmode=640x480
+ insmod gfxterm
+ insmod vbe
+ terminal_output gfxterm
+fi
+
+if background_image /boot/grub/fai.png ; then
+ set color_normal=black/black
+ set color_highlight=red/black
+ set menu_color_normal=black/black
+ set menu_color_highlight=black/yellow
+else
+ set menu_color_normal=white/black
+ set menu_color_highlight=black/yellow
+fi
+
+# make sure we can access partitions
+insmod part_msdos
+insmod part_gpt
+
+if [ ${iso_path} ] ; then
+ set loopback="findiso=${iso_path}"
+fi
+
+menuentry "" --unrestricted {
+ set gfxpayload=$resolution
+}
+menuentry " +------------------------------------------------------+" --unrestricted {
+ set gfxpayload=$resolution
+}
+
+menuentry " | Fully Automatic Installation |" --unrestricted {
+ set gfxpayload=$resolution
+
+}
+menuentry " | _VERSIONSTRING_ |" --unrestricted {
+ set gfxpayload=$resolution
+
+}
+menuentry " | (c) Thomas Lange lange@debian.org |" --unrestricted {
+ set gfxpayload=$resolution
+}
+menuentry " +------------------------------------------------------+" --unrestricted {
+ set gfxpayload=$resolution
+}
+}
+menuentry "" --unrestricted {
+ set gfxpayload=$resolution
+}
+
+menuentry "Netinstall" {
+ set gfxpayload=$resolution
+ linux /boot/vmlinuz libata.force=noncq console=ttyS0,19200n8 FAI_FLAGS="verbose,sshd,createvt,reboot" FAI_ACTION=install FAI_CONFIG_SRC=file:///var/lib/fai/config rd.live.image root=live:CDLABEL=FAI_CD rd.neednet ip=dhcp quiet
+ initrd /boot/initrd.img
+}
+
+
+menuentry "Boot OS of first partition on first disk" --unrestricted {
+ if [ -d (cd) ]; then
+ chainloader (hd0)+1
+ fi
+
+ if [ "$root" = "hd1" ]; then
+ chainloader (hd0)+1
+ fi
+
+ if [ "$root" = "hd0" ]; then
+ set root=(hd1)
+ chainloader (hd1)+1
+ fi
+}
--- /dev/null
+## grub2 configuration
+set default="Netinstall"
+set timeout=2
+set resolution=1024x768
+
+if loadfont /boot/grub/unicode.pf2 ; then
+ insmod png
+ set gfxmode=640x480
+ insmod gfxterm
+ insmod vbe
+ terminal_output gfxterm
+fi
+
+if background_image /boot/grub/fai.png ; then
+ set color_normal=black/black
+ set color_highlight=red/black
+ set menu_color_normal=black/black
+ set menu_color_highlight=black/yellow
+else
+ set menu_color_normal=white/black
+ set menu_color_highlight=black/yellow
+fi
+
+# make sure we can access partitions
+insmod part_msdos
+insmod part_gpt
+
+if [ ${iso_path} ] ; then
+ set loopback="findiso=${iso_path}"
+fi
+
+menuentry "" --unrestricted {
+ set gfxpayload=$resolution
+}
+menuentry " +------------------------------------------------------+" --unrestricted {
+ set gfxpayload=$resolution
+}
+
+menuentry " | Fully Automatic Installation |" --unrestricted {
+ set gfxpayload=$resolution
+
+}
+menuentry " | _VERSIONSTRING_ |" --unrestricted {
+ set gfxpayload=$resolution
+
+}
+menuentry " | (c) Thomas Lange lange@debian.org |" --unrestricted {
+ set gfxpayload=$resolution
+}
+menuentry " +------------------------------------------------------+" --unrestricted {
+ set gfxpayload=$resolution
+}
+}
+menuentry "" --unrestricted {
+ set gfxpayload=$resolution
+}
+
+menuentry "Netinstall" {
+ set gfxpayload=$resolution
+ linux /boot/vmlinuz libata.force=noncq console=ttyS0,19200n8 FAI_FLAGS="verbose,sshd,createvt" FAI_ACTION=install FAI_CONFIG_SRC=file:///var/lib/fai/config rd.live.image root=live:CDLABEL=FAI_CD rd.neednet ip=dhcp quiet
+ initrd /boot/initrd.img
+}
+
+
+menuentry "Boot OS of first partition on first disk" --unrestricted {
+ if [ -d (cd) ]; then
+ chainloader (hd0)+1
+ fi
+
+ if [ "$root" = "hd1" ]; then
+ chainloader (hd0)+1
+ fi
+
+ if [ "$root" = "hd0" ]; then
+ set root=(hd1)
+ chainloader (hd1)+1
+ fi
+}
--- /dev/null
+## grub2 configuration
+set default="Netinstall"
+set timeout=2
+set resolution=1024x768
+
+if loadfont /boot/grub/unicode.pf2 ; then
+ insmod png
+ set gfxmode=640x480
+ insmod gfxterm
+ insmod vbe
+ terminal_output gfxterm
+fi
+
+if background_image /boot/grub/fai.png ; then
+ set color_normal=black/black
+ set color_highlight=red/black
+ set menu_color_normal=black/black
+ set menu_color_highlight=black/yellow
+else
+ set menu_color_normal=white/black
+ set menu_color_highlight=black/yellow
+fi
+
+# make sure we can access partitions
+insmod part_msdos
+insmod part_gpt
+
+if [ ${iso_path} ] ; then
+ set loopback="findiso=${iso_path}"
+fi
+
+menuentry "" --unrestricted {
+ set gfxpayload=$resolution
+}
+menuentry " +------------------------------------------------------+" --unrestricted {
+ set gfxpayload=$resolution
+}
+
+menuentry " | Fully Automatic Installation |" --unrestricted {
+ set gfxpayload=$resolution
+
+}
+menuentry " | _VERSIONSTRING_ |" --unrestricted {
+ set gfxpayload=$resolution
+
+}
+menuentry " | (c) Thomas Lange lange@debian.org |" --unrestricted {
+ set gfxpayload=$resolution
+}
+menuentry " +------------------------------------------------------+" --unrestricted {
+ set gfxpayload=$resolution
+}
+}
+menuentry "" --unrestricted {
+ set gfxpayload=$resolution
+}
+
+menuentry "Netinstall" {
+ set gfxpayload=$resolution
+ linux /boot/vmlinuz console=ttyS0,19200n8 FAI_FLAGS="verbose,sshd,createvt" FAI_ACTION=sysinfo FAI_CONFIG_SRC=file:///var/lib/fai/config rd.live.image root=live:CDLABEL=FAI_CD rd.neednet ip=dhcp quiet
+ initrd /boot/initrd.img
+}
+
+
+menuentry "Boot OS of first partition on first disk" --unrestricted {
+ if [ -d (cd) ]; then
+ chainloader (hd0)+1
+ fi
+
+ if [ "$root" = "hd1" ]; then
+ chainloader (hd0)+1
+ fi
+
+ if [ "$root" = "hd0" ]; then
+ set root=(hd1)
+ chainloader (hd1)+1
+ fi
+}
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+[[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+cd ${x%/*}
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [-h|--help]
+reinstall chboot to /boot subvols, for chboot updates.
+
+We install to /boot in case there is an issue booting and only the /boot
+vol is readily available. For the bootstrap subvol, this is the normal
+case.
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+esac
+
+
+e() { echo "$@"; "$@"; }
+
+boot_dev=$(mount | sed -rn "s#^(\S+) on /boot .*#\1#p")
+mount_point=$(mktemp -d)
+e mount -o subvolid=0 $boot_dev $mount_point
+
+shopt -s nullglob
+for dir in $mount_point/*; do
+ btrfs subvol show $dir &>/dev/null || continue
+ if [[ -e $dir/boot ]]; then
+ dir=$dir/boot
+ fi
+ e install -m 755 -o root -g root bash-trace $dir
+ e install -m 755 -o root -g root chboot $dir
+done
+e umount $mount_point
+e rmdir $mount_point
--- /dev/null
+ 407 root 3204 S /bin/sh /scripts/local-top/cryptroot
+ 423 root 0 IW [kworker/6:2-eve]
+ 432 root 3064 S /bin/sh /lib/cryptsetup/scripts/decrypt_keyctl none
+ 433 root 3204 S /bin/sh /scripts/local-top/cryptroot
+ 434 root 10768 S< /sbin/cryptsetup -T1 --allow-discards --type=luks --key-file=- ope
+ 436 root 2648 S /lib/cryptsetup/askpass Caching passphrase for crypt-vgata-Samsung
--- /dev/null
+lk
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [-h|--help] [HOST]
+fai kexec from upstream live cds, i.e. curl|bash
+
+If HOST argument, ssh to root@HOST before doing kexec. This does what
+pxe would do, but skipping boot sequence up to and including the pxe
+dhcp.
+
+
+You can copy this to a http server, then wget -O- url|sudo bash
+curl is sometimes not preinstalled on a live cd.
+
+Alternative to http server:
+1. on install machine nc -l 1234 | sudo bash
+2. On another machine nc INSTALL_MACHINE 1234 <live-kexec
+Obviously beware that anyone on your network could send commands to the install machine.
+
+This has been tested on trisquel 7 & 8 & ubuntu 16.04 & 18.10. With
+18.10 and trisquel 8 on an x200, kexec was unreliable, resulting in
+freezes and kernel panics. On t11, linux 5.15.0-40-generic, after kexec,
+black screen, ping worked but nothing else. Debian 11 live image worked.
+
+If the screen just sits in a weird color inverted, corrupted looking state,
+it's probably nothing wrong with the computer, but a problem
+with the fai server. If you can do this from a virtual terminal,
+it will print out more info (I know from running it on a vm).
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+ ?*) host=$1
+esac
+
+if [[ $host ]]; then
+ ssh root@$host bash -s < $(readlink -f "$BASH_SOURCE")
+ exit $?
+fi
+
+set -ex
+if grep -q ID=ubuntu /etc/os-release; then
+ # add universe, pxe-kexec is there
+ sed -ri '/^\s*deb/{/universe/!s/$/ universe/}' /etc/apt/sources.list
+fi
+if ! type -p pxe-kexec >/dev/null 2>&1; then
+ apt-get update ||: # try even if we fail
+ apt-get install -y debconf
+ debconf-set-selections <<EOF
+kexec-tools kexec-tools/load_kexec boolean false
+EOF
+ apt-get install -y pxe-kexec
+fi
+# running this piped to bash on belenos, the apt-get goes
+# into the background while it's still installing, and pxe-kexec
+# just exits right away. sleep calls are strangely ignored.
+# I don't know whats going on, but just running the same
+# command again once it finishes works, and this is only
+# rarely used and done manually anyways, so whatever.
+pxe-kexec -n --ignore-whitelist -l fai-generated faiserver
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2018 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+[[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
+
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+x="$(readlink -f -- "$BASH_SOURCE")"; PATH="${x%/*}:$PATH" # directory of this file
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} DISTRO_CODENAME
+Make basefile with desktop packages preinstalled
+
+The longest amount of time when doing a new install is installing
+packages. We can make that faster by preinstalling them in a
+basefile. When a basefile is created, debootstrap allows you to
+specify extra packages, but in trisquel, most packages don't install
+that way. Not sure exactly why. So, we can do a fai dirinstall (fancy
+chroot) to install packages, then turn that into a new basefile.
+
+The script depnds on being in a directory with other scripts from it's repo.
+
+Warning: uses paths specific to author's machine.
+
+-h|--help Print help and exit.
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+read distver <<<"$@"
+
+if [[ $# != 1 ]]; then
+ echo "$0: error: expected one argument"
+ usage 1
+fi
+
+
+case $distver in
+ flidas)
+ distro=trisquel
+ classes="UBUNTU FLIDAS64 VOL_FLIDAS FLIDAS DESKTOP"
+ ;;
+ stretch)
+ classes="DEBIAN STRETCH64 VOL_STRETCH STRETCH DESKTOP"
+;;
+ *)
+ echo "$0: error: unknown DISTRO_CODENAME"
+ usage 1
+ ;;
+esac
+
+distro=trisquel
+
+# background: i tried using a tmpfs for this. it had minimal effect, like 17 mins vs 18 mins
+t=/tmp/dirinstall
+
+
+err-cleanup() {
+ sed -i 's/^#LOGUSER=/LOGUSER=/' /etc/fai/fai.conf
+ for d in proc var/lib/dpkg var/cache; do
+ umount -R $t/$d ||:
+ done
+ rm -rf $t
+}
+
+
+myfai-chboot default
+sed -i 's/^LOGUSER=/#LOGUSER=/' /etc/fai/fai.conf
+# config umount required after a failed run, proc umount always required
+umount /var/lib/fai/config ||: ; umount -R $t/proc ||:
+
+fai-redep faiserver $distro
+echo "echo $classes" > /srv/fai/config/class/51-multi-boot
+
+rm -rf $t; mkdir -p $t
+
+LANG= fai -N -u hostname_does_not_matter dirinstall $t
+
+# Turn a dirinstall into a basefile. taken from mk-basefile
+chroot $t apt-get clean
+rm -f $t/etc/hostname $t/etc/resolv.conf \
+ $t/var/lib/apt/lists/*_* $t/usr/bin/qemu-*-static \
+ $t/etc/udev/rules.d/70-persistent-net.rules
+echo | dd of=$t/etc/machine-id
+tar --one-file-system -C $t -cf - . | zstd -9 > /a/bin/fai-basefiles/basefiles/${distver^^}64BIG.tar.zst
+
+
+cleanup
+exit 0
--- /dev/null
+#!/bin/bash
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+x=$(readlink -f "$BASH_SOURCE"); cd ${x%/*}
+
+usage() {
+ cat <<EOF
+usage: ${0##*/} [OPTIONS] [HOSTNAME|IP|default]
+
+Sets up tftp pxe config and nfs server on host "faiserver".
+
+If our kernel has no nfs support, uses apache intead of nfs, and depends
+on another repo of Ian Kelling, basic-https-conf, where the file is at
+/a/exe/web-conf.
+
+Using this, you can boot into fai with pxe-kexec without changing the
+dhcp server. Note, if you are booting using fai-cd, the pxe config does
+nothing, and only flags affecting FAI_ACTION will have any affect. You
+can change the fai flags in the grub config, for example in
+./grub.cfg.autodiscover, or at runtime by editing a grub menu option.
+We could probably also set FAI_FLAGS the same way we set FAI_ACTION,
+but I haven't tried it.
+
+HOSTNAME|IP|default Sets the host to enable it for. No argument
+ disables pxe config for all hosts, but leaves nfs
+ server alone. Use faiserver-disable to disable the
+ nfs server.
+
+-S sets FAI_ACTION=sysinfo, and remove fai flag reboot.
+ Usefull for doing a system recovery. It reboots automatically anyways :(
+-k Add serial port output for kgped16
+-i sets FAI_ACTION=inventory and remove fai flag reboot.
+ I'm not sure what this is usefull for.
+-b Setup bonded ethernet.
+--no-r Tell fai-chboot not to reboot when its done. This is implied by -i and -S.
+-h|--help Print help and exit.
+
+EOF
+ exit $1
+}
+case $1 in
+ -h|--help) usage ;;
+esac
+
+
+faiserver_addr=$(host faiserver | sed -rn 's/^\S+ has address //p;T;q' ||:)
+host=$(./chost faiserver)
+if ip a | grep "^ *inet.\? $faiserver_addr" &>/dev/null; then
+ ./myfai-chboot-local "$@"
+else
+ ssh root@$host bash -s -- "$@" <myfai-chboot-local
+fi
--- /dev/null
+#!/bin/bash
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+set -x
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+pre="${0##*/}:"
+m() { printf "$pre %s\n" "$*"; "$@"; }
+e() { printf "$pre %s\n" "$*"; }
+err() { echo "[$(date +'%Y-%m-%d %H:%M:%S%z')]: $pre: $*" >&2; }
+
+usage() {
+ cat <<EOF
+Usage: call from myfai-chboot, see its help
+
+# note, this script gets piped to bash, so cant cd to current dir
+
+-h|--help Print help and exit.
+
+Note: Uses util-linux getopt option parsing: spaces between args and
+options, short options can be combined, options before args.
+EOF
+ exit $1
+}
+
+
+kgped16=false
+bond=false
+fai_action=install
+fai_reboot_arg=,reboot
+
+# ensure we can handle args with spaces or empty.
+ret=0; getopt -T || ret=$?
+[[ $ret == 4 ]] || { echo "Install util-linux for enhanced getopt" >&2; exit 1; }
+
+temp=$(getopt -l help,no-r hSi "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ -S)
+ fai_action=sysinfo
+ fai_reboot_arg=
+ ;;
+ -i) #inventory
+ fai_action=inventory
+ fai_reboot_arg=
+ ;;
+ -k)
+ kgped16=true
+ ;;
+ -b)
+ bond=true
+ ;;
+ --no-r)
+ fai_reboot_arg=
+ ;;
+ -h|--help) usage ;;
+ --) shift; break ;;
+ *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;;
+ esac
+ shift
+done
+read -r host <<<"$@"
+readonly host
+
+
+rm -f /srv/tftp/fai/pxelinux.cfg/*
+if [[ ! $1 ]]; then
+ echo "$0: clearing pxe config and exiting"
+ exit 0
+fi
+
+# somewhat duplicated in brc hostip()
+case $host in
+ default) : ;;
+ [0-9:])
+ hostip=$host
+ ;;
+ *)
+ hostip=$(getent ahostsv4 "$host" | awk '{ print $1 }' | head -n1)
+ ;;
+esac
+
+if [[ $hostip ]]; then
+
+ # assuming ipv4, or else we might need to deal with multiple addresses
+ # in an ipv4 + ipv6 network.
+ my_ip=$(ip -4 route get $hostip | sed -nr 's,^.*src\s+(\S+).*,\1,p')
+ if [[ ! $my_ip || $my_ip =~ [[:space:]] ]]; then
+ echo "$0: error: failed to get \$my_ip, got: $my_ip"
+ exit 1
+ fi
+else
+ my_ip=$(ip r show default | sed -r 's/.*via ([^ ]*).*/\1/' | head -n1)
+fi
+
+if [[ $host == default ]]; then
+ ip='*'
+elif [[ $host == [0-9]*.[0-9]*.[0-9]*.[0-9]* ]]; then
+ ip=$host/32
+else
+ type -t host &>/dev/null || apt-get -y install dnsutils
+ ip=$(host $host | sed -rn 's/^\S+ has address //p;T;q' ||:)
+ if [[ ! $ip || $ip =~ [[:space:]] ]]; then
+ echo "$0: error: failed to get \$ip, got: $ip"
+ exit 1
+ fi
+ ip=$ip/32
+ echo "$0: found ip of $host: $ip"
+fi
+
+if modprobe nfsd &>/dev/null; then
+ std_arg="-u nfs://faiserver/srv/fai/config"
+ # nfsv4 wont do rw with overlayfs yet
+ # https://lists.uni-koeln.de/pipermail/linux-fai/2017-March/011641.html
+ root_arg="$my_ip:/srv/fai/nfsroot:vers=3"
+ # fai-setup without -e sets the ip to the local_ip/local_network, eg 192.168.1.3/24
+ # I restrict it to one ip as simple but imperfect access control.
+
+ # we may chattr +i /etc/exports if we dun want it modified
+ # for example, if we made these exports more widely available
+ # while doing multiple installs or a recovery.
+ if [[ -w /etc/exports ]]; then
+ sed -ri --follow-symlinks '\%^/srv/fai/%d' /etc/exports
+ cat >>/etc/exports <<EOF
+/srv/fai/config $ip(async,ro,no_subtree_check,no_root_squash)
+/srv/fai/nfsroot $ip(async,ro,no_subtree_check,no_root_squash)
+EOF
+ exportfs -ra
+ fi
+ systemctl start nfs-server # assumes recent os
+else
+ std_arg="-u http://faiserver:8080/config.tar.gz"
+ root_arg="live:http://faiserver:8080/squash.img"
+ /a/exe/web-conf -i -p 8080 - apache2 faiserver <<EOF
+<Location />
+ Deny from all
+ Allow from $ip
+</Location>
+EOF
+fi
+
+
+
+# man page doesn't explain this, but this deletes & thus disables
+# all chboot systems.
+m fai-chboot -iv $std_arg default # set it to default to get a val out of it next
+kernel=$(fai-chboot -L '^default$' | awk '{print $3}')
+default_k_args=$(fai-chboot -L '^default$' | \
+ sed -r "s/^(\S+\s+){3}(.*)/\2/")
+# example of default_k_args
+# initrd=initrd.img-3.16.0-4-amd64 ip=dhcp root=192.168.1.3:/srv/fai/nfsroot FAI_CONFIG_SRC=nfs://faiserver/srv/fai/config FAI_ACTION=install
+
+# https://wiki.archlinux.org/index.php/Solid_state_drive#Resolving_NCQ_errors
+# currently on needed on d16 samsung 870 qvo, but better to have this
+# and not wait for more conditions where its needed.
+#k_args=(FAI_ACTION=$fai_action libata.force=noncq ifname:bootnet0:08:60:6e:10:f0:fe ifname:bootnet1:08:60:6e:10:f0:98 bond=bond0:bootnet0,bootnet1:mode=balance-rr)
+#k_args=(FAI_ACTION=$fai_action libata.force=noncq ifname:bootnet0:08:60:6e:10:f0:fe biosdevname=0 bootdev=bootnet0)
+k_args=(FAI_ACTION=$fai_action libata.force=noncq)
+if $kgped16; then
+ k_args+=(console=tty0 console=ttyS0,115200)
+fi
+
+for arg in $default_k_args; do
+ case $arg in
+ # default root arg is /srv/fai/nfsroot
+ root=*) k_args+=(root=$root_arg) ;;
+ # note: this works to only dhcp on one interface: ip=eth0:dhcp
+ ip=*)
+ if $bond; then
+ k_args+=("bond=bond0:eth0,eth1:mode=balance-rr ip=bond0:dhcp")
+ else
+ k_args+=($arg)
+ fi
+ ;;
+ *) k_args+=($arg) ;;
+ esac
+done
+rm -f /srv/tftp/fai/pxelinux.cfg/*
+m fai-chboot -k "${k_args[*]}" -v -f verbose,sshd,createvt$fai_reboot_arg $std_arg $kernel "$host"
+
+# this is needed for autodiscover iso. i'm not sure, it might override
+# the fai-chboot method of setting this, i'm not sure.
+echo FAI_ACTION=$fai_action >> /srv/fai/config/class/LAST.var
--- /dev/null
+#!/bin/bash
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+script_dir="${x%/*}"
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [-h|--help] [mk-basefile_args]
+Wrap fai's mk-basefile so output dir is $BASEFILE_DIR if it exists.
+
+And fix things for trisquel. mk-basefile has a trisquel mirror added.
+
+fai-project maintains ubuntu and debian basefiles, but it doesn't update
+them often. Better to build our all our own.
+
+
+Args I've used before:
+
+-z BOOKWORM64
+-z BULLSEYE64
+-z BUSTER64
+-z STRETCH64
+-z XENIAL64
+
+-z ARAMO64
+-z NABIA64
+-z ETIONA64
+-z FLIDAS64
+-z BELENOS64
+
+-h|--help Print help and exit.
+
+Note: Uses GNU getopt options parsing style.
+
+Usage of mk-basefile:
+
+EOF
+ $script_dir/fai/config/basefiles/mk-basefile -h
+ exit $1
+}
+
+case $1 in
+ -h|--help)
+ usage
+ ;;
+esac
+
+if [[ $EUID != 0 ]]; then
+ s=sudo
+fi
+
+cd /usr/share/debootstrap/scripts
+for d in belenos flidas; do
+ if [[ ! -L $d && ! -e $d ]]; then
+ $s ln -sf gutsy $d;
+ fi
+done
+d=etiona
+if [[ ! -L $d && ! -e $d ]]; then
+ $s ln -sf trisquel etiona;
+fi
+
+if [[ $BASEFILE_DIR ]]; then
+ cd $BASEFILE_DIR
+fi
+
+if awk '$2 == "/tmp" && $4 ~ /nodev/' /proc/mounts | grep -q . || [[ $? == 141 ]]; then
+ $s mount -o remount,dev /tmp
+fi
+$s $script_dir/fai/config/basefiles/mk-basefile "$@"
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+readonly this_file="$(readlink -f -- "${BASH_SOURCE[0]}")"
+script_dir="${this_file%/*}"
+# shellcheck source=./bash-trace
+source "${script_dir}/bash-trace"
+cd $script_dir
+PATH="$PATH:$PWD"
+
+
+usage() {
+ cat <<EOF
+Usage: ${0##*/} [OPTIONS] [HOST] [TYPE]
+Configure dnsmasq boot options and fai-chboot if appropriate. This is
+not general purpose, it has code specific to dhcp servers I run.
+
+Without TYPE, disable server and fai server. In that case, HOST is only
+needed for fsf office network.
+
+HOST Only do dhcp pxe for HOST. The hostname must be known to the dhcp
+ server to target its mac. Use "default" for all hosts.
+ Required in fsf office environment.
+
+TYPE One of arch, parabola, plain, fai.
+
+-a Don't setup pxe, just Wait for 2 dhcp acks, then disable the pxe
+ server after a delay. First ack is for pxe boot, 2nd ack is
+ for os boot. Sometimes on debian, there is a 3rd one shortly
+ after the 2nd. I can't remember exactly why this caused a
+ problem, but I'm hoping the sleep will take care of it.
+-d Don't alter dhcp config. Only make sense for fai type, and on network
+ other than home or fsf, when using fai-cd, or pxe-kexec.
+-k Pass -k to myfai-chboot.
+--no-r Pass --no-r to myfai-chboot.
+-r Don't redeploy fai config. For example, if there is a different host
+ that is mid-install.
+
+-S sets FAI_ACTION=sysinfo, see myfai-chboot for more info.
+-w Setup pxe, then wait like -a.
+-h|--help Print help and exit
+
+
+Note, when switching between plain and arch or parabola, you will need to
+do something like:
+ssh wrt
+cd /mnt/usb
+rm tftpboot
+ln -s <arch/parabola/debian iso dir> tftpboot
+
+
+Notes on debugging pxe dhcp tftp:
+
+For debugging dhcp, add to /etc/dnsmasq.conf: log-dhcp
+
+Newer openwrt runs dnsmasq with a whitelist of readable files and dirs:
+
+ps ww :
+/sbin/ujail -t 5 -n dnsmasq -u -l -r /bin/ubus -r /etc/TZ -r /etc/dnsmasq.conf -r /etc/ethers -r /etc/group -r /etc/hosts -r /etc/passwd -w /tmp/dhcp.leases -r /tmp/dnsmasq.d -r /tmp/hosts -r /tmp/resolv.conf.d -r /usr/bin/jshn -r /usr/lib/dnsmasq/dhcp-script.sh -r /usr/share/dnsmasq/dhcpbogushostname.conf -r /usr/share/dnsmasq/rfc6761.conf -r /usr/share/dnsmasq/trust-anchors.conf -r /usr/share/libubox/jshn.sh -r /var/etc/dnsmasq.conf.cfg01411c -w /var/run/dnsmasq/ -- /usr/sbin/dnsmasq -C /var/etc/dnsmasq.conf.cfg01411c -k -x /var/run/dnsmasq/dnsmasq.cfg01411c.pid
+
+logging tftp requests:
+/etc/default/tftpd-hpa:
+add -vv:
+TFTP_OPTIONS="--secure -vv"
+jr -u tftpd-hpa -f
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+pre="${0##*/}:"
+m() { printf "$pre %s\n" "$*"; "$@"; }
+e() { printf "$pre %s\n" "$*"; }
+err() { echo "[$(date +'%Y-%m-%d %H:%M:%S%z')]: $pre: $*" >&2; }
+
+PATH="/a/exe:$PATH"
+
+##### begin command line parsing ########
+
+dhcp=true
+redep=true
+acks=2
+wait=false
+fsf_office=false
+
+case $HOSTNAME in
+ x3|kw) fsf_office=true ;;
+esac
+
+chboot_args=()
+temp=$(getopt -l no-r,help adkrSwh "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ -a) wait=true; set=false; shift ;;
+ -d) dhcp=false; shift ;;
+ -k) chboot_args+=(-k); shift ;;
+ --no-r) chboot_args+=(--no-r); shift ;;
+ -r) redep=false; shift ;;
+ -S) chboot_args+=(-S); shift ;;
+ -w) wait=true; set=true; shift ;;
+ -h|--help) usage ;;
+ --) shift; break ;;
+ *) echo "$0: Internal error!" ; exit 1 ;;
+ esac
+done
+
+read -r host type <<<"$@"
+
+case $# in
+ [01]);;
+ 2)
+ case $type in
+ arch|parabola) cmd=archlike ;;
+ fai) cmd=fai ;;
+ *)
+ echo "$0: error expected type of arch|parabola|fai"
+ echo
+ usage 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "$0: error: expected 0-2 arguments"
+ echo
+ usage 1
+ ;;
+esac
+
+
+if $wait && ! $dhcp; then
+ echo "$0: error -w conflicts with -d, choose one or other" >&2
+ exit 1
+fi
+
+if $fsf_office && [[ ! $host ]]; then
+ echo "$0: at fsf_office, provide HOST arg" >&2
+ exit 1
+ fi
+
+if [[ $host && $host != default ]]; then
+ host_tag="tag:$host,"
+fi
+
+##### end command line parsing ########
+
+archlike() {
+ cat <<EOF
+${host_tag}209,boot/syslinux/${type}iso.cfg
+${host_tag}210,/${type}/
+${host_tag}option:bootfile-name,/${type}/boot/syslinux/lpxelinux.0
+EOF
+}
+
+plain() {
+ # if arch based was used before, this additionally needs
+ # the tftp link in /mnt/usb to be changed.
+ cat <<EOF
+${host_tag}option:bootfile-name,pxelinux.0
+EOF
+}
+
+fai() {
+ cat <<EOF
+${host_tag}option:bootfile-name,pxelinux.0
+${host_tag}option:server-ip-address,$faiserverip
+${host_tag}option:tftp-server,$faiserverip
+EOF
+ # Note, previously used normal dnsmasq option, but it requires dnsmasq
+ # restart, which causes momentary dns failures, which can bork an
+ # install.
+ #
+ # dhcp-boot=${host_tag}pxelinux.0,faiserver.b8.nz,faiserver.b8.nz
+}
+
+ack-wait() {
+ if $fsf_office; then
+ wait_cmd="ssh tarantula.office.fsf.org tail -n0 -f /var/log/syslog"
+ else
+ wait_cmd="ssh cmc logread -f"
+ fi
+ wait_count=$1
+ if [[ $host ]]; then
+ if $fsf_office; then
+ host_regex=" $(getent hosts kw | awk '{print $1}' | sed 's/\./\\./g')"
+ else
+ host_regex=" $host"
+ fi
+ fi
+ regex=".*DHCPACK.*$host_regex\b"
+ i=0
+ while (( i != wait_count )) && read -r line; do
+ if [[ $line =~ $regex ]]; then
+ i=$((i+1))
+ echo $line
+ fi
+ done < <($wait_cmd ||:) # tail returns 2 it seems
+ m sleep 20
+}
+
+set-pxe() {
+ $dhcp || return 0
+ if $fsf_office; then
+ if [[ ! $cmd ]]; then
+ e "removing pxe for $host on tarantula"
+ ssh tarantula.office.fsf.org bash -e <<EOF
+sed -ri 's/^( *host +$host *\{).*/\1/' /etc/dhcp/dhcpd.conf
+systemctl restart isc-dhcp-server
+EOF
+ elif [[ $cmd == fai ]]; then
+ e "adding pxe for $host on tarantula"
+ ssh tarantula.office.fsf.org bash -e <<EOF
+sed -ri 's/^( *host +$host *\{).*/\1 next-server faiserver.office.fsf.org; filename "pxelinux.0";/' /etc/dhcp/dhcpd.conf
+systemctl restart isc-dhcp-server
+EOF
+ fi
+ else
+ e "updating dnsmasq.conf:"
+ m $cmd
+ ${cmd:-:}|ssh cmc "dd of=/var/run/dnsmasq/dhcpopts.conf; /etc/init.d/dnsmasq reload
+$([[ $type == arch || $type == parabola ]] && echo archlike-pxe-mount)"
+ fi
+}
+
+type -t host &>/dev/null || sudo apt-get -y install dnsutils
+faiserverip=$(host faiserver | sed -rn 's/^\S+ has address //p;T;q' ||:)
+if [[ ! $faiserverip || $faiserverip =~ [[:space:]] ]]; then
+ echo "$0: error: failed to get \$faiserverip, got: $faiserverip"
+ exit 1
+fi
+
+
+if $set; then
+ set-pxe
+ if [[ $type == fai ]]; then
+ if $redep; then
+ m fai-redep
+ fi
+ m myfai-chboot ${chboot_args[@]} $host
+ else
+ # This will fail if faiserver is not setup, so ignore any
+ # failure and don't bother us about it.
+ m myfai-chboot &>/dev/null ||:
+ fi
+fi
+
+if $wait; then
+ # fai's debian jessie 8.5ish does 2 dhcp requests when booting,
+ # roughly 4 seconds apart. Earlier
+ # versions did just 1. Now testing on a vm, it does 1.
+ # bleh.
+ echo "waiting for $acks dhcp acks then disabling pxe"
+ ack-wait $acks
+ type=
+ unset cmd
+ set-pxe
+
+ # previously tried waiting for one more ack then disabling faiserver,
+ # since it can contain sensitive info, so turn it off when not in use,
+ # but disabling that for now as it's inconvenient to clean this
+ # up and run it in the background etc.
+
+ # if [[ $type == fai ]]; then
+ # echo "waiting for 1 dhcp ack then disabling fai server"
+ # ack-wait 1
+ # faiserver-disable
+ # fi
+fi
--- /dev/null
+firewall rules, temporarily disabled until I get them working
+
+
+# each port forward needs corresponding forward in the vpn server
+
+
+#http/https
+
+
+
+config redirect
+ option name bittorrent
+ option src vpn
+ option src_dport 63324
+ option dest_ip 192.168.1.2
+ option dest lan
+# making the port open (not sure if this is actually needed)
+config rule
+ option src vpn
+ option target ACCEPT
+ option dest_port 63324
+
+
+
+config redirect
+ option name kdsyncthing
+ option src vpn
+ option src_dport 22000
+ option dest_ip 192.168.1.2
+ option dest lan
+ option proto tcp
+config rule
+ option src vpn
+ option target ACCEPT
+ option dest_port 22000
+
+
+config redirect
+ option name bithtpc
+ option src vpn
+ option src_dport 63325
+ option dest_ip 192.168.1.4
+ option dest lan
+config rule
+ option src vpn
+ option target ACCEPT
+ option dest_port 63325
+
+
+
+#### begin rules for nfs ####
+# https://serverfault.com/questions/377170/which-ports-do-i-need-to-open-in-the-firewall-to-use-nfs
+# https://wiki.debian.org/SecuringNFS
+# I had no /etc/default/quota, or any process named quota anything,
+# so, assumed that was unneeded. seems to work.
+config redirect
+ option src wan
+ option src_dport 111
+ option dest_ip 192.168.1.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 111
+config redirect
+ option src wan
+ option src_dport 2049
+ option dest_ip 192.168.1.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 2049
+config redirect
+ option src wan
+ option src_dport 32764
+ option dest_ip 192.168.1.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 32764
+config redirect
+ option src wan
+ option src_dport 32765
+ option dest_ip 192.168.1.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 32765
+config redirect
+ option src wan
+ option src_dport 32766
+ option dest_ip 192.168.1.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 32766
+config redirect
+ option src wan
+ option src_dport 32767
+ option dest_ip 192.168.1.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 32767
+config redirect
+ option src wan
+ option src_dport 32768
+ option dest_ip 192.168.1.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 32768
+#### end rules for nfs ####
+
+
+config redirect
+ option name mariadb
+ option src wan
+ option src_dport 3306
+ option dest lan
+ option dest_ip 192.168.1.2
+ option proto tcp
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 3306
+ option proto tcp
+
+
--- /dev/null
+#!/bin/sh
+# This file is part of Ian Kelling's automated-distro-installer
+# Copyright (C) 2024 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+set -xe
+# librecmc 1.5.1 is missing nfs-kernel-server and screen
+source /etc/os-release
+if [ "$ID" == librecmc ] && [ "$VERSION" == v1.5.1-core ]; then
+ cat >/etc/opkg/customfeeds.conf <<'EOF'
+src/gz openwrt_packages http://downloads.openwrt.org/releases/19.07.3/packages/mips_24kc/packages
+fi
+EOF
+fi
+
+if ! opkg list-installed|grep bash; then
+ opkg update
+ opkg install bash
+fi
+
+if [ -f /root/bash-bear ]; then
+ mkdir -p /usr/local/lib
+ mv /root/bash-bear /usr/local/lib
+fi
+
+# this isnt used anymore
+export HOME_DOMAIN=$1
+shift
+wrt-setup-local "$@"
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+x="$(readlink -f "$BASH_SOURCE")"; cd ${x%/*}
+
+usage() {
+ cat <<EOF
+usage: ${0##*/} [-h|--help] [HOST/IP] [wrt-setup-local_ARGS]
+setup my router in general: dhcp, dns, etc.
+
+Default HOST is 10.0.0.1 or 10.2.0.1 if they are the gateway, otherwise
+it must be specified.
+
+Note, use -m "''" to send an empty mac arg. When we get a new enough
+bash, we can use ${@@Q} to properly pass an empty var.
+
+
+Note, if we dont have internet yet, then just download the bash package,
+scp it over manually and install it, eg:
+
+cat /etc/opkg/distfeeds.conf
+wget https://librecmc.org/librecmc/downloads/snapshots/v1.5.1-core/packages/mips_24kc/packages/bash_5.0-3_mips_24kc.ipk
+scp bash_5.0-3_mips_24kc.ipk wrt:
+ssh wrt
+opkg install /root/bash_5.0-3_mips_24kc.ipk
+EOF
+ wrt-setup-local -h
+ exit $1
+}
+
+
+case $1 in
+ -h|--help) usage ;;
+ -*) : ;;
+ ?*) h="$1"; shift ;;
+esac
+
+if [[ ! $h ]]; then
+ read -r _ _ gateway _ < <(ip -4 route get 8.8.8.8)
+ case $gateway in
+ 10.0.0.1|10.2.0.1)
+ h=root@$gateway
+ ;;
+ *)
+ echo "$0: error: gateway = $gateway and no HOST/IP specified"
+ exit 1
+ ;;
+ esac
+fi
+
+echo "$0: h=$h"
+# todo: ecdsa key not working with dropbear
+cat ~/.ssh/{h,hrsa,home}.pub | ssh $h dd of=/etc/dropbear/authorized_keys
+scp /a/work/libremanage/libremanage /a/bin/fai/wrt-init /a/bin/fai/wrt-setup-local /a/bin/cedit/cedit $h:/usr/bin
+# relay is built for openwrt 18.06.2, r7676-cddd7b4c77
+
+#/a/opt/openwrt/source/bin/packages/mips_24kc/mypackages/relay_1.0-1_mips_24kc.ipk \
+
+scp /q/root/shadow/router /p/c/machine_specific/wrt/etc/dropbear/dropbear_rsa_host_key \
+ /p/router-secrets /p/c/machine_specific/wrt/etc/wg.{key,psk} /p/c/ptr-data /p/c/{dnsmasq,cmc-firewall}-data /b/bash-bear-trap/bash-bear $h:
+scp ../openwrtkeyring/usign/* $h:/etc/opkg/keys
+
+ssh $h wrt-init ${HOME_DOMAIN:-b8.nz} "$@"
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+f=/usr/local/lib/bash-bear;test -r $f || { echo "error: $0 no $f" >&2;exit 1;}; . $f
+
+usage() {
+ cat <<EOF
+usage: ${0##*/} [-h] [-t 2|3|test|client] [-m WIRELESS_MAC] [hostname]
+setup my router in general: dhcp, dns, etc.
+
+Type 2 or 3 is for setting up a backup device, there are two kinds so
+that you can switch the main device to a backup, then a backup to the
+main. Type test is for setting up a testing device.
+
+Passing an empty string for WIRELESS_MAC, or if none is defined in the
+secrets file, will cause the device's native mac to be used.
+
+EOF
+
+ exit $1
+}
+
+
+
+zblock=false
+if [[ -e /root/zblock ]]; then
+ zblock=true
+fi
+
+dnsmasq_restart=false
+unbound_restart=false
+firewall_restart=false
+dev2=false
+test=false
+client=false
+ap=false
+libremanage_host=wrt2
+lanip=1
+while getopts hm:t:yz opt; do
+ case $opt in
+ h) usage ;;
+ t)
+ case $2 in
+ 2|3)
+ dev2=true
+ libremanage_host=$hostname
+ ;;&
+ 2)
+ lanip=4
+ hostname=wrt2
+ ;;
+ 3)
+ lanip=14
+ hostname=wrt3
+ ;;
+ test)
+ test=true
+ ;;
+ client)
+ client=true
+ ;;
+ ap)
+ ap=true
+ lanip=53
+ hostname=cmcap
+ ;;
+ *) echo "$0: unexpected arg to -t: $*" >&2; usage 1 ;;
+ esac
+ ;;
+ y)
+ zblock=false
+ rm -f /root/zblock
+ ;;
+ z)
+ zblock=true
+ touch /root/zblock
+ ;;
+ m) mac=$OPTARG ;;
+ *) echo "$0: Internal error! unexpected args: $*" >&2 ; usage 1 ;;
+ esac
+done
+shift "$((OPTIND-1))" # Discard the options and sentinel --
+
+if [[ $1 ]]; then
+ h=$1
+elif [[ $hostname ]]; then
+ h=$hostname
+else
+ h=cmc
+fi
+
+if [[ ! $hostname ]]; then
+ hostname=$h
+fi
+
+
+secrets=false
+if [[ -e /root/router-secrets ]]; then
+ secrets=true
+ source /root/router-secrets
+fi
+
+if [[ ! $mac ]] && ! $test && $secrets; then
+ # if we wanted to increment it
+ #mac=${mac:0: -1}$((${mac: -1} + 2))
+ mac=${rwmac[$h]}
+fi
+
+if (( $# != 0 )); then
+ usage 1
+fi
+
+
+macpre=${mac:0: -1}
+macsuf=${mac: -1}
+
+
+p_updated=false
+pmirror() {
+ if $p_updated; then
+ return
+ fi
+ # background: upgrading all packages is not recommended because it
+ # doesn't go into the firmware. build new firmware if you want
+ # lots of upgrades. I think /tmp/opkg-lists is a pre openwrt 14 location.
+ f=(/var/opkg-lists/*)
+ if ! (( $(date -r $f +%s) + 60*60*24 > $(date +%s) )); then
+ if ! opkg update; then
+ echo "$0: warning: opkg update failed" >&2
+ fi
+ p_updated=true
+ fi
+}
+
+pi() {
+ to_install=()
+ for p in "$@"; do
+ pname=${p##*/}
+ pname=${pname%%_*}
+ if [[ ! $(opkg list-installed "$pname") ]]; then
+ to_install+=($p)
+ pmirror
+ fi
+ done
+ if [[ $to_install ]]; then
+ opkg install ${to_install[@]}
+ fi
+}
+
+v() {
+ printf "+ %s\n" "$*"
+ "$@"
+}
+
+######### uci example:#######
+# # https://wiki.openwrt.org/doc/uci
+# wan_index=$(uci show firewall | sed -rn 's/firewall\.@zone\[([0-9])+\]\.name=wan/\1/p')
+# wan="firewall.@zone[$wan_index]"
+# if [[ $(uci get firewall.@forwarding[0].dest) != $forward_dest ]]; then
+# # default is wan
+# v uci set firewall.@forwarding[0].dest=$forward_dest
+# uci commit firewall
+# firewall_restart=true
+# fi
+####### end uci example #####
+
+uset() {
+ printf "+ uset %s\n" "$*"
+ local key="$1"
+ local val="$2"
+ local service="${key%%.*}"
+ restart_var=${service}_restart
+ if [[ ! ${!restart_var} ]]; then
+ eval $restart_var=false
+ fi
+ if [[ $(uci get "$key") != "$val" ]]; then
+ v uci set "$key"="$val"
+ uci commit $service
+ eval $restart_var=true
+ fi
+}
+
+udel() {
+ printf "+ udel %s\n" "$*"
+ local key="$1"
+ local val="$2"
+ local service="${key%%.*}"
+ restart_var=${service}_restart
+ if [[ ! ${!restart_var} ]]; then
+ eval $restart_var=false
+ fi
+ if uci get "$key" &>/dev/null; then
+ v uci set "$key"="$val"
+ uci commit $service
+ eval $restart_var=true
+ fi
+}
+cedit() {
+ v command cedit -v "$@"
+}
+
+
+### network config
+###
+lan=10.0.0.0
+if $test; then
+ lan=10.1.0.0
+elif [[ $hostname == cmc || $hostname == cmcap ]]; then
+ lan=10.2.0.0
+elif $client; then
+ lan=10.3.0.0
+fi
+
+if $test; then
+ ssid="gnuv3"
+elif $secrets; then
+ ssid=${rssid[$h]}
+fi
+
+: ${ssid:=librecmc}
+
+
+if $secrets; then
+ key=${rkey[$h]}
+fi
+: ${key:=pictionary49}
+
+mask=255.255.0.0
+cidr=16
+l=${lan%.0}
+
+# why did we lock this? i don't know
+#passwd -l root ||: #already locked fails
+
+sed -ibak '/^root:/d' /etc/shadow
+# /root/router created by manually running passwd then copying the resulting
+# line. We have no mkpasswd on wrt/librecmc, then we scp it in.
+cat /root/router >>/etc/shadow
+# otherwise, serial console gets root login with no password
+uset system.@system[0].ttylogin 1
+
+
+
+cat >/usr/bin/archlike-pxe-mount <<'EOFOUTER'
+#!/bin/bash
+# symlinks are collapsed for nfs mount points, so use a bind mount.
+# tried putting this in /etc/config/fstab,
+# then doing block mount, it didn't work. This doesn't persist across reboots,
+# todo: figure that out
+rm -f /etc/fstab
+for d in /run/{arch,parabola}iso/bootmnt; do
+cat >>/etc/fstab <<EOF
+/mnt/usb/tftpboot $d none bind 0 0
+EOF
+mount | grep $d &>/dev/null || mount $d
+done
+/etc/init.d/nfsd restart
+EOFOUTER
+chmod +x /usr/bin/archlike-pxe-mount
+
+sed -i '/^root:/s,/bin/ash$,/bin/bash,' /etc/passwd
+
+
+
+uset dropbear.@dropbear[0].PasswordAuth 0
+uset dropbear.@dropbear[0].RootPasswordAuth 0
+uset dropbear.@dropbear[0].Port 2220
+if ! cmp -s /root/dropbear_rsa_host_key /etc/dropbear/dropbear_rsa_host_key; then
+ cp /root/dropbear_rsa_host_key /etc/dropbear/dropbear_rsa_host_key
+ dropbear_restart=true
+fi
+
+if $dropbear_restart; then
+ v /etc/init.d/dropbear restart
+fi
+
+
+uset network.lan.ipaddr $l.$lanip
+uset network.lan.netmask $mask
+if $dev2 || $client || $ap; then
+ if $dev2 || $ap; then
+ uset network.lan.gateway $l.1
+ uset network.wan.proto none
+ uset network.wan6.proto none
+ fi
+ /etc/init.d/dnsmasq stop
+ /etc/init.d/dnsmasq disable
+ /etc/init.d/odhcpd stop
+ /etc/init.d/odhcpd disable
+ rm -f /etc/resolv.conf
+ if $ap; then
+ cat >/etc/resolv.conf <<EOF
+nameserver $l.1
+EOF
+ else
+ cat >/etc/resolv.conf <<'EOF'
+nameserver 8.8.8.8
+nameserver 8.8.4.4
+EOF
+ fi
+
+ # things i tried to keep dnsmasq running but not enabled except local dns,
+ # but it didnt work right and i dont need it anyways.
+ # uset dhcp.wan.ignore $dev2 # default is false
+ # uset dhcp.lan.ignore $dev2 # default is false
+ # uset dhcp.@dnsmasq[0].interface lo
+ # uset dhcp.@dnsmasq[0].localuse 0
+ # uset dhcp.@dnsmasq[0].resolvfile /etc/dnsmasq.conf
+ # uset dhcp.@dnsmasq[0].noresolv 1
+ # todo: populate /etc/resolv.conf with a static value
+
+else
+ # these are the defaults
+
+ # this is not needed unless switching from the above condition.
+ # disabling just to debug
+ #uset network.lan.gateway ''
+
+ uset network.wan.proto dhcp
+ uset network.wan6.proto dhcpv6
+ /etc/init.d/dnsmasq start
+ # todo: figure out why this returns 1
+ /etc/init.d/dnsmasq enable ||:
+ /etc/init.d/odhcpd start
+ /etc/init.d/odhcpd enable
+fi
+
+wireless_restart=false
+
+if $client; then
+ uset wireless.default_radio0.network 'wwan'
+ uset wireless.default_radio0.ssid ${rclientssid[$h]}
+ uset wireless.default_radio0.encryption 'psk2'
+ uset wireless.default_radio0.device 'radio0'
+ uset wireless.default_radio0.mode 'sta'
+ uset wireless.default_radio0.bssid ${rclientbssid[$h]}
+ # todo: look into whether 5g network is available.
+ uset wireless.default_radio0.key ${rclientkey[$h]}
+ uset wireless.radio0.disabled false
+ uset wireless.radio1.disabled true
+else
+ # defaults, just reseting in case client config ran
+ uset wireless.default_radio0.network lan
+ uset wireless.default_radio0.mode ap
+ for x in 0 1; do
+ uset wireless.default_radio$x.ssid "$ssid"
+ uset wireless.default_radio$x.key $key
+ uset wireless.default_radio$x.encryption psk2
+ if [[ $mac ]]; then
+ uset wireless.default_radio$x.macaddr $macpre$((macsuf + 2*x))
+ fi
+ # disable/enable. secondary device has wireless disabled
+ uset wireless.radio$x.disabled $dev2
+ done
+fi
+
+if grep '^OPENWRT_BOARD="mvebu/cortexa9"' /etc/os-release &>/dev/null; then
+ # todo, I also enabled irqbalance, didnt script it though
+ # https://forum.openwrt.org/t/wrt1900acs-wifi-issue-after-upgrade-from-19-07-to-21-02-vacuum-cleaner-legacy-rate-support/113311/28
+ cat >/etc/rc.local <<'EOF'
+echo "0" >> /sys/kernel/debug/ieee80211/phy0/mwlwifi/tx_amsdu
+echo "0" >> /sys/kernel/debug/ieee80211/phy1/mwlwifi/tx_amsdu
+exit 0
+EOF
+ chmod +x /etc/rc.local
+ /etc/rc.local
+ uset wireless.radio0.disassoc_low_ack 0
+ uset wireless.radio1.disassoc_low_ack 0
+fi
+
+
+# found with https://openwrt.org/docs/guide-user/network/wifi/iwchan.
+# However, the default also chooses 11, and better to let it choose in case things change.
+# case $HOSTNAME in
+# cmc)
+# uset wireless.radio0.channel 11
+# ;;
+# esac
+
+
+# usb, screen, relay are for libremanage
+# rsync is for brc
+#
+# relay package temporarily disabled
+# /root/relay_1.0-1_mips_24kc.ipk
+#
+# note: prometheus-node-exporter-lua-openwrt seems to be a dependency of
+# prometheus-node-exporter-lua in practice.
+
+pkgs=(
+ tcpdump
+ screen
+ rsync
+ kmod-usb-storage
+ block-mount
+ kmod-fs-ext4
+ prometheus-node-exporter-lua-openwrt
+ prometheus-node-exporter-lua
+)
+
+if ! $ap; then
+ pkgs+=(
+ unbound-daemon
+ unbound-checkconf
+ )
+fi
+
+v pi "${pkgs[@]}"
+# nfs-kernel-server \
+ # openvpn-openssl adblock libusb-compat \
+ # kmod-usb-serial-cp210x kmod-usb-serial-ftdi \
+
+
+cat >/etc/libremanage.conf <<EOF
+${libremanage_host}_type=switch
+${libremanage_host}_channel=1
+EOF
+
+
+
+v /etc/init.d/fstab enable ||:
+
+# rebooting makes mounting work, but comparing lsmod,
+# i'm guessing this will too. todo, test it.
+# 255 == module already loaded
+for mod in scsi_mod sd_mod; do v modprobe $mod || [[ $? == 255 ]]; done
+
+# for archlike pxe. The default settings in the installer expect to find
+# the NFS at one of these dirs
+mkdir -p /run/archiso/bootmnt
+mkdir -p /run/parabolaiso/bootmnt
+
+# todo: at some later time, i found /mnt/usb not mounted, watch to see if
+# that is the case after running this or rebooting.
+# wiki says safe to do in case of fstab changes:
+
+## ian: usb broke on old router. if that happens, can just comment this to disable problems
+# echo | cedit /etc/config/fstab ||:
+cedit /etc/config/fstab <<EOF || { v block umount; v block mount; }
+config global automount
+ option from_fstab 1
+ option anon_mount 1
+
+config mount
+# /overlay is an / overlay mount for installing extra packages, etc.
+# https://openwrt.org/docs/guide-user/additional-software/extroot_configuration
+ option target /mnt/usb
+# option target /overlay
+ option device /dev/sda1
+ option fstype ext4
+ option options rw,async,noatime,nodiratime
+ option enabled 0
+EOF
+
+
+# ian: disabled because afaik I don't need it, no benefit.
+# config global autoswap
+# option from_fstab 1
+# option anon_swap 1
+
+# config swap
+# option device /dev/sda1
+# option enabled 1
+
+
+
+
+# exportfs -ra wont cut it when its the same path, but now a bind mount
+# todo: restart nfs when nfs is enabled?
+#cedit /etc/exports <<EOF || v /etc/init.d/nfsd restart ||:
+cedit /etc/exports <<EOF ||:
+/mnt/usb $lan/$cidr(rw,no_root_squash,insecure,sync,no_subtree_check)
+# for arch pxe
+/run/archiso/bootmnt $lan/$cidr(rw,no_root_squash,insecure,sync,no_subtree_check)
+/run/parabolaiso/bootmnt $lan/$cidr(rw,no_root_squash,insecure,sync,no_subtree_check)
+EOF
+
+
+# todo: enable nfs when we need it only.
+# v /etc/init.d/portmap start
+# v /etc/init.d/nfsd start
+# v /etc/init.d/portmap enable
+# v /etc/init.d/nfsd enable
+
+
+cedit /etc/config/prometheus-node-exporter-lua <<'EOF' || /etc/init.d/prometheus-node-exporter-lua restart
+config prometheus-node-exporter-lua 'main'
+ option listen_ipv6 '0'
+ option listen_interface 'lan'
+ option listen_port '9100
+EOF
+
+# default, as of this writing is:
+# config prometheus-node-exporter-lua 'main'
+# option listen_interface 'loopback'
+# option listen_port '9100'
+
+
+
+
+
+########## openvpn exampl
+########## missing firewall settings for routing lan
+########## traffic
+# v /etc/init.d/openvpn start
+# v /etc/init.d/openvpn enable
+
+# # from https://wiki.openwrt.org/doc/uci/firewall
+# # todo: not sure if /etc/init.d/network needs restarting.
+# # I did, and I had to restart the vpn afterwards.
+# # This maps a uci interface to a real interface which is
+# # managed outside of uci.
+# cedit /etc/config/network <<'EOF' ||:
+# config interface 'tun0'
+# option ifname 'tun0'
+# option proto 'none'
+# EOF
+# cedit /etc/config/openvpn <<'EOF' || v /etc/init.d/openvpn restart
+# config openvpn my_client_config
+# option enabled 1
+# option config /etc/openvpn/client.conf
+# EOF
+
+wgip4=10.3.0.1/24
+wgip6=fdfd::1/64
+wgport=26000
+
+network_restart=false
+if $client; then
+ cedit wific /etc/config/network <<EOF || network_restart=true
+# https://openwrt.org/docs/guide-user/network/wifi/connect_client_wifi
+config interface 'wwan'
+ option proto 'dhcp'
+EOF
+fi
+
+cedit /etc/config/network <<EOF || network_restart=true
+config 'route' 'transmission'
+ option 'interface' 'lan'
+ option 'target' '10.174.0.0'
+ option 'netmask' '255.255.0.0'
+ option 'gateway' '$l.2'
+
+option interface 'wg0'
+ option proto 'wireguard'
+ option private_key '$(cat /root/wg.key)'
+ option listen_port $wgport
+ list addresses '10.3.0.1/24'
+ list addresses 'fdfd::1/64'
+
+# tp
+config wireguard_wg0 'wgclient'
+ option public_key '3q+WJGrm85r59NgeXOIvppxoW4ux/+koSw6Fee1c1TI='
+ option preshared_key '$(cat /root/wg.psk)'
+ list allowed_ips '10.3.0.2/24'
+ list allowed_ips 'fdfd::2/64'
+EOF
+
+# Need to reload before we change dnsmasq to give out
+# static ips in our new range.
+if $network_restart; then
+ v /etc/init.d/network reload
+fi
+
+firewall-cedit() {
+
+ if $client; then
+ cedit wific /etc/config/firewall <<EOF
+config zone
+ option name wwan
+ option input REJECT
+ option output ACCEPT
+ option forward REJECT
+ option masq 1
+ option mtu_fix 1
+ option network wwan
+EOF
+ fi
+
+ case $hostname in
+ wrt)
+ cedit host /etc/config/firewall <<EOF
+config redirect
+ option name ssh
+ option src wan
+ option src_dport 22
+ option dest_ip $l.3
+ option dest lan
+EOF
+ ;;
+ cmc)
+ cedit host /etc/config/firewall <<EOF
+config redirect
+ option name ssh
+ option src wan
+ option src_dport 22
+ option dest_ip $l.2
+ option dest lan
+EOF
+ ;;
+ esac
+
+
+ cedit /etc/config/firewall <<EOF
+## begin no external dns for ziva
+config rule
+ option src lan
+ option src_ip 10.2.0.23
+ option dest_port 53
+ option dest wan
+ option target REJECT
+
+
+config rule
+ option src wan
+ option dest_ip 10.2.0.23
+ option src_port 53
+ option dest lan
+ option target REJECT
+
+
+config rule
+ option src lan
+ option src_ip 10.2.0.31
+ option dest_port 53
+ option dest wan
+ option target REJECT
+
+
+config rule
+ option src wan
+ option dest_ip 10.2.0.31
+ option src_port 53
+ option dest lan
+ option target REJECT
+
+
+config rule
+ option src lan
+ option src_ip 10.2.0.32
+ option dest_port 53
+ option dest wan
+ option target REJECT
+
+
+config rule
+ option src wan
+ option dest_ip 10.2.0.32
+ option src_port 53
+ option dest lan
+ option target REJECT
+## end no external dns for ziva
+
+$(. /root/cmc-firewall-data)
+
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 22
+
+config redirect
+ option name promkd
+ option src wan
+ option src_dport 9091
+ option dest_port 9091
+ option dest_ip $l.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 9091
+
+# was working on an openvpn server, didn't finish
+# config redirect
+# option name vpnkd
+# option src wan
+# option src_dport 1196
+# option dest_port 1196
+# option dest_ip $l.2
+# option dest lan
+# config rule
+# option src wan
+# option target ACCEPT
+# option dest_port 1196
+
+
+config redirect
+ option name sshkdalt
+ option src wan
+ option src_dport 8989
+ option dest_port 8989
+ option dest_ip $l.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 8989
+
+
+
+config redirect
+ option name icecast
+ option src wan
+ option src_dport 8000
+ option dest_port 8000
+ option dest_ip $l.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 8000
+
+config rule
+ option name sshcmc
+ option src wan
+ option target ACCEPT
+ option dest_port 2220
+
+config rule
+ option name wg
+ option src wan
+ option target ACCEPT
+ option dest_port $wgport
+ option proto udp
+
+config redirect
+ option name navidromehttps
+ option src wan
+ option src_dport 4500
+ option dest_port 4500
+ option dest_ip $l.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 4500
+
+config redirect
+ option name navidrome
+ option src wan
+ option src_dport 4533
+ option dest_port 4533
+ option dest_ip $l.2
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 4533
+
+# So a client can just have b8.nz dns even when they
+# are on the lan.
+#config redirect
+# option name navidromelan
+# option src lan
+# option src_dport 4533
+# option dest_port 4533
+# option dest_ip $l.2
+# option dest lan
+
+
+# config redirect
+# option name icecast
+# option src wan
+# option src_dport 8000
+# option dest_port 8000
+# option dest_ip $l.2
+# option dest lan
+# config rule
+# option src wan
+# option target ACCEPT
+# option dest_port 8000
+
+config redirect
+ option name http
+ option src wan
+ option src_dport 80
+ option dest lan
+ option dest_ip $l.7
+ option proto tcp
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 80
+ option proto tcp
+
+config redirect
+ option name https
+ option src wan
+ option src_dport 443
+ option dest lan
+ option dest_ip $l.7
+ option proto tcp
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 443
+ option proto tcp
+
+# config redirect
+# option name httpskd8448
+# option src wan
+# option src_dport 8448
+# option dest lan
+# option dest_ip $l.2
+# option proto tcp
+# config rule
+# option src wan
+# option target ACCEPT
+# option dest_port 8448
+# option proto tcp
+
+config redirect
+ option name syncthing
+ option src wan
+ option src_dport 22001
+ option dest_ip $l.8
+ option dest lan
+config rule
+ option src wan
+ option target ACCEPT
+ option dest_port 22001
+
+
+#config redirect
+# option name i2p
+# option src wan
+# option src_dport $i2pport
+# option dest_ip $l.178
+# option dest lan
+#config rule
+# option src wan
+# option target ACCEPT
+# option dest_port $i2pport
+
+config rule
+ option name ssh-ipv6
+ option src wan
+ option dest lan
+ # note, using mac transform, we could allow all traffic to a host like this,
+ # replacing 1 as appropriate
+ #option dest_ip ::111:11ff:fe11:1111/::ffff:ffff:ffff:ffff
+ option dest_port 22
+ option target ACCEPT
+ option family ipv6
+
+# config rule
+# option name http-ipv6
+# option src wan
+# option dest lan
+# option dest_port 80
+# option target ACCEPT
+# option family ipv6
+
+# config rule
+# option name https-ipv6
+# option src wan
+# option dest lan
+# option dest_port 443
+# option target ACCEPT
+# option family ipv6
+
+config rule
+ option name node-exporter
+ option src wan
+ option dest lan
+ option dest_port 9101
+ option target ACCEPT
+ option family ipv6
+
+config rule
+ option name mail587-ipv6
+ option src wan
+ option dest lan
+ option dest_port 587
+ option target ACCEPT
+ option family ipv6
+
+EOF
+}
+firewall-cedit || firewall_restart=true
+
+# firewall comment:
+# not using and in newer wrt, fails, probably due to nonexistent file, error output
+# on:
+
+# Reference error: left-hand side expression is not an array or object
+# In [anonymous function](), file /usr/share/ucode/fw4.uc, line 3137, byte 12:
+# called from function [arrow function] (/usr/share/ucode/fw4.uc:733:71)
+# called from function foreach ([C])
+# called from function [anonymous function] (/usr/share/ucode/fw4.uc:733:72)
+# called from function render_ruleset (/usr/share/firewall4/main.uc:56:24)
+# called from anonymous function (/usr/share/firewall4/main.uc:143:29)
+#
+# ` if (!inc.enabled) {`
+# Near here -------^
+#
+#
+# The rendered ruleset contains errors, not doing firewall restart.
+# /usr/bin/wrt-setup-local:160:error: ""$@"" returned 1
+
+## include a file with users custom iptables rules
+#config include
+# option path /etc/firewall.user
+# option type 'restore'
+# option family 'ipv4'
+
+
+
+# not using wireguard for now
+# if ! uci get firewall.@zone[1].network | grep wg0 &>/dev/null; then
+# # cant mix cedit plus uci
+# echo | cedit /etc/config/firewall ||:
+# uci add_list firewall.@zone[1].network=wg0
+# uci commit firewall
+# firewall-cedit ||:
+# firewall_restart=true
+# fi
+
+
+
+cedit /etc/hosts <<EOF ||:
+127.0.1.1 $hostname
+EOF
+
+
+#mail_host=$(grep -F mail.iankelling.org /etc/hosts | awk '{print $1}')
+# if [[ $mail_host ]]; then
+# sed -i '/^$mail_host/a mail.iankelling.org' /etc/hosts
+# fi
+
+
+uset dhcp.@dnsmasq[0].domain b8.nz
+uset system.@system[0].hostname $hostname
+uset dhcp.@dnsmasq[0].local
+
+# uci doesnt seem to have a way to set an empty value,
+# if you delete it, it goes back to the default. this seems
+# to be a decent workaround.
+# todo: setup /etc/resolv.conf to point to 127.0.0.1
+# later note: disabled, I dunno why I set this.
+# uset dhcp.@dnsmasq[0].resolvfile /dev/null
+
+# if dnsmasq happens to not send out a dns server,
+# odhcpd will send one out like this:
+# NetworkManager[953]: <info> [1614982580.5192] dhcp6 (wlan0): option dhcp6_name_servers => 'fd58:5801:8e02::1'
+# but i dont want ipv6 dns, just keep it simple to ipv4.
+# I know my isp doesnt have ipv6 right now,
+# so just stop this thing.
+# note: tried this, it didn't do anything:
+# uset dhcp.@odhcpd[0].dns 10.2.0.1
+
+# iank, disablde while debugging.
+#/etc/init.d/odhcpd stop
+#/etc/init.d/odhcpd disable
+
+# todo: make the above conditional on which server this is.
+
+## left commented in case we have ipv6 problems in the future
+# avoid errors in log. current isp doesnt have ipv6
+#uset unbound.@unbound[0].protocol ip4_only
+
+# todo: im not sure all these are needed, but they all look
+# like good options.
+# https://blog.cloudflare.com/dns-over-tls-for-openwrt/
+# https://gist.github.com/vqiu/7b32d3a19a7a09d32e108d998de166c2
+#https://blog.thestateofme.com/2018/04/04/howto-secure-your-dns-with-a-raspberry-pi-unbound-and-cloudflare-1-1-1-1/
+#
+# # i found that the zone example was having no effect on the config
+# # here:
+# https://github.com/openwrt/packages/blob/openwrt-19.07/net/unbound/files/README.md
+#
+# # todo: unbound-control, i'm not sure what the purpose of that thing is, some
+# # kind of coordination with dhcp of dnsmasq, but what?
+#
+# note: for debugging, edit /etc/init.d/unbound, change
+# procd_set_param command $PROG -d -c $UB_TOTAL_CONF
+# to:
+# procd_set_param command $PROG -vvv -d -c $UB_TOTAL_CONF
+
+if ! $ap; then
+ {
+ cat <<'EOF'
+do-tcp: yes
+prefetch: yes
+qname-minimisation: yes
+rrset-roundrobin: yes
+use-caps-for-id: yes
+do-ip6: no
+private-domain: b8.nz
+local-zone: "10.in-addr.arpa." transparent
+access-control-view: 10.2.0.31/32 "youtube"
+EOF
+
+ if $zblock; then
+ cat <<'EOF'
+# no sy until that dongle is used by ziva
+
+# syw
+#access-control-view: 10.2.0.7/32 "youtube"
+# bow
+access-control-view: 10.2.0.29/32 "youtube"
+# samsungtab
+access-control-view: 10.2.0.32/32 "youtube"
+EOF
+ fi
+ } | cedit /etc/unbound/unbound_srv.conf || unbound_restart=true
+
+
+ # dns based blocking vs ip based. with ip, same
+ # server can have multiple domains. in dns,
+ # you have to make sure clients to use the local dns.
+ # https dns will need to be blocked by ip in
+ # order to be comprehensive
+
+
+ cedit /etc/unbound/unbound_ext.conf <<EOF || unbound_restart=true
+
+$(. /root/ptr-data)
+
+local-data-ptr: "10.2.0.1 cmc.b8.nz"
+
+local-data-ptr: "10.174.2.2 transmission.b8.nz"
+local-data-ptr: "10.173.8.1 defaultnn.b8.nz"
+local-data-ptr: "10.173.8.2 nn.b8.nz"
+
+forward-zone:
+ name: "."
+# forward-addr: 8.8.8.8
+# forward-addr: 8.8.8.8
+
+# ssl disabled due to this error:
+#Sat Dec 24 03:34:44 2022 daemon.err unbound: [6568:0] error: ssl handshake failed crypto error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
+#Sat Dec 24 03:34:44 2022 daemon.notice unbound: [6568:0] notice: ssl handshake failed 1.0.0.3 port 853
+# on OPENWRT_RELEASE="OpenWrt SNAPSHOT r18639-f5865452ac"
+# from about feb 2022
+
+# https://developers.cloudflare.com/1.1.1.1/1.1.1.1-for-families/setup-instructions/dns-over-https
+# forward-addr: 1.1.1.3@853#family.cloudflare-dns.com
+# forward-addr: 1.0.0.3@853#family.cloudflare-dns.com
+# forward-ssl-upstream: yes
+ forward-first: no
+ forward-addr: 1.1.1.3
+ forward-addr: 1.0.0.3
+
+view:
+ name: "youtube"
+ local-zone: "googlevideo.com." refuse
+ local-zone: "video.google.com." refuse
+ local-zone: "youtu.be." refuse
+ local-zone: "youtube-nocookie.com." refuse
+ local-zone: "youtube-ui.l.google.com." refuse
+ local-zone: "youtube.com." refuse
+ local-zone: "youtube.googleapis.com." refuse
+ local-zone: "youtubeeducation.com." refuse
+ local-zone: "youtubei.googleapis.com." refuse
+ local-zone: "yt3.ggpht.com." refuse
+ local-zone: "youtubekids.com." refuse
+ # try global if no match in view
+ view-first: yes
+EOF
+
+
+ if $unbound_restart; then
+ /etc/init.d/unbound restart
+ if ! unbound-checkconf; then
+ echo $0: error: unbound-checkconf failed >&2
+ exit 1
+ fi
+ fi
+fi # end if $ap
+
+# # disabled for now. i want to selectively enable it
+# # for specific hosts.
+# if [[ $(uci get adblock.global.adb_enabled) != 0 ]]; then
+# v uci set adblock.global.adb_enabled=0
+# uci commit adblock
+# /etc/init.d/adblock restart
+# fi
+# # https://github.com/openwrt/packages/tree/master/net/adblock/files
+# cat >/etc/crontabs/root <<'EOF'
+# 0 06 * * * /etc/init.d/adblock reload
+# EOF
+
+
+# useful: http://wiki.openwrt.org/doc/howto/dhcp.dnsmasq
+
+# sometimes /mnt/usb fails, cuz it's just a flash drive,
+# so make sure we have this dir or else dnsmasq will fail
+# to start.
+mkdir -p /mnt/usb/tftpboot
+cedit /etc/dnsmasq.conf <<EOF || dnsmasq_restart=true
+
+# no dns
+port=0
+server=/b8.nz/#
+ptr-record=1.0.2.10.in-addr.arpa.,cmc.b8.nz
+
+# generated with host-info-update
+$(. /root/dnsmasq-data)
+
+# https://ret2got.wordpress.com/2018/01/19/how-your-ethereum-can-be-stolen-using-dns-rebinding/
+stop-dns-rebind
+rebind-domain-ok=b8.nz
+
+# This says the ip of dns server.
+# It is default if dnsmasq is doing dns, otherwise, we have to specify it.
+# To see it in action, I ran this from a client machine:
+# sudo dhcpcd -o domain_name_servers -T
+dhcp-option=option:dns-server,$l.1
+
+# use this when doing fai to get the right timezone, its nfsroot is
+# setup to use this dhcp option only and call ntpdate.
+# generate ips with:
+# for h in 0.ubuntu.pool.ntp.org 1.ubuntu.pool.ntp.org ntp.ubuntu.com; do host -t a $h | awk '{print $NF}'; done | while read -r l; do printf ,$l; done
+dhcp-option=option:ntp-server,188.165.3.28,202.12.97.45,91.236.251.13,50.205.244.23,78.30.254.80,31.131.0.123,202.65.114.202,94.228.220.14,185.125.190.57,185.125.190.58,91.189.91.157,185.125.190.56,91.189.94.4
+
+
+# results from googling around dnsmasq optimizations
+# about 50k in memory. router has 62 megs.
+# in a browsing session, I probably won't ever do 5000 lookups
+# before the ttl expiration or whatever does expiration.
+cache-size=10000
+
+# ask all servers, use the one which responds first.
+# http://ma.ttwagner.com/make-dns-fly-with-dnsmasq-all-servers/
+all-servers
+
+# namebench benchmarks dns servers. google's dns was only
+# slightly less fast than some others, and I trust it more
+# to give accurate results, stay relatively fast, and
+# not do anythin too malicious, so just use that.
+# download namebench and run it like this:
+# for x in all regional isp global preferred nearby; do ./namebench.py -s \$x -c US -i firefox -m weighted -J 10 -w; echo \$x; hr; done
+# google
+server=1.1.1.3
+server=1.0.0.3
+server=2606:4700:4700::1113
+server=2606:4700:4700::1003
+
+server=10.2.0.1
+# server=8.8.4.4
+# server=8.8.8.8
+# server=2001:4860:4860::8888
+# server=2001:4860:4860::8844
+
+
+# to fixup existin ips, on the client you can do
+# sudo dhclient -r; sudo dhclient <interface-name>
+# or on cmc,
+# /etc/init.d/dnsmasq stop
+# vi /tmp/dhcp.leases
+# /etc/init.d/dnsmasq start
+
+
+# default dhcp range is 100-150
+
+# template
+# dhcp-host=,$l.,
+
+# pxe tftpboot for arch-like. todo: openwrt snapshot from 2022-01, it cant
+# access /mnt/usb/tftpboot due to ujail sandbox
+#enable-tftp=br-lan
+#tftp-root=/mnt/usb/tftpboot
+#tftp-root=/var/run/dnsmasq/tftpboot
+
+
+dhcp-optsfile=/var/run/dnsmasq/dhcpopts.conf
+
+# for debugging dhcp
+#log-queries=extra
+EOF
+
+
+if $dnsmasq_restart && ! $dev2 && ! $ap; then
+ # todo: can our ptr records be put in /etc/hosts?
+ # eg: user normal /etc/hosts records, and they wont be used for A resolution
+ # due to the other settings, but will be used for ptr? then maybe
+ # we dont have to restart dnsmasq for a dns update?
+ #
+ # interesing link:
+ # https://www.redpill-linpro.com/techblog/2019/08/27/evaluating-local-dnssec-validators.html#toggling-dnssec-validation-1
+ # we could turn on dnssec validation when wrt gets dnsmasq > 2.80. currently at 2.80.
+ # also we can turn off dnssec in systemd-resolved if we know the router is doing it.
+ #
+ # Also, reload of dnsmasq seems to break things, wifi
+ # clients were not getting internet connectivity.
+
+ v /etc/init.d/dnsmasq restart
+fi
+
+if $ap; then
+ v /etc/init.d/firewall disable
+ v /etc/init.d/firewall stop
+elif $firewall_restart; then
+ v /etc/init.d/firewall restart
+fi
+
+## turn off luci
+# if already stopped, gives error we want to ignore
+/etc/init.d/uhttpd stop |& sed '1{/^Command failed/d}'
+/etc/init.d/uhttpd disable |& sed '1{/^Command failed/d}'
+
+# this may just restart the network and take care of the network_restart below.
+if $wireless_restart; then
+ v wifi
+fi
+
+# todo: we should catch errors and still run this if needed
+if $network_restart; then
+ reboot
+fi
+
+v exit 0