|  | package main | 
|  |  | 
|  | import ( | 
|  | "context" | 
|  | "fmt" | 
|  | "io" | 
|  | "os" | 
|  | "regexp" | 
|  |  | 
|  | "golang.org/x/sys/unix" | 
|  |  | 
|  | "source.monogon.dev/metropolis/pkg/bootparam" | 
|  | "source.monogon.dev/metropolis/pkg/logtree" | 
|  | "source.monogon.dev/metropolis/pkg/supervisor" | 
|  | ) | 
|  |  | 
|  | var validTTYRegexp = regexp.MustCompile(`^[a-zA-Z0-9]+$`) | 
|  |  | 
|  | func main() { | 
|  | setupMounts() | 
|  |  | 
|  | // Set up logger for the Agent. Parse consoles from the kernel command line | 
|  | // as well as adding the two standard tty0/ttyS0 consoles. | 
|  | consoles := make(map[string]bool) | 
|  | cmdline, err := os.ReadFile("/proc/cmdline") | 
|  | if err == nil { | 
|  | params, _, err := bootparam.Unmarshal(string(cmdline)) | 
|  | if err == nil { | 
|  | consoles = params.Consoles() | 
|  | } | 
|  | } | 
|  | consoles["tty0"] = true | 
|  | consoles["ttyS0"] = true | 
|  |  | 
|  | lt := logtree.New() | 
|  | for p := range consoles { | 
|  | f, err := os.OpenFile("/dev/"+p, os.O_WRONLY, 0) | 
|  | if err != nil { | 
|  | continue | 
|  | } | 
|  | reader, err := lt.Read("", logtree.WithChildren(), logtree.WithStream()) | 
|  | if err != nil { | 
|  | panic(fmt.Errorf("could not set up root log reader: %v", err)) | 
|  | } | 
|  | go func(path string, f io.Writer) { | 
|  | for { | 
|  | p := <-reader.Stream | 
|  | fmt.Fprintf(f, "%s\n", p.String()) | 
|  | } | 
|  | }(p, f) | 
|  | } | 
|  |  | 
|  | sCtx := context.Background() | 
|  | supervisor.New(sCtx, agentRunnable, supervisor.WithExistingLogtree(lt)) | 
|  | select {} | 
|  | } | 
|  |  | 
|  | func mkdirAndMount(dir, fs string, flags uintptr) error { | 
|  | if err := os.MkdirAll(dir, 0o755); err != nil { | 
|  | return fmt.Errorf("could not make %s: %w", dir, err) | 
|  | } | 
|  | if err := unix.Mount(fs, dir, fs, flags, ""); err != nil { | 
|  | return fmt.Errorf("could not mount %s on %s: %w", fs, dir, err) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // setupMounts sets up basic mounts like sysfs, procfs, devtmpfs and cgroups. | 
|  | // This should be called early during init as a lot of processes depend on this | 
|  | // being available. | 
|  | func setupMounts() error { | 
|  | // Set up target filesystems. | 
|  | for _, el := range []struct { | 
|  | dir   string | 
|  | fs    string | 
|  | flags uintptr | 
|  | }{ | 
|  | {"/sys", "sysfs", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV}, | 
|  | {"/sys/kernel/tracing", "tracefs", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV}, | 
|  | {"/sys/fs/pstore", "pstore", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV}, | 
|  | {"/proc", "proc", unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV}, | 
|  | {"/dev", "devtmpfs", unix.MS_NOEXEC | unix.MS_NOSUID}, | 
|  | {"/dev/pts", "devpts", unix.MS_NOEXEC | unix.MS_NOSUID}, | 
|  | } { | 
|  | if err := mkdirAndMount(el.dir, el.fs, el.flags); err != nil { | 
|  | return err | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } |