aboutsummaryrefslogtreecommitdiff
path: root/gnu/packages/gnu-doc.scm
blob: b64d8ac454601841992cb06a98babcc98bd5ace4 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014 John Darrington <jmd@gnu.org>
;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
;;;
;;; 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 <http://www.gnu.org/licenses/>.

(define-module (gnu packages gnu-doc)
  #:use-module (gnu packages base)
  #:use-module (gnu packages compression)
  #:use-module (gnu packages texinfo)

  #:use-module (guix build-system gnu)
  #:use-module (guix build-system trivial)
  #:use-module (guix cvs-download)
  #:use-module (guix download)
  #:use-module (guix licenses)
  #:use-module (guix packages))

(define-public miscfiles
  (package
    (name "miscfiles")
    (version "1.5")
    (source
     (origin
      (method url-fetch)
      (uri (string-append "mirror://gnu/" name "/" name "-"
                          version ".tar.gz"))
      (sha256
       (base32
        "005588vfrwx8ghsdv9p7zczj9lbc9a3r4m5aphcaqv8gif4siaka"))))
    (build-system gnu-build-system)
    (home-page "https://www.gnu.org/software/miscfiles/")
    (synopsis
     "Data files for airport codes, zip codes, a dictionary, and more")
    (description
     "GNU Miscfiles is a collection of common data files.  They include, for
example, country abbreviations, names and capital cities; currency
abbreviations and names; a Best Current Practices index; a map of the ASCII
character set; a list of three-letter airport codes; and an English word
list.")
    (license gpl2+)))

(define-public gnu-standards
  (package
    (name "gnu-standards")
    (version "2018-02-18")
    (source
     (origin
       (method cvs-fetch)
       (uri (cvs-reference
             (root-directory
              ":pserver:anonymous@cvs.savannah.gnu.org:/sources/gnustandards")
             (module "gnustandards")
             (revision "2018-02-18")))
       (sha256
        (base32
         "03yh25fpvfn5pnd0d4x7a2wkh01ffk6vbs1vjnzqicqkgc2g33sd"))
       (file-name "gnu-standards-src")))
    (build-system trivial-build-system)
    (native-inputs `(("gzip" ,gzip)
                     ("source" ,source)
                     ("texinfo" ,texinfo)))
    (arguments
     `(#:modules ((guix build utils))
       #:builder
        (begin
          (use-modules (guix build utils))
          (let ((gzip (assoc-ref %build-inputs "gzip"))
                (source (assoc-ref %build-inputs "source"))
                (texinfo (assoc-ref %build-inputs "texinfo"))
                (info-dir (string-append %output "/share/info")))
            (setenv "PATH" (string-append gzip "/bin"
                                          ":" texinfo "/bin"))
            (mkdir-p info-dir)
            (invoke "makeinfo" "--output" info-dir
                    (string-append source "/maintain.texi"))
            (invoke "makeinfo" "--output" info-dir
                    (string-append source "/standards.texi"))
            (invoke "gzip" (string-append info-dir "/maintain.info"))
            (invoke "gzip" (string-append info-dir "/standards.info"))))))
    (home-page "https://www.gnu.org/prep/standards/")
    (synopsis "GNU coding standards and maintainer information")
    (description "The GNU Coding Standards were written by Richard Stallman
and other GNU Project volunteers.  Their purpose is to make the GNU system
clean, consistent, and easy to install.

The information for maintainers of GNU software has guidelines and advice for
someone who is the maintainer of a GNU program on behalf of the GNU Project.")
    (license fdl1.3+)))
h-file-lock' when they access the databases. "/etc/.pwd.lock") (define (database-writer file mode entry->string) (lambda* (entries #:optional (file-or-port file)) "Write ENTRIES to FILE-OR-PORT. When FILE-OR-PORT is a file name, write to it atomically and set the appropriate permissions." (define (write-entries port) (for-each (lambda (entry) (display (entry->string entry) port) (newline port)) (delete-duplicates entries))) (if (port? file-or-port) (write-entries file-or-port) (let* ((template (string-append file-or-port ".XXXXXX")) (port (mkstemp! template))) (dynamic-wind (const #t) (lambda () (chmod port mode) (write-entries port) (fsync port) (close-port port) (rename-file template file-or-port)) (lambda () (unless (port-closed? port) (close-port port)) (when (file-exists? template) (delete-file template)))))))) (define write-passwd (database-writer "/etc/passwd" #o644 password-entry->string)) (define write-shadow (database-writer "/etc/shadow" #o600 shadow-entry->string)) (define write-group (database-writer "/etc/group" #o644 group-entry->string)) (define (database-reader file string->entry) (lambda* (#:optional (file-or-port file)) (define (read-entries port) (let loop ((entries '())) (match (read-line port) ((? eof-object?) (reverse entries)) (line (loop (cons (string->entry line) entries)))))) (if (port? file-or-port) (read-entries file-or-port) (call-with-input-file file-or-port read-entries)))) (define read-passwd (database-reader "/etc/passwd" string->password-entry)) (define read-shadow (database-reader "/etc/shadow" string->shadow-entry)) (define read-group (database-reader "/etc/group" string->group-entry)) ;;; ;;; Building databases. ;;; (define-record-type* <allocation> allocation make-allocation allocation? (ids allocation-ids (default vlist-null)) (next-id allocation-next-id (default %id-min)) (next-system-id allocation-next-system-id (default %system-id-max))) ;; Trick to avoid name clashes... (define-syntax %allocation (identifier-syntax allocation)) ;; Minimum and maximum UIDs and GIDs (from find_new_uid.c and find_new_gid.c ;; in Shadow.) (define %id-min 1000) (define %id-max 60000) (define %system-id-min 100) (define %system-id-max 999) (define (system-id? id) (and (> id %system-id-min) (<= id %system-id-max))) (define (user-id? id) (and (>= id %id-min) (< id %id-max))) (define* (allocate-id assignment #:key system?) "Return two values: a newly allocated ID, and an updated <allocation> record based on ASSIGNMENT. If SYSTEM? is true, return a system ID." (define next ;; Return the next available ID, looping if necessary. (if system? (lambda (id) (let ((next-id (- id 1))) (if (< next-id %system-id-min) %system-id-max next-id))) (lambda (id) (let ((next-id (+ id 1))) (if (>= next-id %id-max) %id-min next-id))))) (let loop ((id (if system? (allocation-next-system-id assignment) (allocation-next-id assignment)))) (if (vhash-assv id (allocation-ids assignment)) (loop (next id)) (let ((taken (vhash-consv id #t (allocation-ids assignment)))) (values (if system? (allocation (inherit assignment) (next-system-id (next id)) (ids taken)) (allocation (inherit assignment) (next-id (next id)) (ids taken))) id))))) (define* (reserve-ids allocation ids #:key (skip? #t)) "Mark the numbers listed in IDS as reserved in ALLOCATION. When SKIP? is true, start allocation after the highest (or lowest, depending on whether it's a system ID allocation) number among IDS." (%allocation (inherit allocation) (next-id (if skip? (+ (reduce max (- (allocation-next-id allocation) 1) (filter user-id? ids)) 1) (allocation-next-id allocation))) (next-system-id (if skip? (- (reduce min (+ 1 (allocation-next-system-id allocation)) (filter system-id? ids)) 1) (allocation-next-system-id allocation))) (ids (fold (cut vhash-consv <> #t <>) (allocation-ids allocation) ids)))) (define (allocated? allocation id) "Return true if ID is already allocated as part of ALLOCATION." (->bool (vhash-assv id (allocation-ids allocation)))) (define (lookup-procedure lst key) "Return a lookup procedure for the elements of LST, calling KEY to obtain the key of each element." (let ((table (fold (lambda (obj table) (vhash-cons (key obj) obj table)) vlist-null lst))) (lambda (key) (match (vhash-assoc key table) (#f #f) ((_ . value) value))))) (define* (allocate-groups groups members #:optional (current-groups '())) "Return a list of group entries for GROUPS, a list of <user-group>. Members for each group are taken from MEMBERS, a vhash that maps group names to member names. GIDs and passwords found in CURRENT-GROUPS, a list of group entries, are reused." (define gids ;; Mark all the currently-used GIDs and the explicitly requested GIDs as ;; reserved. (reserve-ids (reserve-ids (allocation) (map group-entry-gid current-groups)) (filter-map user-group-id groups) #:skip? #f)) (define previous-entry (lookup-procedure current-groups group-entry-name)) (reverse (fold2 (lambda (group result allocation) (let ((name (user-group-name group)) (password (user-group-password group)) (requested-id (user-group-id group)) (system? (user-group-system? group))) (let*-values (((previous) (previous-entry name)) ((allocation id) (cond ((number? requested-id) (values (reserve-ids allocation (list requested-id)) requested-id)) (previous (values allocation (group-entry-gid previous))) (else (allocate-id allocation #:system? system?))))) (values (cons (group-entry (name name) (password (if previous (group-entry-password previous) password)) (gid id) (members (vhash-fold* cons '() name members))) result) allocation)))) '() gids groups))) (define* (allocate-passwd users groups #:optional (current-passwd '())) "Return a list of password entries for USERS, a list of <user-account>. Take GIDs from GROUPS, a list of group entries. Reuse UIDs from CURRENT-PASSWD, a list of password entries, when possible; otherwise allocate new UIDs." (define uids (reserve-ids (reserve-ids (allocation) (map password-entry-uid current-passwd)) (filter-map user-account-uid users) #:skip? #f)) (define previous-entry (lookup-procedure current-passwd password-entry-name)) (define (group-id name) (or (any (lambda (entry) (and (string=? (group-entry-name entry) name) (group-entry-gid entry))) groups) (error "group not found" name))) (reverse (fold2 (lambda (user result allocation) (let ((name (user-account-name user)) (requested-id (user-account-uid user)) (group (user-account-group user)) (real-name (user-account-comment user)) (directory (user-account-home-directory user)) (shell (user-account-shell user)) (system? (user-account-system? user))) (let*-values (((previous) (previous-entry name)) ((allocation id) (cond ((number? requested-id) (values (reserve-ids allocation (list requested-id)) requested-id)) (previous (values allocation (password-entry-uid previous))) (else (allocate-id allocation #:system? system?))))) (values (cons (password-entry (name name) (uid id) (directory directory) (gid (if (number? group) group (group-id group))) ;; Users might change their name to something ;; other than what the sysadmin chose, with ;; 'chfn'. Thus consider it "stateful". (real-name (if (and previous (not system?)) (password-entry-real-name previous) real-name)) ;; Do not reuse the shell of PREVIOUS since (1) ;; that could lead to confusion, and (2) the ;; shell might have been GC'd. See ;; <https://lists.gnu.org/archive/html/guix-devel/2019-04/msg00478.html>. (shell shell)) result) allocation)))) '() uids users))) (define* (days-since-epoch #:optional (current-time current-time)) "Return the number of days elapsed since the 1st of January, 1970." (let* ((now (current-time time-utc)) (epoch (make-time time-utc 0 0)) (diff (time-difference now epoch))) (quotient (time-second diff) (* 24 3600)))) (define* (passwd->shadow users passwd #:optional (current-shadow '()) #:key (current-time current-time)) "Return a list of shadow entries for the password entries listed in PASSWD. Reuse shadow entries from CURRENT-SHADOW when they exist, and take the initial password from USERS." (define previous-entry (lookup-procedure current-shadow shadow-entry-name)) (define now ;; On machines without a real-time clock (typically Arm SBCs), the system ;; clock may be at 1970-01-01 while booting, which would lead us to define ;; NOW as zero. ;; ;; However, the 'isexpired' function in Shadow interprets the combination ;; uninitialized password + last-change = 0 as "The password has expired, ;; it must be changed", which prevents logins altogether. To avoid that, ;; never set 'last-change' to zero. (max (days-since-epoch current-time) 1)) (map (lambda (user passwd) (or (previous-entry (password-entry-name passwd)) (shadow-entry (name (password-entry-name passwd)) (password (user-account-password user)) (last-change now)))) users passwd)) (define (empty-if-not-found thunk) "Call THUNK and return the empty list if that throws to ENOENT." (catch 'system-error thunk (lambda args (if (= ENOENT (system-error-errno args)) '() (apply throw args))))) (define* (user+group-databases users groups #:key (current-passwd (empty-if-not-found read-passwd)) (current-groups (empty-if-not-found read-group)) (current-shadow (empty-if-not-found read-shadow)) (current-time current-time)) "Return three values: the list of group entries, the list of password entries, and the list of shadow entries corresponding to USERS and GROUPS. Preserve stateful bits from CURRENT-PASSWD, CURRENT-GROUPS, and CURRENT-SHADOW: UIDs, GIDs, passwords, user shells, etc." (define members ;; Map group name to user names. (fold (lambda (user members) (fold (cute vhash-cons <> (user-account-name user) <>) members (user-account-supplementary-groups user))) vlist-null users)) (define group-entries (allocate-groups groups members current-groups)) (define passwd-entries (allocate-passwd users group-entries current-passwd)) (define shadow-entries (passwd->shadow users passwd-entries current-shadow #:current-time current-time)) (values group-entries passwd-entries shadow-entries))