linux-modules.scm 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2014, 2016, 2018, 2019, 2022 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
  4. ;;; Copyright © 2018 Danny Milosavljevic <dannym@scratchpost.org>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  8. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  9. ;;; under the terms of the GNU General Public License as published by
  10. ;;; the Free Software Foundation; either version 3 of the License, or (at
  11. ;;; your option) any later version.
  12. ;;;
  13. ;;; GNU Guix is distributed in the hope that it will be useful, but
  14. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;;; GNU General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU General Public License
  19. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  20. (define-module (gnu build linux-modules)
  21. #:use-module (guix elf)
  22. #:use-module (guix glob)
  23. #:use-module (guix build syscalls)
  24. #:use-module ((guix build utils) #:select (find-files invoke))
  25. #:use-module (guix build union)
  26. #:autoload (zlib) (call-with-gzip-input-port)
  27. #:use-module (rnrs io ports)
  28. #:use-module (rnrs bytevectors)
  29. #:use-module (srfi srfi-1)
  30. #:use-module (srfi srfi-9 gnu)
  31. #:use-module (srfi srfi-11)
  32. #:use-module (srfi srfi-26)
  33. #:use-module (ice-9 ftw)
  34. #:use-module (ice-9 vlist)
  35. #:use-module (ice-9 match)
  36. #:use-module (ice-9 rdelim)
  37. #:autoload (ice-9 pretty-print) (pretty-print)
  38. #:export (dot-ko
  39. ensure-dot-ko
  40. module-formal-name
  41. module-aliases
  42. module-dependencies
  43. module-soft-dependencies
  44. normalize-module-name
  45. file-name->module-name
  46. find-module-file
  47. recursive-module-dependencies
  48. modules-loaded
  49. module-loaded?
  50. load-linux-module*
  51. load-linux-modules-from-directory
  52. pci-devices
  53. pci-device?
  54. pci-device-vendor
  55. pci-device-id
  56. pci-device-class
  57. pci-device-module-alias
  58. storage-pci-device?
  59. network-pci-device?
  60. display-pci-device?
  61. load-pci-device-database
  62. current-module-debugging-port
  63. device-module-aliases
  64. known-module-aliases
  65. matching-modules
  66. missing-modules
  67. write-module-name-database
  68. write-module-alias-database
  69. write-module-device-database
  70. make-linux-module-directory))
  71. ;;; Commentary:
  72. ;;;
  73. ;;; Tools to deal with Linux kernel modules.
  74. ;;;
  75. ;;; Code:
  76. (define current-module-debugging-port
  77. (make-parameter (%make-void-port "w")))
  78. (define (section-contents elf section)
  79. "Return the contents of SECTION in ELF as a bytevector."
  80. (let ((contents (make-bytevector (elf-section-size section))))
  81. (bytevector-copy! (elf-bytes elf) (elf-section-offset section)
  82. contents 0
  83. (elf-section-size section))
  84. contents))
  85. (define %not-nul
  86. (char-set-complement (char-set #\nul)))
  87. (define (nul-separated-string->list str)
  88. "Split STR at occurrences of the NUL character and return the resulting
  89. string list."
  90. (string-tokenize str %not-nul))
  91. (define (key=value->pair str)
  92. "Assuming STR has the form \"KEY=VALUE\", return a pair like (KEY
  93. . \"VALUE\")."
  94. (let ((= (string-index str #\=)))
  95. (cons (string->symbol (string-take str =))
  96. (string-drop str (+ 1 =)))))
  97. ;; Matches kernel modules, without compression, with GZIP compression or with
  98. ;; XZ compression.
  99. (define module-regex "\\.ko(\\.gz|\\.xz)?$")
  100. (define (modinfo-section-contents file)
  101. "Return the contents of the '.modinfo' section of FILE as a list of
  102. key/value pairs.."
  103. (define (get-bytevector file)
  104. (cond
  105. ((string-suffix? ".ko.gz" file)
  106. (let ((port (open-file file "r0")))
  107. (dynamic-wind
  108. (lambda ()
  109. #t)
  110. (lambda ()
  111. (call-with-gzip-input-port port get-bytevector-all))
  112. (lambda ()
  113. (close-port port)))))
  114. (else
  115. (call-with-input-file file get-bytevector-all))))
  116. (let* ((bv (get-bytevector file))
  117. (elf (parse-elf bv))
  118. (section (elf-section-by-name elf ".modinfo"))
  119. (modinfo (section-contents elf section)))
  120. (map key=value->pair
  121. (nul-separated-string->list (utf8->string modinfo)))))
  122. (define %not-comma
  123. (char-set-complement (char-set #\,)))
  124. (define (module-formal-name file)
  125. "Return the module name of FILE as it appears in its info section. Usually
  126. the module name is the same as the base name of FILE, modulo hyphens and minus
  127. the \".ko[.gz|.xz]\" extension."
  128. (match (assq 'name (modinfo-section-contents file))
  129. (('name . name) name)
  130. (#f #f)))
  131. (define (module-dependencies file)
  132. "Return the list of modules that FILE depends on. The returned list
  133. contains module names, not actual file names."
  134. (let ((info (modinfo-section-contents file)))
  135. (match (assq 'depends info)
  136. (('depends . what)
  137. (string-tokenize what %not-comma)))))
  138. (define not-softdep-whitespace
  139. (char-set-complement (char-set #\space #\tab)))
  140. (define (module-soft-dependencies file)
  141. "Return the list of modules that can be preloaded, and then the list of
  142. modules that can be postloaded, of the soft dependencies of module FILE."
  143. ;; TEXT: "pre: baz blubb foo post: bax bar"
  144. (define (parse-softdep text)
  145. (let loop ((value '())
  146. (tokens (string-tokenize text not-softdep-whitespace))
  147. (section #f))
  148. (match tokens
  149. ((token rest ...)
  150. (if (string=? (string-take-right token 1) ":") ; section
  151. (loop value rest (string-trim-both (string-drop-right token 1)))
  152. (loop (cons (cons section token) value) rest section)))
  153. (()
  154. value))))
  155. ;; Note: Multiple 'softdep sections are allowed.
  156. (let* ((info (modinfo-section-contents file))
  157. (entries (concatenate
  158. (filter-map (match-lambda
  159. (('softdep . value)
  160. (parse-softdep value))
  161. (_ #f))
  162. (modinfo-section-contents file)))))
  163. (let-values (((pres posts)
  164. (partition (match-lambda
  165. (("pre" . _) #t)
  166. (("post" . _) #f))
  167. entries)))
  168. (values (map (match-lambda
  169. ((_ . value) value))
  170. pres)
  171. (map (match-lambda
  172. ((_ . value) value))
  173. posts)))))
  174. (define (module-aliases file)
  175. "Return the list of aliases of module FILE."
  176. (let ((info (modinfo-section-contents file)))
  177. (filter-map (match-lambda
  178. (('alias . value)
  179. value)
  180. (_ #f))
  181. (modinfo-section-contents file))))
  182. (define (strip-extension filename)
  183. (let ((extension (string-index filename #\.)))
  184. (if extension
  185. (string-take filename extension)
  186. filename)))
  187. (define (dot-ko name compression)
  188. (let ((suffix (match compression
  189. ('xz ".ko.xz")
  190. ('gzip ".ko.gz")
  191. (else ".ko"))))
  192. (string-append name suffix)))
  193. (define (ensure-dot-ko name compression)
  194. "Return NAME with a '.ko[.gz|.xz]' suffix appended, unless it already has
  195. it."
  196. (if (string-contains name ".ko")
  197. name
  198. (dot-ko name compression)))
  199. (define (normalize-module-name module)
  200. "Return the \"canonical\" name for MODULE, replacing hyphens with
  201. underscores."
  202. ;; See 'modname_normalize' in libkmod.
  203. (string-map (lambda (chr)
  204. (case chr
  205. ((#\-) #\_)
  206. (else chr)))
  207. module))
  208. (define (file-name->module-name file)
  209. "Return the module name corresponding to FILE, stripping the trailing
  210. '.ko[.gz|.xz]' and normalizing it."
  211. (normalize-module-name (strip-extension (basename file))))
  212. (define (find-module-file directory module)
  213. "Lookup module NAME under DIRECTORY, and return its absolute file name.
  214. NAME can be a file name with or without '.ko', or it can be a module name.
  215. Raise an error if it could not be found.
  216. Module names can differ from file names in interesting ways; for instance,
  217. module names usually (always?) use underscores as the inter-word separator,
  218. whereas file names often, but not always, use hyphens. Examples:
  219. \"usb-storage.ko\", \"serpent_generic.ko\"."
  220. (define names
  221. ;; List of possible file names. XXX: It would of course be cleaner to
  222. ;; have a database that maps module names to file names and vice versa,
  223. ;; but everyone seems to be doing hacks like this one. Oh well!
  224. (delete-duplicates
  225. (list module
  226. (normalize-module-name module)
  227. (string-map (lambda (chr) ;converse of 'normalize-module-name'
  228. (case chr
  229. ((#\_) #\-)
  230. (else chr)))
  231. module))))
  232. (match (find-files directory
  233. (lambda (file stat)
  234. (member (strip-extension
  235. (basename file)) names)))
  236. ((file)
  237. file)
  238. (()
  239. (error "kernel module not found" module directory))
  240. ((_ ...)
  241. (error "several modules by that name" module directory))))
  242. (define* (recursive-module-dependencies files
  243. #:key (lookup-module dot-ko))
  244. "Return the topologically-sorted list of file names of the modules depended
  245. on by FILES, recursively. File names of modules are determined by applying
  246. LOOKUP-MODULE to the module name."
  247. (let loop ((files files)
  248. (result '())
  249. (visited vlist-null))
  250. (match files
  251. (()
  252. (delete-duplicates (reverse result)))
  253. ((head . tail)
  254. (let* ((visited? (vhash-assoc head visited))
  255. (deps (if visited?
  256. '()
  257. (map lookup-module (module-dependencies head))))
  258. (visited (if visited?
  259. visited
  260. (vhash-cons head #t visited))))
  261. (loop (append deps tail)
  262. (append result deps) visited))))))
  263. (define %not-newline
  264. (char-set-complement (char-set #\newline)))
  265. (define (modules-loaded)
  266. "Return the list of names of currently loaded Linux modules."
  267. (let* ((contents (call-with-input-file "/proc/modules"
  268. get-string-all))
  269. (lines (string-tokenize contents %not-newline)))
  270. (match (map string-tokenize lines)
  271. (((modules . _) ...)
  272. modules))))
  273. (define (module-black-list)
  274. "Return the black list of modules that must not be loaded. This black list
  275. is specified using 'modprobe.blacklist=MODULE1,MODULE2,...' on the kernel
  276. command line; it is honored by libkmod for users that pass
  277. 'KMOD_PROBE_APPLY_BLACKLIST', which includes 'modprobe --use-blacklist' and
  278. udev."
  279. (define parameter
  280. "modprobe.blacklist=")
  281. (let ((command (call-with-input-file "/proc/cmdline"
  282. get-string-all)))
  283. (append-map (lambda (arg)
  284. (if (string-prefix? parameter arg)
  285. (string-tokenize (string-drop arg (string-length parameter))
  286. %not-comma)
  287. '()))
  288. (string-tokenize command))))
  289. (define (module-loaded? module)
  290. "Return #t if MODULE is already loaded. MODULE must be a Linux module name,
  291. not a file name."
  292. (member module (modules-loaded)))
  293. (define* (load-linux-module* file
  294. #:key
  295. (recursive? #t)
  296. (lookup-module dot-ko)
  297. (black-list (module-black-list)))
  298. "Load Linux module from FILE, the name of a '.ko[.gz|.xz]' file; return true
  299. on success, false otherwise. When RECURSIVE? is true, load its dependencies
  300. first (à la 'modprobe'.) The actual files containing modules depended on are
  301. obtained by calling LOOKUP-MODULE with the module name. Modules whose name
  302. appears in BLACK-LIST are not loaded."
  303. (define (black-listed? module)
  304. (let ((result (member module black-list)))
  305. (when result
  306. (format (current-module-debugging-port)
  307. "not loading module '~a' because it's black-listed~%"
  308. module))
  309. result))
  310. (define (load-dependencies file)
  311. (let ((dependencies (module-dependencies file)))
  312. (every (cut load-linux-module* <>
  313. #:lookup-module lookup-module
  314. #:black-list black-list)
  315. (map lookup-module dependencies))))
  316. (and (not (black-listed? (file-name->module-name file)))
  317. (or (not recursive?)
  318. (load-dependencies file))
  319. (let ((fd #f))
  320. (format (current-module-debugging-port)
  321. "loading Linux module from '~a'...~%" file)
  322. (catch 'system-error
  323. (lambda ()
  324. (set! fd (open-fdes file O_RDONLY))
  325. (load-linux-module/fd fd)
  326. (close-fdes fd)
  327. #t)
  328. (lambda args
  329. (when fd (close-fdes fd))
  330. (let ((errno (system-error-errno args)))
  331. (or (and recursive? ; we're operating in ‘modprobe’ style
  332. (member errno
  333. (list EEXIST ; already loaded
  334. EINVAL))) ; unsupported by hardware
  335. (apply throw args))))))))
  336. (define (load-linux-modules-from-directory modules directory)
  337. "Load MODULES and their dependencies from DIRECTORY, a directory containing
  338. the '.ko' files. The '.ko' suffix is automatically added to MODULES if
  339. needed."
  340. (define module-name->file-name
  341. (module-name-lookup directory))
  342. (for-each (lambda (module)
  343. (load-linux-module* (module-name->file-name module)
  344. #:lookup-module module-name->file-name))
  345. modules))
  346. ;;;
  347. ;;; Device modules.
  348. ;;;
  349. ;; Copied from (guix utils). FIXME: Factorize.
  350. (define (readlink* file)
  351. "Call 'readlink' until the result is not a symlink."
  352. (define %max-symlink-depth 50)
  353. (let loop ((file file)
  354. (depth 0))
  355. (define (absolute target)
  356. (if (absolute-file-name? target)
  357. target
  358. (string-append (dirname file) "/" target)))
  359. (if (>= depth %max-symlink-depth)
  360. file
  361. (call-with-values
  362. (lambda ()
  363. (catch 'system-error
  364. (lambda ()
  365. (values #t (readlink file)))
  366. (lambda args
  367. (let ((errno (system-error-errno args)))
  368. (if (or (= errno EINVAL))
  369. (values #f file)
  370. (apply throw args))))))
  371. (lambda (success? target)
  372. (if success?
  373. (loop (absolute target) (+ depth 1))
  374. file))))))
  375. ;; See 'major' and 'minor' in <sys/sysmacros.h>.
  376. (define (stat->device-major st)
  377. (ash (logand #xfff00 (stat:rdev st)) -8))
  378. (define (stat->device-minor st)
  379. (logand #xff (stat:rdev st)))
  380. (define %not-slash
  381. (char-set-complement (char-set #\/)))
  382. (define (read-uevent port)
  383. "Read a /sys 'uevent' file from PORT and return an alist where each car is a
  384. key such as 'MAJOR or 'DEVTYPE and each cdr is the corresponding value."
  385. (let loop ((result '()))
  386. (match (read-line port)
  387. ((? eof-object?)
  388. (reverse result))
  389. (line
  390. (loop (cons (key=value->pair line) result))))))
  391. ;; PCI device known to the Linux kernel.
  392. (define-immutable-record-type <pci-device>
  393. (pci-device vendor device class module-alias)
  394. pci-device?
  395. (vendor pci-device-vendor) ;integer
  396. (device pci-device-id) ;integer
  397. (class pci-device-class) ;integer
  398. (module-alias pci-device-module-alias)) ;string | #f
  399. (define (pci-device-class-predicate mask bits)
  400. (lambda (device)
  401. "Return true if DEVICE has the chosen class."
  402. (= (logand mask (pci-device-class device)) bits)))
  403. (define storage-pci-device? ;"Mass storage controller" class
  404. (pci-device-class-predicate #xff0000 #x010000))
  405. (define network-pci-device? ;"Network controller" class
  406. (pci-device-class-predicate #xff0000 #x020000))
  407. (define display-pci-device? ;"Display controller" class
  408. (pci-device-class-predicate #xff0000 #x030000))
  409. (define (pci-devices)
  410. "Return the list of PCI devices of the system (<pci-device> records)."
  411. (define (read-hex port)
  412. (let ((line (read-line port)))
  413. (and (string? line)
  414. (string-prefix? "0x" line)
  415. (string->number (string-drop line 2) 16))))
  416. (filter-map (lambda (directory)
  417. (define properties
  418. (call-with-input-file (string-append directory "/uevent")
  419. read-uevent))
  420. (define vendor
  421. (call-with-input-file (string-append directory "/vendor")
  422. read-hex))
  423. (define device
  424. (call-with-input-file (string-append directory "/device")
  425. read-hex))
  426. (define class
  427. (call-with-input-file (string-append directory "/class")
  428. read-hex))
  429. (pci-device vendor device class
  430. (assq-ref properties 'MODALIAS)))
  431. (find-files "/sys/bus/pci/devices"
  432. #:stat lstat)))
  433. (define (read-pci-device-database port)
  434. "Parse the 'pci.ids' database that ships with the pciutils package and is
  435. maintained at <https://pci-ids.ucw.cz/>."
  436. (define (comment? str)
  437. (string-prefix? "#" (string-trim str)))
  438. (define (blank? str)
  439. (string-null? (string-trim-both str)))
  440. (define (device? str)
  441. (eqv? #\tab (string-ref str 0)))
  442. (define (subvendor? str)
  443. (string-prefix? "\t\t" str))
  444. (define (class? str)
  445. (string-prefix? "C " str))
  446. (define (parse-id-line str)
  447. (let* ((str (string-trim-both str))
  448. (space (string-index str char-set:whitespace)))
  449. (values (string->number (string-take str space) 16)
  450. (string-trim (string-drop str (+ 1 space))))))
  451. (define (finish vendor vendor-id devices table)
  452. (fold (lambda (device table)
  453. (match device
  454. ((device-id . name)
  455. (vhash-consv (logior (ash vendor-id 16) device-id)
  456. (cons vendor name)
  457. table))))
  458. table
  459. devices))
  460. (let loop ((table vlist-null)
  461. (vendor-id #f)
  462. (vendor #f)
  463. (devices '()))
  464. (match (read-line port)
  465. ((? eof-object?)
  466. (let ((table (if (and vendor vendor-id)
  467. (finish vendor vendor-id devices table)
  468. table)))
  469. (lambda (vendor device)
  470. (match (vhash-assv (logior (ash vendor 16) device) table)
  471. (#f
  472. (values #f #f))
  473. ((_ . (vendor . name))
  474. (values vendor name))))))
  475. ((? comment?)
  476. (loop table vendor-id vendor devices))
  477. ((? blank?)
  478. (loop table vendor-id vendor devices))
  479. ((? subvendor?) ;currently ignored
  480. (loop table vendor-id vendor devices))
  481. ((? class?) ;currently ignored
  482. (loop table vendor-id vendor devices))
  483. ((? device? line)
  484. (let-values (((id name) (parse-id-line line)))
  485. (loop table vendor-id vendor
  486. (if (and vendor-id vendor) ;class or device?
  487. (alist-cons id name devices)
  488. devices))))
  489. (line
  490. (let ((table (if (and vendor vendor-id)
  491. (finish vendor vendor-id devices table)
  492. table)))
  493. (let-values (((vendor-id vendor) (parse-id-line line)))
  494. (loop table vendor-id vendor '())))))))
  495. (define (load-pci-device-database file)
  496. "Read the 'pci.ids' database at FILE (get it from the pciutils package or
  497. from <https://pci-ids.ucw.cz/>) and return a lookup procedure that takes a PCI
  498. vendor ID and a device ID (two integers) and returns the vendor name and
  499. device name as two values."
  500. (let ((port (open-file file "r0")))
  501. (call-with-gzip-input-port port
  502. read-pci-device-database)))
  503. (define (device-module-aliases device)
  504. "Return the list of module aliases required by DEVICE, a /dev file name, as
  505. in this example:
  506. (device-module-aliases \"/dev/sda\")
  507. => (\"scsi:t-0x00\" \"pci:v00008086d00009D03sv0000103Csd000080FAbc01sc06i01\")
  508. The modules corresponding to these aliases can then be found using
  509. 'matching-modules'."
  510. ;; The approach is adapted from
  511. ;; <https://unix.stackexchange.com/questions/97676/how-to-find-the-driver-module-associated-with-a-device-on-linux>.
  512. (let* ((st (stat device))
  513. (type (stat:type st))
  514. (major (stat->device-major st))
  515. (minor (stat->device-minor st))
  516. (sys-name (string-append "/sys/dev/"
  517. (case type
  518. ((block-special) "block")
  519. ((char-special) "char")
  520. (else (symbol->string type)))
  521. "/" (number->string major) ":"
  522. (number->string minor)))
  523. (directory (canonicalize-path (readlink* sys-name))))
  524. (let loop ((components (string-tokenize directory %not-slash))
  525. (aliases '()))
  526. (match components
  527. (("sys" "devices" _)
  528. (reverse aliases))
  529. ((head ... _)
  530. (let ((uevent (string-append (string-join components "/" 'prefix)
  531. "/uevent")))
  532. (if (file-exists? uevent)
  533. (let ((props (call-with-input-file uevent read-uevent)))
  534. (match (assq-ref props 'MODALIAS)
  535. (#f (loop head aliases))
  536. (alias (loop head (cons alias aliases)))))
  537. (loop head aliases))))))))
  538. (define (read-module-aliases port)
  539. "Read from PORT data in the Linux 'modules.alias' file format. Return a
  540. list of alias/module pairs where each alias is a glob pattern as like the
  541. result of:
  542. (string->compiled-sglob \"scsi:t-0x01*\")
  543. and each module is a module name like \"snd_hda_intel\"."
  544. (define (comment? str)
  545. (string-prefix? "#" str))
  546. (define (tokenize str)
  547. ;; Lines have the form "alias ALIAS MODULE", where ALIAS can contain
  548. ;; whitespace. This is why we don't use 'string-tokenize'.
  549. (let* ((str (string-trim-both str))
  550. (left (string-index str #\space))
  551. (right (string-rindex str #\space)))
  552. (list (string-take str left)
  553. (string-trim-both (substring str left right))
  554. (string-trim-both (string-drop str right)))))
  555. (let loop ((aliases '()))
  556. (match (read-line port)
  557. ((? eof-object?)
  558. (reverse aliases))
  559. ((? comment?)
  560. (loop aliases))
  561. (line
  562. (match (tokenize line)
  563. (("alias" alias module)
  564. (loop (alist-cons (string->compiled-sglob alias) module
  565. aliases)))
  566. (() ;empty line
  567. (loop aliases)))))))
  568. (define (current-kernel-directory)
  569. "Return the directory of the currently running Linux kernel."
  570. (string-append (or (getenv "LINUX_MODULE_DIRECTORY")
  571. "/run/booted-system/kernel/lib/modules")
  572. "/" (utsname:release (uname))))
  573. (define (current-alias-file)
  574. "Return the absolute file name of the default 'modules.alias' file."
  575. (string-append (current-kernel-directory) "/modules.alias"))
  576. (define* (known-module-aliases #:optional (alias-file (current-alias-file)))
  577. "Return the list of alias/module pairs read from ALIAS-FILE. Each alias is
  578. actually a pattern."
  579. (call-with-input-file alias-file read-module-aliases))
  580. (define* (matching-modules alias
  581. #:optional (known-aliases (known-module-aliases)))
  582. "Return the list of modules that match ALIAS according to KNOWN-ALIASES.
  583. ALIAS is a string like \"scsi:t-0x00\" as returned by
  584. 'device-module-aliases'."
  585. (filter-map (match-lambda
  586. ((pattern . module)
  587. (and (glob-match? pattern alias)
  588. module)))
  589. known-aliases))
  590. (define* (missing-modules device modules-provided)
  591. "Assuming MODULES-PROVIDED lists kernel modules that are already
  592. provided--e.g., in the initrd, return the list of missing kernel modules that
  593. are required to access DEVICE."
  594. (define aliases
  595. ;; Attempt to load 'modules.alias' from the current kernel, assuming we're
  596. ;; on Guix System, and assuming that corresponds to the kernel we'll be
  597. ;; installing.
  598. (known-module-aliases))
  599. (if aliases
  600. (let* ((modules (delete-duplicates
  601. (append-map (cut matching-modules <> aliases)
  602. (device-module-aliases device))))
  603. ;; Module names (not file names) are supposed to use underscores
  604. ;; instead of hyphens. MODULES is a list of module names, whereas
  605. ;; LINUX-MODULES is file names without '.ko', so normalize them.
  606. (provided (map file-name->module-name modules-provided)))
  607. (remove (cut member <> provided) modules))
  608. '()))
  609. ;;;
  610. ;;; Module databases.
  611. ;;;
  612. (define* (module-name->file-name/guess directory name
  613. #:key compression)
  614. "Guess the file name corresponding to NAME, a module name. That doesn't
  615. always work because sometimes underscores in NAME map to hyphens (e.g.,
  616. \"input-leds.ko\"), sometimes not (e.g., \"mac_hid.ko\"). If the module is
  617. compressed then COMPRESSED can be set to 'xz or 'gzip, depending on the
  618. compression type."
  619. (string-append directory "/" (ensure-dot-ko name compression)))
  620. (define (module-name-lookup directory)
  621. "Return a one argument procedure that takes a module name (e.g.,
  622. \"input_leds\") and returns its absolute file name (e.g.,
  623. \"/.../input-leds.ko\")."
  624. (define (guess-file-name name)
  625. (let ((names (list
  626. (module-name->file-name/guess directory name)
  627. (module-name->file-name/guess directory name
  628. #:compression 'xz)
  629. (module-name->file-name/guess directory name
  630. #:compression 'gzip))))
  631. (or (find file-exists? names)
  632. (first names))))
  633. (catch 'system-error
  634. (lambda ()
  635. (define mapping
  636. (call-with-input-file (string-append directory "/modules.name")
  637. read))
  638. (lambda (name)
  639. (or (assoc-ref mapping name)
  640. (guess-file-name name))))
  641. (lambda args
  642. (if (= ENOENT (system-error-errno args))
  643. (cut guess-file-name <>)
  644. (apply throw args)))))
  645. (define (write-module-name-database directory)
  646. "Write a database that maps \"module names\" as they appear in the relevant
  647. ELF section of '.ko[.gz|.xz]' files, to actual file names. This format is
  648. Guix-specific. It aims to deal with inconsistent naming, in particular
  649. hyphens vs. underscores."
  650. (define mapping
  651. (map (lambda (file)
  652. (match (module-formal-name file)
  653. (#f (cons (strip-extension (basename file)) file))
  654. (name (cons name file))))
  655. (find-files directory module-regex)))
  656. (call-with-output-file (string-append directory "/modules.name")
  657. (lambda (port)
  658. (display ";; Module name to file name mapping.
  659. ;;
  660. ;; This format is Guix-specific; it is not supported by upstream Linux tools.
  661. \n"
  662. port)
  663. (pretty-print mapping port))))
  664. (define (write-module-alias-database directory)
  665. "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding
  666. 'modules.alias' file."
  667. (define aliases
  668. (map (lambda (file)
  669. (cons (file-name->module-name file) (module-aliases file)))
  670. (find-files directory module-regex)))
  671. (call-with-output-file (string-append directory "/modules.alias")
  672. (lambda (port)
  673. (display "# Aliases extracted from modules themselves.\n" port)
  674. (for-each (match-lambda
  675. ((module . aliases)
  676. (for-each (lambda (alias)
  677. (format port "alias ~a ~a\n" alias module))
  678. aliases)))
  679. aliases))))
  680. (define (aliases->device-tuple aliases)
  681. "Traverse ALIASES, a list of module aliases, and search for
  682. \"char-major-M-N\", \"block-major-M-N\", or \"devname:\" aliases. When they
  683. are found, return a tuple (DEVNAME TYPE MAJOR MINOR), otherwise return #f."
  684. (define (char/block-major? alias)
  685. (or (string-prefix? "char-major-" alias)
  686. (string-prefix? "block-major-" alias)))
  687. (define (char/block-major->tuple alias)
  688. (match (string-tokenize alias %not-dash)
  689. ((type "major" (= string->number major) (= string->number minor))
  690. (list (match type
  691. ("char" "c")
  692. ("block" "b"))
  693. major minor))))
  694. (let* ((devname (any (lambda (alias)
  695. (and (string-prefix? "devname:" alias)
  696. (string-drop alias 8)))
  697. aliases))
  698. (major/minor (match (find char/block-major? aliases)
  699. (#f #f)
  700. (str (char/block-major->tuple str)))))
  701. (and devname major/minor
  702. (cons devname major/minor))))
  703. (define %not-dash
  704. (char-set-complement (char-set #\-)))
  705. (define (write-module-device-database directory)
  706. "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding
  707. 'modules.devname' file. This file contains information about modules that can
  708. be loaded on-demand, such as file system modules."
  709. (define aliases
  710. (filter-map (lambda (file)
  711. (match (aliases->device-tuple (module-aliases file))
  712. (#f #f)
  713. (tuple (cons (file-name->module-name file) tuple))))
  714. (find-files directory module-regex)))
  715. (call-with-output-file (string-append directory "/modules.devname")
  716. (lambda (port)
  717. (display "# Device nodes to trigger on-demand module loading.\n" port)
  718. (for-each (match-lambda
  719. ((module devname type major minor)
  720. (format port "~a ~a ~a~a:~a~%"
  721. module devname type major minor)))
  722. aliases))))
  723. (define (depmod version directory)
  724. "Given an (existing) DIRECTORY, invoke depmod on it for
  725. kernel version VERSION."
  726. (let ((destination-directory (string-append directory "/lib/modules/"
  727. version))
  728. ;; Note: "System.map" is an input file.
  729. (maps-file (string-append directory "/System.map"))
  730. ;; Note: "Module.symvers" is an input file.
  731. (symvers-file (string-append directory "/Module.symvers")))
  732. ;; These files will be regenerated by depmod below.
  733. (for-each (lambda (basename)
  734. (when (and (string-prefix? "modules." basename)
  735. ;; Note: "modules.builtin" is an input file.
  736. (not (string=? "modules.builtin" basename))
  737. ;; Note: "modules.order" is an input file.
  738. (not (string=? "modules.order" basename)))
  739. (delete-file (string-append destination-directory "/"
  740. basename))))
  741. (scandir destination-directory))
  742. (invoke "depmod"
  743. "-e" ; Report symbols that aren't supplied
  744. ;"-w" ; Warn on duplicates
  745. "-b" directory
  746. "-F" maps-file
  747. ;"-E" symvers-file ; using both "-E" and "-F" is not possible.
  748. version)))
  749. (define (make-linux-module-directory inputs version output)
  750. "Create a new directory OUTPUT and ensure that the directory
  751. OUTPUT/lib/modules/VERSION can be used as a source of Linux
  752. kernel modules for the first kmod in PATH now to eventually
  753. load. Take modules to put into OUTPUT from INPUTS.
  754. Right now that means it creates @code{modules.*.bin} which
  755. @command{modprobe} will use to find loadable modules."
  756. (union-build output inputs #:create-all-directories? #t)
  757. (depmod version output))
  758. ;;; linux-modules.scm ends here