-
Notifications
You must be signed in to change notification settings - Fork 11
/
main.go
128 lines (111 loc) · 4.02 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// dainit is a simple init system for Linux intended for non-server uses
// (ie. for a programmer's home Linux system.)
//
// It aims to be easy to use.
package main
import (
"io/ioutil"
"log"
"os"
"os/exec"
"syscall"
)
// Runs a command, setting up Stdin/Stdout/Stderr to be the standard OS
// ones, and not /dev/null. This will block until the command finishes.
func run(cmd string, args ...string) error {
c := exec.Command(cmd, args...)
c.Stdout = os.Stdout
c.Stdin = os.Stdin
c.Stderr = os.Stderr
return c.Run()
}
// Runs a command and waits for it to finish.
func runquiet(cmd string, args ...string) error {
c := exec.Command(cmd, args...)
return c.Run()
}
// Set's the hostname for the kernel.
func SetHostname(hostname string) {
proc, err := os.Create("/proc/sys/kernel/hostname")
if err != nil {
log.Println(err)
}
defer proc.Close()
n, err := proc.Write([]byte(hostname))
if n != len(hostname) || err != nil {
log.Println(err)
}
}
func main() {
// Remount root as rw.
//
// This should be handled by mount -a according to mount(8), since the flags that
// / is mounted with don't match /etc/fstab, but for some reason it's not remounting
// root as rw even though it's not ro in /etc/fstab. TODO: Look into this..
println("Remounting root filesystem")
Remount("/")
// Mount local filesytems
println("Mounting local file systems")
netfs := []string{"nfs", "nfs4", "smbfs", "cifs", "codafs", "ncpfs", "shfs", "fuse", "fuseblk", "glusterfs", "davfs", "fuse.glusterfs"}
virtfs := []string{"proc", "sysfs", "tmpfs", "devtmpfs", "devpts"}
MountAllExcept(netfs)
// Activate swap partitions, mount -a doesn't do this since they aren't really mounted anywhere
run("swapon", "-a")
// Set the hostname for getty to be happy.
if hostname, err := ioutil.ReadFile("/etc/hostname"); err == nil {
SetHostname(string(hostname))
}
// There's a little (dare I say, a lot?) of black magic that seems to
// happen on a modern Linux systems for filesystems.
//
// Time was, everything would go into /etc/fstab.
//
// If you read "Demystifying the init system" (https://felipec.wordpress.com/2013/11/04/init/)
// he manually mounts /proc, /sys, /run, etc.
//
// When I do that on my Debian system, I get an "already mounted" error
// despite it not being in /etc/fstab, so I don't mount them here (either
// the kernel is doing it, or Debian is lying about init being the first
// process.)
//
// However, /dev/shm is neither automounted, nor in fstab, and without it
// Chromium won't start, so it's done manually here.
//
// (It should probably just go into my fstab to be honest, but then it seems
// that I'd need to manually add it every time I install a new system..)
Mount("tmpfs", "shm", "/dev/shm", "mode=1777,nosuid,nodev")
// Parse all the configs in /etc/dainit. Finally!
services, err := ParseServiceConfigs("/etc/dainit")
if err != nil {
log.Println(err)
}
StartServices(services)
// Launch an appropriate number of getty processes on ttys.
if conf, err := os.Open("/etc/dainit.conf"); err != nil {
// If the config doesn't exist or can't be opened, use the defaults.
Gettys(nil, false)
} else {
if autologins, persist, err := ParseSetupConfig(conf); err != nil {
// We don't want to defer this because otherwise it won't
// get executed until the system is shutting down..
conf.Close()
// If the config couldn't be parsed, used the defaults
log.Println(err)
Gettys(nil, false)
} else {
conf.Close()
Gettys(autologins, persist)
}
}
// The tty exited. Kill processes, unmount filesystems and halt the system.
// TODO: Run shutdown scripts for services that are started instead
// of just sending them a SIGTERM right off the bat..
println("Killing everything I can find...")
KillAll()
// This needs to be done after all the processes are dead, otherwise
// it will fail due to being in use.
println("Unmounting filesystems...")
UnmountAllExcept(append(netfs, virtfs...))
// Halt the system explicitly to prevent a kernel panic.
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
}