;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2024 Fabio Natali ;;; ;;; This file is part of GNU Guix. ;;; ;;; GNU Guix is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 3 of the License, or (at ;;; your option) any later version. ;;; ;;; GNU Guix is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Guix. If not, see . (define-module (gnu services upnp) #:use-module (gnu build linux-container) #:use-module (gnu packages admin) #:use-module (gnu packages upnp) #:use-module (gnu services admin) #:use-module (gnu services base) #:use-module (gnu services shepherd) #:use-module (gnu services) #:use-module (gnu system file-systems) #:use-module (gnu system shadow) #:use-module (guix gexp) #:use-module (guix least-authority) #:use-module (guix modules) #:use-module (guix records) #:use-module (ice-9 match) #:export (%readymedia-default-cache-directory %readymedia-default-log-directory %readymedia-default-port %readymedia-log-file %readymedia-user-account %readymedia-user-group readymedia-configuration readymedia-configuration? readymedia-configuration-readymedia readymedia-configuration-port readymedia-configuration-cache-directory readymedia-configuration-extra-config readymedia-configuration-friendly-name readymedia-configuration-log-directory readymedia-configuration-media-directories readymedia-media-directory readymedia-media-directory-path readymedia-media-directory-types readymedia-media-directory? readymedia-service-type)) ;;; Commentary: ;;; ;;; UPnP services. ;;; ;;; Code: (define %readymedia-default-cache-directory "/var/cache/readymedia") (define %readymedia-default-log-directory "/var/log/readymedia") (define %readymedia-log-file "minidlna.log") (define %readymedia-user-group "readymedia") (define %readymedia-user-account "readymedia") (define-record-type* readymedia-configuration make-readymedia-configuration readymedia-configuration? (readymedia readymedia-configuration-readymedia (default readymedia)) (port readymedia-configuration-port (default #f)) (cache-directory readymedia-configuration-cache-directory (default %readymedia-default-cache-directory)) (log-directory readymedia-configuration-log-directory (default %readymedia-default-log-directory)) (friendly-name readymedia-configuration-friendly-name (default #f)) (media-directories readymedia-configuration-media-directories) (extra-config readymedia-configuration-extra-config (default '()))) ;; READYMEDIA-MEDIA-DIR is a record that indicates the path of a media folder ;; and the types of media included within it. Allowed individual types are the ;; symbols 'A' for audio, 'V' for video, and 'P' for pictures. The types field ;; can contain any combination of individual types; an empty list means that ;; no type is specified. (define-record-type* readymedia-media-directory make-readymedia-media-directory readymedia-media-directory? (path readymedia-media-directory-path) (types readymedia-media-directory-types (default '()))) (define (readymedia-configuration->config-file config) "Return the ReadyMedia/MiniDLNA configuration file corresponding to CONFIG." (match-record config (port friendly-name cache-directory log-directory media-directories extra-config) (apply mixed-text-file "minidlna.conf" "db_dir=" cache-directory "\n" "log_dir=" log-directory "\n" (if friendly-name (string-append "friendly_name=" friendly-name "\n") "") (if port (string-append "port=" (number->string port) "\n") "") (append (map (match-record-lambda (path types) (apply string-append "media_dir=" (append (map symbol->string types) (match types (() (list)) (_ (list ","))) (list path "\n")))) media-directories) (map (match-lambda ((key . value) (string-append key "=" value "\n"))) extra-config))))) (define (readymedia-shepherd-service config) "Return a least-authority ReadyMedia/MiniDLNA Shepherd service." (match-record config (cache-directory log-directory media-directories) (let ((minidlna-conf (readymedia-configuration->config-file config))) (shepherd-service (documentation "Run the ReadyMedia/MiniDLNA daemon.") (provision '(readymedia)) (requirement '(networking user-processes)) (start #~(make-forkexec-constructor (list #$(least-authority-wrapper (file-append (readymedia-configuration-readymedia config) "/sbin/minidlnad") #:name "minidlna" #:mappings (cons* (file-system-mapping (source cache-directory) (target source) (writable? #t)) (file-system-mapping (source log-directory) (target source) (writable? #t)) (file-system-mapping (source minidlna-conf) (target source)) (map (lambda (directory) (file-system-mapping (source (readymedia-media-directory-path directory)) (target source))) media-directories)) #:namespaces (delq 'net %namespaces)) "-f" #$minidlna-conf "-S") #:log-file #$(string-append log-directory "/" %readymedia-log-file) #:user #$%readymedia-user-account #:group #$%readymedia-user-group)) (stop #~(make-kill-destructor)))))) (define readymedia-accounts (list (user-account (name "readymedia") (group "readymedia") (system? #t) (comment "ReadyMedia/MiniDLNA daemon user") (home-directory "/var/empty") (shell (file-append shadow "/sbin/nologin"))) (user-group (name "readymedia") (system? #t)))) (define (readymedia-activation config) "Set up directories for ReadyMedia/MiniDLNA." (match-record config (cache-directory log-directory media-directories) (with-imported-modules (source-module-closure '((gnu build activation))) #~(begin (use-modules (gnu build activation)) (for-each (lambda (directory) (unless (file-exists? directory) (mkdir-p/perms directory (getpw #$%readymedia-user-account) #o755))) (list #$cache-directory #$log-directory #$@(map readymedia-media-directory-path media-directories))))))) (define readymedia-service-type (service-type (name 'readymedia) (extensions (list (service-extension shepherd-root-service-type (compose list readymedia-shepherd-service)) (service-extension account-service-type (const readymedia-accounts)) (service-extension activation-service-type readymedia-activation))) (description "Run @command{minidlnad}, the ReadyMedia/MiniDLNA media server.")))