Merge branch 'upstream'
authorIan Kelling <iank@fsf.org>
Wed, 18 Aug 2021 04:03:04 +0000 (00:03 -0400)
committerIan Kelling <iank@fsf.org>
Wed, 18 Aug 2021 04:03:04 +0000 (00:03 -0400)
113 files changed:
.gitignore [new file with mode: 0644]
COPYING [new file with mode: 0644]
README [new file with mode: 0644]
arch-init [new file with mode: 0755]
arch-init-chroot [new file with mode: 0755]
arch-init-remote [new file with mode: 0755]
arch-revm [new symlink]
archlike-iso-init [new file with mode: 0644]
archlike-pxe [new file with mode: 0755]
bash-trace [new symlink]
bind/db.0.2.10.in-addr.arpa [new file with mode: 0644]
bind/named.conf [new file with mode: 0644]
bind/named.conf.upstream [new file with mode: 0644]
chboot [new symlink]
chost [new file with mode: 0755]
debian-preseed [new file with mode: 0755]
debian-pxe-preseed [new file with mode: 0755]
devbyid [new symlink]
dsfull [new file with mode: 0755]
eboot [new file with mode: 0755]
encrypt [new file with mode: 0644]
encrypt.upstream [new file with mode: 0644]
fai-redep [new file with mode: 0755]
fai-revm [new file with mode: 0755]
fai-wrapper [new file with mode: 0644]
fai/config/basefiles/mk-basefile
fai/config/class/50-host-classes
fai/config/class/DEBIAN.var
fai/config/class/DEFAULT.var [new file with mode: 0644]
fai/config/class/FAIBASE.var
fai/config/class/LINODE.var [new file with mode: 0644]
fai/config/class/UBUNTU.var
fai/config/disk_config/VM [new file with mode: 0644]
fai/config/distro-install-common/devbyid [new file with mode: 0755]
fai/config/distro-install-common/end [new file with mode: 0755]
fai/config/distro-install-common/libreboot_grub.cfg [new file with mode: 0644]
fai/config/files/boot/bash-trace/DEFAULT [new file with mode: 0644]
fai/config/files/boot/chboot/DEFAULT [new file with mode: 0755]
fai/config/files/etc/apt/preferences.d/belenos/BELENOS [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/etiona-bionic/ETIONA [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/etiona-flidas/ETIONA [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/etiona-focal/ETIONA [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/etiona/ETIONA [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/flidas/FLIDAS [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/nabia-focal/NABIA [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/stretch/STRETCH [new file with mode: 0644]
fai/config/files/etc/apt/preferences.d/unstable/DEBIAN [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/aaa-etiona.list/ETIONA [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/aaa-nabia.list/NABIA [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/belenos.list/BELENOS [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/bionic.list/ETIONA [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/bulleye.list/BULLSEYE_FREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/bulleye.list/BULLSEYE_NONFREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/buster.list/BUSTER_FREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/buster.list/BUSTER_NONFREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/flidas.list/FLIDAS [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/focal.list/ETIONA [new symlink]
fai/config/files/etc/apt/sources.list.d/focal.list/FOCAL [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/focal.list/NABIA [new symlink]
fai/config/files/etc/apt/sources.list.d/stretch.list/STRETCH_FREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/stretch.list/STRETCH_NONFREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/testing.list/TESTING_FREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/testing.list/TESTING_NONFREE [new file with mode: 0644]
fai/config/files/etc/apt/sources.list.d/xenial.list/XENIAL [new file with mode: 0644]
fai/config/files/etc/apt/sources.list/DEFAULT [new file with mode: 0644]
fai/config/files/etc/apt/sources.list/GNOME [deleted file]
fai/config/files/etc/motd/FAIBASE [deleted file]
fai/config/files/etc/systemd/system/faicheck.service/VOL_BUSTER_BOOTSTRAP [new file with mode: 0644]
fai/config/files/root/.ssh/authorized_keys/.gitignore [new file with mode: 0644]
fai/config/files/root/fai-check/VOL_BUSTER_BOOTSTRAP [new file with mode: 0755]
fai/config/files/usr/bin/myncq/kd [new file with mode: 0755]
fai/config/hooks/extrbase.DEFAULT [new file with mode: 0755]
fai/config/hooks/instsoft.DEBIAN
fai/config/hooks/instsoft.DEFAULT [new file with mode: 0755]
fai/config/hooks/partition.DEFAULT [new file with mode: 0755]
fai/config/hooks/updatebase.UBUNTU
fai/config/package_config/DEBIAN
fai/config/package_config/FLIDAS [new file with mode: 0644]
fai/config/package_config/STANDARD
fai/config/package_config/UBUNTU
fai/config/package_config/UBUNTU.asc [new file with mode: 0644]
fai/config/scripts/DEBIAN/10-rootpw
fai/config/scripts/DEBIAN/20-capabilities
fai/config/scripts/DEBIAN/30-interface [deleted file]
fai/config/scripts/DEBIAN/40-misc
fai/config/scripts/DEMO/10-misc [deleted file]
fai/config/scripts/FLIDAS/12-iank [new file with mode: 0755]
fai/config/scripts/GRUB_EFI/11-iank [new symlink]
fai/config/scripts/GRUB_PC/10-setup
fai/config/scripts/GRUB_PC/11-iank [new file with mode: 0755]
fai/config/scripts/LAST/50-misc
fai/config/scripts/UBUNTU/90-apt
faiserver-disable [new file with mode: 0755]
faiserver-revm [new file with mode: 0755]
faiserver-setup [new file with mode: 0755]
faiserver-uninstall [new file with mode: 0755]
fresize [new file with mode: 0755]
grub.cfg.autodiscover [new file with mode: 0644]
grub.cfg.netinst [new file with mode: 0644]
grub.cfg.netinst-noreboot [new file with mode: 0644]
grub.cfg.sysinfo-linode [new file with mode: 0644]
install-chboot [new file with mode: 0755]
live-kexec [new symlink]
lk [new file with mode: 0755]
mk-basefile-big [new file with mode: 0755]
myfai-chboot [new file with mode: 0755]
myfai-chboot-local [new file with mode: 0755]
mymk-basefile [new file with mode: 0755]
pxe-server [new file with mode: 0755]
wrt-disabled-firewall-rules [new file with mode: 0644]
wrt-init [new file with mode: 0755]
wrt-setup [new file with mode: 0755]
wrt-setup-local [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5e08dd9
--- /dev/null
@@ -0,0 +1 @@
+/fai/config/class/51-multi-boot
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                    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.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..a1cb54d
--- /dev/null
+++ b/README
@@ -0,0 +1,315 @@
+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:
+head -c 2048 /dev/urandom | od | s dd of=/q/root/luks/host-demohost
+
+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.
+
+# 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
+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
+
+
+# Replacing a raid 10 disk
+
+# i expect better results with newer kernel and btrfs progs than the default stretch
+fai-server buster
+
+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.
+
+
+# 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
+
+# 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
+
+
+# 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.
diff --git a/arch-init b/arch-init
new file mode 100755 (executable)
index 0000000..2f14ad6
--- /dev/null
+++ b/arch-init
@@ -0,0 +1,114 @@
+#!/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
diff --git a/arch-init-chroot b/arch-init-chroot
new file mode 100755 (executable)
index 0000000..e173863
--- /dev/null
@@ -0,0 +1,169 @@
+#!/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
diff --git a/arch-init-remote b/arch-init-remote
new file mode 100755 (executable)
index 0000000..d8e4e29
--- /dev/null
@@ -0,0 +1,55 @@
+#!/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 $!
diff --git a/arch-revm b/arch-revm
new file mode 120000 (symlink)
index 0000000..de8dd4b
--- /dev/null
+++ b/arch-revm
@@ -0,0 +1 @@
+fai-revm
\ No newline at end of file
diff --git a/archlike-iso-init b/archlike-iso-init
new file mode 100644 (file)
index 0000000..25b9f86
--- /dev/null
@@ -0,0 +1,18 @@
+#!/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
diff --git a/archlike-pxe b/archlike-pxe
new file mode 100755 (executable)
index 0000000..db05bf9
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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
diff --git a/bash-trace b/bash-trace
new file mode 120000 (symlink)
index 0000000..015ae24
--- /dev/null
@@ -0,0 +1 @@
+fai/config/files/boot/bash-trace/DEFAULT
\ No newline at end of file
diff --git a/bind/db.0.2.10.in-addr.arpa b/bind/db.0.2.10.in-addr.arpa
new file mode 100644 (file)
index 0000000..522be5a
--- /dev/null
@@ -0,0 +1,23 @@
+; -*- 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
diff --git a/bind/named.conf b/bind/named.conf
new file mode 100644 (file)
index 0000000..91f58fd
--- /dev/null
@@ -0,0 +1,114 @@
+// 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";
+  };
+};
diff --git a/bind/named.conf.upstream b/bind/named.conf.upstream
new file mode 100644 (file)
index 0000000..ca52cb8
--- /dev/null
@@ -0,0 +1,45 @@
+// 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";
+};
diff --git a/chboot b/chboot
new file mode 120000 (symlink)
index 0000000..b311a15
--- /dev/null
+++ b/chboot
@@ -0,0 +1 @@
+fai/config/files/boot/chboot/DEFAULT
\ No newline at end of file
diff --git a/chost b/chost
new file mode 100755 (executable)
index 0000000..a26529f
--- /dev/null
+++ b/chost
@@ -0,0 +1,15 @@
+#!/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)
+h=${h##* }
+echo $h
diff --git a/debian-preseed b/debian-preseed
new file mode 100755 (executable)
index 0000000..e3df0dc
--- /dev/null
@@ -0,0 +1,144 @@
+#!/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
diff --git a/debian-pxe-preseed b/debian-pxe-preseed
new file mode 100755 (executable)
index 0000000..aaef9a6
--- /dev/null
@@ -0,0 +1,46 @@
+#!/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
diff --git a/devbyid b/devbyid
new file mode 120000 (symlink)
index 0000000..9a02442
--- /dev/null
+++ b/devbyid
@@ -0,0 +1 @@
+fai/config/distro-install-common/devbyid
\ No newline at end of file
diff --git a/dsfull b/dsfull
new file mode 100755 (executable)
index 0000000..709ddab
--- /dev/null
+++ b/dsfull
@@ -0,0 +1,104 @@
+#!/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
diff --git a/eboot b/eboot
new file mode 100755 (executable)
index 0000000..6d5ce5e
--- /dev/null
+++ b/eboot
@@ -0,0 +1,32 @@
+#!/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 "$@"
diff --git a/encrypt b/encrypt
new file mode 100644 (file)
index 0000000..89cc95f
--- /dev/null
+++ b/encrypt
@@ -0,0 +1,129 @@
+#!/usr/bin/ash
+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:
diff --git a/encrypt.upstream b/encrypt.upstream
new file mode 100644 (file)
index 0000000..819c4cf
--- /dev/null
@@ -0,0 +1,139 @@
+#!/usr/bin/ash
+
+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:
diff --git a/fai-redep b/fai-redep
new file mode 100755 (executable)
index 0000000..e7aab6d
--- /dev/null
+++ b/fai-redep
@@ -0,0 +1,146 @@
+#!/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
+
+readonly this_file="$(readlink -f -- "${BASH_SOURCE[0]}")"; cd "${this_file%/*}"
+
+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 ########
+
+# 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=$(chost $host) || faiserver_host=$host
+
+rsync -rlpt --delete --relative --exclude /fai/config/basefiles/ fai/config root@$faiserver_host:/srv
+
+sudo rsync -a /root/.ssh/home.pub \
+    root@$faiserver_host:/srv/fai/config/files/root/.ssh/authorized_keys/STANDARD
+# todo: automatically disable faiserver after a period so
+# these files are not available.
+
+if [[ $target ]]; then
+  if sudo test -e /q/root/shadow/$target; then
+    shadowfile=shadow/$target # empty otherwise
+  fi
+  sudo rsync -lpt --files-from=- /q/root root@$faiserver_host:/srv/fai/config/distro-install-common <<EOF
+luks/$target
+luks/host-$target
+$shadowfile
+EOF
+else
+  sudo rsync -rlpt /q/root/shadow /q/root/luks root@$faiserver_host:/srv/fai/config/distro-install-common
+fi
+
+dirs=(/p/c/machine_specific/${target:-*}/filesystem/etc/ssh)
+if [[ -e ${dirs[0]} ]]; then
+  rsync -rlpt --delete --relative ${dirs[@]} root@$faiserver_host:/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[*]} | \
+  ssh root@$faiserver_host dd of=/srv/fai/config/package_config/DESKTOP 2>/dev/null ||: # broken pipe
+
+
+rsync -rplt --include '/*.gz' --exclude '/**' --delete-excluded $BASEFILE_DIR/ root@$faiserver_host:/srv/fai/config/basefiles/
+ssh root@$faiserver_host bash <<'EOF'
+set -eE -o pipefail
+# 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.
+sed -ri 's,^ *(TFTP_DIRECTORY=).*,\1"/srv/tftp/fai",' /etc/default/tftpd-hpa
+systemctl restart tftpd-hpa
+
+changed=false
+f=/srv/fai/nfsroot/root/.ssh/known_hosts
+install -d -m 700 /srv/fai/nfsroot/root/.ssh
+# the known hosts entries that fai already sets up are like
+# IP,HOSTNAME key_info...
+# we are skipping the ip, because it doesn't block ssh
+# with a prompt as long as you have the user supplied hostname,
+# and i don't want to deal with getting it, it's not adding
+# any important security in this case.
+if ! grep -xFq "$line" $f &>/dev/null; then
+    changed=true
+    printf "%s\n" "$line" >>$f
+fi
+
+if ! modprobe nfsd &>/dev/null; then
+    # no apt-cache on maru debian, because we are low on space already
+    sed -i '/^ *APTPROXY=/d' /srv/fai/config/class/DEBIAN.var
+    # maru debian doesn't have loopback devs created
+    if ! losetup -f; then
+      shopt -s nullglob
+      x=(/dev/loop*)
+      minor=0
+      if (( ${#x[@]} )); then
+        minor=$(( ${x[-1]#/dev/loop} + 1 ))
+      fi
+      mknod -m660 /dev/loop$minor b 7 $minor
+      losetup -f
+    fi
+    # -B boo only iso, no nfsroot, no paritial miorr, no config space.
+    # -f = force, for overwriting
+    # -S = make squash image for http booting
+    # -d config space url, instead of putting it in the squash.img,
+    #  this just makes it so that we don't have to regenerate the img
+    #  when the config changes.
+    cd /srv/fai/config
+    tar czf /var/www/faiserver/html/config.tar.gz .
+    if $changed || [[ ! -e /var/www/faiserver/html/squash.img ]]; then
+      # note, on maru, selinux needs to be disabled in android before
+      # this will work.
+      mount
+      export debug=true
+      fai-cd -d http://faiserver:8080/config.tar.gz  -f -M -S /var/www/faiserver/html/squash.img
+      mount
+    fi
+fi
+EOF
diff --git a/fai-revm b/fai-revm
new file mode 100755 (executable)
index 0000000..0d117e6
--- /dev/null
+++ b/fai-revm
@@ -0,0 +1,198 @@
+#!/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.
+
+
+
+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
+
+Note, sometimes shutting down the existing demohost vm
+fails. Just run again if that happens.
+
+-d         Don't do dhcp setup 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. 1 and > 1 should be the only
+# important things to test.
+disk_count=1
+
+
+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"
+  e ./pxe-server $dhcp_arg
+  ./faiserver-disable
+}
+
+boot_arg=--pxe
+if is_arch_revm; then
+  e ./pxe-server $dhcp_arg demohost arch
+  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
+    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/BUSTER64.tar.gz
+    if [[ ! -e $isopath || $(stat -c %Y $isopath) -lt $(stat -c %Y $isosrc) ]]; then
+      e sudo fai-cd -g $(readlink -f grub.cfg.${iso%%.*}) -f -A $isopath
+    fi
+    boot_arg="--cdrom $isopath"
+    e fai-redep
+    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
+fi
+
+name=demohost
+
+e sudo virsh destroy $name ||:
+e sudo virsh undefine $name ||:
+
+
+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
+    sudo rm -f $f
+    # https://btrfs.wiki.kernel.org/index.php/FAQ
+    sudo touch $f
+    chattr +C $f
+    e sudo 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 sudo 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 sudo 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 sudo systemctl start libvirtd
+e sudo 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 /bin/true; do
+  e sleep 5
+done
+unset -f err-cleanup
+e ./pxe-server $dhcp_arg
+if is_arch_revm; then
+  ./arch-init-remote $name
+fi
diff --git a/fai-wrapper b/fai-wrapper
new file mode 100644 (file)
index 0000000..5efa7f1
--- /dev/null
@@ -0,0 +1,50 @@
+#!/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
index 085b9a486b618dc029e7017a3fca4b8f1651488a..39471d83ae7cbff6e8416731ba7066a2707b4d5d 100755 (executable)
@@ -1,5 +1,4 @@
 #! /bin/bash
-
 # mk-basefile, create basefiles for some distributions
 #
 # Thomas Lange, Uni Koeln, 2011-2021
@@ -22,6 +21,7 @@
 # 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
@@ -34,14 +34,19 @@ EXCLUDE_BOOKWORM=
 EXCLUDE_TRIXIE=
 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
 
 # here you can add packages, that are needed very early
 INCLUDE_DEBIAN=
-
+INCLUDE_ETIONA=ifupdown
+INCLUDE_NABIA=ifupdown
 
 setarch() {
 
@@ -108,6 +113,14 @@ EOM
 
 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 \
@@ -179,12 +192,11 @@ debgeneric() {
     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
@@ -214,8 +226,11 @@ prtdists() {
                  SLC7_64
     TRUSTY32     TRUSTY64
     XENIAL32     XENIAL64
+                 FLIDAS64
                  BIONIC64
+                 ETIONA64
                  FOCAL64
+                 NABIA64
     SQUEEZE32    SQUEEZE64
     WHEEZY32     WHEEZY64
     JESSIE32     JESSIE64
@@ -243,6 +258,8 @@ Usage: mk-basefile [OPTION] ... DISTRIBUTION
    -z                   Use gzip 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
@@ -260,7 +277,7 @@ attributes=
 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 ;;
@@ -270,6 +287,7 @@ while getopts ashzJd:kf: opt ; do
         k) cleanup=0 ;;
         h) usage ;;
         s) prtdists ; exit 0;;
+        x) cmd="$OPTARG" ;;
         ?) exit 3 ;; # error in option parsing
     esac
 done
@@ -298,6 +316,8 @@ case "$target" in
     SLC6_32) slc i386 6 ;;
     SLC6_64) slc amd64 6 ;;
     SLC7_64) slc amd64 7 ;;
+    BELENOS*|FLIDAS*|ETIONA*|NABIA*)
+        debgeneric $target $MIRROR_TRISQUEL ;;
     TRUSTY*|XENIAL*|BIONIC*|FOCAL*)
         debgeneric $target $MIRROR_UBUNTU ;;
     SQUEEZE*|WHEEZY*|JESSIE*|STRETCH*|BUSTER*|BULLSEYE*|BOOKWORM*|TRIXIE*|SID*)
index df38b888827b358166058648db04ad3574fe7de2..f6b7caa4b82e46fc30453dc4cc31392f037ed280 100755 (executable)
-#! /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 FOCAL FOCAL64 XORG";;
-    centos)
-        echo "FAIBASE CENTOS"   # you may want to add class XORG here
-        ifclass AMD64 && echo CENTOS8_64
-       ;;
-    slchost)
-        # Scientific Linux Cern, is very similar to CentOS. SLC should alsways use the class CENTOS
-        echo "FAIBASE CENTOS SLC"  # you may want to add class XORG here
-        ifclass I386 && echo SLC7_32
-        ifclass AMD64 && echo SLC7_64
-       ;;
-    *)
-        echo "FAIBASE DEBIAN DEMO" ;;
-esac
+# set these early so they are lowest priority.
+echo FAIBASE STANDARD DEBIAN
+
+
+# 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,
+# FLIDAS64, FLIDAS64BIG, ETIONA64, NABIA64
+# 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_FLIDAS, VOL_ETIONA, VOL_NABIA
+# 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,
+# BUSTER_FREE, BUSTER_NONFREE,
+# BULLSEYE_FREE, BULLSEYE_NONFREE
+# TESTING_FREE, TESTING_NONFREE,
+# XENIAL_FREE, BIONIC, FOCAL, FLIDAS, ETIONA, NABIA, STRETCH_LINODE.
+#
+# 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.
+#
+# REPARTITION: we try to reuse partitions/filesystems to install a new
+# os into a multi-os system, if we see some basic hueristics, like the
+# right amount of them. This overrides that.
+#
+# PARTITION_PROMPT: If we don't see partitions to reuuse, prompt
+# to make sure we really want to repartition and use a completely
+# fresh install. I use this in case our repartition check has
+# a bug in it, or I accidentally set REPARTITION.
+#
+# ROTATIONAL: in a system with ssd and hdd, install to the hdd
+# instead of the default ssd.
+#
+# RAID0: Use raid 0 even if there are >= 4 disks with boot partititions.
+#
+# LINODE: For running a vm on linode, especially one created with fai-cd.
+
+###### begin Template for 51-multi-boot ######
+#
+# It has reasonable combinations of above classes.
+# It's a noop until we replace _ with host names.
+
+#!/bin/bash
+if [[ ! -e /a/bin/fai/fai-wrapper || $FAI_ACTION == dirinstall ]]; then
+  case $HOSTNAME in
+    # buster based minimal recovery / bootstraping os:
+    _) echo BUSTER64 VOL_BUSTER_BOOTSTRAP BUSTER_FREE ;;
+    # flidas
+    _) echo UBUNTU FLIDAS64 VOL_FLIDAS FLIDAS ;;
+    # etiona
+    _) echo UBUNTU ETIONA64 VOL_ETIONA ETIONA ;;
+    # nabia
+    _) echo UBUNTU NABIA64 VOL_NABIA NABIA ;;
+    # stretch
+    _) echo STRETCH64 VOL_STRETCH STRETCH_FREE ;;
+    # buster
+    _) echo BUSTER64 VOL_BUSTER BUSTER_FREE ;;
+    # testing
+    _) echo STRETCH64 VOL_TESTING TESTING_FREE ;;
+    # xenial
+    _) echo UBUNTU XENIAL64 VOL_XENIAL XENIAL_FREE ;;
+    # bionic
+    _) echo UBUNTU BIONIC64 VOL_BIONIC BIONIC ;;
+    # focal
+    _) echo UBUNTU FOCAL64 VOL_FOCAL FOCAL ;;
+  esac
+fi
+###### end Template for 51-multi-boot ######
+
+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
index dc133a5c5329278ae34de4c2519964e6414af475..a00d0f86720bdea4cef033144ea7965a1319b236 100644 (file)
@@ -1,6 +1,7 @@
-release=bullseye
-apt_cdn=http://deb.debian.org
-security_cdn=http://security.debian.org
+# ian, commented, sources are set with fcopy
+# release=bullseye
+# 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
@@ -20,7 +21,8 @@ MODULESLIST="usbhid psmouse"
 
 # 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
