@@ -21,11 +21,11 @@ import (
2121 "io"
2222 "net"
2323 "os"
24- "path/filepath"
2524 "time"
2625)
2726
2827const defaultAtomControlSocket = "/run/atom/control.sock"
28+ const defaultAtomSDBControlSocket = "/run/atom/sdb-control.sock"
2929
3030const (
3131 atomDialTimeout = 3 * time .Second
@@ -40,52 +40,14 @@ func atomControlSocketPath() string {
4040 return defaultAtomControlSocket
4141}
4242
43- // defaultSdbOptIn is the per-bridge marker sdbd and its unit both require. It is
44- // deliberately NOT the development marker: that one governs the whole image and
45- // lives on the read-only verity tree, while this one governs the bridge alone
46- // and lives on writable storage. Absent means off, so a fresh image carries no
47- // listener until the owner asks for one.
48- const defaultSdbOptIn = "/var/lib/sinty-sdb/enabled"
49-
50- func sdbOptInPath () string {
51- if p := os .Getenv ("USH_SDB_OPT_IN" ); p != "" {
43+ func atomSDBControlSocketPath () string {
44+ if p := os .Getenv ("USH_ATOM_SDB_CONTROL_SOCK" ); p != "" {
5245 return p
5346 }
54- return defaultSdbOptIn
55- }
56-
57- // setSdbOptIn creates or removes the marker. Removal treats an already-absent
58- // marker as done, so turning off a bridge that is already off is not an error.
59- func setSdbOptIn (on bool ) error {
60- path := sdbOptInPath ()
61- if ! on {
62- if err := os .Remove (path ); err != nil && ! os .IsNotExist (err ) {
63- return fmt .Errorf ("sdb opt-in: remove %s: %w" , path , err )
64- }
65- return nil
66- }
67- if err := os .MkdirAll (filepath .Dir (path ), 0o755 ); err != nil {
68- return fmt .Errorf ("sdb opt-in: create dir: %w" , err )
69- }
70- f , err := os .OpenFile (path , os .O_CREATE | os .O_WRONLY , 0o644 )
71- if err != nil {
72- return fmt .Errorf ("sdb opt-in: create %s: %w" , path , err )
47+ if p := os .Getenv ("USH_ATOM_CONTROL_SOCK" ); p != "" {
48+ return p
7349 }
74- return f .Close ()
75- }
76-
77- // sdbUnitName is the unit the debug bridge runs as. It is overridable because
78- // the unit is shipped by the image rather than by this repository; if the name
79- // is wrong, Present reports false and the desktop greys the control out, which
80- // is the safe direction.
81- func sdbUnitName () string {
82- if n := os .Getenv ("USH_SDB_UNIT" ); n != "" {
83- return n
84- }
85- // The image ships the bridge as sdbd.service (package sinty-sdb installs
86- // dist/sdbd.service). sinit reports and keys units by their full file name,
87- // so the broker must match that exactly, including the .service suffix.
88- return "sdbd.service"
50+ return defaultAtomSDBControlSocket
8951}
9052
9153type atomRequest struct {
@@ -141,10 +103,10 @@ func atomReadFrame(r io.Reader, v any) error {
141103
142104// atomControlCall sends one request to PID 1 and returns the reply. Every
143105// failure is an error; a reply that merely arrived is not a success.
144- func atomControlCall ( req atomRequest ) (atomReply , error ) {
145- conn , err := net .DialTimeout ("unix" , atomControlSocketPath () , atomDialTimeout )
106+ func atomControlCallAt ( path string , req atomRequest ) (atomReply , error ) {
107+ conn , err := net .DialTimeout ("unix" , path , atomDialTimeout )
146108 if err != nil {
147- return atomReply {}, fmt .Errorf ("init control unreachable: %w" , err )
109+ return atomReply {}, fmt .Errorf ("init control unreachable at %s : %w" , path , err )
148110 }
149111 defer conn .Close ()
150112
@@ -159,55 +121,38 @@ func atomControlCall(req atomRequest) (atomReply, error) {
159121 return rep , nil
160122}
161123
124+ func atomControlCall (req atomRequest ) (atomReply , error ) {
125+ return atomControlCallAt (atomControlSocketPath (), req )
126+ }
127+
128+ func atomSDBControlCall (req atomRequest ) (atomReply , error ) {
129+ return atomControlCallAt (atomSDBControlSocketPath (), req )
130+ }
131+
162132// atomSdbService controls the debug bridge unit through the init.
163133type atomSdbService struct {}
164134
165- // Present reports whether the unit is known to the init. list-units needs no
166- // privilege, so this answers even where a mutation would be refused .
135+ // Present reports whether the unit file is known to the init. status also sees
136+ // units outside the boot graph without starting them .
167137func (atomSdbService ) Present () (bool , error ) {
168- rep , err := atomControlCall (atomRequest {Cmd : "list-units " })
138+ rep , err := atomSDBControlCall (atomRequest {Cmd : "sdb-status " })
169139 if err != nil {
170140 return false , err
171141 }
172142 if ! rep .OK {
173- return false , fmt .Errorf ("init control: list-units: %s" , atomError (rep ))
174- }
175- want := sdbUnitName ()
176- for _ , u := range rep .Units {
177- if u .Name == want {
178- return true , nil
179- }
143+ return false , fmt .Errorf ("init control: status: %s" , atomError (rep ))
180144 }
181- return false , nil
145+ return rep . State != "unknown" && rep . State != "not-found" , nil
182146}
183147
184- // SetEnabled switches the bridge in both halves: the persistent marker, then the
185- // live state. It deliberately does not attempt to change unit enablement, which
186- // does not exist as a live operation here (see the file comment).
187- //
188- // The marker always moves FIRST, in both directions, and the init command is
189- // issued only if that succeeded. The ordering is the safety property: a crash
190- // between the two steps must leave the closed state, never the open one.
191- //
192- // - disabling removes the marker before the stop, so an interrupted disable
193- // leaves a bridge that is not allowed to come back at next boot
194- // - enabling creates it before the start, so an interrupted enable leaves a
195- // bridge that is allowed but not running, which the next status read reports
196- // honestly as inactive
197- //
198- // A marker that cannot be written is a hard failure and no init command is sent:
199- // changing the live state while the persistent state stayed behind is exactly
200- // the disagreement this ordering exists to prevent.
148+ // SetEnabled asks PID 1 to update both the persistent gate and live state. The
149+ // dedicated socket accepts no arbitrary unit name or general init operation.
201150func (atomSdbService ) SetEnabled (on bool ) error {
202- if err := setSdbOptIn (on ); err != nil {
203- return err
204- }
205-
206- cmd := "stop"
151+ cmd := "sdb-disable"
207152 if on {
208- cmd = "start "
153+ cmd = "sdb-enable "
209154 }
210- rep , err := atomControlCall (atomRequest {Cmd : cmd , Unit : sdbUnitName () })
155+ rep , err := atomSDBControlCall (atomRequest {Cmd : cmd })
211156 if err != nil {
212157 return err
213158 }
0 commit comments