"""Generate jail.conf.d entries.""" from __future__ import annotations from .config import JailConfig, MainConfig def _format_value(value: object) -> str: if isinstance(value, str): return f"\"{value}\"" if isinstance(value, bool): return "true" if value else "false" if isinstance(value, (int, float)): return str(value) raise ValueError(f"unsupported jailconf value type: {type(value).__name__}") def _flatten(prefix: str, value: object, out: list[tuple[str, object]]) -> None: if isinstance(value, dict): for key, val in value.items(): new_prefix = f"{prefix}.{key}" if prefix else str(key) _flatten(new_prefix, val, out) else: out.append((prefix, value)) def render_jail_conf( main: MainConfig, jail: JailConfig, *, jailname: str | None = None, root: str | None = None, ) -> str: """Render jail.conf content for the jail.""" name = jailname or jail.name if not root: raise ValueError("root path is required to render jail.conf") lines = [ f"{name} {{", f" host.hostname = \"{name}\";", f" path = \"{root}\";", " exec.start = \"/bin/sh /etc/rc\";", " exec.stop = \"/bin/sh /etc/rc.shutdown jail\";", ] if jail.jailconf: flattened: list[tuple[str, object]] = [] _flatten("", jail.jailconf, flattened) for key, value in flattened: if value is True: lines.append(f" {key};") continue if value is False: continue lines.append(f" {key} = {_format_value(value)};") # Exec commands from [cmds], with env prefix env_prefix = "" if jail.env: pairs = [f"{k}={v}" for k, v in jail.env.items()] env_prefix = "env " + " ".join(pairs) + " " cmd_map = { "prestart": "exec.prestart", "poststart": "exec.poststart", "prestop": "exec.prestop", "poststop": "exec.poststop", "start": "exec.start", "stop": "exec.stop", } for key, jailconf_key in cmd_map.items(): cmd = jail.cmds.get(key) if cmd: if env_prefix and not cmd.startswith("env "): cmd_value = f"{env_prefix}{cmd}" else: cmd_value = cmd lines.append(f" {jailconf_key} = \"{cmd_value}\";") lines.append("}") return "\n".join(lines) + "\n"