+# APTPROXY=http://faiserver:3142
diff --git a/fai/config/class/DEFAULT.var b/fai/config/class/DEFAULT.var
new file mode 100644 (file)
index 0000000..a999512
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
index 31120399bc94cb7a4c92e596bf5ca1b7825973c8..dc507c77faa2b23e133ab46443036ffd11a6bddc 100644 (file)
@@ -1,3 +1,5 @@
+#### 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
@@ -5,18 +7,11 @@ FAI_ALLOW_UNSIGNED=1
 
 # 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
 
 # set parameter for install_packages(8)
 MAXPACKAGES=800
-
-# a user account will be created
-username=demo
-USERPW='$1$kBnWcO.E$djxB128U7dMkrltJHPf6d1'
diff --git a/fai/config/class/LINODE.var b/fai/config/class/LINODE.var
new file mode 100644 (file)
index 0000000..8f34a2c
--- /dev/null
@@ -0,0 +1,7 @@
+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
index a258b6ab74da4d65874a1ef4d98640fa9a4a996b..6a424950755ff54561c16564363f1a673eb0ba9e 100644 (file)
@@ -1,2 +1,4 @@
-ubuntumirror=http://archive.ubuntu.com
-ubuntudist=focal
+#iank, i define these by classes. commenting
+# to make sure these arent used
+#ubuntumirror=http://archive.ubuntu.com
+#ubuntudist=focal
diff --git a/fai/config/disk_config/VM b/fai/config/disk_config/VM
new file mode 100644 (file)
index 0000000..53c6527
--- /dev/null
@@ -0,0 +1,2 @@
+disk_config disk1 disklabel:gpt-bios bootable:1 fstabkey:uuid
+primary / 100% ext4 noatime,errors=remount-ro
diff --git a/fai/config/distro-install-common/devbyid b/fai/config/distro-install-common/devbyid
new file mode 100755 (executable)
index 0000000..056a83f
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# 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
+
+# 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"
diff --git a/fai/config/distro-install-common/end b/fai/config/distro-install-common/end
new file mode 100755 (executable)
index 0000000..b0e0700
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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
+
+USER2PW=/q/root/shadow/user2
+# if doesn't exist, we dont set one
+ROOTPW=/q/root/shadow/standard
+if [[ ! -e $ROOTPW ]]; then
+  ROOTPW=/q/root/shadow/$HOSTNAME
+fi
+
+chpw() {
+  # 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.
+
+  user=$1
+  pwfile=$2
+  if [[ $pwfile && -e $pwfile ]]; then
+    printf "$user:" | cat - "$pwfile" | $ROOTCMD chpasswd -e
+  else
+    echo "$0: warning: no pw set for $user" >&2
+  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
+}
+
+chpw root "$ROOTPW"
+
+# only setup root pass for bootstrap vol
+if ifclass VOL_BUSTER_BOOTSTRAP; then
+  exit 0
+fi
+
+
+# return of 9 = user already exists. so we are idempotent.
+au iank
+chpw iank "$ROOTPW"
+
+au user2
+if ifclass frodo; then
+  chpw user2 "$USER2PW"
+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
+
+f=$target/etc/sudoers
+line='iank  ALL=(ALL)  NOPASSWD: ALL'
+if [[ ! -e $f ]] || ! grep -xF "$line" $f; then
+  echo "$line" >> $f
+fi
+
+
+au --system -s /bin/false --home-dir /var/lib/bitcoind bitcoin
diff --git a/fai/config/distro-install-common/libreboot_grub.cfg b/fai/config/distro-install-common/libreboot_grub.cfg
new file mode 100644 (file)
index 0000000..54cf468
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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 /buster_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, although it's not used yet.
+
+# 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=/debianbuster_bootstrap # could use 0 here.
+set timeout=1
+
+# grub_extn
+for part in (ahci*7) (ata*7); 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=/debianbuster_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
+}
diff --git a/fai/config/files/boot/bash-trace/DEFAULT b/fai/config/files/boot/bash-trace/DEFAULT
new file mode 100644 (file)
index 0000000..dc1a218
--- /dev/null
@@ -0,0 +1,220 @@
+#!/bin/bash
+# Copyright (C) 2019 Ian Kelling
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Commentary: Print stack trace and exit/return on errors, or use
+# functions below for for more details and manual error handling. See
+# end of file for credits etc.
+
+#######################################
+# 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.
+#
+# 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
+    shopt -s extdebug
+    # shellcheck disable=SC2154
+    trap '_err-bash-trace-interactive $? "$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() {
+  local err=$?
+  # This has to come before most things or vars get changed
+  local msg="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err"
+  set +x
+  if [[ $1 == -* ]]; then
+    err=${1#-}
+    shift
+  elif (( ! err )); then
+    err=1
+  fi
+  if [[ $1 ]]; then
+    msg="$1"
+  fi
+  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
+  bash_command="$2"
+  argc=$(( $3 - 1 ))
+  shift 3
+  argv=("$@")
+  # The trap returns a nonzero, then gets called again. This condition
+  # tells us if we are the first.
+  if (( _err_func_last > last  )); then
+    printf "ERR: \`%s\' returned %s\n" "$bash_command" $ret >&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
+}
+
+# Credits etc:
+#
+# Related: see my bash script template repo at https://iankelling.org/git.
+#
+#
+# Please email me if you have a patches, bugs, feedback, or if you use
+# it or republish it since 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). If you test
diff --git a/fai/config/files/boot/chboot/DEFAULT b/fai/config/files/boot/chboot/DEFAULT
new file mode 100755 (executable)
index 0000000..adfbe1c
--- /dev/null
@@ -0,0 +1,143 @@
+#!/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
diff --git a/fai/config/files/etc/apt/preferences.d/belenos/BELENOS b/fai/config/files/etc/apt/preferences.d/belenos/BELENOS
new file mode 100644 (file)
index 0000000..1e59c86
--- /dev/null
@@ -0,0 +1,3 @@
+Package: *
+Pin: release a=belenos-backports
+Pin-Priority: 500
diff --git a/fai/config/files/etc/apt/preferences.d/etiona-bionic/ETIONA b/fai/config/files/etc/apt/preferences.d/etiona-bionic/ETIONA
new file mode 100644 (file)
index 0000000..4790bbe
--- /dev/null
@@ -0,0 +1,3 @@
+Package: *
+Pin: release n=bionic,o=Ubuntu
+Pin-Priority: -100
diff --git a/fai/config/files/etc/apt/preferences.d/etiona-flidas/ETIONA b/fai/config/files/etc/apt/preferences.d/etiona-flidas/ETIONA
new file mode 100644 (file)
index 0000000..67e2f8c
--- /dev/null
@@ -0,0 +1,11 @@
+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
diff --git a/fai/config/files/etc/apt/preferences.d/etiona-focal/ETIONA b/fai/config/files/etc/apt/preferences.d/etiona-focal/ETIONA
new file mode 100644 (file)
index 0000000..1e6fc34
--- /dev/null
@@ -0,0 +1,3 @@
+Package: *
+Pin: release n=focal,o=Ubuntu
+Pin-Priority: -100
diff --git a/fai/config/files/etc/apt/preferences.d/etiona/ETIONA b/fai/config/files/etc/apt/preferences.d/etiona/ETIONA
new file mode 100644 (file)
index 0000000..223a9f4
--- /dev/null
@@ -0,0 +1,3 @@
+Package: *
+Pin: release a=etiona-backports
+Pin-Priority: 500
diff --git a/fai/config/files/etc/apt/preferences.d/flidas/FLIDAS b/fai/config/files/etc/apt/preferences.d/flidas/FLIDAS
new file mode 100644 (file)
index 0000000..bd19b25
--- /dev/null
@@ -0,0 +1,3 @@
+Package: *
+Pin: release a=flidas-backports
+Pin-Priority: 500
diff --git a/fai/config/files/etc/apt/preferences.d/nabia-focal/NABIA b/fai/config/files/etc/apt/preferences.d/nabia-focal/NABIA
new file mode 100644 (file)
index 0000000..1e6fc34
--- /dev/null
@@ -0,0 +1,3 @@
+Package: *
+Pin: release n=focal,o=Ubuntu
+Pin-Priority: -100
diff --git a/fai/config/files/etc/apt/preferences.d/stretch/STRETCH b/fai/config/files/etc/apt/preferences.d/stretch/STRETCH
new file mode 100644 (file)
index 0000000..f3a0d4b
--- /dev/null
@@ -0,0 +1,21 @@
+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
diff --git a/fai/config/files/etc/apt/preferences.d/unstable/DEBIAN b/fai/config/files/etc/apt/preferences.d/unstable/DEBIAN
new file mode 100644 (file)
index 0000000..a88edb7
--- /dev/null
@@ -0,0 +1,23 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/aaa-etiona.list/ETIONA b/fai/config/files/etc/apt/sources.list.d/aaa-etiona.list/ETIONA
new file mode 100644 (file)
index 0000000..0539b9b
--- /dev/null
@@ -0,0 +1,12 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/aaa-nabia.list/NABIA b/fai/config/files/etc/apt/sources.list.d/aaa-nabia.list/NABIA
new file mode 100644 (file)
index 0000000..85bf23c
--- /dev/null
@@ -0,0 +1,12 @@
+deb http://mirror.fsf.org/trisquel/ nabia main
+deb-src http://mirror.fsf.org/trisquel/ nabia main
+
+deb http://mirror.fsf.org/trisquel/ nabia-updates main
+deb-src http://mirror.fsf.org/trisquel/ nabia-updates main
+
+deb http://archive.trisquel.info/trisquel/ nabia-security main
+deb-src http://archive.trisquel.info/trisquel/ nabia-security main
+
+# Uncomment this lines to enable the backports optional repository
+deb http://mirror.fsf.org/trisquel/ nabia-backports main
+deb-src http://mirror.fsf.org/trisquel/ nabia-backports main
diff --git a/fai/config/files/etc/apt/sources.list.d/belenos.list/BELENOS b/fai/config/files/etc/apt/sources.list.d/belenos.list/BELENOS
new file mode 100644 (file)
index 0000000..17b28dc
--- /dev/null
@@ -0,0 +1,12 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/bionic.list/ETIONA b/fai/config/files/etc/apt/sources.list.d/bionic.list/ETIONA
new file mode 100644 (file)
index 0000000..cb92b36
--- /dev/null
@@ -0,0 +1,6 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/bulleye.list/BULLSEYE_FREE b/fai/config/files/etc/apt/sources.list.d/bulleye.list/BULLSEYE_FREE
new file mode 100644 (file)
index 0000000..04e72ca
--- /dev/null
@@ -0,0 +1,11 @@
+deb http://http.us.debian.org/debian bullseye main
+deb-src http://http.us.debian.org/debian bullseye main
+
+deb http://security.debian.org/ bullseye-security main
+deb-src http://security.debian.org/ bullseye-security main
+
+deb http://http.us.debian.org/debian bullseye-updates main
+deb-src http://http.us.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
diff --git a/fai/config/files/etc/apt/sources.list.d/bulleye.list/BULLSEYE_NONFREE b/fai/config/files/etc/apt/sources.list.d/bulleye.list/BULLSEYE_NONFREE
new file mode 100644 (file)
index 0000000..2b5aa98
--- /dev/null
@@ -0,0 +1,17 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/buster.list/BUSTER_FREE b/fai/config/files/etc/apt/sources.list.d/buster.list/BUSTER_FREE
new file mode 100644 (file)
index 0000000..be9c7e3
--- /dev/null
@@ -0,0 +1,11 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/buster.list/BUSTER_NONFREE b/fai/config/files/etc/apt/sources.list.d/buster.list/BUSTER_NONFREE
new file mode 100644 (file)
index 0000000..fc58c98
--- /dev/null
@@ -0,0 +1,17 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/flidas.list/FLIDAS b/fai/config/files/etc/apt/sources.list.d/flidas.list/FLIDAS
new file mode 100644 (file)
index 0000000..faec0da
--- /dev/null
@@ -0,0 +1,12 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/focal.list/ETIONA b/fai/config/files/etc/apt/sources.list.d/focal.list/ETIONA
new file mode 120000 (symlink)
index 0000000..25af0ff
--- /dev/null
@@ -0,0 +1 @@
+FOCAL
\ No newline at end of file
diff --git a/fai/config/files/etc/apt/sources.list.d/focal.list/FOCAL b/fai/config/files/etc/apt/sources.list.d/focal.list/FOCAL
new file mode 100644 (file)
index 0000000..a317dfa
--- /dev/null
@@ -0,0 +1,14 @@
+# 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
diff --git a/fai/config/files/etc/apt/sources.list.d/focal.list/NABIA b/fai/config/files/etc/apt/sources.list.d/focal.list/NABIA
new file mode 120000 (symlink)
index 0000000..25af0ff
--- /dev/null
@@ -0,0 +1 @@
+FOCAL
\ No newline at end of file
diff --git a/fai/config/files/etc/apt/sources.list.d/stretch.list/STRETCH_FREE b/fai/config/files/etc/apt/sources.list.d/stretch.list/STRETCH_FREE
new file mode 100644 (file)
index 0000000..280fa0a
--- /dev/null
@@ -0,0 +1,11 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/stretch.list/STRETCH_NONFREE b/fai/config/files/etc/apt/sources.list.d/stretch.list/STRETCH_NONFREE
new file mode 100644 (file)
index 0000000..c022d31
--- /dev/null
@@ -0,0 +1,11 @@
+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
diff --git a/fai/config/files/etc/apt/sources.list.d/testing.list/TESTING_FREE b/fai/config/files/etc/apt/sources.list.d/testing.list/TESTING_FREE
new file mode 100644 (file)
index 0000000..031bddf
--- /dev/null
@@ -0,0 +1,11 @@
+deb http://http.us.debian.org/debian testing main
+deb-src http://http.us.debian.org/debian testing main
+
+deb http://security.debian.org/ testing/updates main
+deb-src http://security.debian.org/ testing/updates main
+
+deb http://http.us.debian.org/debian testing-updates main
+deb-src http://http.us.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
diff --git a/fai/config/files/etc/apt/sources.list.d/testing.list/TESTING_NONFREE b/fai/config/files/etc/apt/sources.list.d/testing.list/TESTING_NONFREE
new file mode 100644 (file)
index 0000000..3b57312
--- /dev/null
@@ -0,0 +1,11 @@
+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/updates main contrib non-free
+deb-src http://security.debian.org/ testing/updates 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
diff --git a/fai/config/files/etc/apt/sources.list.d/xenial.list/XENIAL b/fai/config/files/etc/apt/sources.list.d/xenial.list/XENIAL
new file mode 100644 (file)
index 0000000..452f266
--- /dev/null
@@ -0,0 +1,11 @@
+###### 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
diff --git a/fai/config/files/etc/apt/sources.list/DEFAULT b/fai/config/files/etc/apt/sources.list/DEFAULT
new file mode 100644 (file)
index 0000000..0c5461c
--- /dev/null
@@ -0,0 +1 @@
+# intentionaly left empty. only using sources.list.d
diff --git a/fai/config/files/etc/apt/sources.list/GNOME b/fai/config/files/etc/apt/sources.list/GNOME
deleted file mode 100644 (file)
index 20861df..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-deb {%apt_cdn%}/debian {%release%} main
-deb {%security_cdn%}/debian-security {%secsuite%} main
-deb {%apt_cdn%}/debian {%release%}-updates main
diff --git a/fai/config/files/etc/motd/FAIBASE b/fai/config/files/etc/motd/FAIBASE
deleted file mode 100644 (file)
index 4e5a967..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-Plan your installation, and FAI installs your plan.
diff --git a/fai/config/files/etc/systemd/system/faicheck.service/VOL_BUSTER_BOOTSTRAP b/fai/config/files/etc/systemd/system/faicheck.service/VOL_BUSTER_BOOTSTRAP
new file mode 100644 (file)
index 0000000..61f5a1f
--- /dev/null
@@ -0,0 +1,11 @@
+[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
diff --git a/fai/config/files/root/.ssh/authorized_keys/.gitignore b/fai/config/files/root/.ssh/authorized_keys/.gitignore
new file mode 100644 (file)
index 0000000..c078f52
--- /dev/null
@@ -0,0 +1,3 @@
+# empty directory
+*
+!.gitignore
diff --git a/fai/config/files/root/fai-check/VOL_BUSTER_BOOTSTRAP b/fai/config/files/root/fai-check/VOL_BUSTER_BOOTSTRAP
new file mode 100755 (executable)
index 0000000..900c719
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+
+
+usage() {
+  cat <<EOF
+Usage: ${0##*/} [OPTION]
+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 ||:
+}
+
+case $1 in
+  -f|--force)
+    try-kexec
+    exit
+    ;;
+esac
+
+
+first=true
+for dev in $(btrfs fi show / | sed -rn 's#^\s*devid\s.*\s([^0-9 ]+)\S+$#\1#p' \
+               |sort); do
+
+  # Decide which is my grub_ext partition. see partition.DEFAULT file
+  # for details
+  if [[ $(blockdev --getsize64 ${dev}4) == 8388608 ]]; then
+    # Old partition scheme
+    grub_extn=${dev}4
+  elif [[ $(blockdev --getsize64 ${dev}5) == 8388608 ]]; then
+    grub_extn=${dev}5
+  else
+    grub_extn=${dev}7
+  fi
+  mount $dev /mnt
+  if $first; then
+    if [[ -e /mnt/grubenv ]]; then
+      set -x
+      source <(grub-editenv /mnt/grubenv list)
+      set +x
+    fi
+    first=false
+    # we could just as well check if last_boot != /debianbuster_boostrap
+    # the intent with this one is just a little clearer.
+    if [[ $did_fai_check == true ]]; then
+      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.
+    rm -f /mnt/gruvenv
+  fi
+  umount /mnt
+done
+
+# the check for last_boot is not needed afaik, just sanity check.
+if [[ $did_fai_check == true && $last_boot != /debianbuster_boostrap ]]; then
+  # no need to reboot if we actually want to boot into this os.
+  reboot
+fi
diff --git a/fai/config/files/usr/bin/myncq/kd b/fai/config/files/usr/bin/myncq/kd
new file mode 100755 (executable)
index 0000000..2d65edb
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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]}" "$@"
+
+# 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
+
+upgrub=true
+if [[ $1 == no-upgrub ]]; then
+  upgrub=false
+fi
+
+byid=/dev/disk/by-id/ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V
+if [[ ! -e $byid ]]; then
+  # not plugged in we assume
+  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
+    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
diff --git a/fai/config/hooks/extrbase.DEFAULT b/fai/config/hooks/extrbase.DEFAULT
new file mode 100755 (executable)
index 0000000..1d1a931
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# exit for any vm which is not our test vm
+if ifclass VM && ! ifclass demohost; then
+    exit 0
+fi
+
index 35ac3064f48afe0b4848f917bec04f1353705a8e..34e6ebbfbc92764394109d684c6ffc27c3b2d0ed 100755 (executable)
@@ -1,5 +1,6 @@
 #! /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
