default.nix (3605B)
1 # The ideal is that a Liminix system can boot with only the files in 2 # /nix/store. This package generates a small program that is run at early 3 # boot (from the initramfs) to populate directories such as /etc, 4 # /bin, /home according to whatever the configuration says 5 # they should contain 6 7 { 8 writeText, 9 writeFennel, 10 buildPackages, 11 lib, 12 s6-init-bin, 13 closureInfo, 14 stdenv, 15 }: 16 let 17 inherit (lib.attrsets) mapAttrsToList; 18 escaped = 19 msg: builtins.replaceStrings [ "\n" "=" "\"" "$" ] [ "\\x0a" "\\x3d" "\\x22" "\\x24" ] msg; 20 21 visit = 22 prefix: attrset: 23 let 24 makeFile = 25 prefix: filename: 26 { 27 type ? "f", 28 mode ? null, 29 target ? null, 30 contents ? null, 31 file ? null, 32 major ? null, 33 minor ? null, 34 uid ? 0, 35 gid ? 0, 36 }: 37 let 38 pathname = "${prefix}/${filename}"; 39 qpathname = builtins.toJSON pathname; 40 mode' = if mode != null then mode else (if type == "d" then "0755" else "0644"); 41 cmds = { 42 "f" = "PRINTFILE(${qpathname}, ${mode'}, ${builtins.toJSON (escaped file)});"; 43 "d" = 44 "MKDIR(${qpathname}, ${mode'});\n" + (builtins.concatStringsSep "\n" (visit pathname contents)); 45 "c" = "MKNOD_C(${qpathname}, ${mode'}, ${major}, ${minor});"; 46 "b" = "MKNOD_B(${qpathname}, ${mode'}, ${major}, ${minor});"; 47 "s" = "LN_S(${builtins.toJSON target}, ${qpathname});"; 48 "l" = "LN(${builtins.toJSON target}, ${qpathname})"; 49 "i" = "MKNOD_P(${qpathname}, ${mode'});"; 50 }; 51 cmd = cmds.${type}; 52 chown = 53 if uid > 0 || gid > 0 then "\nCHOWN(${qpathname},${toString uid},${toString gid});\n" else ""; 54 in 55 "unlink(${qpathname}); ${cmd} ${chown}"; 56 in 57 mapAttrsToList (makeFile prefix) attrset; 58 in 59 attrset: 60 let 61 activateScript = writeText "activate.c" '' 62 #include "defs.h" 63 int main(int argc, char* argv[]) { 64 chdir(argv[1]); 65 ${(builtins.concatStringsSep "\n" (visit "." attrset))} 66 } 67 ''; 68 in 69 stdenv.mkDerivation { 70 name = "system-configuration"; 71 src = ./.; 72 73 CFLAGS = "-Os"; 74 LDFLAGS = "-static -Xlinker -static"; 75 76 postConfigure = '' 77 cp ${activateScript} activate.c 78 ''; 79 makeFlags = [ "activate" ]; 80 installPhase = '' 81 closure=${closureInfo { rootPaths = [ activateScript ]; }} 82 mkdir -p $out/bin $out/etc 83 cp $closure/store-paths $out/etc/nix-store-paths 84 $STRIP --remove-section=.note --remove-section=.comment --strip-all activate -o $out/bin/activate 85 ln -s ${s6-init-bin}/bin/init $out/bin/init 86 cp -p ${writeFennel "restart-services" { } ./restart-services.fnl} $out/bin/restart-services 87 cat > $out/bin/install <<EOF 88 #!/bin/sh -e 89 prefix=\''${1-/} 90 src=\''${prefix}$out 91 dest=\$prefix 92 ${ 93 # if we are running on a normal mounted system then 94 # the actual device root is mounted on /persist 95 # and /nix is bind mounted from /persist/nix 96 # (see the code in preinit). So we need to check for this 97 # case otherwise we will install into a ramfs/rootfs 98 "" 99 } 100 if test -d \$dest/persist; then dest=\$dest/persist; fi 101 cp -v -fP \$src/bin/* \$src/etc/* \$dest 102 ${ 103 if attrset ? boot then 104 '' 105 (cd \$dest 106 test -d boot || mkdir boot 107 cd boot 108 cp ../${lib.strings.removePrefix "/" attrset.boot.target}/* . 109 sync; sync 110 ) 111 '' 112 else 113 "" 114 } 115 EOF 116 chmod +x $out/bin/install 117 ''; 118 }