Commit | Line | Data |
---|---|---|
f2ec23d1 AW |
1 | ;;; GNU Guix --- Functional package management for GNU |
2 | ;;; Copyright © 2016 Andy Wingo <wingo@pobox.com> | |
e57bd0be | 3 | ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> |
86cd3f97 | 4 | ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net> |
36273ebd | 5 | ;;; Copyright © 2019 Alex Griffin <a@ajgrf.com> |
f2ec23d1 AW |
6 | ;;; |
7 | ;;; This file is part of GNU Guix. | |
8 | ;;; | |
9 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | |
10 | ;;; under the terms of the GNU General Public License as published by | |
11 | ;;; the Free Software Foundation; either version 3 of the License, or (at | |
12 | ;;; your option) any later version. | |
13 | ;;; | |
14 | ;;; GNU Guix is distributed in the hope that it will be useful, but | |
15 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | ;;; GNU General Public License for more details. | |
18 | ;;; | |
19 | ;;; You should have received a copy of the GNU General Public License | |
20 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | |
21 | ||
22 | (define-module (gnu services cups) | |
23 | #:use-module (gnu services) | |
24 | #:use-module (gnu services shepherd) | |
5305ed20 | 25 | #:use-module (gnu services configuration) |
f2ec23d1 AW |
26 | #:use-module (gnu system shadow) |
27 | #:use-module (gnu packages admin) | |
28 | #:use-module (gnu packages cups) | |
29 | #:use-module (gnu packages tls) | |
30 | #:use-module (guix packages) | |
31 | #:use-module (guix records) | |
32 | #:use-module (guix gexp) | |
f2ec23d1 AW |
33 | #:use-module (ice-9 match) |
34 | #:use-module ((srfi srfi-1) #:select (append-map)) | |
5305ed20 | 35 | #:export (cups-service-type |
f2ec23d1 AW |
36 | cups-configuration |
37 | opaque-cups-configuration | |
38 | ||
39 | files-configuration | |
40 | policy-configuration | |
41 | location-access-control | |
42 | operation-access-control | |
43 | method-access-control)) | |
44 | ||
45 | ;;; Commentary: | |
46 | ;;; | |
47 | ;;; Service defininition for the CUPS printing system. | |
48 | ;;; | |
49 | ;;; Code: | |
50 | ||
f2ec23d1 AW |
51 | (define %cups-accounts |
52 | (list (user-group (name "lp") (system? #t)) | |
53 | (user-group (name "lpadmin") (system? #t)) | |
54 | (user-account | |
55 | (name "lp") | |
56 | (group "lp") | |
57 | (system? #t) | |
58 | (comment "System user for invoking printing helper programs") | |
59 | (home-directory "/var/empty") | |
60 | (shell (file-append shadow "/sbin/nologin"))))) | |
61 | ||
720cb10c CL |
62 | (define (uglify-field-name field-name) |
63 | (let ((str (symbol->string field-name))) | |
64 | (string-concatenate | |
65 | (map string-titlecase | |
66 | (string-split (if (string-suffix? "?" str) | |
67 | (substring str 0 (1- (string-length str))) | |
68 | str) | |
69 | #\-))))) | |
70 | ||
71 | (define (serialize-field field-name val) | |
72 | (format #t "~a ~a\n" (uglify-field-name field-name) val)) | |
73 | ||
74 | (define (serialize-string field-name val) | |
75 | (serialize-field field-name val)) | |
76 | ||
f2ec23d1 AW |
77 | (define (multiline-string-list? val) |
78 | (and (list? val) | |
79 | (and-map (lambda (x) | |
80 | (and (string? x) (not (string-index x #\space)))) | |
81 | val))) | |
82 | (define (serialize-multiline-string-list field-name val) | |
83 | (for-each (lambda (str) (serialize-field field-name str)) val)) | |
84 | ||
720cb10c CL |
85 | (define (space-separated-string-list? val) |
86 | (and (list? val) | |
87 | (and-map (lambda (x) | |
88 | (and (string? x) (not (string-index x #\space)))) | |
89 | val))) | |
90 | (define (serialize-space-separated-string-list field-name val) | |
91 | (serialize-field field-name (string-join val " "))) | |
92 | ||
f2ec23d1 AW |
93 | (define (space-separated-symbol-list? val) |
94 | (and (list? val) (and-map symbol? val))) | |
95 | (define (serialize-space-separated-symbol-list field-name val) | |
96 | (serialize-field field-name (string-join (map symbol->string val) " "))) | |
97 | ||
720cb10c CL |
98 | (define (file-name? val) |
99 | (and (string? val) | |
100 | (string-prefix? "/" val))) | |
101 | (define (serialize-file-name field-name val) | |
102 | (serialize-string field-name val)) | |
103 | ||
104 | (define (serialize-boolean field-name val) | |
105 | (serialize-string field-name (if val "yes" "no"))) | |
106 | ||
f2ec23d1 AW |
107 | (define (non-negative-integer? val) |
108 | (and (exact-integer? val) (not (negative? val)))) | |
109 | (define (serialize-non-negative-integer field-name val) | |
110 | (serialize-field field-name val)) | |
111 | ||
112 | (define-syntax define-enumerated-field-type | |
113 | (lambda (x) | |
114 | (define (id-append ctx . parts) | |
115 | (datum->syntax ctx (apply symbol-append (map syntax->datum parts)))) | |
116 | (syntax-case x () | |
117 | ((_ name (option ...)) | |
118 | #`(begin | |
119 | (define (#,(id-append #'name #'name #'?) x) | |
120 | (memq x '(option ...))) | |
121 | (define (#,(id-append #'name #'serialize- #'name) field-name val) | |
122 | (serialize-field field-name val))))))) | |
123 | ||
124 | (define-enumerated-field-type access-log-level | |
125 | (config actions all)) | |
126 | (define-enumerated-field-type browse-local-protocols | |
127 | (all dnssd none)) | |
128 | (define-enumerated-field-type default-auth-type | |
129 | (Basic Negotiate)) | |
130 | (define-enumerated-field-type default-encryption | |
131 | (Never IfRequested Required)) | |
132 | (define-enumerated-field-type error-policy | |
133 | (abort-job retry-job retry-this-job stop-printer)) | |
134 | (define-enumerated-field-type log-level | |
135 | (none emerg alert crit error warn notice info debug debug2)) | |
136 | (define-enumerated-field-type log-time-format | |
137 | (standard usecs)) | |
138 | (define-enumerated-field-type server-tokens | |
139 | (None ProductOnly Major Minor Minimal OS Full)) | |
140 | (define-enumerated-field-type method | |
141 | (DELETE GET HEAD OPTIONS POST PUT TRACE)) | |
142 | (define-enumerated-field-type sandboxing | |
143 | (relaxed strict)) | |
144 | ||
145 | (define (method-list? val) | |
146 | (and (list? val) (and-map method? val))) | |
147 | (define (serialize-method-list field-name val) | |
148 | (serialize-field field-name (string-join (map symbol->string val) " "))) | |
149 | ||
150 | (define (host-name-lookups? val) | |
151 | (memq val '(#f #t 'double))) | |
152 | (define (serialize-host-name-lookups field-name val) | |
153 | (serialize-field field-name | |
154 | (match val (#f "No") (#t "Yes") ('double "Double")))) | |
155 | ||
156 | (define (host-name-list-or-*? x) | |
157 | (or (eq? x '*) | |
158 | (and (list? x) (and-map string? x)))) | |
159 | (define (serialize-host-name-list-or-* field-name val) | |
160 | (serialize-field field-name (match val | |
161 | ('* '*) | |
162 | (names (string-join names " "))))) | |
163 | ||
164 | (define (boolean-or-non-negative-integer? x) | |
165 | (or (boolean? x) (non-negative-integer? x))) | |
166 | (define (serialize-boolean-or-non-negative-integer field-name x) | |
167 | (if (boolean? x) | |
168 | (serialize-boolean field-name x) | |
169 | (serialize-non-negative-integer field-name x))) | |
170 | ||
171 | (define (ssl-options? x) | |
172 | (and (list? x) | |
173 | (and-map (lambda (elt) (memq elt '(AllowRC4 AllowSSL3))) x))) | |
174 | (define (serialize-ssl-options field-name val) | |
175 | (serialize-field field-name | |
176 | (match val | |
177 | (() "None") | |
178 | (opts (string-join (map symbol->string opts) " "))))) | |
179 | ||
180 | (define (serialize-access-control x) | |
181 | (display x) | |
182 | (newline)) | |
183 | (define (serialize-access-control-list field-name val) | |
184 | (for-each serialize-access-control val)) | |
185 | (define (access-control-list? val) | |
186 | (and (list? val) (and-map string? val))) | |
187 | ||
188 | (define-configuration operation-access-control | |
189 | (operations | |
190 | (space-separated-symbol-list '()) | |
191 | "IPP operations to which this access control applies.") | |
192 | (access-controls | |
193 | (access-control-list '()) | |
194 | "Access control directives, as a list of strings. Each string should be one directive, such as \"Order allow,deny\".")) | |
195 | ||
196 | (define-configuration method-access-control | |
197 | (reverse? | |
198 | (boolean #f) | |
199 | "If @code{#t}, apply access controls to all methods except the listed | |
200 | methods. Otherwise apply to only the listed methods.") | |
201 | (methods | |
202 | (method-list '()) | |
203 | "Methods to which this access control applies.") | |
204 | (access-controls | |
205 | (access-control-list '()) | |
206 | "Access control directives, as a list of strings. Each string should be one directive, such as \"Order allow,deny\".")) | |
207 | ||
208 | (define (serialize-operation-access-control x) | |
209 | (format #t "<Limit ~a>\n" | |
210 | (string-join (map symbol->string | |
211 | (operation-access-control-operations x)) " ")) | |
212 | (serialize-configuration | |
213 | x | |
214 | (filter (lambda (field) | |
215 | (not (eq? (configuration-field-name field) 'operations))) | |
216 | operation-access-control-fields)) | |
217 | (format #t "</Limit>\n")) | |
218 | ||
219 | (define (serialize-method-access-control x) | |
220 | (let ((limit (if (method-access-control-reverse? x) "LimitExcept" "Limit"))) | |
221 | (format #t "<~a ~a>\n" limit | |
222 | (string-join (map symbol->string | |
223 | (method-access-control-methods x)) " ")) | |
224 | (serialize-configuration | |
225 | x | |
226 | (filter (lambda (field) | |
227 | (case (configuration-field-name field) | |
228 | ((reverse? methods) #f) | |
229 | (else #t))) | |
230 | method-access-control-fields)) | |
231 | (format #t "</~a>\n" limit))) | |
232 | ||
233 | (define (operation-access-control-list? val) | |
234 | (and (list? val) (and-map operation-access-control? val))) | |
235 | (define (serialize-operation-access-control-list field-name val) | |
236 | (for-each serialize-operation-access-control val)) | |
237 | ||
238 | (define (method-access-control-list? val) | |
239 | (and (list? val) (and-map method-access-control? val))) | |
240 | (define (serialize-method-access-control-list field-name val) | |
241 | (for-each serialize-method-access-control val)) | |
242 | ||
243 | (define-configuration location-access-control | |
244 | (path | |
5305ed20 | 245 | (file-name (configuration-missing-field 'location-access-control 'path)) |
f2ec23d1 AW |
246 | "Specifies the URI path to which the access control applies.") |
247 | (access-controls | |
248 | (access-control-list '()) | |
249 | "Access controls for all access to this path, in the same format as the | |
250 | @code{access-controls} of @code{operation-access-control}.") | |
251 | (method-access-controls | |
252 | (method-access-control-list '()) | |
253 | "Access controls for method-specific access to this path.")) | |
254 | ||
255 | (define (serialize-location-access-control x) | |
256 | (format #t "<Location ~a>\n" (location-access-control-path x)) | |
257 | (serialize-configuration | |
258 | x | |
259 | (filter (lambda (field) | |
260 | (not (eq? (configuration-field-name field) 'path))) | |
261 | location-access-control-fields)) | |
262 | (format #t "</Location>\n")) | |
263 | ||
264 | (define (location-access-control-list? val) | |
265 | (and (list? val) (and-map location-access-control? val))) | |
266 | (define (serialize-location-access-control-list field-name val) | |
267 | (for-each serialize-location-access-control val)) | |
268 | ||
269 | (define-configuration policy-configuration | |
270 | (name | |
5305ed20 | 271 | (string (configuration-missing-field 'policy-configuration 'name)) |
f2ec23d1 AW |
272 | "Name of the policy.") |
273 | (job-private-access | |
274 | (string "@OWNER @SYSTEM") | |
275 | "Specifies an access list for a job's private values. @code{@@ACL} maps to | |
276 | the printer's requesting-user-name-allowed or requesting-user-name-denied | |
277 | values. @code{@@OWNER} maps to the job's owner. @code{@@SYSTEM} maps to the | |
278 | groups listed for the @code{system-group} field of the @code{files-config} | |
279 | configuration, which is reified into the @code{cups-files.conf(5)} file. | |
280 | Other possible elements of the access list include specific user names, and | |
281 | @code{@@@var{group}} to indicate members of a specific group. The access list | |
282 | may also be simply @code{all} or @code{default}.") | |
283 | (job-private-values | |
284 | (string (string-join '("job-name" "job-originating-host-name" | |
285 | "job-originating-user-name" "phone"))) | |
286 | "Specifies the list of job values to make private, or @code{all}, | |
287 | @code{default}, or @code{none}.") | |
288 | ||
289 | (subscription-private-access | |
290 | (string "@OWNER @SYSTEM") | |
291 | "Specifies an access list for a subscription's private values. | |
292 | @code{@@ACL} maps to the printer's requesting-user-name-allowed or | |
293 | requesting-user-name-denied values. @code{@@OWNER} maps to the job's owner. | |
294 | @code{@@SYSTEM} maps to the groups listed for the @code{system-group} field of | |
295 | the @code{files-config} configuration, which is reified into the | |
296 | @code{cups-files.conf(5)} file. Other possible elements of the access list | |
297 | include specific user names, and @code{@@@var{group}} to indicate members of a | |
298 | specific group. The access list may also be simply @code{all} or | |
299 | @code{default}.") | |
300 | (subscription-private-values | |
301 | (string (string-join '("notify-events" "notify-pull-method" | |
302 | "notify-recipient-uri" "notify-subscriber-user-name" | |
303 | "notify-user-data") | |
304 | " ")) | |
305 | "Specifies the list of job values to make private, or @code{all}, | |
306 | @code{default}, or @code{none}.") | |
307 | ||
308 | (access-controls | |
309 | (operation-access-control-list '()) | |
310 | "Access control by IPP operation.")) | |
311 | ||
312 | (define (serialize-policy-configuration x) | |
313 | (format #t "<Policy ~a>\n" (policy-configuration-name x)) | |
314 | (serialize-configuration | |
315 | x | |
316 | (filter (lambda (field) | |
317 | (not (eq? (configuration-field-name field) 'name))) | |
318 | policy-configuration-fields)) | |
319 | (format #t "</Policy>\n")) | |
320 | ||
321 | (define (policy-configuration-list? x) | |
322 | (and (list? x) (and-map policy-configuration? x))) | |
323 | (define (serialize-policy-configuration-list field-name x) | |
324 | (for-each serialize-policy-configuration x)) | |
325 | ||
326 | (define (log-location? x) | |
327 | (or (file-name? x) | |
328 | (eq? x 'stderr) | |
329 | (eq? x 'syslog))) | |
330 | (define (serialize-log-location field-name x) | |
331 | (if (string? x) | |
332 | (serialize-file-name field-name x) | |
333 | (serialize-field field-name x))) | |
334 | ||
335 | (define-configuration files-configuration | |
336 | (access-log | |
337 | (log-location "/var/log/cups/access_log") | |
338 | "Defines the access log filename. Specifying a blank filename disables | |
339 | access log generation. The value @code{stderr} causes log entries to be sent | |
340 | to the standard error file when the scheduler is running in the foreground, or | |
341 | to the system log daemon when run in the background. The value @code{syslog} | |
342 | causes log entries to be sent to the system log daemon. The server name may | |
343 | be included in filenames using the string @code{%s}, as in | |
344 | @code{/var/log/cups/%s-access_log}.") | |
345 | (cache-dir | |
346 | (file-name "/var/cache/cups") | |
347 | "Where CUPS should cache data.") | |
348 | (config-file-perm | |
349 | (string "0640") | |
350 | "Specifies the permissions for all configuration files that the scheduler | |
351 | writes. | |
352 | ||
353 | Note that the permissions for the printers.conf file are currently masked to | |
354 | only allow access from the scheduler user (typically root). This is done | |
355 | because printer device URIs sometimes contain sensitive authentication | |
356 | information that should not be generally known on the system. There is no way | |
357 | to disable this security feature.") | |
358 | ;; Not specifying data-dir and server-bin options as we handle these | |
359 | ;; manually. For document-root, the CUPS package has that path | |
360 | ;; preconfigured. | |
361 | (error-log | |
362 | (log-location "/var/log/cups/error_log") | |
363 | "Defines the error log filename. Specifying a blank filename disables | |
364 | access log generation. The value @code{stderr} causes log entries to be sent | |
365 | to the standard error file when the scheduler is running in the foreground, or | |
366 | to the system log daemon when run in the background. The value @code{syslog} | |
367 | causes log entries to be sent to the system log daemon. The server name may | |
368 | be included in filenames using the string @code{%s}, as in | |
369 | @code{/var/log/cups/%s-error_log}.") | |
370 | (fatal-errors | |
371 | (string "all -browse") | |
372 | "Specifies which errors are fatal, causing the scheduler to exit. The kind | |
373 | strings are: | |
374 | @table @code | |
375 | @item none | |
376 | No errors are fatal. | |
377 | @item all | |
378 | All of the errors below are fatal. | |
379 | @item browse | |
380 | Browsing initialization errors are fatal, for example failed connections to | |
381 | the DNS-SD daemon. | |
382 | @item config | |
383 | Configuration file syntax errors are fatal. | |
384 | @item listen | |
385 | Listen or Port errors are fatal, except for IPv6 failures on the loopback or | |
386 | @code{any} addresses. | |
387 | @item log | |
388 | Log file creation or write errors are fatal. | |
389 | @item permissions | |
390 | Bad startup file permissions are fatal, for example shared TLS certificate and | |
391 | key files with world-read permissions. | |
392 | @end table") | |
393 | (file-device? | |
394 | (boolean #f) | |
395 | "Specifies whether the file pseudo-device can be used for new printer | |
396 | queues. The URI @url{file:///dev/null} is always allowed.") | |
397 | (group | |
398 | (string "lp") | |
399 | "Specifies the group name or ID that will be used when executing external | |
400 | programs.") | |
401 | (log-file-perm | |
402 | (string "0644") | |
403 | "Specifies the permissions for all log files that the scheduler writes.") | |
404 | (page-log | |
405 | (log-location "/var/log/cups/page_log") | |
406 | "Defines the page log filename. Specifying a blank filename disables | |
407 | access log generation. The value @code{stderr} causes log entries to be sent | |
408 | to the standard error file when the scheduler is running in the foreground, or | |
409 | to the system log daemon when run in the background. The value @code{syslog} | |
410 | causes log entries to be sent to the system log daemon. The server name may | |
411 | be included in filenames using the string @code{%s}, as in | |
412 | @code{/var/log/cups/%s-page_log}.") | |
413 | (remote-root | |
414 | (string "remroot") | |
415 | "Specifies the username that is associated with unauthenticated accesses by | |
416 | clients claiming to be the root user. The default is @code{remroot}.") | |
417 | (request-root | |
418 | (file-name "/var/spool/cups") | |
419 | "Specifies the directory that contains print jobs and other HTTP request | |
420 | data.") | |
421 | (sandboxing | |
422 | (sandboxing 'strict) | |
423 | "Specifies the level of security sandboxing that is applied to print | |
424 | filters, backends, and other child processes of the scheduler; either | |
425 | @code{relaxed} or @code{strict}. This directive is currently only | |
426 | used/supported on macOS.") | |
427 | (server-keychain | |
428 | (file-name "/etc/cups/ssl") | |
429 | "Specifies the location of TLS certificates and private keys. CUPS will | |
430 | look for public and private keys in this directory: a @code{.crt} files for | |
431 | PEM-encoded certificates and corresponding @code{.key} files for PEM-encoded | |
432 | private keys.") | |
433 | (server-root | |
434 | (file-name "/etc/cups") | |
435 | "Specifies the directory containing the server configuration files.") | |
436 | (sync-on-close? | |
437 | (boolean #f) | |
438 | "Specifies whether the scheduler calls fsync(2) after writing configuration | |
439 | or state files.") | |
440 | (system-group | |
441 | (space-separated-string-list '("lpadmin" "wheel" "root")) | |
442 | "Specifies the group(s) to use for @code{@@SYSTEM} group authentication.") | |
443 | (temp-dir | |
444 | (file-name "/var/spool/cups/tmp") | |
445 | "Specifies the directory where temporary files are stored.") | |
446 | (user | |
447 | (string "lp") | |
448 | "Specifies the user name or ID that is used when running external | |
449 | programs.")) | |
450 | ||
451 | (define (serialize-files-configuration field-name val) | |
452 | #f) | |
453 | ||
454 | (define (environment-variables? vars) | |
455 | (space-separated-string-list? vars)) | |
456 | (define (serialize-environment-variables field-name vars) | |
457 | (unless (null? vars) | |
458 | (serialize-space-separated-string-list field-name vars))) | |
459 | ||
460 | (define (package-list? val) | |
461 | (and (list? val) (and-map package? val))) | |
462 | (define (serialize-package-list field-name val) | |
463 | #f) | |
464 | ||
465 | (define-configuration cups-configuration | |
466 | (cups | |
467 | (package cups) | |
468 | "The CUPS package.") | |
469 | (extensions | |
470 | (package-list (list cups-filters)) | |
471 | "Drivers and other extensions to the CUPS package.") | |
472 | (files-configuration | |
473 | (files-configuration (files-configuration)) | |
474 | "Configuration of where to write logs, what directories to use for print | |
475 | spools, and related privileged configuration parameters.") | |
476 | (access-log-level | |
477 | (access-log-level 'actions) | |
478 | "Specifies the logging level for the AccessLog file. The @code{config} | |
479 | level logs when printers and classes are added, deleted, or modified and when | |
480 | configuration files are accessed or updated. The @code{actions} level logs | |
481 | when print jobs are submitted, held, released, modified, or canceled, and any | |
482 | of the conditions for @code{config}. The @code{all} level logs all | |
483 | requests.") | |
484 | (auto-purge-jobs? | |
485 | (boolean #f) | |
486 | "Specifies whether to purge job history data automatically when it is no | |
487 | longer required for quotas.") | |
488 | (browse-local-protocols | |
489 | (browse-local-protocols 'dnssd) | |
490 | "Specifies which protocols to use for local printer sharing.") | |
491 | (browse-web-if? | |
492 | (boolean #f) | |
493 | "Specifies whether the CUPS web interface is advertised.") | |
494 | (browsing? | |
495 | (boolean #f) | |
496 | "Specifies whether shared printers are advertised.") | |
497 | (classification | |
498 | (string "") | |
499 | "Specifies the security classification of the server. | |
500 | Any valid banner name can be used, including \"classified\", \"confidential\", | |
501 | \"secret\", \"topsecret\", and \"unclassified\", or the banner can be omitted | |
502 | to disable secure printing functions.") | |
503 | (classify-override? | |
504 | (boolean #f) | |
505 | "Specifies whether users may override the classification (cover page) of | |
506 | individual print jobs using the @code{job-sheets} option.") | |
507 | (default-auth-type | |
508 | (default-auth-type 'Basic) | |
509 | "Specifies the default type of authentication to use.") | |
510 | (default-encryption | |
511 | (default-encryption 'Required) | |
512 | "Specifies whether encryption will be used for authenticated requests.") | |
513 | (default-language | |
514 | (string "en") | |
515 | "Specifies the default language to use for text and web content.") | |
516 | (default-paper-size | |
517 | (string "Auto") | |
518 | "Specifies the default paper size for new print queues. @samp{\"Auto\"} | |
519 | uses a locale-specific default, while @samp{\"None\"} specifies there is no | |
520 | default paper size. Specific size names are typically @samp{\"Letter\"} or | |
521 | @samp{\"A4\"}.") | |
522 | (default-policy | |
523 | (string "default") | |
524 | "Specifies the default access policy to use.") | |
525 | (default-shared? | |
526 | (boolean #t) | |
527 | "Specifies whether local printers are shared by default.") | |
528 | (dirty-clean-interval | |
529 | (non-negative-integer 30) | |
530 | "Specifies the delay for updating of configuration and state files, in | |
531 | seconds. A value of 0 causes the update to happen as soon as possible, | |
532 | typically within a few milliseconds.") | |
533 | (error-policy | |
534 | (error-policy 'stop-printer) | |
535 | "Specifies what to do when an error occurs. Possible values are | |
536 | @code{abort-job}, which will discard the failed print job; @code{retry-job}, | |
537 | which will retry the job at a later time; @code{retry-this-job}, which retries | |
538 | the failed job immediately; and @code{stop-printer}, which stops the | |
539 | printer.") | |
540 | (filter-limit | |
541 | (non-negative-integer 0) | |
542 | "Specifies the maximum cost of filters that are run concurrently, which can | |
543 | be used to minimize disk, memory, and CPU resource problems. A limit of 0 | |
544 | disables filter limiting. An average print to a non-PostScript printer needs | |
545 | a filter limit of about 200. A PostScript printer needs about half | |
546 | that (100). Setting the limit below these thresholds will effectively limit | |
547 | the scheduler to printing a single job at any time.") | |
548 | (filter-nice | |
549 | (non-negative-integer 0) | |
550 | "Specifies the scheduling priority of filters that are run to print a job. | |
551 | The nice value ranges from 0, the highest priority, to 19, the lowest | |
552 | priority.") | |
553 | ;; Add this option if the package is built with Kerberos support. | |
554 | ;; (gss-service-name | |
555 | ;; (string "http") | |
556 | ;; "Specifies the service name when using Kerberos authentication.") | |
557 | (host-name-lookups | |
558 | (host-name-lookups #f) | |
559 | "Specifies whether to do reverse lookups on connecting clients. | |
560 | The @code{double} setting causes @code{cupsd} to verify that the hostname | |
561 | resolved from the address matches one of the addresses returned for that | |
562 | hostname. Double lookups also prevent clients with unregistered addresses | |
563 | from connecting to your server. Only set this option to @code{#t} or | |
564 | @code{double} if absolutely required.") | |
565 | ;; Add this option if the package is built with launchd/systemd support. | |
566 | ;; (idle-exit-timeout | |
567 | ;; (non-negative-integer 60) | |
568 | ;; "Specifies the length of time to wait before shutting down due to | |
569 | ;; inactivity. Note: Only applicable when @code{cupsd} is run on-demand | |
570 | ;; (e.g., with @code{-l}).") | |
571 | (job-kill-delay | |
572 | (non-negative-integer 30) | |
573 | "Specifies the number of seconds to wait before killing the filters and | |
574 | backend associated with a canceled or held job.") | |
575 | (job-retry-interval | |
576 | (non-negative-integer 30) | |
577 | "Specifies the interval between retries of jobs in seconds. This is | |
578 | typically used for fax queues but can also be used with normal print queues | |
579 | whose error policy is @code{retry-job} or @code{retry-current-job}.") | |
580 | (job-retry-limit | |
581 | (non-negative-integer 5) | |
582 | "Specifies the number of retries that are done for jobs. This is typically | |
583 | used for fax queues but can also be used with normal print queues whose error | |
584 | policy is @code{retry-job} or @code{retry-current-job}.") | |
585 | (keep-alive? | |
586 | (boolean #t) | |
587 | "Specifies whether to support HTTP keep-alive connections.") | |
588 | (keep-alive-timeout | |
589 | (non-negative-integer 30) | |
590 | "Specifies how long an idle client connection remains open, in seconds.") | |
591 | (limit-request-body | |
592 | (non-negative-integer 0) | |
593 | "Specifies the maximum size of print files, IPP requests, and HTML form | |
594 | data. A limit of 0 disables the limit check.") | |
595 | (listen | |
596 | (multiline-string-list '("localhost:631" "/var/run/cups/cups.sock")) | |
597 | "Listens on the specified interfaces for connections. Valid values are of | |
598 | the form @var{address}:@var{port}, where @var{address} is either an IPv6 | |
599 | address enclosed in brackets, an IPv4 address, or @code{*} to indicate all | |
600 | addresses. Values can also be file names of local UNIX domain sockets. The | |
601 | Listen directive is similar to the Port directive but allows you to restrict | |
602 | access to specific interfaces or networks.") | |
603 | (listen-back-log | |
604 | (non-negative-integer 128) | |
605 | "Specifies the number of pending connections that will be allowed. This | |
606 | normally only affects very busy servers that have reached the MaxClients | |
607 | limit, but can also be triggered by large numbers of simultaneous connections. | |
608 | When the limit is reached, the operating system will refuse additional | |
609 | connections until the scheduler can accept the pending ones.") | |
610 | (location-access-controls | |
611 | (location-access-control-list | |
612 | (list (location-access-control | |
613 | (path "/") | |
614 | (access-controls '("Order allow,deny" | |
615 | "Allow localhost"))) | |
616 | (location-access-control | |
617 | (path "/admin") | |
618 | (access-controls '("Order allow,deny" | |
619 | "Allow localhost"))) | |
620 | (location-access-control | |
621 | (path "/admin/conf") | |
622 | (access-controls '("Order allow,deny" | |
623 | "AuthType Basic" | |
624 | "Require user @SYSTEM" | |
625 | "Allow localhost"))))) | |
626 | "Specifies a set of additional access controls.") | |
627 | (log-debug-history | |
628 | (non-negative-integer 100) | |
629 | "Specifies the number of debugging messages that are retained for logging | |
630 | if an error occurs in a print job. Debug messages are logged regardless of | |
631 | the LogLevel setting.") | |
632 | (log-level | |
633 | (log-level 'info) | |
634 | "Specifies the level of logging for the ErrorLog file. The value | |
635 | @code{none} stops all logging while @code{debug2} logs everything.") | |
636 | (log-time-format | |
637 | (log-time-format 'standard) | |
638 | "Specifies the format of the date and time in the log files. The value | |
639 | @code{standard} logs whole seconds while @code{usecs} logs microseconds.") | |
640 | (max-clients | |
641 | (non-negative-integer 100) | |
642 | "Specifies the maximum number of simultaneous clients that are allowed by | |
643 | the scheduler.") | |
644 | (max-clients-per-host | |
645 | (non-negative-integer 100) | |
646 | "Specifies the maximum number of simultaneous clients that are allowed from | |
647 | a single address.") | |
648 | (max-copies | |
649 | (non-negative-integer 9999) | |
650 | "Specifies the maximum number of copies that a user can print of each | |
651 | job.") | |
652 | (max-hold-time | |
653 | (non-negative-integer 0) | |
654 | "Specifies the maximum time a job may remain in the @code{indefinite} hold | |
655 | state before it is canceled. A value of 0 disables cancellation of held | |
656 | jobs.") | |
657 | (max-jobs | |
658 | (non-negative-integer 500) | |
659 | "Specifies the maximum number of simultaneous jobs that are allowed. Set | |
660 | to 0 to allow an unlimited number of jobs.") | |
661 | (max-jobs-per-printer | |
662 | (non-negative-integer 0) | |
663 | "Specifies the maximum number of simultaneous jobs that are allowed per | |
664 | printer. A value of 0 allows up to MaxJobs jobs per printer.") | |
665 | (max-jobs-per-user | |
666 | (non-negative-integer 0) | |
667 | "Specifies the maximum number of simultaneous jobs that are allowed per | |
668 | user. A value of 0 allows up to MaxJobs jobs per user.") | |
669 | (max-job-time | |
670 | (non-negative-integer 10800) | |
671 | "Specifies the maximum time a job may take to print before it is canceled, | |
672 | in seconds. Set to 0 to disable cancellation of \"stuck\" jobs.") | |
673 | (max-log-size | |
674 | (non-negative-integer 1048576) | |
675 | "Specifies the maximum size of the log files before they are rotated, in | |
676 | bytes. The value 0 disables log rotation.") | |
677 | (multiple-operation-timeout | |
678 | (non-negative-integer 300) | |
679 | "Specifies the maximum amount of time to allow between files in a multiple | |
680 | file print job, in seconds.") | |
681 | (page-log-format | |
682 | (string "") | |
683 | "Specifies the format of PageLog lines. Sequences beginning with | |
684 | percent (@samp{%}) characters are replaced with the corresponding information, | |
685 | while all other characters are copied literally. The following percent | |
686 | sequences are recognized: | |
687 | ||
688 | @table @samp | |
689 | @item %% | |
690 | insert a single percent character | |
691 | @item %@{name@} | |
692 | insert the value of the specified IPP attribute | |
693 | @item %C | |
694 | insert the number of copies for the current page | |
695 | @item %P | |
696 | insert the current page number | |
697 | @item %T | |
698 | insert the current date and time in common log format | |
699 | @item %j | |
700 | insert the job ID | |
701 | @item %p | |
702 | insert the printer name | |
703 | @item %u | |
704 | insert the username | |
705 | @end table | |
706 | ||
707 | A value of the empty string disables page logging. The string @code{%p %u %j | |
708 | %T %P %C %@{job-billing@} %@{job-originating-host-name@} %@{job-name@} | |
709 | %@{media@} %@{sides@}} creates a page log with the standard items.") | |
710 | (environment-variables | |
711 | (environment-variables '()) | |
712 | "Passes the specified environment variable(s) to child processes; a list of | |
713 | strings.") | |
714 | (policies | |
715 | (policy-configuration-list | |
716 | (list (policy-configuration | |
717 | (name "default") | |
718 | (access-controls | |
719 | (list | |
720 | (operation-access-control | |
721 | (operations | |
722 | '(Send-Document | |
723 | Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs | |
724 | Cancel-Job Close-Job Cancel-My-Jobs Set-Job-Attributes | |
725 | Create-Job-Subscription Renew-Subscription | |
726 | Cancel-Subscription Get-Notifications | |
727 | Reprocess-Job Cancel-Current-Job Suspend-Current-Job | |
728 | Resume-Job CUPS-Move-Job Validate-Job | |
729 | CUPS-Get-Document)) | |
730 | (access-controls '("Require user @OWNER @SYSTEM" | |
731 | "Order deny,allow"))) | |
732 | (operation-access-control | |
733 | (operations | |
734 | '(Pause-Printer | |
735 | Cancel-Jobs | |
736 | Resume-Printer Set-Printer-Attributes Enable-Printer | |
737 | Disable-Printer Pause-Printer-After-Current-Job | |
738 | Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer | |
739 | Activate-Printer Restart-Printer Shutdown-Printer | |
740 | Startup-Printer Promote-Job Schedule-Job-After | |
741 | CUPS-Authenticate-Job CUPS-Add-Printer | |
742 | CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class | |
743 | CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default)) | |
744 | (access-controls '("AuthType Basic" | |
745 | "Require user @SYSTEM" | |
746 | "Order deny,allow"))) | |
747 | (operation-access-control | |
748 | (operations '(All)) | |
749 | (access-controls '("Order deny,allow")))))))) | |
750 | "Specifies named access control policies.") | |
751 | #; | |
752 | (port | |
753 | (non-negative-integer 631) | |
754 | "Listens to the specified port number for connections.") | |
755 | (preserve-job-files | |
756 | (boolean-or-non-negative-integer 86400) | |
757 | "Specifies whether job files (documents) are preserved after a job is | |
758 | printed. If a numeric value is specified, job files are preserved for the | |
759 | indicated number of seconds after printing. Otherwise a boolean value applies | |
760 | indefinitely.") | |
761 | (preserve-job-history | |
762 | (boolean-or-non-negative-integer #t) | |
763 | "Specifies whether the job history is preserved after a job is printed. | |
764 | If a numeric value is specified, the job history is preserved for the | |
765 | indicated number of seconds after printing. If @code{#t}, the job history is | |
766 | preserved until the MaxJobs limit is reached.") | |
767 | (reload-timeout | |
768 | (non-negative-integer 30) | |
769 | "Specifies the amount of time to wait for job completion before restarting | |
770 | the scheduler.") | |
771 | (rip-cache | |
772 | (string "128m") | |
773 | "Specifies the maximum amount of memory to use when converting documents into bitmaps for a printer.") | |
774 | (server-admin | |
775 | (string "root@localhost.localdomain") | |
776 | "Specifies the email address of the server administrator.") | |
777 | (server-alias | |
778 | (host-name-list-or-* '*) | |
779 | "The ServerAlias directive is used for HTTP Host header validation when | |
780 | clients connect to the scheduler from external interfaces. Using the special | |
781 | name @code{*} can expose your system to known browser-based DNS rebinding | |
782 | attacks, even when accessing sites through a firewall. If the auto-discovery | |
783 | of alternate names does not work, we recommend listing each alternate name | |
784 | with a ServerAlias directive instead of using @code{*}.") | |
785 | (server-name | |
786 | (string "localhost") | |
787 | "Specifies the fully-qualified host name of the server.") | |
788 | (server-tokens | |
789 | (server-tokens 'Minimal) | |
790 | "Specifies what information is included in the Server header of HTTP | |
791 | responses. @code{None} disables the Server header. @code{ProductOnly} | |
792 | reports @code{CUPS}. @code{Major} reports @code{CUPS 2}. @code{Minor} | |
793 | reports @code{CUPS 2.0}. @code{Minimal} reports @code{CUPS 2.0.0}. @code{OS} | |
794 | reports @code{CUPS 2.0.0 (@var{uname})} where @var{uname} is the output of the | |
795 | @code{uname} command. @code{Full} reports @code{CUPS 2.0.0 (@var{uname}) | |
796 | IPP/2.0}.") | |
797 | (set-env | |
798 | (string "variable value") | |
799 | "Set the specified environment variable to be passed to child processes.") | |
800 | (ssl-listen | |
801 | (multiline-string-list '()) | |
802 | "Listens on the specified interfaces for encrypted connections. Valid | |
803 | values are of the form @var{address}:@var{port}, where @var{address} is either | |
804 | an IPv6 address enclosed in brackets, an IPv4 address, or @code{*} to indicate | |
805 | all addresses.") | |
806 | (ssl-options | |
807 | (ssl-options '()) | |
808 | "Sets encryption options. | |
809 | By default, CUPS only supports encryption using TLS v1.0 or higher using known | |
810 | secure cipher suites. The @code{AllowRC4} option enables the 128-bit RC4 | |
811 | cipher suites, which are required for some older clients that do not implement | |
812 | newer ones. The @code{AllowSSL3} option enables SSL v3.0, which is required | |
813 | for some older clients that do not support TLS v1.0.") | |
814 | #; | |
815 | (ssl-port | |
816 | (non-negative-integer 631) | |
817 | "Listens on the specified port for encrypted connections.") | |
818 | (strict-conformance? | |
819 | (boolean #f) | |
820 | "Specifies whether the scheduler requires clients to strictly adhere to the | |
821 | IPP specifications.") | |
822 | (timeout | |
823 | (non-negative-integer 300) | |
824 | "Specifies the HTTP request timeout, in seconds.") | |
825 | (web-interface? | |
826 | (boolean #f) | |
827 | "Specifies whether the web interface is enabled.")) | |
828 | ||
829 | (define-configuration opaque-cups-configuration | |
830 | (cups | |
831 | (package cups) | |
832 | "The CUPS package.") | |
833 | (extensions | |
834 | (package-list '()) | |
835 | "Drivers and other extensions to the CUPS package.") | |
836 | (cupsd.conf | |
5305ed20 JL |
837 | (string (configuration-missing-field 'opaque-cups-configuration |
838 | 'cupsd.conf)) | |
f2ec23d1 AW |
839 | "The contents of the @code{cupsd.conf} to use.") |
840 | (cups-files.conf | |
5305ed20 JL |
841 | (string (configuration-missing-field 'opaque-cups-configuration |
842 | 'cups-files.conf)) | |
f2ec23d1 AW |
843 | "The contents of the @code{cups-files.conf} to use.")) |
844 | ||
845 | (define %cups-activation | |
846 | ;; Activation gexp. | |
847 | (with-imported-modules '((guix build utils)) | |
848 | #~(begin | |
e57bd0be | 849 | (use-modules (guix build utils)) |
f2ec23d1 AW |
850 | (define (mkdir-p/perms directory owner perms) |
851 | (mkdir-p directory) | |
852 | (chown "/var/run/cups" (passwd:uid owner) (passwd:gid owner)) | |
853 | (chmod directory perms)) | |
854 | (define (build-subject parameters) | |
855 | (string-concatenate | |
856 | (map (lambda (pair) | |
857 | (let ((k (car pair)) (v (cdr pair))) | |
858 | (define (escape-char str chr) | |
859 | (string-join (string-split str chr) (string #\\ chr))) | |
860 | (string-append "/" k "=" | |
861 | (escape-char (escape-char v #\=) #\/)))) | |
862 | (filter (lambda (pair) (cdr pair)) parameters)))) | |
863 | (define* (create-self-signed-certificate-if-absent | |
864 | #:key private-key public-key (owner (getpwnam "root")) | |
865 | (common-name (gethostname)) | |
59e80445 | 866 | (organization-name "Guix") |
f2ec23d1 AW |
867 | (organization-unit-name "Default Self-Signed Certificate") |
868 | (subject-parameters `(("CN" . ,common-name) | |
869 | ("O" . ,organization-name) | |
870 | ("OU" . ,organization-unit-name))) | |
871 | (subject (build-subject subject-parameters))) | |
872 | ;; Note that by default, OpenSSL outputs keys in PEM format. This | |
873 | ;; is what we want. | |
874 | (unless (file-exists? private-key) | |
875 | (cond | |
876 | ((zero? (system* (string-append #$openssl "/bin/openssl") | |
877 | "genrsa" "-out" private-key "2048")) | |
878 | (chown private-key (passwd:uid owner) (passwd:gid owner)) | |
879 | (chmod private-key #o400)) | |
880 | (else | |
881 | (format (current-error-port) | |
882 | "Failed to create private key at ~a.\n" private-key)))) | |
883 | (unless (file-exists? public-key) | |
884 | (cond | |
885 | ((zero? (system* (string-append #$openssl "/bin/openssl") | |
886 | "req" "-new" "-x509" "-key" private-key | |
887 | "-out" public-key "-days" "3650" | |
888 | "-batch" "-subj" subject)) | |
889 | (chown public-key (passwd:uid owner) (passwd:gid owner)) | |
890 | (chmod public-key #o444)) | |
891 | (else | |
892 | (format (current-error-port) | |
893 | "Failed to create public key at ~a.\n" public-key))))) | |
894 | (let ((user (getpwnam "lp"))) | |
895 | (mkdir-p/perms "/var/run/cups" user #o755) | |
896 | (mkdir-p/perms "/var/spool/cups" user #o755) | |
897 | (mkdir-p/perms "/var/spool/cups/tmp" user #o755) | |
898 | (mkdir-p/perms "/var/log/cups" user #o755) | |
36273ebd | 899 | (mkdir-p/perms "/var/cache/cups" user #o770) |
f2ec23d1 AW |
900 | (mkdir-p/perms "/etc/cups" user #o755) |
901 | (mkdir-p/perms "/etc/cups/ssl" user #o700) | |
902 | ;; This certificate is used for HTTPS connections to the CUPS web | |
903 | ;; interface. | |
904 | (create-self-signed-certificate-if-absent | |
905 | #:private-key "/etc/cups/ssl/localhost.key" | |
906 | #:public-key "/etc/cups/ssl/localhost.crt" | |
907 | #:owner (getpwnam "root") | |
908 | #:common-name (format #f "CUPS service on ~a" (gethostname))))))) | |
909 | ||
910 | (define (union-directory name packages paths) | |
911 | (computed-file | |
912 | name | |
913 | (with-imported-modules '((guix build utils)) | |
914 | #~(begin | |
915 | (use-modules (guix build utils) | |
916 | (srfi srfi-1)) | |
917 | (mkdir #$output) | |
918 | (for-each | |
919 | (lambda (package) | |
920 | (for-each | |
921 | (lambda (path) | |
922 | (for-each | |
923 | (lambda (src) | |
924 | (let* ((tail (substring src (string-length package))) | |
925 | (dst (string-append #$output tail))) | |
926 | (mkdir-p (dirname dst)) | |
927 | ;; CUPS currently symlinks in some data from cups-filters | |
928 | ;; to its output dir. Probably we should stop doing this | |
929 | ;; and instead rely only on the CUPS service to union the | |
930 | ;; relevant set of CUPS packages. | |
931 | (if (file-exists? dst) | |
932 | (format (current-error-port) "warning: ~a exists\n" dst) | |
933 | (symlink src dst)))) | |
4ce8860d | 934 | (find-files (string-append package path) #:stat stat))) |
f2ec23d1 AW |
935 | (list #$@paths))) |
936 | (list #$@packages)) | |
937 | #t)))) | |
938 | ||
939 | (define (cups-server-bin-directory extensions) | |
940 | "Return the CUPS ServerBin directory, containing binaries for CUPS and all | |
941 | extensions that it uses." | |
942 | (union-directory "cups-server-bin" extensions | |
943 | ;; /bin | |
944 | '("/lib/cups" "/share/ppd" "/share/cups"))) | |
945 | ||
946 | (define (cups-shepherd-service config) | |
947 | "Return a list of <shepherd-service> for CONFIG." | |
948 | (let* ((cupsd.conf-str | |
949 | (cond | |
950 | ((opaque-cups-configuration? config) | |
951 | (opaque-cups-configuration-cupsd.conf config)) | |
952 | (else | |
953 | (with-output-to-string | |
954 | (lambda () | |
955 | (serialize-configuration config | |
956 | cups-configuration-fields)))))) | |
957 | (cups-files.conf-str | |
958 | (cond | |
959 | ((opaque-cups-configuration? config) | |
960 | (opaque-cups-configuration-cups-files.conf config)) | |
961 | (else | |
962 | (with-output-to-string | |
963 | (lambda () | |
964 | (serialize-configuration | |
965 | (cups-configuration-files-configuration config) | |
966 | files-configuration-fields)))))) | |
967 | (cups (if (opaque-cups-configuration? config) | |
968 | (opaque-cups-configuration-cups config) | |
969 | (cups-configuration-cups config))) | |
970 | (server-bin | |
971 | (cups-server-bin-directory | |
972 | (cons cups | |
973 | (cond | |
974 | ((opaque-cups-configuration? config) | |
975 | (opaque-cups-configuration-extensions config)) | |
976 | (else | |
977 | (cups-configuration-extensions config)))))) | |
978 | ;;"SetEnv PATH " server-bin "/bin" "\n" | |
979 | (cupsd.conf | |
980 | (plain-file "cupsd.conf" cupsd.conf-str)) | |
981 | (cups-files.conf | |
982 | (mixed-text-file | |
983 | "cups-files.conf" | |
984 | cups-files.conf-str | |
985 | "CacheDir /var/cache/cups\n" | |
986 | "StateDir /var/run/cups\n" | |
987 | "DataDir " server-bin "/share/cups" "\n" | |
988 | "ServerBin " server-bin "/lib/cups" "\n"))) | |
989 | (list (shepherd-service | |
990 | (documentation "Run the CUPS print server.") | |
991 | (provision '(cups)) | |
992 | (requirement '(networking)) | |
993 | (start #~(make-forkexec-constructor | |
994 | (list (string-append #$cups "/sbin/cupsd") | |
995 | "-f" "-c" #$cupsd.conf "-s" #$cups-files.conf))) | |
996 | (stop #~(make-kill-destructor)))))) | |
997 | ||
998 | (define cups-service-type | |
999 | (service-type (name 'cups) | |
1000 | (extensions | |
1001 | (list (service-extension shepherd-root-service-type | |
1002 | cups-shepherd-service) | |
1003 | (service-extension activation-service-type | |
1004 | (const %cups-activation)) | |
1005 | (service-extension account-service-type | |
1006 | (const %cups-accounts)))) | |
1007 | ||
1008 | ;; Extensions consist of lists of packages (representing CUPS | |
1009 | ;; drivers, etc) that we just concatenate. | |
1010 | (compose append) | |
1011 | ||
1012 | ;; Add extension packages by augmenting the cups-configuration | |
1013 | ;; 'extensions' field. | |
1014 | (extend | |
1015 | (lambda (config extensions) | |
1016 | (cond | |
1017 | ((cups-configuration? config) | |
1018 | (cups-configuration | |
1019 | (inherit config) | |
1020 | (extensions | |
1021 | (append (cups-configuration-extensions config) | |
1022 | extensions)))) | |
1023 | (else | |
1024 | (opaque-cups-configuration | |
1025 | (inherit config) | |
1026 | (extensions | |
1027 | (append (opaque-cups-configuration-extensions config) | |
3d3c5650 LC |
1028 | extensions))))))) |
1029 | ||
86cd3f97 RW |
1030 | (default-value (cups-configuration)) |
1031 | (description | |
1032 | "Run the CUPS print server."))) | |
f2ec23d1 AW |
1033 | |
1034 | ;; A little helper to make it easier to document all those fields. | |
5305ed20 JL |
1035 | (define (generate-cups-documentation) |
1036 | (generate-documentation | |
f2ec23d1 AW |
1037 | `((cups-configuration |
1038 | ,cups-configuration-fields | |
1039 | (files-configuration files-configuration) | |
1040 | (policies policy-configuration) | |
1041 | (location-access-controls location-access-controls)) | |
1042 | (files-configuration ,files-configuration-fields) | |
1043 | (policy-configuration | |
1044 | ,policy-configuration-fields | |
1045 | (operation-access-controls operation-access-controls)) | |
1046 | (location-access-controls | |
1047 | ,location-access-control-fields | |
1048 | (method-access-controls method-access-controls)) | |
1049 | (operation-access-controls ,operation-access-control-fields) | |
5305ed20 JL |
1050 | (method-access-controls ,method-access-control-fields)) |
1051 | 'cups-configuration)) |