@@ -7,7 +8,6 @@ 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
diff --git a/fai/config/hooks/instsoft.DEFAULT b/fai/config/hooks/instsoft.DEFAULT
new file mode 100755 (executable)
index 0000000..07adc1d
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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_BUSTER_BOOTSTRAP || [[ ! $FAI_ACTION || $FAI_ACTION = dirinstall ]]; then
+  exit 0
+fi
+
+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
+f=/var/lib/fai/config/files/root/.ssh/authorized_keys/STANDARD
+d=$target/etc/initramfs-tools
+d2=$target/etc/dropbear-initramfs
+mkdir -p $d/root/.ssh $d2
+chmod 700 $d/root $d/root/.ssh
+# i think buster uses the second, flidas uses the first.
+cp -p $f $d/root/.ssh/authorized_keys
+cp -p $f $d2/authorized_keys
diff --git a/fai/config/hooks/partition.DEFAULT b/fai/config/hooks/partition.DEFAULT
new file mode 100755 (executable)
index 0000000..afbca5a
--- /dev/null
@@ -0,0 +1,805 @@
+#!/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.
+
+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:
+# fai-redep
+#
+# 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
+#
+# OPTIONS:
+#
+# mkroot2: for running outside of fai and setting up the root2/boot2 luks and btrfs
+#
+# environment variables:
+#
+# HOSTNAME: if frodo, we exclude 2 devices from the /boot array, which
+# the bios does not see. if demohost, we set the luks password to just
+# 'x'.
+#
+# 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
+#
+# ROTATIONAL: forces to install onto hdds instead of sdds. normally sdds
+# are chosen if they exist.
+#
+# PARTITION_PROMPT: command line prompt before partitioning
+#
+# RAID0: forces raid0 filesystem. Normally with 4+ devices, we use
+# raid10.
+# RAID1: forces raid1 filesystem.
+
+mkroot2=false
+if [[ $1 ]]; then
+  case $1 in
+    mkroot2)
+      mkroot2=true
+      ;;
+    *)
+      echo "$0: error: unsupported arg: $1" >&2
+      exit 1
+      ;;
+  esac
+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
+# root
+# swap
+# boot
+
+rootn=1
+root2n=2
+swapn=3
+bootn=4
+boot2n=5
+efin=6
+# 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=7
+# bios boot partition,
+# https://wiki.archlinux.org/index.php/GRUB
+bios_grubn=8
+even_bign=9
+lastn=$bios_grubn
+
+
+
+##### end configuration
+
+
+add-part() { # add partition suffix to $dev
+  local d part
+  if [[ $# == 1 ]]; then
+    d=$dev
+    part=$1
+  else
+    d=$1
+    part=$2
+  fi
+  echo $d-part$part
+}
+
+rootdev() { add-part $@ $rootn; }
+root2dev() { add-part $@ $root2n; }
+swapdev() { add-part $@ $swapn; }
+bootdev() { add-part $@ $bootn; }
+boot2dev() { add-part $@ $boot2n; }
+efidev() { add-part $@ $efin; }
+grub_extdev() { add-part $@ $grub_extn; }
+bios_grubdev() { add-part $@ $bios_grubn; }
+even_bigdev() { add-part $@ $even_bign; }
+
+crypt-dev() { echo /dev/mapper/crypt_dev_${1##*/}; }
+crypt-name() { echo crypt_dev_${1##*/}; }
+root-cryptdev() { crypt-dev $(rootdev $@); }
+root2-cryptdev() { crypt-dev $(root2dev $@); }
+swap-cryptdev() { crypt-dev $(swapdev $@); }
+root-cryptname() { crypt-name $(rootdev $@); }
+root2-cryptname() { crypt-name $(root2dev $@); }
+swap-cryptname() { crypt-name $(swapdev $@); }
+
+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"
+  # 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 $(crypt-name $luksdev) --key-file $luks_file
+}
+
+##### end function defs
+
+if ifclass REPARTITION; then
+  partition=true # force a full wipe
+else
+  partition=false # change to true to force a full wipe
+fi
+if ifclass NOWIPE; then
+  wipe=false
+else
+  wipe=true
+fi
+
+if (($(nproc) > 2)); then
+  mopts=,compress=zstd
+fi
+
+declare -A disk_excludes
+if ! $mkroot2 && ! 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
+      PKNAME="$KNAME"
+    fi
+    if [[ $MOUNTPOINT ]]; then
+      disk_excludes[$PKNAME]=true
+    fi
+  done < <(lsblk -nP -o KNAME,MOUNTPOINT,PKNAME)
+fi
+
+hdds=()
+ssds=()
+# this excludes usb. note: i may encounter some other type in the future.
+for disk in $(lsblk -do name,tran -n | awk '$2 ~ "^(sata|nvme)$" { print $1 }'); do
+  if [[ ${disk_excludes[$disk]} ]]; then
+    continue
+  fi
+  case $(cat /sys/block/$disk/queue/rotational) in
+    0) ssds+=(/dev/$disk) ;;
+    1) hdds+=(/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.
+# TODO: find a reliable way to ignore them.
+if ! ifclass ROTATIONAL && (( ${#ssds[@]} > 0 )); then
+  short_devs=( ${ssds[@]} )
+else
+  short_devs=( ${hdds[@]} )
+fi
+
+# 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)
+  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:"
+  echo "  ${short_devs[*]}"
+  read -r
+fi
+
+devs=()
+shopt -s extglob
+for short_dev in ${short_devs[@]}; do
+  devs+=($(devbyid $short_dev))
+done
+if [[ ! ${devs[0]} ]]; then
+  echo "$0: error: failed to detect devs" >&2
+  exit 1
+fi
+
+boot_space=0
+first=true
+boot_devs=()
+boot2_devs=()
+for dev in ${devs[@]}; do
+  if ifclass frodo; then
+    # I ran into a machine 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
+      boot_devs+=($(bootdev))
+      boot2_devs+=($(boot2dev))
+    fi
+  else
+    boot_space=$(( boot_space + $(parted -m $dev unit MiB print | \
+                                    sed -nr "s#^/dev/[^:]+:([0-9]+).*#\1#p") - 1))
+    boot_devs+=($(bootdev))
+    boot2_devs+=($(boot2dev))
+  fi
+  if $first && [[ $boot_devs ]]; then
+    first_efi=$(efidev)
+    first_grub_extdev=$(grub_extdev)
+    first=false
+  fi
+done
+first_boot_dev=${boot_devs[0]}
+
+even_raid=false
+if ifclass RAID0 || (( ${#boot_devs[@]} == 1 )); then
+  raid_level=0
+elif ifclass RAID1 || (( ${#boot_devs[@]} <= 3 )); then
+  if (( ${#boot_devs[@]} == 2 )); then
+    even_raid=true
+  fi
+  raid_level=1
+else
+  raid_level=10
+fi
+
+### Begin calculate boot partition space
+# due to raid duplication
+case $raid_level in
+  1*) boot_space=$(( boot_space / 2 )) ;;
+esac
+if (( boot_space > 60000 )); 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=200000
+  boot2_mib=2000
+elif (( boot_spa_ce > 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.
+  boot_mib=500
+  root2_mib=100
+  boot2_mib=100
+fi
+case $raid_level in
+  1*)
+    boot_mib=$(( boot_mib * 2 ))
+    boot2_mib=$(( boot2_mib * 2 ))
+    root2_mib=$(( root2_mib * 2 ))
+    ;;
+esac
+### end calculate boot partition space
+
+
+
+if [[ ! $DISTRO ]]; then
+  if ifclass VOL_BUSTER_BOOTSTRAP; then
+    DISTRO=debianbuster_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_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_FLIDAS; then
+    DISTRO=trisquelflidas
+  elif ifclass VOL_ETIONA; then
+    DISTRO=trisqueletiona
+  elif ifclass VOL_NABIA; then
+    DISTRO=trisquelnabia
+  elif $mkroot2; then
+    :
+  else
+    echo "PARTITIONER ERROR: no distro class/var set" >&2
+    exit 1
+  fi
+fi
+
+
+bpart() { # btrfs a partition
+  case $raid_level in
+    0) mkfs.btrfs -f $@ ;;
+    1) mkfs.btrfs -f -m raid1 -d raid1 $@ ;;
+    10) mkfs.btrfs -f -m raid10 -d raid10 $@ ;;
+  esac
+}
+
+
+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
+  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
+
+
+first_root_crypt=$(root-cryptdev ${devs[0]})
+
+# 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 ))
+
+mkdir -p /tmp/fai
+root_devs=()
+for dev in ${devs[@]}; do
+  root_devs+=($(rootdev))
+done
+shopt -s nullglob
+
+# 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 $mkroot2; then
+  if $partition; then
+    echo $0: error: found partition=true but have mkroot2 arg
+    exit 1
+  fi
+  for dev in ${devs[@]}; do
+    luks_file=$luks_dir/host-amy
+    lukspw=$(cat $luks_dir/amy)
+    luks-setup $(root2dev)
+    cat >>/mnt/root/root2-crypttab <<EOF
+$(root2-cryptname) $(root2dev)  $luks_file  discard,luks,initramfs
+EOF
+  done
+  bpart $(for dev in ${devs[@]}; do root2-cryptdev; done)
+  bpart ${boot2_devs[@]}
+  mkdir -p /mnt/root2 /mnt/boot2
+  cat >>/mnt/root/root2-fstab <<EOF
+$(root2-cryptdev ${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
+fi
+
+
+if $partition; then
+  ### begin wipefs
+  if [[ ! $SPECIAL_DISK ]]; then
+    for dev in ${devs[@]}; do
+      # if we repartition to the same as an old partition,
+      # we don't want any old fses hanging around.
+      for (( i=1; i <= lastn; i++ )); do
+        x=$(add-part $i)
+        [[ -e $x ]] || continue
+        count_down=10
+        # wipefs has failed, manual run works, google suggests timing issue
+        while ! wipefs -a $x; do
+          sleep 2
+          count_down=$((count_down - 1))
+          (( count_down > 0 )) || exit 1
+        done
+      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
+
+  for dev in ${devs[@]}; do
+    if [[ $SPECIAL_DISK ]]; then
+      dev=$(devbyid $SPECIAL_DISK)
+    fi
+
+    # 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
+
+    boot_part_mib=$(( boot_mib / ${#boot_devs[@]} ))
+    boot2_part_mib=$(( boot2_mib / ${#boot_devs[@]} ))
+    root2_part_mib=$(( root2_mib / ${#root_devs[@]} ))
+    root_end=$(( disk_mib - root2_part_mib - swap_mib - boot_part_mib - boot2_part_mib ))
+    root2_end=$(( root_end + root2_part_mib ))
+    swap_end=$(( root2_end + swap_mib ))
+    boot_end=$(( swap_end + boot_part_mib ))
+
+    parted -s $dev mklabel gpt
+    # MiB because parted complains about alignment otherwise.
+    pcmd="parted -a optimal -s -- $dev"
+    # root partition, the main big one
+    $pcmd mkpart primary ext3 524MiB ${root_end}MiB
+    # without naming, systemd gives us misc errors like:
+    # dev-disk-by\x2dpartlabel-primary.device: Dev dev-disk-by\x2dpartlabel-primary.device appeared twice
+    $pcmd name $rootn root
+    # root2 partition
+    $pcmd mkpart primary ext3 ${root_end}MiB ${root2_end}MiB
+    $pcmd name $root2n root2
+    # normally a swap is type "linux-swap", but this is encrypted swap. using that
+    # label will confuse systemd.
+    # swap partition
+    $pcmd mkpart primary "" ${root2_end}MiB ${swap_end}MiB
+    $pcmd name $swapn swap
+    # boot partition
+    $pcmd mkpart primary "" ${swap_end}MiB ${boot_end}MiB
+    $pcmd name $bootn boot
+    # boot2 partition
+    $pcmd mkpart primary "" ${boot_end}MiB ${disk_mib}MiB
+    $pcmd name $boot2n boot2
+    # uefi partition. efi sucks, half a gig, rediculous.
+    $pcmd mkpart primary "fat32" 12MiB 524MiB
+    $pcmd name $efin efi
+    $pcmd set $efin esp on
+    # note, this is shown here: https://support.system76.com/articles/bootloader/
+    # but not mentioned https://wiki.archlinux.org/index.php/EFI_system_partition
+    # probably not needed
+    $pcmd set $bootn boot on
+    $pcmd set $boot2n boot 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 $(bios_grubdev) ]] && (( secs < 10 )); do
+      sleep 1
+      secs=$((secs +1))
+    done
+    sleep 3
+
+    mkfs.fat -F32 $(efidev)
+
+    if $even_big_part  && [[ $dev == "$even_big_dev" ]]; then
+      luks-setup $(even_bigdev)
+      mkfs.btrfs -f $(crypt-dev $(even_bigdev))
+    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 $(grub_extdev)
+    luks-setup $(rootdev)
+
+    if [[ $SPECIAL_DISK ]]; then
+      exit 0
+    fi
+  done
+  ls -la /dev/btrfs-control # this was probably for debugging...
+  sleep 1
+  bpart $(for dev in ${devs[@]}; do root-cryptdev; done)
+  bpart ${boot_devs[@]}
+else
+  for dev in ${devs[@]}; do
+    if [[ -e /dev/mapper/$(root-cryptname) ]]; then
+      continue
+    fi
+    cryptsetup luksOpen $(rootdev) $(root-cryptname) \
+               --key-file $luks_file
+  done
+  sleep 1
+fi
+
+
+if $wipe && [[ $DISTRO != debianbuster_bootstrap ]]; then
+  # bootstrap distro doesn't use separate encrypted root.
+  mount -o subvolid=0 $first_root_crypt /mnt
+  # systemd creates subvolumes we want to delete.
+  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
+cp $FAI/distro-install-common/libreboot_grub.cfg /mnt/grub2
+
+if [[ $DISTRO == debianbuster_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
+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 ##
+
+dev=${boot_devs[0]}
+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
+
+fstabstd=x-systemd.device-timeout=30s,x-systemd.mount-timeout=30s
+if [[ $DISTRO == debianbuster_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_crypt  /  btrfs $fstabstdopts,noatime,subvol=root_$DISTRO$mopts  0 0
+$first_root_crypt  /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
+  swaps=()
+  rm -f /tmp/fai/crypttab
+  for dev in ${devs[@]}; do
+    swaps+=($(swap-cryptname))
+    cat >>/tmp/fai/crypttab <<EOF
+$(root-cryptname) $(rootdev)  none  keyscript=/root/keyscript,discard,luks,initramfs
+$(swap-cryptname) $(swapdev)  /dev/urandom  swap,cipher=aes-xts-plain64,size=256,hash=ripemd160
+EOF
+    cat >> /tmp/fai/fstab <<EOF
+$(swap-cryptdev)  none  swap  nofail,$fstabstd,sw  0 0
+EOF
+  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_crypt}
+SWAPLIST=\${SWAPLIST:-"${swaps[@]}"}
+EOF
+
+  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-part${even_bign} /dev/disk/by-id/ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V-part7  none  keyscript=decrypt_keyctl,discard,luks,initramfs
+crypt_dev_ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1 /dev/disk/by-id/ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1  none  keyscript=decrypt_keyctl,discard,luks,initramfs
+crypt_dev_ata-ST6000DM001-1XY17Z_Z4D29EBL-part1 /dev/disk/by-id/ata-ST6000DM001-1XY17Z_Z4D29EBL-part1  none  keyscript=decrypt_keyctl,discard,luks,initramfs
+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-part${even_bign}  /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
+
+# initial setup of extra data fs, mounted,
+# btrfs subvol create nocow
+# chattr +C nocow
+# chown iank.iank nocow
+
index 2d1161c5ea833e12eb6284023962fb7f73fbd4a8..e5050cd12464bbfc6cbfa4d3fdb24715d39cd327 100755 (executable)
@@ -1,15 +1,5 @@
 #! /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
-
-
 # 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
 # changed.  There is a /var/lib/dpkg/info/locales.config file, which
index fe7cff752f4b569c6227fc272940b356d5ebb374..c1cb0bf77d09275dce20d6c8bed9643ef031a066 100644 (file)
@@ -1,19 +1,6 @@
-PACKAGES install-norec
-apt-transport-https # is only needed for stretch
-debconf-utils
-file
-less
-linuxlogo
-rsync
-openssh-client openssh-server
-time
-procinfo
-nullmailer
-eject
-locales
-console-setup kbd
-pciutils usbutils
-unattended-upgrades
+# otherwise sshd takes like 10 seconds to start
+PACKAGES install BUSTER
+haveged
 
 PACKAGES install NONFREE
 # you may want these non-free kernel drivers
@@ -34,6 +21,8 @@ memtest86+
 PACKAGES install CHROOT
 linux-image-686-pae-
 linux-image-amd64-
+initramfs-tools-core-
+dropbear-initramfs-
 
 PACKAGES install AMD64
 linux-image-amd64
@@ -43,11 +32,13 @@ PACKAGES install ARM64
 grub-efi-arm64
 linux-image-arm64
 
-PACKAGES install GRUB_PC
-grub-pc
+# this is duplicate with STANDARD.
+#PACKAGES install GRUB_PC
+#grub-pc
+
+#PACKAGES install GRUB_EFI
+#grub-efi
 
-PACKAGES install GRUB_EFI
-grub-efi
 
 PACKAGES install LVM
 lvm2
diff --git a/fai/config/package_config/FLIDAS b/fai/config/package_config/FLIDAS
new file mode 100644 (file)
index 0000000..9aab2d5
--- /dev/null
@@ -0,0 +1,6 @@
+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
index de178aecaae59cb99e30c99fce7e1c8118bb0202..413254f958391b5386813a11f4aac0801d047eca 100644 (file)
@@ -18,20 +18,64 @@ man-db
 manpages
 mime-support
 ncurses-term
-netcat-traditional
 openssh-client
 pciutils
 perl
+# ian: newer distros dont have python, it gets naturally removed
+python
+python-minimal
+python3
+python3-minimal
 reportbug
 telnet
 traceroute
 ucf
 xz-utils
+# ian standard packages
+# lsof is used in my btrfs util scritps.
+# netcat is used for proxy.
+keyutils
+cryptsetup
+btrfs-progs
+sudo
+bridge-utils
+netcat-openbsd
+lsof
+debconf-utils
+file
+less
+rsync
+openssh-client openssh-server
+time
+procinfo
+locales
+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
+# https://wiki.debian.org/UsrMerge
+usrmerge
+# for btrbk
+zstd
 
-PACKAGES install-norec STRETCH BUSTER
-python
-python-minimal
+# iank, copied from DEBIAN so it goes into ubuntu too
+PACKAGES install GRUB_PC
+grub-pc
 
-PACKAGES install-norec BULLSEYE
-python3
-python3-minimal
+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
index 47e9e73eeeeaa04977e34e5bcb411b9c81bf3ec2..e672026c2aefa42bc98d263d1fa75d9fe5ce7761 100644 (file)
@@ -9,12 +9,13 @@ PACKAGES install AMD64
 linux-image-generic
 memtest86+
 
-PACKAGES install GRUB_PC
-grub-pc
 
-PACKAGES install
-ubuntu-minimal
-ubuntu-server
+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 GERMAN
 language-pack-gnome-de
diff --git a/fai/config/package_config/UBUNTU.asc b/fai/config/package_config/UBUNTU.asc
new file mode 100644 (file)
index 0000000..932dea0
--- /dev/null
@@ -0,0 +1,597 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+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
+=yMYl
+-----END PGP PUBLIC KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+Twx6DKLF+3rF5nf1F3Q=
+=PBAe
+-----END PGP PUBLIC KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+qnIlKN70FUMxdKabTsePWdIAB2DVOz1Cx6bw
+=p3ci
+-----END PGP PUBLIC KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+=yMYl
+-----END PGP PUBLIC KEY BLOCK-----
index 329e2f6220caa87a16eaf66a13f4937e60d43e5e..539f2eb6c3badfe173022b0f7fc0e05959bdfebd 100755 (executable)
@@ -7,11 +7,6 @@ if [ -n "$ROOTPW" ]; then
     $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
index ea650fa984a90231f58afccd6b056c0e05a761d8..b057587a65d9f5328592f7c1772a0b384576a125 100755 (executable)
@@ -4,6 +4,9 @@
 # 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
diff --git a/fai/config/scripts/DEBIAN/30-interface b/fai/config/scripts/DEBIAN/30-interface
deleted file mode 100755 (executable)
index 4b0dcf4..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-#! /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() {
-
-    # determine predictable network names only for stretch and above
-    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
index 714be559ca00935587199405a90e7d593f127605..54ca499776933ec6df716178d5e8a1e772c05d6d 100755 (executable)
@@ -3,6 +3,22 @@
 # (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
diff --git a/fai/config/scripts/DEMO/10-misc b/fai/config/scripts/DEMO/10-misc
deleted file mode 100755 (executable)
index d77c048..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#! /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-login --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
diff --git a/fai/config/scripts/FLIDAS/12-iank b/fai/config/scripts/FLIDAS/12-iank
new file mode 100755 (executable)
index 0000000..27e285e
--- /dev/null
@@ -0,0 +1,14 @@
+#!/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
diff --git a/fai/config/scripts/GRUB_EFI/11-iank b/fai/config/scripts/GRUB_EFI/11-iank
new file mode 120000 (symlink)
index 0000000..e135aad
--- /dev/null
@@ -0,0 +1 @@
+../GRUB_PC/11-iank
\ No newline at end of file
index 270b356b3f372b3eb8c386c7c3c049b56a7d0fec..e26aa2671180c03eccc373cac1c9845eef818688 100755 (executable)
@@ -3,6 +3,7 @@
 
 error=0; trap 'error=$(($?>$error?$?:$error))' ERR # save maximum error code
 
+set -x
 set -a
 
 # do not set up grub during dirinstall
@@ -55,6 +56,7 @@ fi
 
 # 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
@@ -70,13 +72,15 @@ if [[ $BOOT_DEVICE =~ '/dev/md' ]]; then
     # remove last ,
     mbrdevices=${mbrdevices%, }
 else
-    mbrdevices=$(get_stable_devname $BOOT_DEVICE)
+  for dev in $BOOT_DEVICE; do
+    mbrdevices=$(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"
+    echo "Installing grub on $dev = $mbrdevices"
     $ROOTCMD grub-install --no-floppy "$mbrdevices"
+  done
 fi
 
 echo "grub-pc grub-pc/install_devices multiselect $mbrdevices" | $ROOTCMD debconf-set-selections
diff --git a/fai/config/scripts/GRUB_PC/11-iank b/fai/config/scripts/GRUB_PC/11-iank
new file mode 100755 (executable)
index 0000000..8143d4e
--- /dev/null
@@ -0,0 +1,378 @@
+#!/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
+
+if ! type -t fcopy &>/dev/null; then
+  sudo apt-get -y install fai-client
+fi
+
+if [[ -e /a/bin/fai/fai-wrapper ]]; then
+  chroot() {
+    shift
+    "$@"
+  }
+fi
+
+
+
+# -r = recursive
+# -i = ignore non-matching class warnings, always exit 0
+# -B = no backup files
+fcopy -riB /boot
+# this is also done by FABASE/10-misc by default (without B)
+fcopy -riB /root
+
+
+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
+chroot $FAI_ROOT /usr/bin/apt-cache policy >$tmpfile1 ||:
+fcopy -riBM /etc/apt
+tmpfile2=$(mktemp)
+chroot $FAI_ROOT /usr/bin/apt-cache policy >$tmpfile2
+if ! diff -q $tmpfile1 $tmpfile2; then
+  chroot $FAI_ROOT /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
+chroot $FAI_ROOT bash <<'EOFOUTER'
+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
+apt-get install -y pxe-kexec
+
+# this is usefull. Only thing reason I see this being disabled by default is
+# that a normal user can disrupt the system, eg cause a reboot.
+sed -i '$a kernel.sysrq=1
+/^kernel.sysrq=/d' /etc/sysctl.conf
+
+EOFOUTER
+
+
+if [[ $FAI_ACTION != dirinstall ]] && ! ifclass NOCRYPT; then
+  # 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.
+  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
+
+        chroot $FAI_ROOT 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
+
+  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=$speed
+terminal_input --append  serial
+terminal_output --append serial
+EOF
+
+
+  chroot $FAI_ROOT bash <<EOF
+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
+sed -ri 's/^ *GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="$cmdline"/' /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
+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
+if lspci|grep -q 'GeForce GTX 6[0-9][0-9]\]'; 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 type -p iw &>/dev/null && [[ $(iw dev) ]]; then
+  chroot $FAI_ROOT bash <<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
+  if [[ $HOSTNAME == frodo ]]; then
+    cat > $target/etc/network/interfaces <<-EOF
+# generated by FAI
+auto lo eth0
+iface lo inet loopback
+iface eth0 inet static
+address 10.3.0.2/16
+EOF
+  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
+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
+EOF
+  fi
+fi
+
+# I prefer to stick with ifup/down for now. a. 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
+
+##### end network setup  #####
+
+
+if ifclass VOL_BUSTER_BOOTSTRAP; then
+  fcopy /etc/systemd/system/faicheck.service
+  chroot $FAI_ROOT bash <<'EOFOUTER'
+systemctl enable faicheck.service
+EOFOUTER
+  exit 0 # avoid unnecessary stuff in bootstrap vol
+fi
+
+
+## misc settings
+chroot $FAI_ROOT bash <<'EOFOUTER'
+#### begin .ssh setup ###
+set -x
+set -eE -o pipefail
+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
+# https://ticktockhouse.svbtle.com/my-obligatory-ubuntu-ssh-agent-post
+# systemctl --user is not available at fai time, so create the link ourselves
+d=/home/iank/.config/systemd/user/default.target.wants
+sudo -u iank mkdir -p $d
+sudo -u iank ln -sf /usr/lib/systemd/user/ssh-agent.service $d
+#### 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, sudo, root
+for g in cdrom floppy audio dip video plugdev netdev adm sudo; do
+  if getent gropu $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
index a573f5081e7a95dcf74472725342ff269676f65e..687700a6a5c112f79b5be81459456ba6eac24bdd 100755 (executable)
@@ -15,13 +15,15 @@ else
     fi
   fi
 
-  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
-       echo ERROR: Found lvm devices, but the lvm2 package was not installed
-       error=1
-    fi
-  fi
+  # i use dm for crypt, not lvm, so this gives false positive. todo, send patch to remove this
+  # upstream.
+  # 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
+  #       echo ERROR: Found lvm devices, but the lvm2 package was not installed
+  #       error=1
+  #   fi
+  # fi
 fi
 
 # remove backup files from cfengine, but only if cfengine is installed
@@ -45,7 +47,7 @@ if [ $do_init_tasks -eq 1 ] ; 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
 
index 4da7029538c9bf03566e470d84f73ef83c10645e..440ffb264d6433173382e069e1fe667807802d48 100755 (executable)
@@ -1,11 +1,16 @@
 #! /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
diff --git a/faiserver-disable b/faiserver-disable
new file mode 100755 (executable)
index 0000000..0a9ad8d
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+usage() {
+    cat <<EOF
+Usage: ${0##*/}
+Disable the fai nfs server exports
+EOF
+    exit $1
+}
+
+if [[ $1 ]]; then
+    usage 1
+fi
+
+ssh root@$(chost faiserver) bash <<'EOF'
+set -eE -o pipefail
+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
+EOF
diff --git a/faiserver-revm b/faiserver-revm
new file mode 100755 (executable)
index 0000000..bb4650e
--- /dev/null
@@ -0,0 +1,49 @@
+#!/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
diff --git a/faiserver-setup b/faiserver-setup
new file mode 100755 (executable)
index 0000000..42ecb3b
--- /dev/null
@@ -0,0 +1,349 @@
+#!/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]}" "$@"
+
+LC_USEBASHRC=t; . ~/.bashrc
+
+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 buster. Default ARCH is 64. The script expects corresponding
+$BASEFILE_DIR/${UPCASED_BASE_CODENAME}${ARCH}.tar.(gz|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.
+
+
+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:-buster}
+arch=${2:-64}
+
+if [[ $base == [[:upper:]] ]]; then
+  echo $0: error: use lowercase base
+  exit 1
+fi
+
+basefile=($BASEFILE_DIR/${base^^}${arch^^}.tar.gz)
+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/2BF8D9FE074BCDE4.asc | apt-key add -
+
+update=false
+case $base in
+  stretch|buster|bullseye)
+    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 (( cachtime > 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
+pkgs=(fai-doc tftpd-hpa tar reprepro squashfs-tools binutils xorriso perl-tk)
+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
+
+
+$sed -f - /etc/fai/nfsroot.conf <<EOF
+$ a FAI_ROOTPW='$(</q/root/shadow/standard)'
+/^\s*FAI_ROOTPW/d
+$ 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
+  $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
+
+
+# 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
diff --git a/faiserver-uninstall b/faiserver-uninstall
new file mode 100755 (executable)
index 0000000..71a4ea0
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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
diff --git a/fresize b/fresize
new file mode 100755 (executable)
index 0000000..a7df414
--- /dev/null
+++ b/fresize
@@ -0,0 +1,296 @@
+#!/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
diff --git a/grub.cfg.autodiscover b/grub.cfg.autodiscover
new file mode 100644 (file)
index 0000000..31bcb08
--- /dev/null
@@ -0,0 +1,66 @@
+## 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
+}
diff --git a/grub.cfg.netinst b/grub.cfg.netinst
new file mode 100644 (file)
index 0000000..489af69
--- /dev/null
@@ -0,0 +1,78 @@
+## 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
+}
diff --git a/grub.cfg.netinst-noreboot b/grub.cfg.netinst-noreboot
new file mode 100644 (file)
index 0000000..3db6a80
--- /dev/null
@@ -0,0 +1,78 @@
+## 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
+}
diff --git a/grub.cfg.sysinfo-linode b/grub.cfg.sysinfo-linode
new file mode 100644 (file)
index 0000000..b5d1126
--- /dev/null
@@ -0,0 +1,78 @@
+## 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
+}
diff --git a/install-chboot b/install-chboot
new file mode 100755 (executable)
index 0000000..acb6531
--- /dev/null
@@ -0,0 +1,55 @@
+#!/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
diff --git a/live-kexec b/live-kexec
new file mode 120000 (symlink)
index 0000000..3baf2bb
--- /dev/null
@@ -0,0 +1 @@
+lk
\ No newline at end of file
diff --git a/lk b/lk
new file mode 100755 (executable)
index 0000000..d3d13ea
--- /dev/null
+++ b/lk
@@ -0,0 +1,76 @@
+#!/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.
+
+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
+    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
diff --git a/mk-basefile-big b/mk-basefile-big
new file mode 100755 (executable)
index 0000000..873b7ff
--- /dev/null
@@ -0,0 +1,107 @@
+#!/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 - . | gzip > /a/bin/fai-basefiles/basefiles/${distver^^}64BIG.tar.gz
+
+
+cleanup
+exit 0
diff --git a/myfai-chboot b/myfai-chboot
new file mode 100755 (executable)
index 0000000..7d775ea
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+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.
+
+Usng this, you can boot into fai with pxe-kexec without changing
+the dhcp server.
+
+Argument 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.
+-h|--help   Print help and exit.
+
+EOF
+  exit $1
+}
+case $1 in
+  -h|--help) usage ;;
+esac
+
+host=$(./chost faiserver)
+if [[ $host == $(./chost $HOSTNAME) ]]; then
+  ./myfai-chboot-local "$@"
+else
+  ssh root@$host bash -s -- "$@" <myfai-chboot-local
+fi
diff --git a/myfai-chboot-local b/myfai-chboot-local
new file mode 100755 (executable)
index 0000000..4fc6f06
--- /dev/null
@@ -0,0 +1,133 @@
+#!/bin/bash
+# note, this script gets piped to bash, so cant cd to current dir
+
+[[ $EUID == 0 ]] || exec sudo "${BASH_SOURCE}" "$@"
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+kgped16=false
+fai_action=install
+fai_reboot_arg=,reboot
+while [[ $1 == -* ]]; do
+  case $1 in
+    -h|--help)
+      echo "see help from myfai-chboot"
+      exit 0
+      ;;
+    -S)
+      fai_action=sysinfo
+      fai_reboot_arg=
+      shift
+      ;;
+    -i) #inventory
+      fai_action=inventory
+      fai_reboot_arg=
+      shift
+      ;;
+    -k)
+      kgped16=true;
+      shift
+      ;;
+  esac
+done
+
+pre="${0##*/}:"
+m() { printf "$pre %s\n"  "$*"; "$@"; }
+e() { printf "$pre %s\n"  "$*"; }
+err() { echo "[$(date +'%Y-%m-%d %H:%M:%S%z')]: $pre: $*" >&2; }
+
+host=$1
+
+rm -f /srv/tftp/fai/pxelinux.cfg/*
+if [[ ! $1 ]]; then
+  echo "$0: clearing pxe config and exiting"
+  exit 0
+fi
+
+# assuming ipv4, or else we might need to deal with multiple addresses
+# in an ipv4 + ipv6 network.
+my_ip=$(ip -4 route get 8.8.8.8 | 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
+
+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)
+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) ;;
+    *) 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
diff --git a/mymk-basefile b/mymk-basefile
new file mode 100755 (executable)
index 0000000..a784e00
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+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 BUSTER64
+-z STRETCH64
+-z XENIAL64
+-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 "$@"
diff --git a/pxe-server b/pxe-server
new file mode 100755 (executable)
index 0000000..37dbb79
--- /dev/null
@@ -0,0 +1,254 @@
+#!/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.
+
+
+
+x="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
+
+
+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       A hostname known to the dhcp server, or default for all.
+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.
+-k         Pass -k 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
+
+
+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; }
+
+##### begin command line parsing ########
+
+dhcp=true
+redep=true
+acks=2
+wait=false
+fsf=false
+
+case $HOSTNAME in
+  x3|kw) fsf=true ;;
+esac
+
+chboot_args=()
+temp=$(getopt -l 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 ;;
+    -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"
+  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; 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; 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; 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=/etc/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.
+    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
diff --git a/wrt-disabled-firewall-rules b/wrt-disabled-firewall-rules
new file mode 100644 (file)
index 0000000..b2cfdf0
--- /dev/null
@@ -0,0 +1,135 @@
+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
+
+
diff --git a/wrt-init b/wrt-init
new file mode 100755 (executable)
index 0000000..ebfac9c
--- /dev/null
+++ b/wrt-init
@@ -0,0 +1,18 @@
+#!/bin/sh
+set -x
+# 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
+export HOME_DOMAIN=$1
+shift
+wrt-setup-local "$@"
diff --git a/wrt-setup b/wrt-setup
new file mode 100755 (executable)
index 0000000..db7f5c9
--- /dev/null
+++ b/wrt-setup
@@ -0,0 +1,81 @@
+#!/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
+
+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"
+
+cat ~/.ssh/home.pub | ssh $h dd of=/etc/dropbear/authorized_keys 2>/dev/null
+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 \
+
+sudo 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} $h:
+scp ../openwrtkeyring/usign/* $h:/etc/opkg/keys
+
+ssh $h wrt-init ${HOME_DOMAIN:-b8.nz} "$@"
diff --git a/wrt-setup-local b/wrt-setup-local
new file mode 100755 (executable)
index 0000000..2c28dca
--- /dev/null
@@ -0,0 +1,1130 @@
+#!/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
+
+
+usage() {
+  cat <<EOF
+usage: ${0##*/} [-h] [-t 2|3|test|client] [-m WIRELESS_MAC]
+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
+}
+
+
+secrets=false
+if [[ -e /root/router-secrets ]]; then
+  secrets=true
+  source /root/router-secrets
+fi
+rmac=$(cat /sys/class/net/eth0/address)
+if $secrets; then
+  hostname=${rhost[$rmac]}
+fi
+: ${hostname:=wrt}
+
+
+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
+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
+          ;;
+        *) 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 [[ ! $mac ]] && ! $test && $secrets; then
+  # if we wanted to increment it
+  #mac=${mac:0: -1}$((${mac: -1} + 2))
+  mac=${rwmac[$rmac]}
+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 ]]; 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[$rmac]}
+fi
+
+: ${ssid:=librecmc}
+
+
+if $secrets; then
+  key=${rkey[$rmac]}
+fi
+: ${key:=pictionary49}
+
+mask=255.255.0.0
+cidr=16
+l=${lan%.0}
+
+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; then
+  if $dev2; 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
+  cat >/etc/resolv.conf <<'EOF'
+nameserver 8.8.8.8
+nameserver 8.8.4.4
+EOF
+
+  # 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
+  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[$rmac]}
+  uset wireless.default_radio0.encryption 'psk2'
+  uset wireless.default_radio0.device 'radio0'
+  uset wireless.default_radio0.mode 'sta'
+  uset wireless.default_radio0.bssid ${rclientbssid[$rmac]}
+  # todo: look into whether 5g network is available.
+  uset wireless.default_radio0.key ${rclientkey[$rmac]}
+  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
+    # secondary device has wireless disabled
+    uset wireless.radio$x.disabled $dev2
+  done
+fi
+
+
+
+
+
+# usb, screen, relay are for libremanage
+# rsync is for brc
+#
+# relay package temporarily disabled
+# /root/relay_1.0-1_mips_24kc.ipk
+v pi kmod-usb-storage block-mount kmod-fs-ext4 nfs-kernel-server \
+  tcpdump openvpn-openssl adblock libusb-compat \
+  screen kmod-usb-serial-cp210x kmod-usb-serial-ftdi rsync\
+  unbound-daemon-heavy unbound-checkconf
+
+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
+
+
+
+
+
+
+
+
+########## 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.173.0.0'
+ option 'netmask' '255.255.0.0'
+ option 'gateway' '$l.3'
+
+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
+
+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
+
+
+config rule
+ option src              wan
+ option target           ACCEPT
+ option dest_port        22
+
+config redirect
+ option name sshkd
+ option src              wan
+ option src_dport        2202
+ option dest_port        22
+ option dest_ip          $l.2
+ option dest             lan
+config rule
+ option src              wan
+ option target           ACCEPT
+ option dest_port        2202
+
+
+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 sshx2
+ option src              wan
+ option src_dport        2205
+ option dest_port        22
+ option dest_ip          $l.5
+ option dest             lan
+config rule
+ option src              wan
+ option target           ACCEPT
+ option dest_port        2205
+
+config redirect
+ option name sshx3
+ option src              wan
+ option src_dport        2207
+ option dest_port        22
+ option dest_ip          $l.7
+ option dest             lan
+config rule
+ option src              wan
+ option target           ACCEPT
+ option dest_port        2207
+
+config redirect
+ option name sshtp
+ option src              wan
+ option src_dport        2208
+ option dest_port        22
+ option dest_ip          $l.8
+ option dest             lan
+config rule
+ option src              wan
+ option target           ACCEPT
+ option dest_port        2208
+
+config redirect
+ option name sshbb8
+ option src              wan
+ option src_dport        2209
+ option dest_port        22
+ option dest_ip          $l.9
+ option dest             lan
+config rule
+ option src              wan
+ option target           ACCEPT
+ option dest_port        2209
+
+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 sshwrt
+ 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 httpkd
+ option src              wan
+ option src_dport        80
+ option dest             lan
+ option dest_ip          $l.2
+ option proto            tcp
+config rule
+ option src              wan
+ option target           ACCEPT
+ option dest_port        80
+ option proto            tcp
+
+config redirect
+ option name httpskd
+ option src              wan
+ option src_dport        443
+ option dest             lan
+ option dest_ip          $l.2
+ 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 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
+
+# include a file with users custom iptables rules
+config include
+       option path /etc/firewall.user
+       option type 'restore'
+       option family 'ipv4'
+
+
+EOF
+}
+firewall-cedit || firewall_restart=true
+
+# 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
+# not sure this case statement is needed
+case $hostname in
+  cmc)
+    cedit host /etc/hosts <<EOF
+$l.1 $hostname
+# 127.0.0.1 www.youtube.com
+# 127.0.0.1 googlevideo.com
+# 127.0.0.1 youtu.be
+# 127.0.0.1 youtube-nocookie.com
+# 127.0.0.1 youtube.com
+# 127.0.0.1 youtube.googleapis.com
+# 127.0.0.1 youtubei.googleapis.com
+# 127.0.0.1 ytimg.com
+# 127.0.0.1 ytimg.l.google.com
+EOF
+    ;;
+esac
+
+
+#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
+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
+/etc/init.d/odhcpd stop
+/etc/init.d/odhcpd disable
+# todo: make the above conditional on which server this is.
+
+# 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
+
+{
+  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'
+# amy, amyw, samsungtab
+access-control-view: 10.2.0.8/32 "youtube"
+access-control-view: 10.2.0.23/32 "youtube"
+access-control-view: 10.2.0.32/32 "youtube"
+EOF
+  fi
+} | cedit /etc/unbound/unbound_srv.conf  || restart_unbound=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' || restart_unbound=true
+local-data-ptr: "10.2.0.1 cmc.b8.nz"
+local-data-ptr: "10.2.0.2 kd.b8.nz"
+local-data-ptr: "10.2.0.3 sy.b8.nz"
+local-data-ptr: "10.2.0.4 wrt2.b8.nz"
+local-data-ptr: "10.2.0.5 x2.b8.nz"
+local-data-ptr: "10.2.0.6 x2w.b8.nz"
+local-data-ptr: "10.2.0.7 syw.b8.nz"
+local-data-ptr: "10.2.0.8 amy.b8.nz"
+local-data-ptr: "10.2.0.9 bb8.b8.nz"
+local-data-ptr: "10.2.0.12 demohost.b8.nz"
+local-data-ptr: "10.2.0.14 wrt3.b8.nz"
+local-data-ptr: "10.2.0.19 brother.b8.nz"
+local-data-ptr: "10.2.0.23 amyw.b8.nz"
+local-data-ptr: "10.2.0.25 hp.b8.nz"
+local-data-ptr: "10.2.0.31 amazontab.b8.nz"
+local-data-ptr: "10.2.0.32 samsungtab.b8.nz"
+local-data-ptr: "10.173.0.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: "."
+# 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
+
+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 $restart_unbound; then
+  /etc/init.d/unbound restart
+  if ! unbound-checkconf; then
+    echo $0: error: unbound-checkconf failed >&2
+    exit 1
+  fi
+fi
+
+
+# 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
+
+# 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=6,$l.1
+
+
+
+# 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
+# bottom port,  iPXE (PCI 03:00.0) in seabios boot menu
+dhcp-host=c8:60:00:31:6b:75,set:kd,$l.2,kd
+dhcp-host=94:05:bb:1e:2c:2e,set:sy,$l.3,sy
+# top port, iPXE (PCI 04:00.0) in seabios boot menu
+#dhcp-host=c8:60:00:2b:15:07,set:kd,$l.2,kd
+# 4 is reserved for a staticly configured host wrt2
+# old x2 with bad fan
+#dhcp-host=00:1f:16:16:39:24,set:x2,$l.5,x2
+dhcp-host=f0:de:f1:81:ec:88,set:x2,$l.5,x2
+dhcp-host=c4:8e:8f:44:f5:63,set:x2w,$l.6,x2w
+dhcp-host=34:7d:f6:ed:ec:07,set:syw,$l.7,syw
+dhcp-host=80:fa:5b:1c:6e:cf,set:amy,$l.8,amy
+# This is so fai can have an explicit name to use for testing,
+# or else any random machine which did a pxe boot would get
+# reformatted. The mac is from doing a virt-install, cancelling it,
+# and copying the generated mac, so it should be randomish.
+dhcp-host=52:54:00:9c:ef:ad,set:demohost,$l.12,demohost
+dhcp-host=62:03:cb:a8:3e:a3,set:trp,$1.13,trp
+# 14 = wrt3
+dhcp-host=00:1f:16:14:01:d8,set:x3,$l.18,x3
+# BRN001BA98CA823 in dhcp logs
+dhcp-host=00:1b:a9:8c:a8:23,set:brother,$l.19,brother
+
+dhcp-host=00:26:b6:f7:d4:d8,set:amyw,$l.23,amyw
+dhcp-host=9a:c6:52:6f:ce:7c,set:onep9,$l.24,onep9
+dhcp-host=38:63:bb:07:5a:f9,set:hp,$l.25,hp
+dhcp-host=00:26:b6:f6:0f:e9,set:frodow,$l.28,frodow
+dhcp-host=6c:56:97:88:7b:74,set:amazontab,$l.31,amazontab
+dhcp-host=0a:8a:9b:cf:b5:ec,set:samsungtab,$l.32,samsungtab
+
+
+
+# faiserver vm
+dhcp-host=52:54:00:56:09:f9,set:faiserver,$l.15,faiserver
+
+# This is the ip it picks by default if dhcp fails,
+# so might as well use it.
+# hostname is the name it uses according to telnet
+dhcp-host=b4:75:0e:94:29:ca,set:switch9429ca,$l.251,switch9429ca
+
+# template
+# dhcp-host=,$l.,
+
+# Just leave the tftp server up even if we aren't doing pxe boot.
+# It has no sensitive info.
+enable-tftp=br-lan
+tftp-root=/mnt/usb/tftpboot
+dhcp-optsfile=/etc/dnsmasq-dhcpopts.conf
+
+#log-queries=extra
+EOF
+
+
+if $dnsmasq_restart && ! $dev2; 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 $firewall_restart; then
+  v /etc/init.d/firewall restart
+fi
+
+# 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
+
+exit 0