1// Package ddwrt implements the dd-wrt init system.
2
3package ddwrt
4
5import (
6	"os"
7	"os/exec"
8	"strings"
9
10	"github.com/nextdns/nextdns/host/service"
11	"github.com/nextdns/nextdns/host/service/internal"
12)
13
14type Service struct {
15	service.Config
16	service.ConfigFileStorer
17	Path string
18}
19
20func New(c service.Config) (Service, error) {
21	if b, err := exec.Command("uname", "-o").Output(); err != nil ||
22		!strings.HasPrefix(string(b), "DD-WRT") {
23		return Service{}, service.ErrNotSuported
24	}
25	return Service{
26		Config:           c,
27		ConfigFileStorer: service.ConfigFileStorer{File: "/jffs/etc/" + c.Name + ".conf"},
28		Path:             "/jffs/etc/config/" + c.Name + ".startup",
29	}, nil
30}
31
32func (s Service) Install() error {
33	return internal.CreateWithTemplate(s.Path, tmpl, 0755, s.Config)
34}
35
36func (s Service) Uninstall() error {
37	return os.Remove(s.Path)
38}
39
40func (s Service) Status() (service.Status, error) {
41	if _, err := os.Stat(s.Path); os.IsNotExist(err) {
42		return service.StatusNotInstalled, nil
43	}
44
45	err := internal.Run(s.Path, "status")
46	if internal.ExitCode(err) == 1 {
47		return service.StatusStopped, nil
48	} else if err != nil {
49		return service.StatusUnknown, err
50	}
51	return service.StatusRunning, nil
52}
53
54func (s Service) Start() error {
55	return internal.Run(s.Path, "start")
56}
57
58func (s Service) Stop() error {
59	return internal.Run(s.Path, "stop")
60}
61
62func (s Service) Restart() error {
63	return internal.Run(s.Path, "restart")
64}
65
66var tmpl = `#!/bin/sh
67
68name="{{.Name}}"
69cmd="{{.Executable}}{{range .Arguments}} {{.}}{{end}}"
70pid_file="/tmp/$name.pid"
71
72get_pid() {
73	cat "$pid_file"
74}
75
76is_running() {
77	test -f "$pid_file" && ps | grep -q "^ *$(get_pid) "
78}
79
80action=$1
81if [ -z "$action" ]; then
82	action=start
83fi
84
85case "$action" in
86	start)
87		if is_running; then
88			echo "Already started"
89		else
90			echo "Starting $name"
91			export {{.RunModeEnv}}=1
92			$cmd &
93			echo $! > "$pid_file"
94			if ! is_running; then
95				echo "Unable to start"
96				exit 1
97			fi
98		fi
99	;;
100	stop)
101		if is_running; then
102			echo -n "Stopping $name.."
103			kill $(get_pid)
104			for i in 1 2 3 4 5 6 7 8 9 10; do
105				if ! is_running; then
106					break
107				fi
108				echo -n "."
109				sleep 1
110			done
111			echo
112			if is_running; then
113				echo "Not stopped; may still be shutting down or shutdown may have failed"
114				exit 1
115			else
116				echo "Stopped"
117				if [ -f "$pid_file" ]; then
118					rm "$pid_file"
119				fi
120			fi
121		else
122			echo "Not running"
123		fi
124	;;
125	restart)
126		$0 stop
127		if is_running; then
128			echo "Unable to stop, will not attempt to start"
129			exit 1
130		fi
131		$0 start
132	;;
133	status)
134		if is_running; then
135			echo "Running"
136		else
137			echo "Stopped"
138			exit 1
139		fi
140	;;
141	*)
142	echo "Usage: $0 {start|stop|restart|status}"
143	exit 1
144	;;
145esac
146exit 0
147`
148