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