aboutsummaryrefslogtreecommitdiff
path: root/src/util.lisp
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2021-07-18 12:24:42 -0700
committerSean Whitton <spwhitton@spwhitton.name>2021-07-23 09:00:18 -0700
commit2d24e818248ae1c845128884b4c26b43f951a979 (patch)
tree6ad7866bb8bd9f066fa6a2b04d4e472cb3be74c4 /src/util.lisp
parentbcbaae2d689a20c87aa17d67f1b9d05e1f43713d (diff)
downloadconsfigurator-2d24e818248ae1c845128884b4c26b43f951a979.tar.gz
add mkfifo(3) wrapper & utils
Signed-off-by: Sean Whitton <spwhitton@spwhitton.name>
Diffstat (limited to 'src/util.lisp')
-rw-r--r--src/util.lisp51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/util.lisp b/src/util.lisp
index d772364..265496e 100644
--- a/src/util.lisp
+++ b/src/util.lisp
@@ -340,6 +340,57 @@ expansion as a starting point for your own DEFPACKAGE form for your consfig."
(car args))
:int))
+(define-constant +alphanum+
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ :test #'string=)
+
+(defun mkfifo ()
+ "Use mkfifo(3) to create a named pipe with a mkstemp(3)-like name."
+ (let* ((dir (drop-trailing-slash (or (getenv "TMPDIR") "/tmp")))
+ (dir-ls (run-program
+ `("env" "LANG=C" "ls" "-nd" ,dir) :output :string))
+ (prefix (strcat dir "/tmp.")))
+ (unless (and (char= #\d (char dir-ls 0))
+ (char-equal #\t (char dir-ls 9))
+ (zerop (parse-integer (caddr (split-string dir-ls)))))
+ (error "~A is not a root-owned dir with the sticky bit set." dir))
+ (flet ((mktemp ()
+ ;; We need to generate a temporary name. We don't have to worry
+ ;; about race conditions as mkfifo(3) will fail if the file
+ ;; already exists.
+ (loop with result = (make-string (+ 6 (length prefix)))
+ initially (setf (subseq result 0 (length prefix)) prefix)
+ for i from (length prefix) below (length result)
+ do (setf (char result i)
+ (char +alphanum+ (random #.(length +alphanum+))))
+ finally (return result)))
+ (mkfifo (temp)
+ (handler-case
+ (progn
+ #+sbcl (sb-posix:mkfifo temp #o600)
+ #-(or sbcl)
+ (unless (zerop
+ (foreign-funcall
+ "mkfifo" :string temp :unsigned-int #o600 :int))
+ (error "mkfifo(3) failed!"))
+ t)
+ (serious-condition (c)
+ (if (or (file-exists-p temp) (directory-exists-p temp))
+ nil
+ (signal c))))))
+ (loop with *random-state* = (make-random-state t)
+ repeat 3 for temp = (mktemp)
+ when (mkfifo temp) return (pathname temp)))))
+
+(defmacro with-mkfifos ((&rest mkfifos) &body forms)
+ `(let ,(loop for mkfifo in mkfifos collect `(,mkfifo (mkfifo)))
+ (unwind-protect (progn ,@forms)
+ ,@(loop for mkfifo in mkfifos collect `(delete-file ,mkfifo)))))
+
+(defun write-to-mkfifo (object fifo)
+ (with-standard-io-syntax
+ (write object :stream fifo) (terpri fifo) (finish-output fifo)))
+
;;;; Progress & debug printing