Compare commits
No commits in common. "master" and "1eb77e513e0f1bc4cb265dcf748025058d2643d8" have entirely different histories.
master
...
1eb77e513e
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
init
|
11
README.md
11
README.md
|
@ -1,11 +0,0 @@
|
|||
# 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
22
device.go
|
@ -1,22 +0,0 @@
|
|||
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,27 +30,13 @@ var ActionMap = map[string]Action{
|
|||
"ctrlaltdel": CtrlAltDel,
|
||||
}
|
||||
|
||||
type InitTabEntry struct {
|
||||
Device string
|
||||
type TabEntry struct {
|
||||
Id string
|
||||
Action Action
|
||||
Process string
|
||||
}
|
||||
|
||||
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{
|
||||
var DefaultInittab = []TabEntry{
|
||||
{"", SysInit, "/etc/init.d/rcS"},
|
||||
{"", AskFirst, "/bin/sh"},
|
||||
{"", CtrlAltDel, "/sbin/reboot"},
|
||||
|
@ -62,8 +48,8 @@ var DefaultInitTab = InitTab{
|
|||
{"tty4", AskFirst, "/bin/sh"},
|
||||
}
|
||||
|
||||
func ParseInitTab(reader io.Reader) InitTab {
|
||||
var res InitTab
|
||||
func ParseInittab(reader io.Reader) []TabEntry {
|
||||
var res []TabEntry
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
@ -81,8 +67,8 @@ func ParseInitTab(reader io.Reader) InitTab {
|
|||
continue
|
||||
}
|
||||
|
||||
res = append(res, InitTabEntry{
|
||||
Device: tokens[0],
|
||||
res = append(res, TabEntry{
|
||||
Id: tokens[0],
|
||||
Action: action,
|
||||
Process: tokens[3],
|
||||
})
|
||||
|
|
96
main.go
96
main.go
|
@ -1,99 +1,5 @@
|
|||
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
44
process.go
|
@ -1,44 +0,0 @@
|
|||
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