dotfiles
My PC Dotfiles & Websitegit clone https://github.com/maydayv7/dotfiles
modules/system/filesystem.nix (10554B)
1## File System Configuration ##
2{
3 config,
4 inputs,
5 ...
6}: let
7 inherit (config.flake) files;
8in {
9 flake.modules = {
10 nixos.filesystem = {
11 config,
12 lib,
13 pkgs,
14 ...
15 }: let
16 inherit
17 (lib)
18 filterAttrs
19 hasPrefix
20 mkAliasOptionModule
21 mkDefault
22 mkIf
23 mkMerge
24 mkOption
25 nameValuePair
26 optional
27 types
28 ;
29
30 cfg = config.system.fs;
31 in {
32 imports = [
33 inputs.disko.nixosModules.disko
34 (
35 mkAliasOptionModule
36 ["system" "fs" "persist"]
37 [
38 "environment"
39 "persistence"
40 files.path.data
41 ]
42 )
43 ];
44
45 options.system.fs = {
46 scheme = mkOption {
47 description = "Disk Filesystem Scheme";
48 type = with types;
49 nullOr (enum [
50 "simple"
51 "advanced"
52 ]);
53 default = null;
54 };
55
56 disk = mkOption {
57 description = "Target Disk for Installation";
58 type = types.str;
59 default = "/dev/disk/by-id/disko-placeholder";
60 example = "/dev/disk/by-id/nvme-eui.0123456789abcdef";
61 };
62
63 swap = mkOption {
64 description = "Size of SWAP Partition";
65 type = types.str;
66 default = "8G";
67 example = "16G";
68 };
69 };
70
71 config = mkMerge [
72 {
73 warnings = optional (cfg.scheme == null) "Disk Filesystem Scheme is unset";
74 system.fs.persist.enable = mkDefault false;
75
76 boot = {
77 supportedFilesystems = {
78 ntfs = true;
79 vfat = true;
80 zfs = true;
81 };
82 zfs.forceImportRoot = false;
83 };
84
85 ## Disk Layout
86 disko.devices = mkMerge [
87 (mkIf (cfg.scheme != null) {
88 disk.main = {
89 type = "disk";
90 device = cfg.disk;
91 content = {
92 type = "gpt";
93 partitions = {
94 # EFI System Partition
95 ESP = {
96 label = "ESP";
97 type = "EF00";
98 size = "1024M";
99 content = {
100 type = "filesystem";
101 format = "vfat";
102 mountpoint = "/boot";
103 mountOptions = ["umask=0077"];
104 };
105 };
106
107 # SWAP Partition
108 swap = {
109 label = "swap";
110 size = cfg.swap;
111 content = {
112 type = "swap";
113 resumeDevice = true;
114 };
115 };
116
117 # System Partition
118 System = {
119 label = "System";
120 size = "100%";
121 content =
122 if cfg.scheme == "advanced"
123 then {
124 type = "zfs";
125 pool = "fspool";
126 }
127 else {
128 type = "filesystem";
129 format = "ext4";
130 mountpoint = "/";
131 };
132 };
133 };
134 };
135 };
136 })
137
138 (mkIf (cfg.scheme == "advanced") {
139 zpool.fspool = {
140 type = "zpool";
141 options = {
142 ashift = "12";
143 cachefile = "none";
144 };
145 rootFsOptions = {
146 atime = "off";
147 compression = "zstd";
148 dnodesize = "auto";
149 encryption = "on";
150 keyformat = "passphrase";
151 keylocation = "prompt";
152 mountpoint = "none";
153 xattr = "sa";
154 acltype = "posixacl";
155 };
156
157 datasets = {
158 # ROOT Dataset
159 "system/root" = {
160 type = "zfs_fs";
161 mountpoint = "/";
162 options.mountpoint = "legacy";
163 postCreateHook = "zfs snapshot fspool/system/root@blank";
164 };
165
166 # NIX Store Dataset
167 "system/nix" = {
168 type = "zfs_fs";
169 mountpoint = "/nix";
170 options = {
171 mountpoint = "legacy";
172 recordsize = "1M";
173 };
174 };
175
176 # Persisted Dataset
177 "data" = {
178 type = "zfs_fs";
179 mountpoint = files.path.data;
180 options = {
181 mountpoint = "legacy";
182 "com.sun:auto-snapshot" = "true";
183 };
184 };
185
186 # Reserved space
187 # ? # Free with 'zfs set refreservation=none fspool/reserve'
188 "reserve" = {
189 type = "zfs_fs";
190 options = {
191 canmount = "off";
192 mountpoint = "none";
193 refreservation = "1G";
194 };
195 };
196 };
197 };
198 })
199 ];
200 }
201
202 (mkIf (cfg.scheme != null) {
203 programs.fuse.userAllowOther = true;
204 boot.kernel.sysctl."vm.swappiness" = 1; # SWAP Behaviour
205
206 system.activationScripts.dotfiles = with files.path; let
207 path =
208 if cfg.scheme == "advanced"
209 then "${persist}/"
210 else "";
211 dir = "${path}${system}";
212 in ''
213 chown root:keys ${dir}
214 chmod -R u=rwX,g=rwX,o= ${dir}
215 chmod g+s ${dir}
216 '';
217 })
218
219 ## Advanced File System Configuration using ZFS ##
220 (mkIf (cfg.scheme == "advanced") (
221 let
222 rollback = ''
223 zfs rollback -r fspool/system/root@blank && echo "Rollback Complete!"
224 '';
225 in {
226 fileSystems =
227 {
228 "${files.path.data}".neededForBoot = true;
229 }
230 // filterAttrs (name: _: hasPrefix "/etc" name) (
231 builtins.listToAttrs (
232 map (
233 item:
234 nameValuePair item.directory {
235 device = "${files.path.persist}${item.directory}";
236 fsType = "none";
237 options = ["bind"];
238 neededForBoot = true;
239 }
240 )
241 config.environment.persist.directories
242 )
243 );
244
245 # Early Boot Requirements
246 boot = {
247 zfs = {
248 forceImportAll = false;
249 devNodes = "/dev/disk/by-partlabel/System";
250 };
251
252 initrd.systemd = {
253 enable = true;
254 services.rollback = {
255 description = "Wipe ZFS partition for Opt-In State Configuration";
256 wantedBy = ["initrd.target"];
257 after = ["zfs-import-fspool.service"];
258 before = ["sysroot.mount"];
259 path = [pkgs.zfs];
260 unitConfig.DefaultDependencies = "no";
261 serviceConfig.Type = "oneshot";
262 script = rollback;
263 };
264 };
265 };
266
267 # Maintainence
268 services.zfs = {
269 trim = {
270 enable = true;
271 interval = "weekly";
272 };
273
274 autoScrub = {
275 enable = true;
276 interval = "monthly";
277 };
278
279 autoSnapshot = {
280 enable = true;
281 hourly = 12;
282 daily = 7;
283 weekly = 3;
284 monthly = 1;
285 };
286 };
287
288 # Persisted Files
289 system.fs.persist.enable = true;
290 environment.persistence."${files.path.persist}" = {
291 enable = true;
292 files = ["/etc/machine-id"];
293 directories = [
294 files.path.system
295 "/var/log"
296 "/var/lib/AccountsService"
297 "/var/lib/nixos"
298 "/var/lib/systemd"
299 ];
300 };
301 }
302 ))
303 ];
304 };
305
306 homeManager.filesystem = {
307 lib,
308 pkgs,
309 osConfig ? null,
310 ...
311 }: let
312 advanced = osConfig != null && (osConfig.system.fs.scheme or null) == "advanced";
313 in {
314 imports = [(lib.mkAliasOptionModule ["home" "persist"] ["home" "persistence" files.path.data])];
315
316 home.persistence."${files.path.data}" = {
317 enable = advanced;
318 allowTrash = true;
319 hideMounts = true;
320 directories = [
321 "Desktop"
322 "Documents"
323 "Downloads"
324 "Music"
325 "Pictures"
326 "Public"
327 "Videos"
328 {
329 directory = ".local/share/keyrings";
330 mode = "0700";
331 }
332 ];
333 };
334
335 # Persist Trash Folder
336 systemd.user.services.persist-trash = lib.mkIf advanced {
337 Unit.Description = "Persist Trash Folder";
338 Install.WantedBy = ["default.target"];
339 Service = let
340 run = script:
341 lib.getExe (
342 pkgs.writeShellApplication {
343 name = "script";
344 runtimeInputs = [pkgs.coreutils];
345 text = ''
346 LOCAL="$HOME/.local/share/Trash"
347 PERSIST="${files.path.data}/home/$USER/Trash"
348 mkdir -p "$LOCAL"
349 ${script}
350 '';
351 }
352 );
353 in {
354 Type = "oneshot";
355 RemainAfterExit = true;
356 StandardOutput = "journal";
357 ExecStart = run ''
358 if [ -d "$PERSIST" ]
359 then
360 cp -r "$PERSIST"/. "$LOCAL"
361 rm -rf "$PERSIST"
362 fi
363 '';
364 ExecStop = run ''
365 mkdir -p "$PERSIST"
366 cp -r "$LOCAL"/. "$PERSIST"
367 '';
368 };
369 };
370 };
371 };
372}