@@ -56,6 +56,43 @@ func (name FdName) isSocket() bool {
5656 return strings .HasSuffix (string (name ), ".socket" )
5757}
5858
59+ type Store interface {
60+ // Add passes a file descriptor to systemd associated with a name
61+ // to reuse it across snapd restarts.
62+ //
63+ // - The file descriptors can be retrieved by calling Get().
64+ // - Only a single file descriptor can associated with a FdName.
65+ //
66+ // Maintains a copy of the underlying file descriptor internally. It
67+ // is the caller's responsibility to close f when finished.
68+ Add (name FdName , f * os.File ) error
69+ // Get retrieves a duplicate of the file descriptor passed from systemd by
70+ // its name. close-on-exec is set on the returned file descriptor. An error
71+ // matching ErrNotFound is returned if no matching file descriptor is found.
72+ // Passed name cannot be a socket (i.e. cannot end in ".socket"), for
73+ // activation sockets use ActivationListeners() instead.
74+ //
75+ // The fdstore holds a copy of the file descriptor, the caller needs to
76+ // call Remove() on top of closing all privately held references in order
77+ // to release all resources associated with a given fd.
78+ Get (name FdName ) (* os.File , error )
79+ // Remove removes file descriptors from systemd given their name.
80+ // Remove cannot remove activation sockets.
81+ Remove (name FdName ) error
82+ // ActivationListeners returns activation listeners that were passed
83+ // from systemd. Only sockets whose name has a ".socket" suffix are
84+ // returned. Order of returned listeners is not deterministic.
85+ //
86+ // It is the caller's responsibility to close returned listeners when finished.
87+ ActivationListeners () ([]net.Listener , error )
88+ }
89+
90+ type store struct {}
91+
92+ func New () Store {
93+ return & store {}
94+ }
95+
5996var (
6097 osGetpid = os .Getpid
6198 osFileClose = (* os .File ).Close
@@ -76,7 +113,7 @@ var mu sync.RWMutex
76113// passed from systemd.
77114const sd_LISTEN_FDS_START = 3
78115
79- func initFdstore () {
116+ func ( s * store ) initFdstore () {
80117 mu .Lock ()
81118 defer mu .Unlock ()
82119
@@ -149,7 +186,7 @@ func initFdstore() {
149186 }
150187 if shouldRemove {
151188 logger .Noticef ("removing unexpected fdstore entry %q" , name )
152- if err := remove (name ); err != nil {
189+ if err := s . remove (name ); err != nil {
153190 logger .Noticef ("internal error: cannot remove fdstore entry %q: %v" , name , err )
154191 continue
155192 }
@@ -172,10 +209,8 @@ func checkSystemdVersion() error {
172209 return nil
173210}
174211
175- // Remove removes file descriptors from systemd given their name.
176- // Remove cannot remove activation sockets.
177- func Remove (name FdName ) error {
178- initFdstore ()
212+ func (s * store ) Remove (name FdName ) error {
213+ s .initFdstore ()
179214
180215 if err := checkSystemdVersion (); err != nil {
181216 return fmt .Errorf ("cannot remove file descriptor from fdstore: %w" , err )
@@ -194,13 +229,13 @@ func Remove(name FdName) error {
194229 return fmt .Errorf ("cannot remove file descriptor from fdstore: %w" , ErrNotFound )
195230 }
196231
197- return remove (name )
232+ return s . remove (name )
198233}
199234
200235// remove file descriptors from systemd given their name.
201236//
202237// Caller must hold the fdstore lock.
203- func remove (name FdName ) error {
238+ func ( s * store ) remove (name FdName ) error {
204239 state := fmt .Sprintf ("FDSTOREREMOVE=1\n FDNAME=%s" , name )
205240 if err := sdNotify (state ); err != nil {
206241 return err
@@ -226,17 +261,8 @@ func duplicateFile(name FdName, f *os.File) (*os.File, error) {
226261 return os .NewFile (uintptr (duplicatedFd ), string (name )), nil
227262}
228263
229- // Get retrieves a duplicate of the file descriptor passed from systemd by
230- // its name. close-on-exec is set on the returned file descriptor. An error
231- // matching ErrNotFound is returned if no matching file descriptor is found.
232- // Passed name cannot be a socket (i.e. cannot end in ".socket"), for
233- // activation sockets use ActivationListeners() instead.
234- //
235- // The fdstore holds a copy of the file descriptor, the caller needs to
236- // call Remove() on top of closing all privately held references in order
237- // to release all resources associated with a given fd.
238- func Get (name FdName ) (* os.File , error ) {
239- initFdstore ()
264+ func (s * store ) Get (name FdName ) (* os.File , error ) {
265+ s .initFdstore ()
240266
241267 if err := checkSystemdVersion (); err != nil {
242268 return nil , fmt .Errorf ("cannot get file descriptor from fdstore: %w" , err )
@@ -261,16 +287,8 @@ func Get(name FdName) (*os.File, error) {
261287 return duplicateFile (name , fds [0 ])
262288}
263289
264- // Add passes a file descriptor to systemd associated with a name
265- // to reuse it across snapd restarts.
266- //
267- // - The file descriptors can be retrieved by calling Get().
268- // - Only a single file descriptor can associated with a FdName.
269- //
270- // Maintains a copy of the underlying file descriptor internally. It
271- // is the caller's responsibility to close f when finished.
272- func Add (name FdName , f * os.File ) error {
273- initFdstore ()
290+ func (s * store ) Add (name FdName , f * os.File ) error {
291+ s .initFdstore ()
274292
275293 if err := checkSystemdVersion (); err != nil {
276294 return fmt .Errorf ("cannot add file descriptor to fdstore: %w" , err )
@@ -307,13 +325,8 @@ func Add(name FdName, f *os.File) error {
307325 return nil
308326}
309327
310- // ActivationListeners returns activation listeners that were passed
311- // from systemd. Only sockets whose name has a ".socket" suffix are
312- // returned. Order of returned listeners is not deterministic.
313- //
314- // It is the caller's responsibility to close returned listeners when finished.
315- func ActivationListeners () (retListeners []net.Listener , retErr error ) {
316- initFdstore ()
328+ func (s * store ) ActivationListeners () (retListeners []net.Listener , retErr error ) {
329+ s .initFdstore ()
317330
318331 mu .RLock ()
319332 defer mu .RUnlock ()
0 commit comments