liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

watch.fnl (2431B)


      1 (local { : assoc : system : dirname } (require :anoia))
      2 (local { : mktree : rmtree : symlink } (require :anoia.fs))
      3 (local { : AF_LOCAL : SOCK_STREAM } (require :anoia.net.constants))
      4 (local ll (require :lualinux))
      5 
      6 (local { : view } (require :fennel))
      7 
      8 (fn parse-args [args]
      9   (match args
     10     ["-s" service & rest] (assoc (parse-args rest) :service service)
     11     ["-n" path & rest] (assoc (parse-args rest) :linkname path)
     12     matches { :matches (table.concat matches " ") }
     13     _  nil))
     14 
     15 (fn %% [fmt ...] (string.format fmt ...))
     16 
     17 (var up :unknown)
     18 
     19 (fn start-service [devname linkname service]
     20   (match (if linkname (symlink (.. "/dev/" devname) linkname) true)
     21     ok (pcall system (%% "s6-rc-up-tree %q" service))
     22     (nil err) false))
     23 
     24 (fn stop-service [linkname service]
     25   (match (pcall system (%% "s6-rc -b -d change %q" service))
     26     ok (if linkname (os.remove linkname) true)
     27     (nil err) false))
     28 
     29 (fn toggle-service [devname linkname service wanted?]
     30   (when (not (= up wanted?))
     31     (set up
     32          (if wanted?
     33              (start-service devname linkname service)
     34              (not (stop-service linkname service))))))
     35 
     36 (fn parse-uevent [s]
     37   (when s
     38     (let [(nl nxt) (string.find s "\0" 1 true)]
     39       (collect [k v (string.gmatch
     40                      (string.sub s (+ 1 nxt))
     41                      "(%g-)=(%g+)")]
     42         (k:lower) v))))
     43 
     44 (fn run-with-fh [fh args]
     45   (set up :unknown)
     46   (let [parameters
     47         (assert (parse-args args) (.. "can't parse args: " (table.concat args " ")))]
     48     (when parameters.linkname (mktree (dirname parameters.linkname)))
     49     (var finished? false)
     50 
     51     (print "registering for events" (fh:write parameters.matches))
     52 
     53     (while (not finished?)
     54       (let [e (parse-uevent (fh:read))]
     55         (when e
     56           (let [wanted? (. {:add true :change true} e.action)]
     57             (toggle-service e.devname parameters.linkname parameters.service wanted?)))
     58         (set finished? (= e nil))
     59         ))))
     60 
     61 (fn unix-connect [pathname]
     62   (let [addr (string.pack "=Hz" AF_LOCAL pathname)]
     63     (match (ll.socket AF_LOCAL SOCK_STREAM 0)
     64       sock (doto sock (ll.connect addr))
     65       (nil err) (error err))))
     66 
     67 
     68 (fn run [args]
     69   (let [fd (assert (unix-connect "/run/devout.sock"))
     70         devout {
     71                 :read #(ll.read fd)
     72                 :write #(ll.write fd $2)
     73                 :close #(ll.close fd)
     74                 }]
     75     (run-with-fh devout arg)))
     76 
     77 { : run : run-with-fh  }