]> git.ipfire.org Git - thirdparty/dracut.git/blob - install/dracut-install.c
dracut_mkdir(): create parent directories as needed.
[thirdparty/dracut.git] / install / dracut-install.c
1 /* dracut-install.c -- install files and executables
2
3 Copyright (C) 2012 Harald Hoyer
4 Copyright (C) 2012 Red Hat, Inc. All rights reserved.
5
6 This program is free software: you can redistribute it and/or modify
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program; If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #define PROGRAM_VERSION_STRING "2"
21
22 #ifndef _GNU_SOURCE
23 #define _GNU_SOURCE
24 #endif
25 #undef _FILE_OFFSET_BITS
26 #include <ctype.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <getopt.h>
30 #include <libgen.h>
31 #include <limits.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
40 #include <sys/ioctl.h>
41 #include <libkmod.h>
42 #include <fts.h>
43 #include <regex.h>
44 #include <sys/utsname.h>
45
46 #include "log.h"
47 #include "hashmap.h"
48 #include "util.h"
49 #include "strv.h"
50
51 static bool arg_hmac = false;
52 static bool arg_createdir = false;
53 static int arg_loglevel = -1;
54 static bool arg_optional = false;
55 static bool arg_silent = false;
56 static bool arg_all = false;
57 static bool arg_module = false;
58 static bool arg_modalias = false;
59 static bool arg_resolvelazy = false;
60 static bool arg_resolvedeps = false;
61 static bool arg_hostonly = false;
62 static bool no_xattr = false;
63 static char *destrootdir = NULL;
64 static char *sysrootdir = NULL;
65 static size_t sysrootdirlen = 0;
66 static char *kerneldir = NULL;
67 static size_t kerneldirlen = 0;
68 static char **firmwaredirs = NULL;
69 static char **pathdirs;
70 static char *ldd = NULL;
71 static char *logdir = NULL;
72 static char *logfile = NULL;
73 FILE *logfile_f = NULL;
74 static Hashmap *items = NULL;
75 static Hashmap *items_failed = NULL;
76 static Hashmap *modules_loaded = NULL;
77 static regex_t mod_filter_path;
78 static regex_t mod_filter_nopath;
79 static regex_t mod_filter_symbol;
80 static regex_t mod_filter_nosymbol;
81 static regex_t mod_filter_noname;
82 static bool arg_mod_filter_path = false;
83 static bool arg_mod_filter_nopath = false;
84 static bool arg_mod_filter_symbol = false;
85 static bool arg_mod_filter_nosymbol = false;
86 static bool arg_mod_filter_noname = false;
87
88 static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps, bool hashdst);
89
90
91 static inline void kmod_module_unrefp(struct kmod_module **p) {
92 if (*p)
93 kmod_module_unref(*p);
94 }
95 #define _cleanup_kmod_module_unref_ _cleanup_(kmod_module_unrefp)
96
97 static inline void kmod_module_unref_listp(struct kmod_list **p) {
98 if (*p)
99 kmod_module_unref_list(*p);
100 }
101 #define _cleanup_kmod_module_unref_list_ _cleanup_(kmod_module_unref_listp)
102
103 static inline void kmod_module_info_free_listp(struct kmod_list **p) {
104 if (*p)
105 kmod_module_info_free_list(*p);
106 }
107 #define _cleanup_kmod_module_info_free_list_ _cleanup_(kmod_module_info_free_listp)
108
109 static inline void kmod_unrefp(struct kmod_ctx **p) {
110 kmod_unref(*p);
111 }
112 #define _cleanup_kmod_unref_ _cleanup_(kmod_unrefp)
113
114 static inline void kmod_module_dependency_symbols_free_listp(struct kmod_list **p) {
115 if (*p)
116 kmod_module_dependency_symbols_free_list(*p);
117 }
118 #define _cleanup_kmod_module_dependency_symbols_free_list_ _cleanup_(kmod_module_dependency_symbols_free_listp)
119
120 static inline void fts_closep(FTS **p) {
121 if (*p)
122 fts_close(*p);
123 }
124 #define _cleanup_fts_close_ _cleanup_(fts_closep)
125
126
127
128 static size_t dir_len(char const *file)
129 {
130 size_t length;
131
132 if (!file)
133 return 0;
134
135 /* Strip the basename and any redundant slashes before it. */
136 for (length = strlen(file) - 1; 0 < length; length--)
137 if (file[length] == '/' && file[length - 1] != '/')
138 break;
139 return length;
140 }
141
142 static char *convert_abs_rel(const char *from, const char *target)
143 {
144 /* we use the 4*MAXPATHLEN, which should not overrun */
145 char relative_from[MAXPATHLEN * 4];
146 _cleanup_free_ char *realtarget = NULL;
147 _cleanup_free_ char *target_dir_p = NULL, *realpath_p = NULL;
148 const char *realfrom = from;
149 size_t level = 0, fromlevel = 0, targetlevel = 0;
150 int l;
151 size_t i, rl, dirlen;
152 int ret;
153
154 target_dir_p = strdup(target);
155 if (!target_dir_p)
156 return strdup(from);
157
158 dirlen = dir_len(target_dir_p);
159 target_dir_p[dirlen] = '\0';
160 realpath_p = realpath(target_dir_p, NULL);
161
162 if (realpath_p == NULL) {
163 log_warning("convert_abs_rel(): target '%s' directory has no realpath.", target);
164 return strdup(from);
165 }
166
167 /* dir_len() skips double /'s e.g. //lib64, so we can't skip just one
168 * character - need to skip all leading /'s */
169 rl = strlen(target);
170 for (i = dirlen + 1; i < rl; ++i)
171 if (target_dir_p[i] != '/')
172 break;
173 ret = asprintf(&realtarget, "%s/%s", realpath_p, &target_dir_p[i]);
174 if (ret < 0) {
175 log_error("Out of memory!");
176 exit(EXIT_FAILURE);
177 }
178
179 /* now calculate the relative path from <from> to <target> and
180 store it in <relative_from>
181 */
182 relative_from[0] = 0;
183 rl = 0;
184
185 /* count the pathname elements of realtarget */
186 for (targetlevel = 0, i = 0; realtarget[i]; i++)
187 if (realtarget[i] == '/')
188 targetlevel++;
189
190 /* count the pathname elements of realfrom */
191 for (fromlevel = 0, i = 0; realfrom[i]; i++)
192 if (realfrom[i] == '/')
193 fromlevel++;
194
195 /* count the pathname elements, which are common for both paths */
196 for (level = 0, i = 0; realtarget[i] && (realtarget[i] == realfrom[i]); i++)
197 if (realtarget[i] == '/')
198 level++;
199
200 /* add "../" to the relative_from path, until the common pathname is
201 reached */
202 for (i = level; i < targetlevel; i++) {
203 if (i != level)
204 relative_from[rl++] = '/';
205 relative_from[rl++] = '.';
206 relative_from[rl++] = '.';
207 }
208
209 /* set l to the next uncommon pathname element in realfrom */
210 for (l = 1, i = 1; i < level; i++)
211 for (l++; realfrom[l] && realfrom[l] != '/'; l++) ;
212 /* skip next '/' */
213 l++;
214
215 /* append the uncommon rest of realfrom to the relative_from path */
216 for (i = level; i <= fromlevel; i++) {
217 if (rl)
218 relative_from[rl++] = '/';
219 while (realfrom[l] && realfrom[l] != '/')
220 relative_from[rl++] = realfrom[l++];
221 l++;
222 }
223
224 relative_from[rl] = 0;
225 return strdup(relative_from);
226 }
227
228 static int ln_r(const char *src, const char *dst)
229 {
230 int ret;
231 _cleanup_free_ const char *points_to = convert_abs_rel(src, dst);
232
233 log_info("ln -s '%s' '%s'", points_to, dst);
234 ret = symlink(points_to, dst);
235
236 if (ret != 0) {
237 log_error("ERROR: ln -s '%s' '%s': %m", points_to, dst);
238 return 1;
239 }
240
241 return 0;
242 }
243
244 /* Perform the O(1) btrfs clone operation, if possible.
245 Upon success, return 0. Otherwise, return -1 and set errno. */
246 static inline int clone_file(int dest_fd, int src_fd)
247 {
248 #undef BTRFS_IOCTL_MAGIC
249 #define BTRFS_IOCTL_MAGIC 0x94
250 #undef BTRFS_IOC_CLONE
251 #define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int)
252 return ioctl(dest_fd, BTRFS_IOC_CLONE, src_fd);
253 }
254
255 static bool use_clone = true;
256
257 static int cp(const char *src, const char *dst)
258 {
259 int pid;
260 int ret = 0;
261
262 if (use_clone) {
263 struct stat sb;
264 _cleanup_close_ int dest_desc = -1, source_desc = -1;
265
266 if (lstat(src, &sb) != 0)
267 goto normal_copy;
268
269 if (S_ISLNK(sb.st_mode))
270 goto normal_copy;
271
272 source_desc = open(src, O_RDONLY | O_CLOEXEC);
273 if (source_desc < 0)
274 goto normal_copy;
275
276 dest_desc =
277 open(dst, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC,
278 (sb.st_mode) & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO));
279
280 if (dest_desc < 0) {
281 goto normal_copy;
282 }
283
284 ret = clone_file(dest_desc, source_desc);
285
286 if (ret == 0) {
287 struct timeval tv[2];
288 if (fchown(dest_desc, sb.st_uid, sb.st_gid) != 0)
289 if(fchown(dest_desc, (uid_t) - 1, sb.st_gid) != 0) {
290 if (geteuid() == 0)
291 log_error("Failed to chown %s: %m", dst);
292 else
293 log_info("Failed to chown %s: %m", dst);
294 }
295
296 tv[0].tv_sec = sb.st_atime;
297 tv[0].tv_usec = 0;
298 tv[1].tv_sec = sb.st_mtime;
299 tv[1].tv_usec = 0;
300 futimes(dest_desc, tv);
301 return ret;
302 }
303 close(dest_desc);
304 dest_desc = -1;
305 /* clone did not work, remove the file */
306 unlink(dst);
307 /* do not try clone again */
308 use_clone = false;
309 }
310
311 normal_copy:
312 pid = fork();
313 if (pid == 0) {
314 if (geteuid() == 0 && no_xattr == false)
315 execlp("cp", "cp", "--reflink=auto", "--sparse=auto", "--preserve=mode,xattr,timestamps", "-fL", src, dst,
316 NULL);
317 else
318 execlp("cp", "cp", "--reflink=auto", "--sparse=auto", "--preserve=mode,timestamps", "-fL", src, dst,
319 NULL);
320 _exit(EXIT_FAILURE);
321 }
322
323 while (waitpid(pid, &ret, 0) < 0) {
324 if (errno != EINTR) {
325 ret = -1;
326 if (geteuid() == 0 && no_xattr == false)
327 log_error("Failed: cp --reflink=auto --sparse=auto --preserve=mode,xattr,timestamps -fL %s %s", src,
328 dst);
329 else
330 log_error("Failed: cp --reflink=auto --sparse=auto --preserve=mode,timestamps -fL %s %s", src,
331 dst);
332 break;
333 }
334 }
335 log_debug("cp ret = %d", ret);
336 return ret;
337 }
338
339 static int library_install(const char *src, const char *lib)
340 {
341 _cleanup_free_ char *p = NULL;
342 _cleanup_free_ char *pdir = NULL, *ppdir = NULL, *clib = NULL;
343 char *q;
344 int r, ret = 0;
345
346 p = strdup(lib);
347
348 r = dracut_install(p, p, false, false, true);
349 if (r != 0)
350 log_error("ERROR: failed to install '%s' for '%s'", p, src);
351 else
352 log_debug("Lib install: '%s'", p);
353 ret += r;
354
355 /* also install lib.so for lib.so.* files */
356 q = strstr(p, ".so.");
357 if (q) {
358 q[3] = '\0';
359
360 /* ignore errors for base lib symlink */
361 if (dracut_install(p, p, false, false, true) == 0)
362 log_debug("Lib install: '%s'", p);
363 }
364
365 /* Also try to install the same library from one directory above.
366 This fixes the case, where only the HWCAP lib would be installed
367 # ldconfig -p|grep -F libc.so
368 libc.so.6 (libc6,64bit, hwcap: 0x0000001000000000, OS ABI: Linux 2.6.32) => /lib64/power6/libc.so.6
369 libc.so.6 (libc6,64bit, hwcap: 0x0000000000000200, OS ABI: Linux 2.6.32) => /lib64/power6x/libc.so.6
370 libc.so.6 (libc6,64bit, OS ABI: Linux 2.6.32) => /lib64/libc.so.6
371 */
372
373 free(p);
374 p = strdup(lib);
375
376 pdir = dirname(p);
377 if (!pdir)
378 return ret;
379
380 pdir = strdup(pdir);
381 ppdir = dirname(pdir);
382 if (!ppdir)
383 return ret;
384
385 ppdir = strdup(ppdir);
386
387 strcpy(p, lib);
388
389 clib = strjoin(ppdir, "/", basename(p), NULL);
390 if (dracut_install(clib, clib, false, false, true) == 0)
391 log_debug("Lib install: '%s'", clib);
392 /* also install lib.so for lib.so.* files */
393 q = strstr(clib, ".so.");
394 if (q) {
395 q[3] = '\0';
396
397 /* ignore errors for base lib symlink */
398 if (dracut_install(clib, clib, false, false, true) == 0)
399 log_debug("Lib install: '%s'", p);
400 }
401
402 return ret;
403 }
404
405 static char *get_real_file(const char *src, bool fullyresolve)
406 {
407 char linktarget[PATH_MAX + 1];
408 ssize_t linksz;
409 _cleanup_free_ char *fullsrcpath;
410 char *abspath = NULL;
411 struct stat sb;
412
413 if (sysrootdirlen) {
414 if (strncmp(src, sysrootdir, sysrootdirlen) == 0)
415 fullsrcpath = strdup(src);
416 else if (asprintf(&fullsrcpath, "%s/%s", (sysrootdirlen ? sysrootdir : ""), (src[0] == '/' ? src+1 : src)) < 0)
417 _exit(EXIT_FAILURE);
418 } else
419 fullsrcpath = strdup(src);
420
421 log_debug("get_real_file('%s')", fullsrcpath);
422
423 if (lstat(fullsrcpath, &sb) < 0)
424 return NULL;
425
426 switch (sb.st_mode & S_IFMT) {
427 case S_IFDIR:
428 case S_IFREG:
429 return strdup(fullsrcpath);
430 case S_IFLNK:
431 break;
432 default:
433 return NULL;
434 }
435
436 linksz = readlink(fullsrcpath, linktarget, sizeof(linktarget));
437 if (linksz < 0)
438 return NULL;
439 linktarget[linksz] = '\0';
440
441 log_debug("get_real_file: readlink('%s') returns '%s'", fullsrcpath, linktarget);
442
443 if (linktarget[0] == '/') {
444 if (asprintf(&abspath, "%s%s", (sysrootdirlen ? sysrootdir : ""), linktarget) < 0)
445 return NULL;
446 } else {
447 _cleanup_free_ char *fullsrcdir = strdup(fullsrcpath);
448
449 if (!fullsrcdir) {
450 log_error("Out of memory!");
451 return NULL;
452 }
453
454 fullsrcdir[dir_len(fullsrcdir)] = '\0';
455
456 if (asprintf(&abspath, "%s/%s", fullsrcdir, linktarget) < 0)
457 return NULL;
458 }
459
460 if (fullyresolve) {
461 struct stat st;
462 if (lstat(abspath, &st) < 0) {
463 if (errno != ENOENT)
464 return NULL;
465 }
466 if (S_ISLNK(st.st_mode))
467 return get_real_file(abspath, fullyresolve);
468 }
469
470 log_debug("get_real_file('%s') => '%s'", src, abspath);
471 return abspath;
472 }
473
474 static int resolve_deps(const char *src)
475 {
476 int ret = 0;
477
478 _cleanup_free_ char *buf = NULL;
479 size_t linesize = LINE_MAX;
480 _cleanup_pclose_ FILE *fptr = NULL;
481 _cleanup_free_ char *cmd = NULL;
482 _cleanup_free_ char *fullsrcpath = NULL;
483
484 fullsrcpath = get_real_file(src, true);
485 log_debug("resolve_deps('%s') -> get_real_file('%s', true) = '%s'", src, src, fullsrcpath);
486 if (!fullsrcpath)
487 return 0;
488
489 buf = malloc(LINE_MAX);
490 if (buf == NULL)
491 return -errno;
492
493 if (strstr(src, ".so") == 0) {
494 _cleanup_close_ int fd = -1;
495 fd = open(fullsrcpath, O_RDONLY | O_CLOEXEC);
496 if (fd < 0)
497 return -errno;
498
499 ret = read(fd, buf, LINE_MAX);
500 if (ret == -1)
501 return -errno;
502
503 buf[LINE_MAX - 1] = '\0';
504 if (buf[0] == '#' && buf[1] == '!') {
505 /* we have a shebang */
506 char *p, *q;
507 for (p = &buf[2]; *p && isspace(*p); p++) ;
508 for (q = p; *q && (!isspace(*q)); q++) ;
509 *q = '\0';
510 log_debug("Script install: '%s'", p);
511 ret = dracut_install(p, p, false, true, false);
512 if (ret != 0)
513 log_error("ERROR: failed to install '%s'", p);
514 return ret;
515 }
516 }
517
518 /* run ldd */
519 ret = asprintf(&cmd, "%s %s 2>&1", ldd, fullsrcpath);
520 if (ret < 0) {
521 log_error("Out of memory!");
522 exit(EXIT_FAILURE);
523 }
524
525 log_debug("%s", cmd);
526
527 ret = 0;
528
529 fptr = popen(cmd, "r");
530
531 while (!feof(fptr)) {
532 char *p;
533
534 if (getline(&buf, &linesize, fptr) <= 0)
535 continue;
536
537 log_debug("ldd: '%s'", buf);
538
539 if (strstr(buf, "you do not have execution permission")) {
540 log_error("%s", buf);
541 ret += 1;
542 break;
543 }
544
545 /* errors from cross-compiler-ldd */
546 if (strstr(buf, "unable to find sysroot") || strstr(buf, "command not found")) {
547 log_error("%s", buf);
548 ret += 1;
549 break;
550 }
551
552 /* musl ldd */
553 if (strstr(buf, "Not a valid dynamic program"))
554 break;
555
556 /* glibc */
557 if (strstr(buf, "cannot execute binary file"))
558 break;
559
560 if (strstr(buf, "not a dynamic executable"))
561 break;
562
563 if (strstr(buf, "loader cannot load itself"))
564 break;
565
566 if (strstr(buf, "not regular file"))
567 break;
568
569 if (strstr(buf, "cannot read header"))
570 break;
571
572 if (strstr(buf, destrootdir))
573 break;
574
575 p = strchr(buf, '/');
576 if (p) {
577 char *q;
578
579 for (q = p; *q && *q != ' ' && *q != '\n'; q++) ;
580 *q = '\0';
581
582 ret += library_install(src, p);
583
584 }
585 }
586
587 return ret;
588 }
589
590 /* Install ".<filename>.hmac" file for FIPS self-checks */
591 static int hmac_install(const char *src, const char *dst, const char *hmacpath)
592 {
593 _cleanup_free_ char *srcpath = strdup(src);
594 _cleanup_free_ char *dstpath = strdup(dst);
595 _cleanup_free_ char *srchmacname = NULL;
596 _cleanup_free_ char *dsthmacname = NULL;
597 int ret;
598
599 if (!(srcpath && dstpath))
600 return -ENOMEM;
601
602 size_t dlen = dir_len(src);
603
604 if (endswith(src, ".hmac"))
605 return 0;
606
607 if (!hmacpath) {
608 hmac_install(src, dst, "/lib/fipscheck");
609 hmac_install(src, dst, "/lib64/fipscheck");
610 hmac_install(src, dst, "/lib/hmaccalc");
611 hmac_install(src, dst, "/lib64/hmaccalc");
612 }
613
614 srcpath[dlen] = '\0';
615 dstpath[dir_len(dst)] = '\0';
616 if (hmacpath) {
617 ret = asprintf(&srchmacname, "%s/%s.hmac", hmacpath, &src[dlen + 1]);
618 if (ret < 0) {
619 log_error("Out of memory!");
620 exit(EXIT_FAILURE);
621 }
622
623 ret = asprintf(&dsthmacname, "%s/%s.hmac", hmacpath, &src[dlen + 1]);
624 if (ret < 0) {
625 log_error("Out of memory!");
626 exit(EXIT_FAILURE);
627 }
628 } else {
629 ret = asprintf(&srchmacname, "%s/.%s.hmac", srcpath, &src[dlen + 1]);
630 if (ret < 0) {
631 log_error("Out of memory!");
632 exit(EXIT_FAILURE);
633 }
634
635 ret = asprintf(&dsthmacname, "%s/.%s.hmac", dstpath, &src[dlen + 1]);
636 if (ret < 0) {
637 log_error("Out of memory!");
638 exit(EXIT_FAILURE);
639 }
640 }
641 log_debug("hmac cp '%s' '%s')", srchmacname, dsthmacname);
642 dracut_install(srchmacname, dsthmacname, false, false, true);
643 return 0;
644 }
645
646 void mark_hostonly(const char *path)
647 {
648 _cleanup_free_ char *fulldstpath = NULL;
649 _cleanup_fclose_ FILE *f = NULL;
650 int ret;
651
652 ret = asprintf(&fulldstpath, "%s/lib/dracut/hostonly-files", destrootdir);
653 if (ret < 0) {
654 log_error("Out of memory!");
655 exit(EXIT_FAILURE);
656 }
657
658 f = fopen(fulldstpath, "a");
659
660 if (f == NULL) {
661 log_error("Could not open '%s' for writing.", fulldstpath);
662 return;
663 }
664
665 fprintf(f, "%s\n", path);
666 }
667
668 void dracut_log_cp(const char *path)
669 {
670 int ret;
671 ret = fprintf(logfile_f, "%s\n", path);
672 if (ret < 0)
673 log_error("Could not append '%s' to logfile '%s': %m", path, logfile);
674 }
675
676 static bool check_hashmap(Hashmap *hm, const char *item)
677 {
678 char *existing;
679 existing = hashmap_get(hm, item);
680 if (existing) {
681 if (strcmp(existing, item) == 0) {
682 return true;
683 }
684 }
685 return false;
686 }
687
688 static int dracut_mkdir(const char *src) {
689 _cleanup_free_ char *parent = NULL;
690 char *path;
691 struct stat sb;
692
693 parent = strdup(src);
694 if (!parent)
695 return 1;
696
697 path = parent[0] == '/' ? parent+1 : parent;
698 while (path) {
699 path = strstr(path, "/");
700 if (path)
701 *path = '\0';
702
703 if (stat(parent, &sb) == 0) {
704 if (!S_ISDIR(sb.st_mode)) {
705 log_error("%s exists but is not a directory!", parent);
706 return 1;
707 }
708 } else if (errno != ENOENT) {
709 log_error("ERROR: stat '%s': %s", parent, strerror(errno));
710 return 1;
711 } else {
712 if (mkdir(parent, 0755) < 0) {
713 log_error("ERROR: mkdir '%s': %s", parent, strerror(errno));
714 return 1;
715 }
716 }
717
718 if (path) {
719 *path = '/';
720 path++;
721 }
722 }
723
724 return 0;
725 }
726
727 static int dracut_install(const char *orig_src, const char *orig_dst, bool isdir, bool resolvedeps, bool hashdst)
728 {
729 struct stat sb, db;
730 _cleanup_free_ char *fullsrcpath = NULL;
731 _cleanup_free_ char *fulldstpath = NULL;
732 _cleanup_free_ char *fulldstdir = NULL;
733 int ret;
734 bool src_islink = false;
735 bool src_isdir = false;
736 mode_t src_mode = 0;
737 bool dst_exists = true;
738 char *i = NULL;
739 _cleanup_free_ char *src;
740 _cleanup_free_ char *dst;
741
742 if (sysrootdirlen) {
743 if (strncmp(orig_src, sysrootdir, sysrootdirlen) == 0) {
744 src = strdup(orig_src + sysrootdirlen);
745 fullsrcpath = strdup(orig_src);
746 } else {
747 src = strdup(orig_src);
748 if (asprintf(&fullsrcpath, "%s%s", sysrootdir, src) < 0)
749 _exit(EXIT_FAILURE);
750 }
751 if (strncmp(orig_dst, sysrootdir, sysrootdirlen) == 0)
752 dst = strdup(orig_dst + sysrootdirlen);
753 else
754 dst = strdup(orig_dst);
755 } else {
756 src = strdup(orig_src);
757 fullsrcpath = strdup(src);
758 dst = strdup(orig_dst);
759 }
760
761 log_debug("dracut_install('%s', '%s', %d, %d, %d)", src, dst, isdir, resolvedeps, hashdst);
762
763 if (check_hashmap(items_failed, src)) {
764 log_debug("hash hit items_failed for '%s'", src);
765 return 1;
766 }
767
768 if (hashdst && check_hashmap(items, dst)) {
769 log_debug("hash hit items for '%s'", dst);
770 return 0;
771 }
772
773 if (lstat(fullsrcpath, &sb) < 0) {
774 if (!isdir) {
775 i = strdup(src);
776 hashmap_put(items_failed, i, i);
777 /* src does not exist */
778 return 1;
779 }
780 } else {
781 src_islink = S_ISLNK(sb.st_mode);
782 src_isdir = S_ISDIR(sb.st_mode);
783 src_mode = sb.st_mode;
784 }
785
786 ret = asprintf(&fulldstpath, "%s/%s", destrootdir, (dst[0]=='/' ? (dst+1) : dst));
787 if (ret < 0) {
788 log_error("Out of memory!");
789 exit(EXIT_FAILURE);
790 }
791
792 ret = stat(fulldstpath, &sb);
793
794 if (ret != 0) {
795 dst_exists = false;
796 if (errno != ENOENT) {
797 log_error("ERROR: stat '%s': %m", fulldstpath);
798 return 1;
799 }
800 }
801
802 if (ret == 0) {
803 if (resolvedeps && S_ISREG(sb.st_mode) && (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
804 log_debug("'%s' already exists, but checking for any deps", fulldstpath);
805 ret = resolve_deps(fullsrcpath + sysrootdirlen);
806 } else
807 log_debug("'%s' already exists", fulldstpath);
808
809 /* dst does already exist */
810 return ret;
811 }
812
813 /* check destination directory */
814 fulldstdir = strdup(fulldstpath);
815 if (!fulldstdir) {
816 log_error("Out of memory!");
817 return 1;
818 }
819 fulldstdir[dir_len(fulldstdir)] = '\0';
820
821 ret = stat(fulldstdir, &db);
822
823 if (ret < 0) {
824 _cleanup_free_ char *dname = NULL;
825
826 if (errno != ENOENT) {
827 log_error("ERROR: stat '%s': %m", fulldstdir);
828 return 1;
829 }
830 /* create destination directory */
831 log_debug("dest dir '%s' does not exist", fulldstdir);
832 dname = strdup(dst);
833 if (!dname)
834 return 1;
835
836 dname[dir_len(dname)] = '\0';
837 ret = dracut_install(dname, dname, true, false, true);
838
839 if (ret != 0) {
840 log_error("ERROR: failed to create directory '%s'", fulldstdir);
841 return 1;
842 }
843 }
844
845 if (src_isdir) {
846 if (dst_exists) {
847 if (S_ISDIR(sb.st_mode)) {
848 log_debug("dest dir '%s' already exists", fulldstpath);
849 return 0;
850 }
851 log_error("dest dir '%s' already exists but is not a directory", fulldstpath);
852 return 1;
853 }
854
855 log_info("mkdir '%s'", fulldstpath);
856 ret = dracut_mkdir(fulldstpath);
857 if (ret == 0) {
858 i = strdup(dst);
859 if (!i)
860 return -ENOMEM;
861
862 hashmap_put(items, i, i);
863 }
864 return ret;
865 }
866
867 /* ready to install src */
868
869 if (src_islink) {
870 _cleanup_free_ char *abspath = NULL;
871
872 abspath = get_real_file(src, false);
873
874 if (abspath == NULL)
875 return 1;
876
877 if (dracut_install(abspath, abspath, false, resolvedeps, hashdst)) {
878 log_debug("'%s' install error", abspath);
879 return 1;
880 }
881
882 if (lstat(abspath, &sb) != 0) {
883 log_debug("lstat '%s': %m", abspath);
884 return 1;
885 }
886
887 if (lstat(fulldstpath, &sb) != 0) {
888 _cleanup_free_ char *absdestpath = NULL;
889
890 ret = asprintf(&absdestpath, "%s/%s", destrootdir, (abspath[0]=='/' ? (abspath+1) : abspath) + sysrootdirlen);
891 if (ret < 0) {
892 log_error("Out of memory!");
893 exit(EXIT_FAILURE);
894 }
895
896 ln_r(absdestpath, fulldstpath);
897 }
898
899 if (arg_hmac) {
900 /* copy .hmac files also */
901 hmac_install(src, dst, NULL);
902 }
903
904 return 0;
905 }
906
907 if (src_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
908 if (resolvedeps)
909 ret += resolve_deps(fullsrcpath + sysrootdirlen);
910 if (arg_hmac) {
911 /* copy .hmac files also */
912 hmac_install(src, dst, NULL);
913 }
914 }
915
916 log_debug("dracut_install ret = %d", ret);
917
918 if (arg_hostonly && !arg_module)
919 mark_hostonly(dst);
920
921 if (isdir) {
922 log_info("mkdir '%s'", fulldstpath);
923 ret += dracut_mkdir(fulldstpath);
924 } else {
925 log_info("cp '%s' '%s'", fullsrcpath, fulldstpath);
926 ret += cp(fullsrcpath, fulldstpath);
927 }
928
929 if (ret == 0) {
930 i = strdup(dst);
931 if (!i)
932 return -ENOMEM;
933
934 hashmap_put(items, i, i);
935
936 if (logfile_f)
937 dracut_log_cp(src);
938 }
939
940 log_debug("dracut_install ret = %d", ret);
941
942 return ret;
943 }
944
945 static void item_free(char *i)
946 {
947 assert(i);
948 free(i);
949 }
950
951 static void usage(int status)
952 {
953 /* */
954 printf("Usage: %s -D DESTROOTDIR [-r SYSROOTDIR] [OPTION]... -a SOURCE...\n"
955 "or: %s -D DESTROOTDIR [-r SYSROOTDIR] [OPTION]... SOURCE DEST\n"
956 "or: %s -D DESTROOTDIR [-r SYSROOTDIR] [OPTION]... -m KERNELMODULE [KERNELMODULE …]\n"
957 "\n"
958 "Install SOURCE (from rootfs or SYSROOTDIR) to DEST in DESTROOTDIR with all needed dependencies.\n"
959 "\n"
960 " KERNELMODULE can have the format:\n"
961 " <absolute path> with a leading /\n"
962 " =<kernel subdir>[/<kernel subdir>…] like '=drivers/hid'\n"
963 " <module name>\n"
964 "\n"
965 " -D --destrootdir Install all files to DESTROOTDIR as the root\n"
966 " -r --sysrootdir Install all files from SYSROOTDIR\n"
967 " -a --all Install all SOURCE arguments to DESTROOTDIR\n"
968 " -o --optional If SOURCE does not exist, do not fail\n"
969 " -d --dir SOURCE is a directory\n"
970 " -l --ldd Also install shebang executables and libraries\n"
971 " -L --logdir <DIR> Log files, which were installed from the host to <DIR>\n"
972 " -R --resolvelazy Only install shebang executables and libraries\n"
973 " for all SOURCE files\n"
974 " -H --hostonly Mark all SOURCE files as hostonly\n\n"
975 " -f --fips Also install all '.SOURCE.hmac' files\n"
976 "\n"
977 " --module,-m Install kernel modules, instead of files\n"
978 " --kerneldir Specify the kernel module directory\n"
979 " --firmwaredirs Specify the firmware directory search path with : separation\n"
980 " --silent Don't display error messages for kernel module install\n"
981 " --modalias Only generate module list from /sys/devices modalias list\n"
982 " -o --optional If kernel module does not exist, do not fail\n"
983 " -p --mod-filter-path Filter kernel modules by path regexp\n"
984 " -P --mod-filter-nopath Exclude kernel modules by path regexp\n"
985 " -s --mod-filter-symbol Filter kernel modules by symbol regexp\n"
986 " -S --mod-filter-nosymbol Exclude kernel modules by symbol regexp\n"
987 " -N --mod-filter-noname Exclude kernel modules by name regexp\n"
988 "\n"
989 " -v --verbose Show more output\n"
990 " --debug Show debug output\n"
991 " --version Show package version\n"
992 " -h --help Show this help\n"
993 "\n",
994 program_invocation_short_name, program_invocation_short_name,
995 program_invocation_short_name);
996 exit(status);
997 }
998
999 static int parse_argv(int argc, char *argv[])
1000 {
1001 int c;
1002
1003 enum {
1004 ARG_VERSION = 0x100,
1005 ARG_SILENT,
1006 ARG_MODALIAS,
1007 ARG_KERNELDIR,
1008 ARG_FIRMWAREDIRS,
1009 ARG_DEBUG
1010 };
1011
1012 static struct option const options[] = {
1013 {"help", no_argument, NULL, 'h'},
1014 {"version", no_argument, NULL, ARG_VERSION},
1015 {"dir", no_argument, NULL, 'd'},
1016 {"debug", no_argument, NULL, ARG_DEBUG},
1017 {"verbose", no_argument, NULL, 'v'},
1018 {"ldd", no_argument, NULL, 'l'},
1019 {"resolvelazy", no_argument, NULL, 'R'},
1020 {"optional", no_argument, NULL, 'o'},
1021 {"hostonly", no_argument, NULL, 'H'},
1022 {"all", no_argument, NULL, 'a'},
1023 {"module", no_argument, NULL, 'm'},
1024 {"fips", no_argument, NULL, 'f'},
1025 {"destrootdir", required_argument, NULL, 'D'},
1026 {"sysrootdir", required_argument, NULL, 'r'},
1027 {"logdir", required_argument, NULL, 'L'},
1028 {"mod-filter-path", required_argument, NULL, 'p'},
1029 {"mod-filter-nopath", required_argument, NULL, 'P'},
1030 {"mod-filter-symbol", required_argument, NULL, 's'},
1031 {"mod-filter-nosymbol", required_argument, NULL, 'S'},
1032 {"mod-filter-noname", required_argument, NULL, 'N'},
1033 {"modalias", no_argument, NULL, ARG_MODALIAS},
1034 {"silent", no_argument, NULL, ARG_SILENT},
1035 {"kerneldir", required_argument, NULL, ARG_KERNELDIR},
1036 {"firmwaredirs", required_argument, NULL, ARG_FIRMWAREDIRS},
1037 {NULL, 0, NULL, 0}
1038 };
1039
1040 while ((c = getopt_long(argc, argv, "madfhlL:oD:Hr:Rp:P:s:S:N:v", options, NULL)) != -1) {
1041 switch (c) {
1042 case ARG_VERSION:
1043 puts(PROGRAM_VERSION_STRING);
1044 return 0;
1045 case 'd':
1046 arg_createdir = true;
1047 break;
1048 case ARG_DEBUG:
1049 arg_loglevel = LOG_DEBUG;
1050 break;
1051 case ARG_SILENT:
1052 arg_silent = true;
1053 break;
1054 case ARG_MODALIAS:
1055 arg_modalias = true;
1056 return 1;
1057 break;
1058 case 'v':
1059 arg_loglevel = LOG_INFO;
1060 break;
1061 case 'o':
1062 arg_optional = true;
1063 break;
1064 case 'l':
1065 arg_resolvedeps = true;
1066 break;
1067 case 'R':
1068 arg_resolvelazy = true;
1069 break;
1070 case 'a':
1071 arg_all = true;
1072 break;
1073 case 'm':
1074 arg_module = true;
1075 break;
1076 case 'D':
1077 destrootdir = strdup(optarg);
1078 break;
1079 case 'r':
1080 sysrootdir = strdup(optarg);
1081 sysrootdirlen = strlen(sysrootdir);
1082 break;
1083 case 'p':
1084 if (regcomp(&mod_filter_path, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
1085 log_error("Module path filter %s is not a regular expression", optarg);
1086 exit(EXIT_FAILURE);
1087 }
1088 arg_mod_filter_path = true;
1089 break;
1090 case 'P':
1091 if (regcomp(&mod_filter_nopath, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
1092 log_error("Module path filter %s is not a regular expression", optarg);
1093 exit(EXIT_FAILURE);
1094 }
1095 arg_mod_filter_nopath = true;
1096 break;
1097 case 's':
1098 if (regcomp(&mod_filter_symbol, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
1099 log_error("Module symbol filter %s is not a regular expression", optarg);
1100 exit(EXIT_FAILURE);
1101 }
1102 arg_mod_filter_symbol = true;
1103 break;
1104 case 'S':
1105 if (regcomp(&mod_filter_nosymbol, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
1106 log_error("Module symbol filter %s is not a regular expression", optarg);
1107 exit(EXIT_FAILURE);
1108 }
1109 arg_mod_filter_nosymbol = true;
1110 break;
1111 case 'N':
1112 if (regcomp(&mod_filter_noname, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
1113 log_error("Module symbol filter %s is not a regular expression", optarg);
1114 exit(EXIT_FAILURE);
1115 }
1116 arg_mod_filter_noname = true;
1117 break;
1118 case 'L':
1119 logdir = strdup(optarg);
1120 break;
1121 case ARG_KERNELDIR:
1122 kerneldir = strdup(optarg);
1123 break;
1124 case ARG_FIRMWAREDIRS:
1125 firmwaredirs = strv_split(optarg, ":");
1126 break;
1127 case 'f':
1128 arg_hmac = true;
1129 break;
1130 case 'H':
1131 arg_hostonly = true;
1132 break;
1133 case 'h':
1134 usage(EXIT_SUCCESS);
1135 break;
1136 default:
1137 usage(EXIT_FAILURE);
1138 }
1139 }
1140
1141 if (!kerneldir) {
1142 struct utsname buf;
1143 uname(&buf);
1144 kerneldir = strdup(buf.version);
1145 }
1146
1147 if (arg_modalias) {
1148 return 1;
1149 }
1150
1151 if (arg_module) {
1152 if (!firmwaredirs) {
1153 char *path = NULL;
1154
1155 path = getenv("DRACUT_FIRMWARE_PATH");
1156
1157 if (path == NULL) {
1158 log_error("Environment variable DRACUT_FIRMWARE_PATH is not set");
1159 exit(EXIT_FAILURE);
1160 }
1161
1162 log_debug("DRACUT_FIRMWARE_PATH=%s", path);
1163
1164 firmwaredirs = strv_split(path, ":");
1165 }
1166 }
1167
1168 if (!optind || optind == argc) {
1169 log_error("No SOURCE argument given");
1170 usage(EXIT_FAILURE);
1171 }
1172
1173 return 1;
1174 }
1175
1176 static int resolve_lazy(int argc, char **argv)
1177 {
1178 int i;
1179 size_t destrootdirlen = strlen(destrootdir);
1180 int ret = 0;
1181 char *item;
1182 for (i = 0; i < argc; i++) {
1183 const char *src = argv[i];
1184 char *p = argv[i];
1185 char *existing;
1186
1187 log_debug("resolve_deps('%s')", src);
1188
1189 if (strstr(src, destrootdir)) {
1190 p = &argv[i][destrootdirlen];
1191 }
1192
1193 existing = hashmap_get(items, p);
1194 if (existing) {
1195 if (strcmp(existing, p) == 0)
1196 continue;
1197 }
1198
1199 item = strdup(p);
1200 hashmap_put(items, item, item);
1201
1202 ret += resolve_deps(src);
1203 }
1204 return ret;
1205 }
1206
1207 static char **find_binary(const char *src)
1208 {
1209 char **ret = NULL;
1210 char **q;
1211 char *fullsrcpath;
1212 char *newsrc = NULL;
1213
1214 STRV_FOREACH(q, pathdirs) {
1215 struct stat sb;
1216 int r;
1217
1218 r = asprintf(&newsrc, "%s/%s", *q, src);
1219 if (r < 0) {
1220 log_error("Out of memory!");
1221 exit(EXIT_FAILURE);
1222 }
1223
1224 fullsrcpath = get_real_file(newsrc, false);
1225
1226 if (!fullsrcpath) {
1227 log_debug("get_real_file(%s) not found", newsrc);
1228 free(newsrc);
1229 newsrc = NULL;
1230 continue;
1231 }
1232
1233 if (lstat(fullsrcpath, &sb) != 0) {
1234 log_debug("stat(%s) != 0", fullsrcpath);
1235 free(newsrc);
1236 newsrc = NULL;
1237 free(fullsrcpath);
1238 fullsrcpath = NULL;
1239 continue;
1240 }
1241
1242 strv_push(&ret, newsrc);
1243
1244 free(fullsrcpath);
1245 fullsrcpath = NULL;
1246 };
1247
1248 if (ret) {
1249 STRV_FOREACH(q, ret) {
1250 log_debug("find_binary(%s) == %s", src, *q);
1251 }
1252 }
1253
1254 return ret;
1255 }
1256
1257 static int install_one(const char *src, const char *dst)
1258 {
1259 int r = EXIT_SUCCESS;
1260 int ret = 0;
1261
1262 if (strchr(src, '/') == NULL) {
1263 char **p = find_binary(src);
1264 if (p) {
1265 char **q = NULL;
1266 STRV_FOREACH(q, p) {
1267 char *newsrc = *q;
1268 log_debug("dracut_install '%s' '%s'", newsrc, dst);
1269 ret = dracut_install(newsrc, dst, arg_createdir, arg_resolvedeps, true);
1270 if (ret == 0) {
1271 log_debug("dracut_install '%s' '%s' OK", newsrc, dst);
1272 }
1273 }
1274 strv_free(p);
1275 } else {
1276 ret = -1;
1277 }
1278 } else {
1279 ret = dracut_install(src, dst, arg_createdir, arg_resolvedeps, true);
1280 }
1281
1282 if ((ret != 0) && (!arg_optional)) {
1283 log_error("ERROR: installing '%s' to '%s'", src, dst);
1284 r = EXIT_FAILURE;
1285 }
1286
1287 return r;
1288 }
1289
1290 static int install_all(int argc, char **argv)
1291 {
1292 int r = EXIT_SUCCESS;
1293 int i;
1294 for (i = 0; i < argc; i++) {
1295 int ret = 0;
1296 log_debug("Handle '%s'", argv[i]);
1297
1298 if (strchr(argv[i], '/') == NULL) {
1299 char **p = find_binary(argv[i]);
1300 if (p) {
1301 char **q = NULL;
1302 STRV_FOREACH(q, p) {
1303 char *newsrc = *q;
1304 log_debug("dracut_install '%s'", newsrc);
1305 ret = dracut_install(newsrc, newsrc, arg_createdir, arg_resolvedeps, true);
1306 if (ret == 0) {
1307 log_debug("dracut_install '%s' OK", newsrc);
1308 }
1309 }
1310 strv_free(p);
1311 } else {
1312 ret = -1;
1313 }
1314
1315 } else {
1316 _cleanup_free_ char *dest = strdup(argv[i]);
1317 ret = dracut_install(argv[i], dest, arg_createdir, arg_resolvedeps, true);
1318 }
1319
1320 if ((ret != 0) && (!arg_optional)) {
1321 log_error("ERROR: installing '%s'", argv[i]);
1322 r = EXIT_FAILURE;
1323 }
1324 }
1325 return r;
1326 }
1327
1328 static int install_firmware(struct kmod_module *mod)
1329 {
1330 struct kmod_list *l;
1331 _cleanup_kmod_module_info_free_list_ struct kmod_list *list = NULL;
1332 int ret;
1333
1334 char **q;
1335
1336 ret = kmod_module_get_info(mod, &list);
1337 if (ret < 0) {
1338 log_error("could not get modinfo from '%s': %s\n",
1339 kmod_module_get_name(mod), strerror(-ret));
1340 return ret;
1341 }
1342 kmod_list_foreach(l, list) {
1343 const char *key = kmod_module_info_get_key(l);
1344 const char *value = NULL;
1345
1346 if (!streq("firmware", key))
1347 continue;
1348
1349 value = kmod_module_info_get_value(l);
1350 log_debug("Firmware %s", value);
1351 ret = -1;
1352 STRV_FOREACH(q, firmwaredirs) {
1353 _cleanup_free_ char *fwpath = NULL;
1354 _cleanup_free_ char *fwpath_xz = NULL;
1355 const char *fw;
1356 struct stat sb;
1357 int r;
1358
1359 r = asprintf(&fwpath, "%s/%s", *q, value);
1360 if (r < 0) {
1361 log_error("Out of memory!");
1362 exit(EXIT_FAILURE);
1363 }
1364
1365 fw = fwpath;
1366 if (stat(fwpath, &sb) != 0) {
1367 r = asprintf(&fwpath_xz, "%s.xz", fwpath);
1368 if (r < 0) {
1369 log_error("Out of memory!");
1370 exit(EXIT_FAILURE);
1371 }
1372 if (stat(fwpath_xz, &sb) != 0) {
1373 log_debug("stat(%s) != 0", fwpath);
1374 continue;
1375 }
1376 fw = fwpath_xz;
1377 }
1378
1379 ret = dracut_install(fw, fw, false, false, true);
1380 if (ret == 0)
1381 log_debug("dracut_install '%s' OK", fwpath);
1382 }
1383
1384 if (ret != 0) {
1385 log_info("Possible missing firmware %s for kernel module %s", value, kmod_module_get_name(mod));
1386 }
1387 }
1388 return 0;
1389 }
1390
1391 static bool check_module_symbols(struct kmod_module *mod)
1392 {
1393 struct kmod_list *itr;
1394 _cleanup_kmod_module_dependency_symbols_free_list_ struct kmod_list *deplist = NULL;
1395
1396 if (!arg_mod_filter_symbol && !arg_mod_filter_nosymbol)
1397 return true;
1398
1399 if (kmod_module_get_dependency_symbols(mod, &deplist) < 0) {
1400 log_debug("kmod_module_get_dependency_symbols failed");
1401 if (arg_mod_filter_symbol)
1402 return false;
1403 return true;
1404 }
1405
1406 if (arg_mod_filter_nosymbol) {
1407 kmod_list_foreach(itr, deplist) {
1408 const char *symbol = kmod_module_symbol_get_symbol(itr);
1409 // log_debug("Checking symbol %s", symbol);
1410 if (regexec(&mod_filter_nosymbol, symbol, 0, NULL, 0) == 0) {
1411 log_debug("Module %s: symbol %s matched exclusion filter", kmod_module_get_name(mod), symbol);
1412 return false;
1413 }
1414 }
1415 }
1416
1417 if (arg_mod_filter_symbol) {
1418 kmod_list_foreach(itr, deplist) {
1419 const char *symbol = kmod_module_dependency_symbol_get_symbol(itr);
1420 // log_debug("Checking symbol %s", symbol);
1421 if (regexec(&mod_filter_symbol, symbol, 0, NULL, 0) == 0) {
1422 log_debug("Module %s: symbol %s matched inclusion filter", kmod_module_get_name(mod), symbol);
1423 return true;
1424 }
1425 }
1426 return false;
1427 }
1428
1429 return true;
1430 }
1431
1432 static bool check_module_path(const char *path)
1433 {
1434 if (arg_mod_filter_nopath && (regexec(&mod_filter_nopath, path, 0, NULL, 0) == 0)) {
1435 log_debug("Path %s matched exclusion filter", path);
1436 return false;
1437 }
1438
1439 if (arg_mod_filter_path && (regexec(&mod_filter_path, path, 0, NULL, 0) != 0)) {
1440 log_debug("Path %s matched inclusion filter", path);
1441 return false;
1442 }
1443 return true;
1444 }
1445
1446 static int install_dependent_modules(struct kmod_list *modlist)
1447 {
1448 struct kmod_list *itr;
1449 const char *path = NULL;
1450 const char *name = NULL;
1451 int ret = 0;
1452
1453 kmod_list_foreach(itr, modlist) {
1454 _cleanup_kmod_module_unref_ struct kmod_module *mod = NULL;
1455 mod = kmod_module_get_module(itr);
1456 path = kmod_module_get_path(mod);
1457
1458 if (path == NULL)
1459 continue;
1460
1461 if (check_hashmap(items_failed, path))
1462 return -1;
1463
1464 if (check_hashmap(items, path)) {
1465 continue;
1466 }
1467
1468 name = kmod_module_get_name(mod);
1469
1470 if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
1471 continue;
1472 }
1473
1474 ret = dracut_install(path, &path[kerneldirlen], false, false, true);
1475 if (ret == 0) {
1476 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1477 _cleanup_kmod_module_unref_list_ struct kmod_list *modpre = NULL;
1478 _cleanup_kmod_module_unref_list_ struct kmod_list *modpost = NULL;
1479 log_debug("dracut_install '%s' '%s' OK", path, &path[kerneldirlen]);
1480 install_firmware(mod);
1481 modlist = kmod_module_get_dependencies(mod);
1482 ret = install_dependent_modules(modlist);
1483 if (ret == 0) {
1484 ret = kmod_module_get_softdeps(mod, &modpre, &modpost);
1485 if (ret == 0)
1486 ret = install_dependent_modules(modpre);
1487 }
1488 } else {
1489 log_error("dracut_install '%s' '%s' ERROR", path, &path[kerneldirlen]);
1490 }
1491 }
1492
1493 return ret;
1494 }
1495
1496 static int install_module(struct kmod_module *mod)
1497 {
1498 int ret = 0;
1499 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1500 _cleanup_kmod_module_unref_list_ struct kmod_list *modpre = NULL;
1501 _cleanup_kmod_module_unref_list_ struct kmod_list *modpost = NULL;
1502 const char *path = NULL;
1503 const char *name = NULL;
1504
1505 name = kmod_module_get_name(mod);
1506 if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
1507 log_debug("dracut_install '%s' is excluded", name);
1508 return 0;
1509 }
1510
1511 if (arg_hostonly && !check_hashmap(modules_loaded, name)) {
1512 log_debug("dracut_install '%s' not hostonly", name);
1513 return 0;
1514 }
1515
1516 path = kmod_module_get_path(mod);
1517 if (!path)
1518 return -ENOENT;
1519
1520 if (check_hashmap(items_failed, path))
1521 return -1;
1522
1523 if (check_hashmap(items, path))
1524 return 0;
1525
1526 if (!check_module_path(path) || !check_module_symbols(mod)) {
1527 log_debug("No symbol or path match for '%s'", path);
1528 return 1;
1529 }
1530
1531 log_debug("dracut_install '%s' '%s'", path, &path[kerneldirlen]);
1532
1533 ret = dracut_install(path, &path[kerneldirlen], false, false, true);
1534 if (ret == 0) {
1535 log_debug("dracut_install '%s' OK", kmod_module_get_name(mod));
1536 } else if (!arg_optional) {
1537 if (!arg_silent)
1538 log_error("dracut_install '%s' ERROR", kmod_module_get_name(mod));
1539 return ret;
1540 }
1541 install_firmware(mod);
1542
1543 modlist = kmod_module_get_dependencies(mod);
1544 ret = install_dependent_modules(modlist);
1545
1546 if (ret == 0) {
1547 ret = kmod_module_get_softdeps(mod, &modpre, &modpost);
1548 if (ret == 0)
1549 ret = install_dependent_modules(modpre);
1550 }
1551
1552 return ret;
1553 }
1554
1555 static int modalias_list(struct kmod_ctx *ctx)
1556 {
1557 int err;
1558 struct kmod_list *loaded_list = NULL;
1559 struct kmod_list *itr, *l;
1560 _cleanup_fts_close_ FTS *fts = NULL;
1561
1562 {
1563 char *paths[] = { "/sys/devices", NULL };
1564 fts = fts_open(paths, FTS_NOCHDIR|FTS_NOSTAT, NULL);
1565 }
1566 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1567 _cleanup_fclose_ FILE *f = NULL;
1568 _cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
1569 struct kmod_list *l;
1570
1571 int err;
1572
1573 char alias[2048];
1574 size_t len;
1575
1576 if (strncmp("modalias", ftsent->fts_name, 8) != 0)
1577 continue;
1578 if (!(f = fopen(ftsent->fts_accpath, "r")))
1579 continue;
1580
1581 if(!fgets(alias, sizeof(alias), f))
1582 continue;
1583
1584 len = strlen(alias);
1585
1586 if (len == 0)
1587 continue;
1588
1589 if (alias[len-1] == '\n')
1590 alias[len-1] = 0;
1591
1592 err = kmod_module_new_from_lookup(ctx, alias, &list);
1593 if (err < 0)
1594 continue;
1595
1596 kmod_list_foreach(l, list) {
1597 struct kmod_module *mod = kmod_module_get_module(l);
1598 char *name = strdup(kmod_module_get_name(mod));
1599 kmod_module_unref(mod);
1600 hashmap_put(modules_loaded, name, name);
1601 }
1602 }
1603
1604 err = kmod_module_new_from_loaded(ctx, &loaded_list);
1605 if (err < 0) {
1606 errno = err;
1607 log_error("Could not get list of loaded modules: %m. Switching to non-hostonly mode.");
1608 arg_hostonly = false;
1609 } else {
1610 kmod_list_foreach(itr, loaded_list) {
1611 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1612
1613 struct kmod_module *mod = kmod_module_get_module(itr);
1614 char *name = strdup(kmod_module_get_name(mod));
1615 hashmap_put(modules_loaded, name, name);
1616 kmod_module_unref(mod);
1617
1618 /* also put the modules from the new kernel in the hashmap,
1619 * which resolve the name as an alias, in case a kernel module is
1620 * renamed.
1621 */
1622 err = kmod_module_new_from_lookup(ctx, name, &modlist);
1623 if (err < 0)
1624 continue;
1625 if (!modlist)
1626 continue;
1627 kmod_list_foreach(l, modlist) {
1628 mod = kmod_module_get_module(l);
1629 char *name = strdup(kmod_module_get_name(mod));
1630 hashmap_put(modules_loaded, name, name);
1631 kmod_module_unref(mod);
1632 }
1633 }
1634 kmod_module_unref_list(loaded_list);
1635 }
1636 return 0;
1637 }
1638
1639 static int install_modules(int argc, char **argv)
1640 {
1641 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
1642 struct kmod_list *itr;
1643
1644 struct kmod_module *mod = NULL, *mod_o = NULL;
1645
1646 const char *abskpath = NULL;
1647 char *p;
1648 int i;
1649 int modinst = 0;
1650
1651 ctx = kmod_new(kerneldir, NULL);
1652 abskpath = kmod_get_dirname(ctx);
1653
1654 p = strstr(abskpath, "/lib/modules/");
1655 if (p != NULL)
1656 kerneldirlen = p - abskpath;
1657
1658 if (arg_hostonly) {
1659 char *modalias_file;
1660 modalias_file = getenv("DRACUT_KERNEL_MODALIASES");
1661
1662 if (modalias_file == NULL) {
1663 modalias_list(ctx);
1664 } else {
1665 _cleanup_fclose_ FILE *f = NULL;
1666 if ((f = fopen(modalias_file, "r"))) {
1667 char name[2048];
1668
1669 while (!feof(f)) {
1670 size_t len;
1671 char *dupname = NULL;
1672
1673 if(!(fgets(name, sizeof(name), f)))
1674 continue;
1675 len = strlen(name);
1676
1677 if (len == 0)
1678 continue;
1679
1680 if (name[len-1] == '\n')
1681 name[len-1] = 0;
1682
1683 log_debug("Adding module '%s' to hostonly module list", name);
1684 dupname = strdup(name);
1685 hashmap_put(modules_loaded, dupname, dupname);
1686 }
1687 }
1688 }
1689
1690 }
1691
1692 for (i = 0; i < argc; i++) {
1693 int r = 0;
1694 int ret = -1;
1695 log_debug("Handle module '%s'", argv[i]);
1696
1697 if (argv[i][0] == '/') {
1698 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1699 _cleanup_free_ const char *modname = NULL;
1700
1701 r = kmod_module_new_from_path(ctx, argv[i], &mod_o);
1702 if (r < 0) {
1703 log_debug("Failed to lookup modules path '%s': %m", argv[i]);
1704 if (!arg_optional)
1705 return -ENOENT;
1706 continue;
1707 }
1708 /* Check, if we have to load another module with that name instead */
1709 modname = strdup(kmod_module_get_name(mod_o));
1710
1711 if (!modname) {
1712 if (!arg_optional) {
1713 if (!arg_silent)
1714 log_error("Failed to get name for module '%s'", argv[i]);
1715 return -ENOENT;
1716 }
1717 log_info("Failed to get name for module '%s'", argv[i]);
1718 continue;
1719 }
1720
1721 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1722 kmod_module_unref(mod_o);
1723 mod_o = NULL;
1724
1725 if (r < 0) {
1726 if (!arg_optional) {
1727 if (!arg_silent)
1728 log_error("3 Failed to lookup alias '%s': %d", modname, r);
1729 return -ENOENT;
1730 }
1731 log_info("3 Failed to lookup alias '%s': %d", modname, r);
1732 continue;
1733 }
1734 if (!modlist) {
1735 if (!arg_optional) {
1736 if (!arg_silent)
1737 log_error("Failed to find module '%s' %s", modname, argv[i]);
1738 return -ENOENT;
1739 }
1740 log_info("Failed to find module '%s' %s", modname, argv[i]);
1741 continue;
1742 }
1743 kmod_list_foreach(itr, modlist) {
1744 mod = kmod_module_get_module(itr);
1745 r = install_module(mod);
1746 kmod_module_unref(mod);
1747 if ((r < 0) && !arg_optional) {
1748 if (!arg_silent)
1749 log_error("ERROR: installing module '%s'", modname);
1750 return -ENOENT;
1751 };
1752 ret = ( ret == 0 ? 0 : r );
1753 modinst = 1;
1754 }
1755 } else if (argv[i][0] == '=') {
1756 _cleanup_free_ char *path1 = NULL, *path2 = NULL, *path3 = NULL;
1757 _cleanup_fts_close_ FTS *fts = NULL;
1758
1759 log_debug("Handling =%s", &argv[i][1]);
1760 /* FIXME and add more paths*/
1761 r = asprintf(&path2, "%s/kernel/%s", kerneldir, &argv[i][1]);
1762 if (r < 0) {
1763 log_error("Out of memory!");
1764 exit(EXIT_FAILURE);
1765 }
1766
1767 r = asprintf(&path1, "%s/extra/%s", kerneldir, &argv[i][1]);
1768 if (r < 0) {
1769 log_error("Out of memory!");
1770 exit(EXIT_FAILURE);
1771 }
1772
1773 r = asprintf(&path3, "%s/updates/%s", kerneldir, &argv[i][1]);
1774 if (r < 0) {
1775 log_error("Out of memory!");
1776 exit(EXIT_FAILURE);
1777 }
1778
1779 {
1780 char *paths[] = { path1, path2, path3, NULL };
1781 fts = fts_open(paths, FTS_COMFOLLOW|FTS_NOCHDIR|FTS_NOSTAT|FTS_LOGICAL, NULL);
1782 }
1783
1784 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1785 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1786 _cleanup_free_ const char *modname = NULL;
1787
1788 if((ftsent->fts_info == FTS_D) && !check_module_path(ftsent->fts_accpath)) {
1789 fts_set(fts, ftsent, FTS_SKIP);
1790 log_debug("Skipping %s", ftsent->fts_accpath);
1791 continue;
1792 }
1793 if((ftsent->fts_info != FTS_F) && (ftsent->fts_info != FTS_SL)) {
1794 log_debug("Ignoring %s", ftsent->fts_accpath);
1795 continue;
1796 }
1797 log_debug("Handling %s", ftsent->fts_accpath);
1798 r = kmod_module_new_from_path(ctx, ftsent->fts_accpath, &mod_o);
1799 if (r < 0) {
1800 log_debug("Failed to lookup modules path '%s': %m",
1801 ftsent->fts_accpath);
1802 if (!arg_optional) {
1803 return -ENOENT;
1804 }
1805 continue;
1806 }
1807
1808 /* Check, if we have to load another module with that name instead */
1809 modname = strdup(kmod_module_get_name(mod_o));
1810
1811 if (!modname) {
1812 log_error("Failed to get name for module '%s'", ftsent->fts_accpath);
1813 if (!arg_optional) {
1814 return -ENOENT;
1815 }
1816 continue;
1817 }
1818 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1819 kmod_module_unref(mod_o);
1820 mod_o = NULL;
1821
1822 if (r < 0) {
1823 log_error("Failed to lookup alias '%s': %m", modname);
1824 if (!arg_optional) {
1825 return -ENOENT;
1826 }
1827 continue;
1828 }
1829
1830 if (!modlist) {
1831 log_error("Failed to find module '%s' %s", modname,
1832 ftsent->fts_accpath);
1833 if (!arg_optional) {
1834 return -ENOENT;
1835 }
1836 continue;
1837 }
1838 kmod_list_foreach(itr, modlist) {
1839 mod = kmod_module_get_module(itr);
1840 r = install_module(mod);
1841 kmod_module_unref(mod);
1842 if ((r < 0) && !arg_optional) {
1843 if (!arg_silent)
1844 log_error("ERROR: installing module '%s'", modname);
1845 return -ENOENT;
1846 };
1847 ret = ( ret == 0 ? 0 : r );
1848 modinst = 1;
1849 }
1850 }
1851 if (errno) {
1852 log_error("FTS ERROR: %m");
1853 }
1854 } else {
1855 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1856 char *modname = argv[i];
1857
1858 if (endswith(modname, ".ko")) {
1859 int len = strlen(modname);
1860 modname[len-3]=0;
1861 }
1862 if (endswith(modname, ".ko.xz") || endswith(modname, ".ko.gz")) {
1863 int len = strlen(modname);
1864 modname[len-6]=0;
1865 }
1866 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1867 if (r < 0) {
1868 if (!arg_optional) {
1869 if (!arg_silent)
1870 log_error("Failed to lookup alias '%s': %m", modname);
1871 return -ENOENT;
1872 }
1873 log_info("Failed to lookup alias '%s': %m", modname);
1874 continue;
1875 }
1876 if (!modlist) {
1877 if (!arg_optional) {
1878 if (!arg_silent)
1879 log_error("Failed to find module '%s'", modname);
1880 return -ENOENT;
1881 }
1882 log_info("Failed to find module '%s'", modname);
1883 continue;
1884 }
1885 kmod_list_foreach(itr, modlist) {
1886 mod = kmod_module_get_module(itr);
1887 r = install_module(mod);
1888 kmod_module_unref(mod);
1889 if ((r < 0) && !arg_optional) {
1890 if (!arg_silent)
1891 log_error("ERROR: installing '%s'", argv[i]);
1892 return -ENOENT;
1893 };
1894 ret = ( ret == 0 ? 0 : r );
1895 modinst = 1;
1896 }
1897 }
1898
1899 if ((modinst != 0) && (ret != 0) && (!arg_optional)) {
1900 if (!arg_silent)
1901 log_error("ERROR: installing '%s'", argv[i]);
1902 return EXIT_FAILURE;
1903 }
1904 }
1905
1906 return EXIT_SUCCESS;
1907 }
1908
1909 int main(int argc, char **argv)
1910 {
1911 int r;
1912 char *i;
1913 char *path = NULL;
1914 char *env_no_xattr = NULL;
1915
1916 r = parse_argv(argc, argv);
1917 if (r <= 0)
1918 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1919
1920 log_set_target(LOG_TARGET_CONSOLE);
1921 log_parse_environment();
1922
1923 if (arg_loglevel >= 0)
1924 log_set_max_level(arg_loglevel);
1925
1926 log_open();
1927
1928 modules_loaded = hashmap_new(string_hash_func, string_compare_func);
1929 if (arg_modalias) {
1930 Iterator i;
1931 char *name;
1932 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
1933 ctx = kmod_new(kerneldir, NULL);
1934
1935 modalias_list(ctx);
1936 HASHMAP_FOREACH(name, modules_loaded, i) {
1937 printf("%s\n", name);
1938 }
1939 exit(0);
1940 }
1941
1942 log_debug("Program arguments:");
1943 for (r = 0; r < argc; r++)
1944 log_debug("%s", argv[r]);
1945
1946 path = getenv("DRACUT_INSTALL_PATH");
1947 if (path == NULL)
1948 path = getenv("PATH");
1949
1950 if (path == NULL) {
1951 log_error("PATH is not set");
1952 exit(EXIT_FAILURE);
1953 }
1954
1955 log_debug("PATH=%s", path);
1956
1957 ldd = getenv("DRACUT_LDD");
1958 if (ldd == NULL)
1959 ldd = "ldd";
1960 log_debug("LDD=%s", ldd);
1961
1962 env_no_xattr = getenv("DRACUT_NO_XATTR");
1963 if (env_no_xattr != NULL)
1964 no_xattr = true;
1965
1966 pathdirs = strv_split(path, ":");
1967
1968 umask(0022);
1969
1970 if (destrootdir == NULL || strlen(destrootdir) == 0) {
1971 destrootdir = getenv("DESTROOTDIR");
1972 if (destrootdir == NULL || strlen(destrootdir) == 0) {
1973 log_error("Environment DESTROOTDIR or argument -D is not set!");
1974 usage(EXIT_FAILURE);
1975 }
1976 destrootdir = strdup(destrootdir);
1977 }
1978
1979 if (strcmp(destrootdir, "/") == 0) {
1980 log_error("Environment DESTROOTDIR or argument -D is set to '/'!");
1981 usage(EXIT_FAILURE);
1982 }
1983
1984 i = destrootdir;
1985 destrootdir = realpath(destrootdir, NULL);
1986 if (!destrootdir) {
1987 log_error("Environment DESTROOTDIR or argument -D is set to '%s': %m", i);
1988 r = EXIT_FAILURE;
1989 goto finish;
1990 }
1991 free(i);
1992
1993 items = hashmap_new(string_hash_func, string_compare_func);
1994 items_failed = hashmap_new(string_hash_func, string_compare_func);
1995
1996 if (!items || !items_failed || !modules_loaded) {
1997 log_error("Out of memory");
1998 r = EXIT_FAILURE;
1999 goto finish;
2000 }
2001
2002 if (logdir) {
2003 int ret;
2004
2005 ret = asprintf(&logfile, "%s/%d.log", logdir, getpid());
2006 if (ret < 0) {
2007 log_error("Out of memory!");
2008 exit(EXIT_FAILURE);
2009 }
2010
2011 logfile_f = fopen(logfile, "a");
2012 if (logfile_f == NULL) {
2013 log_error("Could not open %s for logging: %m", logfile);
2014 r = EXIT_FAILURE;
2015 goto finish;
2016 }
2017 }
2018
2019 r = EXIT_SUCCESS;
2020
2021 if (((optind + 1) < argc) && (strcmp(argv[optind + 1], destrootdir) == 0)) {
2022 /* ugly hack for compat mode "inst src $destrootdir" */
2023 if ((optind + 2) == argc) {
2024 argc--;
2025 } else {
2026 /* ugly hack for compat mode "inst src $destrootdir dst" */
2027 if ((optind + 3) == argc) {
2028 argc--;
2029 argv[optind + 1] = argv[optind + 2];
2030 }
2031 }
2032 }
2033
2034 if (arg_module) {
2035 r = install_modules(argc - optind, &argv[optind]);
2036 } else if (arg_resolvelazy) {
2037 r = resolve_lazy(argc - optind, &argv[optind]);
2038 } else if (arg_all || (argc - optind > 2) || ((argc - optind) == 1)) {
2039 r = install_all(argc - optind, &argv[optind]);
2040 } else {
2041 /* simple "inst src dst" */
2042 r = install_one(argv[optind], argv[optind + 1]);
2043 }
2044
2045 if (arg_optional)
2046 r = EXIT_SUCCESS;
2047
2048 finish:
2049 if (logfile_f)
2050 fclose(logfile_f);
2051
2052 while ((i = hashmap_steal_first(modules_loaded)))
2053 item_free(i);
2054
2055 while ((i = hashmap_steal_first(items)))
2056 item_free(i);
2057
2058 while ((i = hashmap_steal_first(items_failed)))
2059 item_free(i);
2060
2061 hashmap_free(items);
2062 hashmap_free(items_failed);
2063 hashmap_free(modules_loaded);
2064
2065 free(destrootdir);
2066 strv_free(firmwaredirs);
2067 strv_free(pathdirs);
2068 return r;
2069 }