1{ config, lib, pkgs, ... }:
2with lib;
3let
4 cfg = config.services.diod;
5
6 diodBool = b: if b then "1" else "0";
7
8 diodConfig = pkgs.writeText "diod.conf" ''
9 allsquash = ${diodBool cfg.allsquash}
10 auth_required = ${diodBool cfg.authRequired}
11 exportall = ${diodBool cfg.exportall}
12 exportopts = "${concatStringsSep "," cfg.exportopts}"
13 exports = { ${concatStringsSep ", " (map (s: ''"${s}"'' ) cfg.exports)} }
14 listen = { ${concatStringsSep ", " (map (s: ''"${s}"'' ) cfg.listen)} }
15 logdest = "${cfg.logdest}"
16 nwthreads = ${toString cfg.nwthreads}
17 squashuser = "${cfg.squashuser}"
18 statfs_passthru = ${diodBool cfg.statfsPassthru}
19 userdb = ${diodBool cfg.userdb}
20 ${cfg.extraConfig}
21 '';
22in
23{
24 options = {
25 services.diod = {
26 enable = mkOption {
27 type = types.bool;
28 default = false;
29 description = "Whether to enable the diod 9P file server.";
30 };
31
32 listen = mkOption {
33 type = types.listOf types.str;
34 default = [ "0.0.0.0:564" ];
35 description = ''
36 [ "IP:PORT" [,"IP:PORT",...] ]
37 List the interfaces and ports that diod should listen on.
38 '';
39 };
40
41 exports = mkOption {
42 type = types.listOf types.str;
43 default = [];
44 description = ''
45 List the file systems that clients will be allowed to mount. All paths should
46 be fully qualified. The exports table can include two types of element:
47 a string element (as above),
48 or an alternate table element form { path="/path", opts="ro" }.
49 In the alternate form, the (optional) opts attribute is a comma-separated list
50 of export options. The two table element forms can be mixed in the exports
51 table. Note that although diod will not traverse file system boundaries for a
52 given mount due to inode uniqueness constraints, subdirectories of a file
53 system can be separately exported.
54 '';
55 };
56
57 exportall = mkOption {
58 type = types.bool;
59 default = true;
60 description = ''
61 Export all file systems listed in /proc/mounts. If new file systems are mounted
62 after diod has started, they will become immediately mountable. If there is a
63 duplicate entry for a file system in the exports list, any options listed in
64 the exports entry will apply.
65 '';
66 };
67
68 exportopts = mkOption {
69 type = types.listOf types.str;
70 default = [];
71 description = ''
72 Establish a default set of export options. These are overridden, not appended
73 to, by opts attributes in an "exports" entry.
74 '';
75 };
76
77 nwthreads = mkOption {
78 type = types.int;
79 default = 16;
80 description = ''
81 Sets the (fixed) number of worker threads created to handle 9P
82 requests for a unique aname.
83 '';
84 };
85
86 authRequired = mkOption {
87 type = types.bool;
88 default = false;
89 description = ''
90 Allow clients to connect without authentication, i.e. without a valid MUNGE credential.
91 '';
92 };
93
94 userdb = mkOption {
95 type = types.bool;
96 default = false;
97 description = ''
98 This option disables password/group lookups. It allows any uid to attach and
99 assumes gid=uid, and supplementary groups contain only the primary gid.
100 '';
101 };
102
103 allsquash = mkOption {
104 type = types.bool;
105 default = true;
106 description = ''
107 Remap all users to "nobody". The attaching user need not be present in the
108 password file.
109 '';
110 };
111
112 squashuser = mkOption {
113 type = types.str;
114 default = "nobody";
115 description = ''
116 Change the squash user. The squash user must be present in the password file.
117 '';
118 };
119
120 logdest = mkOption {
121 type = types.str;
122 default = "syslog:daemon:err";
123 description = ''
124 Set the destination for logging.
125 The value has the form of "syslog:facility:level" or "filename".
126 '';
127 };
128
129
130 statfsPassthru = mkOption {
131 type = types.bool;
132 default = false;
133 description = ''
134 This option configures statfs to return the host file system's type
135 rather than V9FS_MAGIC.
136 '';
137 };
138
139 extraConfig = mkOption {
140 type = types.lines;
141 default = "";
142 description = "Extra configuration options for diod.conf.";
143 };
144 };
145 };
146
147 config = mkIf config.services.diod.enable {
148 environment.systemPackages = [ pkgs.diod ];
149
150 systemd.services.diod = {
151 description = "diod 9P file server";
152 wantedBy = [ "multi-user.target" ];
153 after = [ "network.target" ];
154 serviceConfig = {
155 ExecStart = "${pkgs.diod}/sbin/diod -f -c ${diodConfig}";
156 CapabilityBoundingSet = "cap_net_bind_service+=ep";
157 };
158 };
159 };
160}