Compare commits
13 commits
1eb77e513e
...
master
Author | SHA1 | Date | |
---|---|---|---|
ptrcnull | 941d8a814b | ||
ptrcnull | 8c6d9e4ab6 | ||
ptrcnull | 543e1cdd14 | ||
ptrcnull | 83a7661a7d | ||
ptrcnull | 180881639b | ||
ptrcnull | b57328e20b | ||
ptrcnull | 2454b772dc | ||
ptrcnull | e8591c5770 | ||
ptrcnull | 068cb742f5 | ||
ptrcnull | 6c8e8c3003 | ||
ptrcnull | 945b295bdf | ||
ptrcnull | b5808e7773 | ||
ptrcnull | 8650c833bf |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
init
|
11
README.md
Normal file
11
README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# ptrcnull/init
|
||||
|
||||
Experimental implementation of PID 1.
|
||||
|
||||
Drop-in replacement for busybox init (kind of)
|
||||
|
||||
The canonical URL of this repository is https://git.ptrc.gay/ptrcnull/init
|
||||
|
||||
### TODO
|
||||
|
||||
- askfirst handling
|
22
device.go
Normal file
22
device.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var devices = map[string]*os.File{}
|
||||
|
||||
func GetDevice(name string) (*os.File, error) {
|
||||
if dev, ok := devices[name]; ok {
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
dev, err := os.OpenFile("/dev/"+name, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open: %w", err)
|
||||
}
|
||||
|
||||
devices[name] = dev
|
||||
return dev, nil
|
||||
}
|
28
inittab.go
28
inittab.go
|
@ -30,13 +30,27 @@ var ActionMap = map[string]Action{
|
|||
"ctrlaltdel": CtrlAltDel,
|
||||
}
|
||||
|
||||
type TabEntry struct {
|
||||
Id string
|
||||
type InitTabEntry struct {
|
||||
Device string
|
||||
Action Action
|
||||
Process string
|
||||
}
|
||||
|
||||
var DefaultInittab = []TabEntry{
|
||||
type InitTab []InitTabEntry
|
||||
|
||||
func (i InitTab) Entries(action Action) InitTab {
|
||||
var res InitTab
|
||||
|
||||
for _, entry := range i {
|
||||
if entry.Action == action {
|
||||
res = append(res, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
var DefaultInitTab = InitTab{
|
||||
{"", SysInit, "/etc/init.d/rcS"},
|
||||
{"", AskFirst, "/bin/sh"},
|
||||
{"", CtrlAltDel, "/sbin/reboot"},
|
||||
|
@ -48,8 +62,8 @@ var DefaultInittab = []TabEntry{
|
|||
{"tty4", AskFirst, "/bin/sh"},
|
||||
}
|
||||
|
||||
func ParseInittab(reader io.Reader) []TabEntry {
|
||||
var res []TabEntry
|
||||
func ParseInitTab(reader io.Reader) InitTab {
|
||||
var res InitTab
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
@ -67,8 +81,8 @@ func ParseInittab(reader io.Reader) []TabEntry {
|
|||
continue
|
||||
}
|
||||
|
||||
res = append(res, TabEntry{
|
||||
Id: tokens[0],
|
||||
res = append(res, InitTabEntry{
|
||||
Device: tokens[0],
|
||||
Action: action,
|
||||
Process: tokens[3],
|
||||
})
|
||||
|
|
96
main.go
96
main.go
|
@ -1,5 +1,99 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
inittab := DefaultInitTab
|
||||
if file, err := os.OpenFile("/etc/inittab", os.O_RDONLY, 0644); err == nil {
|
||||
inittab = ParseInitTab(file)
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("error closing inittab: %s\n", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("error reading inittab: %s\n", err)
|
||||
}
|
||||
|
||||
inittab.Entries(SysInit).ExecAll()
|
||||
inittab.Entries(Wait).ExecAll()
|
||||
inittab.Entries(Once).SpawnAll()
|
||||
inittab.Entries(Respawn).RespawnAll()
|
||||
|
||||
// TODO implement AskFirst handling
|
||||
|
||||
sigs := make(chan os.Signal, 1)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
sig := <-sigs
|
||||
switch sig {
|
||||
case syscall.SIGUSR2:
|
||||
// shutdown
|
||||
inittab.Entries(Shutdown).ExecAll()
|
||||
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
|
||||
|
||||
case syscall.SIGTERM:
|
||||
// reboot
|
||||
inittab.Entries(Shutdown).ExecAll()
|
||||
syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
|
||||
|
||||
case syscall.SIGQUIT:
|
||||
inittab.Entries(Shutdown).ExecAll()
|
||||
restart := inittab.Entries(Restart)[0]
|
||||
cmdline := strings.Split(restart.Process, " ")
|
||||
syscall.Exec(cmdline[0], cmdline[1:], []string{})
|
||||
|
||||
case syscall.SIGINT:
|
||||
inittab.Entries(CtrlAltDel).ExecAll()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
signal.Notify(sigs, syscall.SIGUSR2, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
syscall.Wait4(-1, nil, 0, nil)
|
||||
}
|
||||
}()
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func (i InitTab) ExecAll() {
|
||||
for _, entry := range i {
|
||||
err := Exec(entry)
|
||||
if err != nil {
|
||||
fmt.Printf("error executing \"%s\": %s\n", entry.Process, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i InitTab) SpawnAll() {
|
||||
for _, entry := range i {
|
||||
_, err := Spawn(entry)
|
||||
if err != nil {
|
||||
fmt.Printf("error spawning \"%s\": %s\n", entry.Process, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i InitTab) RespawnAll() {
|
||||
for _, entry := range i {
|
||||
go func(entry InitTabEntry) {
|
||||
for {
|
||||
err := Exec(entry)
|
||||
if err != nil {
|
||||
fmt.Printf("error respawning \"%s\": %s\n", entry.Process, err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}(entry)
|
||||
}
|
||||
}
|
||||
|
|
44
process.go
Normal file
44
process.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Spawn(entry InitTabEntry) (*exec.Cmd, error) {
|
||||
cmdline := strings.Split(entry.Process, " ")
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
|
||||
stdio := os.Stdout
|
||||
if entry.Device != "" {
|
||||
dev, err := GetDevice(entry.Device)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open device %s: %w", entry.Device, err)
|
||||
}
|
||||
stdio = dev
|
||||
}
|
||||
cmd.Stdin = stdio
|
||||
cmd.Stdout = stdio
|
||||
cmd.Stderr = stdio
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func Exec(entry InitTabEntry) error {
|
||||
cmd, err := Spawn(entry)
|
||||
if err != nil {
|
||||
return fmt.Errorf("spawn: %w", err)
|
||||
}
|
||||
|
||||
// skipping error handling due to wait4 in main
|
||||
cmd.Wait()
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in a new issue