summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2015-08-26 23:01:23 -0600
committerLuke Shumaker <lukeshu@sbcglobal.net>2015-08-26 23:01:23 -0600
commit4ab446ed2a12e4f8b599f5912b9d4aabf20e2975 (patch)
treeb810043933c5675788edd32ec61414db9d3dc1eb
parent13bb2e14fcdd260d060b7240357d4a8a80002114 (diff)
stuff
-rw-r--r--.gitignore1
-rw-r--r--Makefile37
-rw-r--r--src/inotify/AUTHORS3
-rw-r--r--src/inotify/CONTRIBUTORS3
-rw-r--r--src/inotify/LICENSE27
-rw-r--r--src/inotify/PATENTS22
-rw-r--r--src/inotify/inotify_linux.go300
-rw-r--r--src/inotify/inotify_linux_test.go107
-rw-r--r--src/nshd/main.go87
-rw-r--r--src/nslcd_systemd/nslcd_systemd.go119
10 files changed, 154 insertions, 552 deletions
diff --git a/.gitignore b/.gitignore
index f037d68..0de96dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/pkg
/bin
+/src/*.*/ \ No newline at end of file
diff --git a/Makefile b/Makefile
index aa394e8..e95e43b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,21 +1,44 @@
prefix = /usr/local
bindir = $(prefix)/bin
+libdir = $(prefix)/lib
+systemddir = $(libdir)/systemd
-export GOPATH=$(realpath $(dir $(lastword $(MAKEFILE_LIST))))
+GOPATH := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
all: build
-generate:
+deps = golang.org/x/exp/inotify gopkg.in/yaml.v2
+
+$(foreach d,$(deps),$(eval src/$d: ; GOPATH='$(GOPATH)' go get -d -u $d))
+
+generate: generate-nslcd_proto $(addprefix src/,$(deps))
+generate-nslcd_proto:
$(MAKE) -C src/nslcd_proto
+.PHONY: generate-nslcd_proto
build: generate
- go install nshd
+ GOPATH='$(GOPATH)' go install nshd
clean:
- rm -rf -- pkg bin
+ rm -rf -- pkg bin src/*.*/
$(MAKE) -C src/nslcd_proto clean
-install: build
- install -Dm755 bin/nshd $(bindir)/nshd
+install = $(addprefix $(DESTDIR),$(bindir)/nshd $(systemddir)/system/nshd.socket $(systemddir)/system/nshd.service)
+
+install: $(install)
+
+uninstall:
+ rm -f -- $(install)
+ rmdir -p -- $(sort $(dir $(install))) 2>/dev/null || true
+
+bin/nshd: build
+
+$(DESTDIR)$(bindir)/%: bin/%
+ install -Dm755 $< $@
+$(DESTDIR)$(systemddir)/system/%.socket: %.socket
+ install -Dm644 $< $@
+$(DESTDIR)$(systemddir)/system/%.service: %.service
+ install -Dm644 $< $@
-.PHONY: all generate build clean
+.PHONY: all generate build clean install uninstall
+.SECONDARY:
diff --git a/src/inotify/AUTHORS b/src/inotify/AUTHORS
deleted file mode 100644
index 15167cd..0000000
--- a/src/inotify/AUTHORS
+++ /dev/null
@@ -1,3 +0,0 @@
-# This source code refers to The Go Authors for copyright purposes.
-# The master list of authors is in the main Go distribution,
-# visible at http://tip.golang.org/AUTHORS.
diff --git a/src/inotify/CONTRIBUTORS b/src/inotify/CONTRIBUTORS
deleted file mode 100644
index 1c4577e..0000000
--- a/src/inotify/CONTRIBUTORS
+++ /dev/null
@@ -1,3 +0,0 @@
-# This source code was written by the Go contributors.
-# The master list of contributors is in the main Go distribution,
-# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/src/inotify/LICENSE b/src/inotify/LICENSE
deleted file mode 100644
index 6a66aea..0000000
--- a/src/inotify/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/inotify/PATENTS b/src/inotify/PATENTS
deleted file mode 100644
index 7330990..0000000
--- a/src/inotify/PATENTS
+++ /dev/null
@@ -1,22 +0,0 @@
-Additional IP Rights Grant (Patents)
-
-"This implementation" means the copyrightable works distributed by
-Google as part of the Go project.
-
-Google hereby grants to You a perpetual, worldwide, non-exclusive,
-no-charge, royalty-free, irrevocable (except as stated in this section)
-patent license to make, have made, use, offer to sell, sell, import,
-transfer and otherwise run, modify and propagate the contents of this
-implementation of Go, where such license applies only to those patent
-claims, both currently owned or controlled by Google and acquired in
-the future, licensable by Google that are necessarily infringed by this
-implementation of Go. This grant does not include claims that would be
-infringed only as a consequence of further modification of this
-implementation. If you or your agent or exclusive licensee institute or
-order or agree to the institution of patent litigation against any
-entity (including a cross-claim or counterclaim in a lawsuit) alleging
-that this implementation of Go or any code incorporated within this
-implementation of Go constitutes direct or contributory patent
-infringement, or inducement of patent infringement, then any patent
-rights granted to you under this License for this implementation of Go
-shall terminate as of the date such litigation is filed.
diff --git a/src/inotify/inotify_linux.go b/src/inotify/inotify_linux.go
deleted file mode 100644
index 41ac558..0000000
--- a/src/inotify/inotify_linux.go
+++ /dev/null
@@ -1,300 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package inotify implements a wrapper for the Linux inotify system.
-
-Example:
- watcher, err := inotify.NewWatcher()
- if err != nil {
- log.Fatal(err)
- }
- err = watcher.Watch("/tmp")
- if err != nil {
- log.Fatal(err)
- }
- for {
- select {
- case ev := <-watcher.Event:
- log.Println("event:", ev)
- case err := <-watcher.Error:
- log.Println("error:", err)
- }
- }
-
-*/
-package inotify
-
-import (
- "errors"
- "fmt"
- "os"
- "strings"
- "sync"
- "syscall"
- "unsafe"
-)
-
-type Event struct {
- Mask uint32 // Mask of events
- Cookie uint32 // Unique cookie associating related events (for rename(2))
- Name string // File name (optional)
-}
-
-type watch struct {
- wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
- flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
-}
-
-type Watcher struct {
- mu sync.Mutex
- fd int // File descriptor (as returned by the inotify_init() syscall)
- watches map[string]*watch // Map of inotify watches (key: path)
- paths map[int]string // Map of watched paths (key: watch descriptor)
- Error chan error // Errors are sent on this channel
- Event chan *Event // Events are returned on this channel
- done chan bool // Channel for sending a "quit message" to the reader goroutine
- isClosed bool // Set to true when Close() is first called
-}
-
-// NewWatcher creates and returns a new inotify instance using inotify_init(2)
-func NewWatcher() (*Watcher, error) {
- fd, errno := syscall.InotifyInit()
- if fd == -1 {
- return nil, os.NewSyscallError("inotify_init", errno)
- }
- w := &Watcher{
- fd: fd,
- watches: make(map[string]*watch),
- paths: make(map[int]string),
- Event: make(chan *Event),
- Error: make(chan error),
- done: make(chan bool, 1),
- }
-
- go w.readEvents()
- return w, nil
-}
-
-// Close closes an inotify watcher instance
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the inotify instance
-func (w *Watcher) Close() error {
- if w.isClosed {
- return nil
- }
- w.isClosed = true
-
- // Send "quit" message to the reader goroutine
- w.done <- true
- for path := range w.watches {
- w.RemoveWatch(path)
- }
-
- return nil
-}
-
-// AddWatch adds path to the watched file set.
-// The flags are interpreted as described in inotify_add_watch(2).
-func (w *Watcher) AddWatch(path string, flags uint32) error {
- if w.isClosed {
- return errors.New("inotify instance already closed")
- }
-
- watchEntry, found := w.watches[path]
- if found {
- watchEntry.flags |= flags
- flags |= syscall.IN_MASK_ADD
- }
-
- w.mu.Lock() // synchronize with readEvents goroutine
-
- wd, err := syscall.InotifyAddWatch(w.fd, path, flags)
- if err != nil {
- w.mu.Unlock()
- return &os.PathError{
- Op: "inotify_add_watch",
- Path: path,
- Err: err,
- }
- }
-
- if !found {
- w.watches[path] = &watch{wd: uint32(wd), flags: flags}
- w.paths[wd] = path
- }
- w.mu.Unlock()
- return nil
-}
-
-// Watch adds path to the watched file set, watching all events.
-func (w *Watcher) Watch(path string) error {
- return w.AddWatch(path, IN_ALL_EVENTS)
-}
-
-// RemoveWatch removes path from the watched file set.
-func (w *Watcher) RemoveWatch(path string) error {
- watch, ok := w.watches[path]
- if !ok {
- return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
- }
- success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
- if success == -1 {
- return os.NewSyscallError("inotify_rm_watch", errno)
- }
- delete(w.watches, path)
- return nil
-}
-
-// readEvents reads from the inotify file descriptor, converts the
-// received events into Event objects and sends them via the Event channel
-func (w *Watcher) readEvents() {
- var buf [syscall.SizeofInotifyEvent * 4096]byte
-
- for {
- n, err := syscall.Read(w.fd, buf[:])
- // See if there is a message on the "done" channel
- var done bool
- select {
- case done = <-w.done:
- default:
- }
-
- // If EOF or a "done" message is received
- if n == 0 || done {
- // The syscall.Close can be slow. Close
- // w.Event first.
- close(w.Event)
- err := syscall.Close(w.fd)
- if err != nil {
- w.Error <- os.NewSyscallError("close", err)
- }
- close(w.Error)
- return
- }
- if n < 0 {
- w.Error <- os.NewSyscallError("read", err)
- continue
- }
- if n < syscall.SizeofInotifyEvent {
- w.Error <- errors.New("inotify: short read in readEvents()")
- continue
- }
-
- var offset uint32 = 0
- // We don't know how many events we just read into the buffer
- // While the offset points to at least one whole event...
- for offset <= uint32(n-syscall.SizeofInotifyEvent) {
- // Point "raw" to the event in the buffer
- raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
- event := new(Event)
- event.Mask = uint32(raw.Mask)
- event.Cookie = uint32(raw.Cookie)
- nameLen := uint32(raw.Len)
- // If the event happened to the watched directory or the watched file, the kernel
- // doesn't append the filename to the event, but we would like to always fill the
- // the "Name" field with a valid filename. We retrieve the path of the watch from
- // the "paths" map.
- w.mu.Lock()
- event.Name = w.paths[int(raw.Wd)]
- w.mu.Unlock()
- if nameLen > 0 {
- // Point "bytes" at the first byte of the filename
- bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
- // The filename is padded with NUL bytes. TrimRight() gets rid of those.
- event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
- }
- // Send the event on the events channel
- w.Event <- event
-
- // Move to the next event in the buffer
- offset += syscall.SizeofInotifyEvent + nameLen
- }
- }
-}
-
-// String formats the event e in the form
-// "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
-func (e *Event) String() string {
- var events string = ""
-
- m := e.Mask
- for _, b := range eventBits {
- if m&b.Value == b.Value {
- m &^= b.Value
- events += "|" + b.Name
- }
- }
-
- if m != 0 {
- events += fmt.Sprintf("|%#x", m)
- }
- if len(events) > 0 {
- events = " == " + events[1:]
- }
-
- return fmt.Sprintf("%q: %#x%s", e.Name, e.Mask, events)
-}
-
-const (
- // Options for inotify_init() are not exported
- // IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
- // IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
-
- // Options for AddWatch
- IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
- IN_ONESHOT uint32 = syscall.IN_ONESHOT
- IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
-
- // The "IN_MASK_ADD" option is not exported, as AddWatch
- // adds it automatically, if there is already a watch for the given path
- // IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
-
- // Events
- IN_ACCESS uint32 = syscall.IN_ACCESS
- IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
- IN_ATTRIB uint32 = syscall.IN_ATTRIB
- IN_CLOSE uint32 = syscall.IN_CLOSE
- IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
- IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
- IN_CREATE uint32 = syscall.IN_CREATE
- IN_DELETE uint32 = syscall.IN_DELETE
- IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
- IN_MODIFY uint32 = syscall.IN_MODIFY
- IN_MOVE uint32 = syscall.IN_MOVE
- IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
- IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
- IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
- IN_OPEN uint32 = syscall.IN_OPEN
-
- // Special events
- IN_ISDIR uint32 = syscall.IN_ISDIR
- IN_IGNORED uint32 = syscall.IN_IGNORED
- IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
- IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
-)
-
-var eventBits = []struct {
- Value uint32
- Name string
-}{
- {IN_ACCESS, "IN_ACCESS"},
- {IN_ATTRIB, "IN_ATTRIB"},
- {IN_CLOSE, "IN_CLOSE"},
- {IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE"},
- {IN_CLOSE_WRITE, "IN_CLOSE_WRITE"},
- {IN_CREATE, "IN_CREATE"},
- {IN_DELETE, "IN_DELETE"},
- {IN_DELETE_SELF, "IN_DELETE_SELF"},
- {IN_MODIFY, "IN_MODIFY"},
- {IN_MOVE, "IN_MOVE"},
- {IN_MOVED_FROM, "IN_MOVED_FROM"},
- {IN_MOVED_TO, "IN_MOVED_TO"},
- {IN_MOVE_SELF, "IN_MOVE_SELF"},
- {IN_OPEN, "IN_OPEN"},
- {IN_ISDIR, "IN_ISDIR"},
- {IN_IGNORED, "IN_IGNORED"},
- {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"},
- {IN_UNMOUNT, "IN_UNMOUNT"},
-}
diff --git a/src/inotify/inotify_linux_test.go b/src/inotify/inotify_linux_test.go
deleted file mode 100644
index 1685b77..0000000
--- a/src/inotify/inotify_linux_test.go
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build linux
-
-package inotify
-
-import (
- "io/ioutil"
- "os"
- "sync/atomic"
- "testing"
- "time"
-)
-
-func TestInotifyEvents(t *testing.T) {
- // Create an inotify watcher instance and initialize it
- watcher, err := NewWatcher()
- if err != nil {
- t.Fatalf("NewWatcher failed: %s", err)
- }
-
- dir, err := ioutil.TempDir("", "inotify")
- if err != nil {
- t.Fatalf("TempDir failed: %s", err)
- }
- defer os.RemoveAll(dir)
-
- // Add a watch for "_test"
- err = watcher.Watch(dir)
- if err != nil {
- t.Fatalf("Watch failed: %s", err)
- }
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- testFile := dir + "/TestInotifyEvents.testfile"
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var eventsReceived int32 = 0
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == testFile {
- atomic.AddInt32(&eventsReceived, 1)
- t.Logf("event received: %s", event)
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the inotify event queue
- _, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file: %s", err)
- }
-
- // We expect this event to be received almost immediately, but let's wait 1 s to be sure
- time.Sleep(1 * time.Second)
- if atomic.AddInt32(&eventsReceived, 0) == 0 {
- t.Fatal("inotify event hasn't been received after 1 second")
- }
-
- // Try closing the inotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(1 * time.Second):
- t.Fatal("event stream was not closed after 1 second")
- }
-}
-
-func TestInotifyClose(t *testing.T) {
- watcher, _ := NewWatcher()
- watcher.Close()
-
- done := make(chan bool)
- go func() {
- watcher.Close()
- done <- true
- }()
-
- select {
- case <-done:
- case <-time.After(50 * time.Millisecond):
- t.Fatal("double Close() test failed: second Close() call didn't return")
- }
-
- err := watcher.Watch(os.TempDir())
- if err == nil {
- t.Fatal("expected error on Watch() after Close(), got nil")
- }
-}
diff --git a/src/nshd/main.go b/src/nshd/main.go
index 45b7b33..986e019 100644
--- a/src/nshd/main.go
+++ b/src/nshd/main.go
@@ -1,90 +1,11 @@
package main
import (
- "os"
- "fmt"
- "net"
- "nslcd_proto"
- sd "sd_daemon"
- "sd_daemon/logger"
- _ "inotify"
- "syscall"
+ _ "golang.org/x/exp/inotify"
+ _ "gopkg.in/yaml.v2"
+ "nslcd_systemd"
)
-func get_socket() (socket net.Listener, err error) {
- socket = nil
- err = nil
- fds := sd.ListenFds(true);
- if (fds == nil) {
- err = fmt.Errorf("failed to aquire sockets from systemd")
- return
- }
- if (len(fds) != 1) {
- err = fmt.Errorf("wrong number of sockets from systemd: expected %d but got %d", 1, len(fds))
- return
- }
- socket, err = net.FileListener(fds[0])
- fds[0].Close()
- return
-}
-
-func getpeercred(conn *net.UnixConn) (cred *syscall.Ucred, err error) {
- cred = nil
- file, err := conn.File()
- if err != nil {
- return
- }
- defer file.Close()
- cred, err = syscall.GetsockoptUcred(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_PEERCRED)
- return
-}
-
-func handler(conn *net.UnixConn, backend nslcd_proto.Backend) {
- cred, err := getpeercred(conn)
- if err != nil {
- logger.Debug("connection from unknown client")
- } else {
- logger.Debug("connection from pid=%v uid=%v gid=%v",
- cred.Pid, cred.Uid, cred.Gid)
- }
- err = nslcd_proto.HandleRequest(backend, conn, conn, *cred)
- if err != nil {
- logger.Debug("Error while handling request: %v", err)
- }
-
-
-}
-
func main() {
- var err error = nil
- var socket net.Listener = nil
- defer func() {
- if socket != nil {
- socket.Close()
- }
- }()
-
- socket, err = get_socket()
- if err != nil {
- logger.Err("%s", err.Error())
- sd.Notify(false, "STOPPING=1")
- os.Exit(1)
- }
-
- sd.Notify(false, "READY=1")
-
- for {
- conn, err := socket.Accept()
- if err != nil {
- logger.Notice("%s", err.Error())
- }
- go handler(conn.(*net.UnixConn), nil)
- }
-
- sd.Notify(false, "STOPPING=1")
- os.Exit(0)
+ nslcd_systemd.Main(nil)
}
-
-
-// Initialize() error { func
-// }
diff --git a/src/nslcd_systemd/nslcd_systemd.go b/src/nslcd_systemd/nslcd_systemd.go
new file mode 100644
index 0000000..80e23b2
--- /dev/null
+++ b/src/nslcd_systemd/nslcd_systemd.go
@@ -0,0 +1,119 @@
+package nslcd_systemd
+
+import (
+ "fmt"
+ "net"
+ "nslcd_proto"
+ "os"
+ "os/signal"
+ sd "sd_daemon"
+ "sd_daemon/logger"
+ "sync"
+ "syscall"
+)
+
+type Backend interface {
+ nslcd_proto.Backend
+ Reload()
+}
+
+func get_socket() (socket net.Listener, err error) {
+ socket = nil
+ err = nil
+ fds := sd.ListenFds(true)
+ if fds == nil {
+ err = fmt.Errorf("failed to aquire sockets from systemd")
+ return
+ }
+ if len(fds) != 1 {
+ err = fmt.Errorf("wrong number of sockets from systemd: expected %d but got %d", 1, len(fds))
+ return
+ }
+ socket, err = net.FileListener(fds[0])
+ fds[0].Close()
+ return
+}
+
+func getpeercred(conn *net.UnixConn) (cred *syscall.Ucred, err error) {
+ cred = nil
+ file, err := conn.File()
+ if err != nil {
+ return
+ }
+ defer file.Close()
+ cred, err = syscall.GetsockoptUcred(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_PEERCRED)
+ return
+}
+
+func handler(conn *net.UnixConn, backend nslcd_proto.Backend) {
+ defer conn.Close()
+ cred, err := getpeercred(conn)
+ if err != nil {
+ logger.Debug("connection from unknown client")
+ } else {
+ logger.Debug("connection from pid=%v uid=%v gid=%v",
+ cred.Pid, cred.Uid, cred.Gid)
+ }
+ err = nslcd_proto.HandleRequest(backend, conn, conn, *cred)
+ if err != nil {
+ logger.Debug("Error while handling request: %v", err)
+ }
+}
+
+func Main(backend Backend) {
+ var err error = nil
+ var socket net.Listener = nil
+ defer func() {
+ if socket != nil {
+ socket.Close()
+ }
+ }()
+
+ socket, err = get_socket()
+ if err != nil {
+ logger.Err("%s", err.Error())
+ sd.Notify(false, "STOPPING=1")
+ os.Exit(1)
+ }
+
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGTERM, syscall.SIGHUP)
+
+ sock := make(chan *net.UnixConn, 1)
+ go func() {
+ for {
+ conn, err := socket.Accept()
+ if err != nil {
+ logger.Notice("%s", err.Error())
+ }
+ sock <- conn.(*net.UnixConn)
+ }
+ }()
+
+ var wg sync.WaitGroup
+ sd.Notify(false, "READY=1")
+Loop:
+ for {
+ select {
+ case sig := <-sigs:
+ switch sig {
+ case syscall.SIGTERM:
+ sd.Notify(false, "STOPPING=1")
+ break Loop
+ case syscall.SIGHUP:
+ sd.Notify(false, "RELOADING=1")
+ backend.Reload()
+ sd.Notify(false, "READY=1")
+ }
+ case conn := <-sock:
+ go func() {
+ wg.Add(1)
+ defer wg.Done()
+ handler(conn, backend)
+ }()
+ }
+ }
+ wg.Wait()
+
+ os.Exit(0)
+}