summaryrefslogtreecommitdiff
path: root/sd_login/monitor.go
diff options
context:
space:
mode:
Diffstat (limited to 'sd_login/monitor.go')
-rw-r--r--sd_login/monitor.go114
1 files changed, 114 insertions, 0 deletions
diff --git a/sd_login/monitor.go b/sd_login/monitor.go
new file mode 100644
index 0000000..2422f06
--- /dev/null
+++ b/sd_login/monitor.go
@@ -0,0 +1,114 @@
+// Copyright (C) 2016-2017 Luke Shumaker <lukeshu@sbcglobal.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sd_login
+
+import (
+ "git.lukeshu.com/go/libgnulinux/inotify"
+ "golang.org/x/sys/unix"
+)
+
+// A Monitor monitors several types of events, so you don't have to do
+// busy-polling.
+//
+// However, Monitor won't actually give you the event that happened,
+// you'll need to read it yourself.
+type Monitor struct {
+ in *inotify.Inotify
+}
+
+type MonitorCategory uint
+
+const (
+ MonitorSeats MonitorCategory = 1 << iota
+ MonitorSessions
+ MonitorUsers
+ MonitorMachines
+
+ MonitorAll = MonitorSeats | MonitorSessions | MonitorUsers | MonitorMachines
+)
+
+func NewMonitor(categories MonitorCategory) (*Monitor, error) {
+ if categories == 0 {
+ return nil, unix.EINVAL
+ }
+
+ in, err := inotify.InotifyInit1(inotify.IN_CLOEXEC)
+ if err != nil {
+ return nil, err
+ }
+
+ if categories&MonitorSeats != 0 {
+ _, err := in.AddWatch("/run/systemd/seats/", inotify.IN_MOVED_TO|inotify.IN_DELETE)
+ if err != nil {
+ in.Close()
+ return nil, err
+ }
+ }
+
+ if categories&MonitorSessions != 0 {
+ _, err := in.AddWatch("/run/systemd/sessions/", inotify.IN_MOVED_TO|inotify.IN_DELETE)
+ if err != nil {
+ in.Close()
+ return nil, err
+ }
+ }
+
+ if categories&MonitorUsers != 0 {
+ _, err := in.AddWatch("/run/systemd/users/", inotify.IN_MOVED_TO|inotify.IN_DELETE)
+ if err != nil {
+ in.Close()
+ return nil, err
+ }
+ }
+
+ if categories&MonitorMachines != 0 {
+ _, err := in.AddWatch("/run/systemd/machines/", inotify.IN_MOVED_TO|inotify.IN_DELETE)
+ if err != nil {
+ in.Close()
+ return nil, err
+ }
+ }
+
+ return &Monitor{in: in}, nil
+}
+
+// Close closes the monitor. After calling Close, further calls to
+// the monitor will fail.
+func (m *Monitor) Close() error {
+ return m.in.Close()
+}
+
+// Flush discards any events that have happened since the last Flush
+// or Wait call.
+func (m *Monitor) Flush() error {
+ for {
+ ev, err := m.in.ReadNonblock()
+ if err != nil {
+ return err
+ }
+ if ev.Wd < 0 {
+ return nil
+ }
+ }
+}
+
+// Wait blocks until a watched for event has happened. A single call
+// to Wait discards only discards first event; if multiple events
+// happen at once, multiple calls to Wait will immediately return
+// unless Flush is called.
+func (m *Monitor) Wait() error {
+ _, err := m.in.ReadBlock()
+ return err
+}