]> git.ipfire.org Git - thirdparty/dracut.git/blob - install/dracut-install.c
dracut-install: simplify ldd parsing logic
[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 = strchr(buf, '/');
483 if (p) {
484 char *q;
485
486 for (q = p; *q && *q != ' ' && *q != '\n'; q++) ;
487 *q = '\0';
488
489 ret += library_install(src, p);
490
491 }
492 }
493
494 return ret;
495 }
496
497 /* Install ".<filename>.hmac" file for FIPS self-checks */
498 static int hmac_install(const char *src, const char *dst, const char *hmacpath)
499 {
500 _cleanup_free_ char *srcpath = strdup(src);
501 _cleanup_free_ char *dstpath = strdup(dst);
502 _cleanup_free_ char *srchmacname = NULL;
503 _cleanup_free_ char *dsthmacname = NULL;
504 int ret;
505
506 if (!(srcpath && dstpath))
507 return -ENOMEM;
508
509 size_t dlen = dir_len(src);
510
511 if (endswith(src, ".hmac"))
512 return 0;
513
514 if (!hmacpath) {
515 hmac_install(src, dst, "/lib/fipscheck");
516 hmac_install(src, dst, "/lib64/fipscheck");
517 hmac_install(src, dst, "/lib/hmaccalc");
518 hmac_install(src, dst, "/lib64/hmaccalc");
519 }
520
521 srcpath[dlen] = '\0';
522 dstpath[dir_len(dst)] = '\0';
523 if (hmacpath) {
524 ret = asprintf(&srchmacname, "%s/%s.hmac", hmacpath, &src[dlen + 1]);
525 if (ret < 0) {
526 log_error("Out of memory!");
527 exit(EXIT_FAILURE);
528 }
529
530 ret = asprintf(&dsthmacname, "%s/%s.hmac", hmacpath, &src[dlen + 1]);
531 if (ret < 0) {
532 log_error("Out of memory!");
533 exit(EXIT_FAILURE);
534 }
535 } else {
536 ret = asprintf(&srchmacname, "%s/.%s.hmac", srcpath, &src[dlen + 1]);
537 if (ret < 0) {
538 log_error("Out of memory!");
539 exit(EXIT_FAILURE);
540 }
541
542 ret = asprintf(&dsthmacname, "%s/.%s.hmac", dstpath, &src[dlen + 1]);
543 if (ret < 0) {
544 log_error("Out of memory!");
545 exit(EXIT_FAILURE);
546 }
547 }
548 log_debug("hmac cp '%s' '%s')", srchmacname, dsthmacname);
549 dracut_install(srchmacname, dsthmacname, false, false, true);
550 return 0;
551 }
552
553 void mark_hostonly(const char *path)
554 {
555 _cleanup_free_ char *fulldstpath = NULL;
556 _cleanup_fclose_ FILE *f = NULL;
557 int ret;
558
559 ret = asprintf(&fulldstpath, "%s/lib/dracut/hostonly-files", destrootdir);
560 if (ret < 0) {
561 log_error("Out of memory!");
562 exit(EXIT_FAILURE);
563 }
564
565 f = fopen(fulldstpath, "a");
566
567 if (f == NULL) {
568 log_error("Could not open '%s' for writing.", fulldstpath);
569 return;
570 }
571
572 fprintf(f, "%s\n", path);
573 }
574
575 void dracut_log_cp(const char *path)
576 {
577 int ret;
578 ret = fprintf(logfile_f, "%s\n", path);
579 if (ret < 0)
580 log_error("Could not append '%s' to logfile '%s': %m", path, logfile);
581 }
582
583 static bool check_hashmap(Hashmap *hm, const char *item)
584 {
585 char *existing;
586 existing = hashmap_get(hm, item);
587 if (existing) {
588 if (strcmp(existing, item) == 0) {
589 return true;
590 }
591 }
592 return false;
593 }
594
595 static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps, bool hashdst)
596 {
597 struct stat sb, db;
598 _cleanup_free_ char *fulldstpath = NULL;
599 _cleanup_free_ char *fulldstdir = NULL;
600 int ret;
601 bool src_exists = true;
602 char *i = NULL;
603
604 log_debug("dracut_install('%s', '%s')", src, dst);
605
606 if (check_hashmap(items_failed, src)) {
607 log_debug("hash hit items_failed for '%s'", src);
608 return 1;
609 }
610
611 if (hashdst && check_hashmap(items, dst)) {
612 log_debug("hash hit items for '%s'", dst);
613 return 0;
614 }
615
616 if (lstat(src, &sb) < 0) {
617 src_exists = false;
618 if (!isdir) {
619 i = strdup(src);
620 hashmap_put(items_failed, i, i);
621 /* src does not exist */
622 return 1;
623 }
624 }
625
626 i = strdup(dst);
627 if (!i)
628 return -ENOMEM;
629
630 hashmap_put(items, i, i);
631
632 ret = asprintf(&fulldstpath, "%s/%s", destrootdir, (dst[0]=='/' ? (dst+1) : dst));
633 if (ret < 0) {
634 log_error("Out of memory!");
635 exit(EXIT_FAILURE);
636 }
637
638 ret = stat(fulldstpath, &sb);
639
640 if (ret != 0 && (errno != ENOENT)) {
641 log_error("ERROR: stat '%s': %m", fulldstpath);
642 return 1;
643 }
644
645 if (ret == 0) {
646 if (resolvedeps && S_ISREG(sb.st_mode) && (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
647 log_debug("'%s' already exists, but checking for any deps", fulldstpath);
648 ret = resolve_deps(src);
649 } else
650 log_debug("'%s' already exists", fulldstpath);
651
652 /* dst does already exist */
653 return ret;
654 }
655
656 /* check destination directory */
657 fulldstdir = strdup(fulldstpath);
658 fulldstdir[dir_len(fulldstdir)] = '\0';
659
660 ret = stat(fulldstdir, &db);
661
662 if (ret < 0) {
663 _cleanup_free_ char *dname = NULL;
664
665 if (errno != ENOENT) {
666 log_error("ERROR: stat '%s': %m", fulldstdir);
667 return 1;
668 }
669 /* create destination directory */
670 log_debug("dest dir '%s' does not exist", fulldstdir);
671 dname = strdup(dst);
672 if (!dname)
673 return 1;
674
675 dname[dir_len(dname)] = '\0';
676 ret = dracut_install(dname, dname, true, false, true);
677
678 if (ret != 0) {
679 log_error("ERROR: failed to create directory '%s'", fulldstdir);
680 return 1;
681 }
682 }
683
684 if (isdir && !src_exists) {
685 log_info("mkdir '%s'", fulldstpath);
686 ret = mkdir(fulldstpath, 0755);
687 return ret;
688 }
689
690 /* ready to install src */
691
692 if (S_ISDIR(sb.st_mode)) {
693 log_info("mkdir '%s'", fulldstpath);
694 ret = mkdir(fulldstpath, sb.st_mode | S_IWUSR);
695 return ret;
696 }
697
698 if (S_ISLNK(sb.st_mode)) {
699 _cleanup_free_ char *abspath = NULL;
700
701 abspath = realpath(src, NULL);
702
703 if (abspath == NULL)
704 return 1;
705
706 if (dracut_install(abspath, abspath, false, resolvedeps, hashdst)) {
707 log_debug("'%s' install error", abspath);
708 return 1;
709 }
710
711 if (lstat(abspath, &sb) != 0) {
712 log_debug("lstat '%s': %m", abspath);
713 return 1;
714 }
715
716 if (lstat(fulldstpath, &sb) != 0) {
717 _cleanup_free_ char *absdestpath = NULL;
718
719 ret = asprintf(&absdestpath, "%s/%s", destrootdir, (abspath[0]=='/' ? (abspath+1) : abspath));
720 if (ret < 0) {
721 log_error("Out of memory!");
722 exit(EXIT_FAILURE);
723 }
724
725 ln_r(absdestpath, fulldstpath);
726 }
727
728 if (arg_hmac) {
729 /* copy .hmac files also */
730 hmac_install(src, dst, NULL);
731 }
732
733 return 0;
734 }
735
736 if (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
737 if (resolvedeps)
738 ret += resolve_deps(src);
739 if (arg_hmac) {
740 /* copy .hmac files also */
741 hmac_install(src, dst, NULL);
742 }
743 }
744
745 log_debug("dracut_install ret = %d", ret);
746 log_info("cp '%s' '%s'", src, fulldstpath);
747
748 if (arg_hostonly && !arg_module)
749 mark_hostonly(dst);
750
751 ret += cp(src, fulldstpath);
752 if (ret == 0 && logfile_f)
753 dracut_log_cp(src);
754
755 log_debug("dracut_install ret = %d", ret);
756
757 return ret;
758 }
759
760 static void item_free(char *i)
761 {
762 assert(i);
763 free(i);
764 }
765
766 static void usage(int status)
767 {
768 /* */
769 printf("Usage: %s -D DESTROOTDIR [OPTION]... -a SOURCE...\n"
770 "or: %s -D DESTROOTDIR [OPTION]... SOURCE DEST\n"
771 "or: %s -D DESTROOTDIR [OPTION]... -m KERNELMODULE [KERNELMODULE …]\n"
772 "\n"
773 "Install SOURCE to DEST in DESTROOTDIR with all needed dependencies.\n"
774 "\n"
775 " KERNELMODULE can have the format:\n"
776 " <absolute path> with a leading /\n"
777 " =<kernel subdir>[/<kernel subdir>…] like '=drivers/hid'\n"
778 " <module name>\n"
779 "\n"
780 " -D --destrootdir Install all files to DESTROOTDIR as the root\n"
781 " -a --all Install all SOURCE arguments to DESTROOTDIR\n"
782 " -o --optional If SOURCE does not exist, do not fail\n"
783 " -d --dir SOURCE is a directory\n"
784 " -l --ldd Also install shebang executables and libraries\n"
785 " -L --logdir <DIR> Log files, which were installed from the host to <DIR>\n"
786 " -R --resolvelazy Only install shebang executables and libraries\n"
787 " for all SOURCE files\n"
788 " -H --hostonly Mark all SOURCE files as hostonly\n\n"
789 " -f --fips Also install all '.SOURCE.hmac' files\n"
790 "\n"
791 " --module,-m Install kernel modules, instead of files\n"
792 " --kerneldir Specify the kernel module directory\n"
793 " --firmwaredirs Specify the firmware directory search path with : separation\n"
794 " --silent Don't display error messages for kernel module install\n"
795 " --modalias Only generate module list from /sys/devices modalias list\n"
796 " -o --optional If kernel module does not exist, do not fail\n"
797 " -p --mod-filter-path Filter kernel modules by path regexp\n"
798 " -P --mod-filter-nopath Exclude kernel modules by path regexp\n"
799 " -s --mod-filter-symbol Filter kernel modules by symbol regexp\n"
800 " -S --mod-filter-nosymbol Exclude kernel modules by symbol regexp\n"
801 " -N --mod-filter-noname Exclude kernel modules by name regexp\n"
802 "\n"
803 " -v --verbose Show more output\n"
804 " --debug Show debug output\n"
805 " --version Show package version\n"
806 " -h --help Show this help\n"
807 "\n",
808 program_invocation_short_name, program_invocation_short_name,
809 program_invocation_short_name);
810 exit(status);
811 }
812
813 static int parse_argv(int argc, char *argv[])
814 {
815 int c;
816
817 enum {
818 ARG_VERSION = 0x100,
819 ARG_SILENT,
820 ARG_MODALIAS,
821 ARG_KERNELDIR,
822 ARG_FIRMWAREDIRS,
823 ARG_DEBUG
824 };
825
826 static struct option const options[] = {
827 {"help", no_argument, NULL, 'h'},
828 {"version", no_argument, NULL, ARG_VERSION},
829 {"dir", no_argument, NULL, 'd'},
830 {"debug", no_argument, NULL, ARG_DEBUG},
831 {"verbose", no_argument, NULL, 'v'},
832 {"ldd", no_argument, NULL, 'l'},
833 {"resolvelazy", no_argument, NULL, 'R'},
834 {"optional", no_argument, NULL, 'o'},
835 {"hostonly", no_argument, NULL, 'H'},
836 {"all", no_argument, NULL, 'a'},
837 {"module", no_argument, NULL, 'm'},
838 {"fips", no_argument, NULL, 'f'},
839 {"destrootdir", required_argument, NULL, 'D'},
840 {"logdir", required_argument, NULL, 'L'},
841 {"mod-filter-path", required_argument, NULL, 'p'},
842 {"mod-filter-nopath", required_argument, NULL, 'P'},
843 {"mod-filter-symbol", required_argument, NULL, 's'},
844 {"mod-filter-nosymbol", required_argument, NULL, 'S'},
845 {"mod-filter-noname", required_argument, NULL, 'N'},
846 {"modalias", no_argument, NULL, ARG_MODALIAS},
847 {"silent", no_argument, NULL, ARG_SILENT},
848 {"kerneldir", required_argument, NULL, ARG_KERNELDIR},
849 {"firmwaredirs", required_argument, NULL, ARG_FIRMWAREDIRS},
850 {NULL, 0, NULL, 0}
851 };
852
853 while ((c = getopt_long(argc, argv, "madfhlL:oD:HRp:P:s:S:N:", options, NULL)) != -1) {
854 switch (c) {
855 case ARG_VERSION:
856 puts(PROGRAM_VERSION_STRING);
857 return 0;
858 case 'd':
859 arg_createdir = true;
860 break;
861 case ARG_DEBUG:
862 arg_loglevel = LOG_DEBUG;
863 break;
864 case ARG_SILENT:
865 arg_silent = true;
866 break;
867 case ARG_MODALIAS:
868 arg_modalias = true;
869 return 1;
870 break;
871 case 'v':
872 arg_loglevel = LOG_INFO;
873 break;
874 case 'o':
875 arg_optional = true;
876 break;
877 case 'l':
878 arg_resolvedeps = true;
879 break;
880 case 'R':
881 arg_resolvelazy = true;
882 break;
883 case 'a':
884 arg_all = true;
885 break;
886 case 'm':
887 arg_module = true;
888 break;
889 case 'D':
890 destrootdir = strdup(optarg);
891 break;
892 case 'p':
893 if (regcomp(&mod_filter_path, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
894 log_error("Module path filter %s is not a regular expression", optarg);
895 exit(EXIT_FAILURE);
896 }
897 arg_mod_filter_path = true;
898 break;
899 case 'P':
900 if (regcomp(&mod_filter_nopath, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
901 log_error("Module path filter %s is not a regular expression", optarg);
902 exit(EXIT_FAILURE);
903 }
904 arg_mod_filter_nopath = true;
905 break;
906 case 's':
907 if (regcomp(&mod_filter_symbol, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
908 log_error("Module symbol filter %s is not a regular expression", optarg);
909 exit(EXIT_FAILURE);
910 }
911 arg_mod_filter_symbol = true;
912 break;
913 case 'S':
914 if (regcomp(&mod_filter_nosymbol, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
915 log_error("Module symbol filter %s is not a regular expression", optarg);
916 exit(EXIT_FAILURE);
917 }
918 arg_mod_filter_nosymbol = true;
919 break;
920 case 'N':
921 if (regcomp(&mod_filter_noname, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
922 log_error("Module symbol filter %s is not a regular expression", optarg);
923 exit(EXIT_FAILURE);
924 }
925 arg_mod_filter_noname = true;
926 break;
927 case 'L':
928 logdir = strdup(optarg);
929 break;
930 case ARG_KERNELDIR:
931 kerneldir = strdup(optarg);
932 break;
933 case ARG_FIRMWAREDIRS:
934 firmwaredirs = strv_split(optarg, ":");
935 break;
936 case 'f':
937 arg_hmac = true;
938 break;
939 case 'H':
940 arg_hostonly = true;
941 break;
942 case 'h':
943 usage(EXIT_SUCCESS);
944 break;
945 default:
946 usage(EXIT_FAILURE);
947 }
948 }
949
950 if (!kerneldir) {
951 struct utsname buf;
952 uname(&buf);
953 kerneldir = strdup(buf.version);
954 }
955
956 if (arg_modalias) {
957 return 1;
958 }
959
960 if (arg_module) {
961 if (!firmwaredirs) {
962 char *path = NULL;
963
964 path = getenv("DRACUT_FIRMWARE_PATH");
965
966 if (path == NULL) {
967 log_error("Environment variable DRACUT_FIRMWARE_PATH is not set");
968 exit(EXIT_FAILURE);
969 }
970
971 log_debug("DRACUT_FIRMWARE_PATH=%s", path);
972
973 firmwaredirs = strv_split(path, ":");
974 }
975 }
976
977 if (!optind || optind == argc) {
978 log_error("No SOURCE argument given");
979 usage(EXIT_FAILURE);
980 }
981
982 return 1;
983 }
984
985 static int resolve_lazy(int argc, char **argv)
986 {
987 int i;
988 size_t destrootdirlen = strlen(destrootdir);
989 int ret = 0;
990 char *item;
991 for (i = 0; i < argc; i++) {
992 const char *src = argv[i];
993 char *p = argv[i];
994 char *existing;
995
996 log_debug("resolve_deps('%s')", src);
997
998 if (strstr(src, destrootdir)) {
999 p = &argv[i][destrootdirlen];
1000 }
1001
1002 existing = hashmap_get(items, p);
1003 if (existing) {
1004 if (strcmp(existing, p) == 0)
1005 continue;
1006 }
1007
1008 item = strdup(p);
1009 hashmap_put(items, item, item);
1010
1011 ret += resolve_deps(src);
1012 }
1013 return ret;
1014 }
1015
1016 static char **find_binary(const char *src)
1017 {
1018 char **ret = NULL;
1019 char **q;
1020 char *newsrc = NULL;
1021
1022 STRV_FOREACH(q, pathdirs) {
1023 struct stat sb;
1024 int r;
1025
1026 r = asprintf(&newsrc, "%s/%s", *q, src);
1027 if (r < 0) {
1028 log_error("Out of memory!");
1029 exit(EXIT_FAILURE);
1030 }
1031
1032 if (stat(newsrc, &sb) != 0) {
1033 log_debug("stat(%s) != 0", newsrc);
1034 free(newsrc);
1035 newsrc = NULL;
1036 continue;
1037 }
1038
1039 strv_push(&ret, newsrc);
1040
1041 };
1042
1043 if (ret) {
1044 STRV_FOREACH(q, ret) {
1045 log_debug("find_binary(%s) == %s", src, *q);
1046 }
1047 }
1048
1049 return ret;
1050 }
1051
1052 static int install_one(const char *src, const char *dst)
1053 {
1054 int r = EXIT_SUCCESS;
1055 int ret = 0;
1056
1057 if (strchr(src, '/') == NULL) {
1058 char **p = find_binary(src);
1059 if (p) {
1060 char **q = NULL;
1061 STRV_FOREACH(q, p) {
1062 char *newsrc = *q;
1063 log_debug("dracut_install '%s' '%s'", newsrc, dst);
1064 ret = dracut_install(newsrc, dst, arg_createdir, arg_resolvedeps, true);
1065 if (ret == 0) {
1066 log_debug("dracut_install '%s' '%s' OK", newsrc, dst);
1067 }
1068 }
1069 strv_free(p);
1070 } else {
1071 ret = -1;
1072 }
1073 } else {
1074 ret = dracut_install(src, dst, arg_createdir, arg_resolvedeps, true);
1075 }
1076
1077 if ((ret != 0) && (!arg_optional)) {
1078 log_error("ERROR: installing '%s' to '%s'", src, dst);
1079 r = EXIT_FAILURE;
1080 }
1081
1082 return r;
1083 }
1084
1085 static int install_all(int argc, char **argv)
1086 {
1087 int r = EXIT_SUCCESS;
1088 int i;
1089 for (i = 0; i < argc; i++) {
1090 int ret = 0;
1091 log_debug("Handle '%s'", argv[i]);
1092
1093 if (strchr(argv[i], '/') == NULL) {
1094 char **p = find_binary(argv[i]);
1095 if (p) {
1096 char **q = NULL;
1097 STRV_FOREACH(q, p) {
1098 char *newsrc = *q;
1099 log_debug("dracut_install '%s'", newsrc);
1100 ret = dracut_install(newsrc, newsrc, arg_createdir, arg_resolvedeps, true);
1101 if (ret == 0) {
1102 log_debug("dracut_install '%s' OK", newsrc);
1103 }
1104 }
1105 strv_free(p);
1106 } else {
1107 ret = -1;
1108 }
1109
1110 } else {
1111 _cleanup_free_ char *dest = strdup(argv[i]);
1112 ret = dracut_install(argv[i], dest, arg_createdir, arg_resolvedeps, true);
1113 }
1114
1115 if ((ret != 0) && (!arg_optional)) {
1116 log_error("ERROR: installing '%s'", argv[i]);
1117 r = EXIT_FAILURE;
1118 }
1119 }
1120 return r;
1121 }
1122
1123 static int install_firmware(struct kmod_module *mod)
1124 {
1125 struct kmod_list *l;
1126 _cleanup_kmod_module_info_free_list_ struct kmod_list *list = NULL;
1127 int ret;
1128
1129 char **q;
1130
1131 ret = kmod_module_get_info(mod, &list);
1132 if (ret < 0) {
1133 log_error("could not get modinfo from '%s': %s\n",
1134 kmod_module_get_name(mod), strerror(-ret));
1135 return ret;
1136 }
1137 kmod_list_foreach(l, list) {
1138 const char *key = kmod_module_info_get_key(l);
1139 const char *value = NULL;
1140
1141 if (!streq("firmware", key))
1142 continue;
1143
1144 value = kmod_module_info_get_value(l);
1145 log_debug("Firmware %s", value);
1146 ret = -1;
1147 STRV_FOREACH(q, firmwaredirs) {
1148 _cleanup_free_ char *fwpath = NULL;
1149 struct stat sb;
1150 int r;
1151
1152 r = asprintf(&fwpath, "%s/%s", *q, value);
1153 if (r < 0) {
1154 log_error("Out of memory!");
1155 exit(EXIT_FAILURE);
1156 }
1157
1158 if (stat(fwpath, &sb) != 0) {
1159 log_debug("stat(%s) != 0", fwpath);
1160 continue;
1161 }
1162
1163 ret = dracut_install(fwpath, fwpath, false, false, true);
1164 if (ret == 0)
1165 log_debug("dracut_install '%s' OK", fwpath);
1166 }
1167
1168 if (ret != 0) {
1169 log_info("Possible missing firmware %s for kernel module %s", value, kmod_module_get_name(mod));
1170 }
1171 }
1172 return 0;
1173 }
1174
1175 static bool check_module_symbols(struct kmod_module *mod)
1176 {
1177 struct kmod_list *itr;
1178 _cleanup_kmod_module_dependency_symbols_free_list_ struct kmod_list *deplist = NULL;
1179
1180 if (!arg_mod_filter_symbol && !arg_mod_filter_nosymbol)
1181 return true;
1182
1183 if (kmod_module_get_dependency_symbols(mod, &deplist) < 0) {
1184 log_debug("kmod_module_get_dependency_symbols failed");
1185 if (arg_mod_filter_symbol)
1186 return false;
1187 return true;
1188 }
1189
1190 if (arg_mod_filter_nosymbol) {
1191 kmod_list_foreach(itr, deplist) {
1192 const char *symbol = kmod_module_symbol_get_symbol(itr);
1193 // log_debug("Checking symbol %s", symbol);
1194 if (regexec(&mod_filter_nosymbol, symbol, 0, NULL, 0) == 0) {
1195 log_debug("Module %s: symbol %s matched exclusion filter", kmod_module_get_name(mod), symbol);
1196 return false;
1197 }
1198 }
1199 }
1200
1201 if (arg_mod_filter_symbol) {
1202 kmod_list_foreach(itr, deplist) {
1203 const char *symbol = kmod_module_dependency_symbol_get_symbol(itr);
1204 // log_debug("Checking symbol %s", symbol);
1205 if (regexec(&mod_filter_symbol, symbol, 0, NULL, 0) == 0) {
1206 log_debug("Module %s: symbol %s matched inclusion filter", kmod_module_get_name(mod), symbol);
1207 return true;
1208 }
1209 }
1210 return false;
1211 }
1212
1213 return true;
1214 }
1215
1216 static bool check_module_path(const char *path)
1217 {
1218 if (arg_mod_filter_nopath && (regexec(&mod_filter_nopath, path, 0, NULL, 0) == 0)) {
1219 log_debug("Path %s matched exclusion filter", path);
1220 return false;
1221 }
1222
1223 if (arg_mod_filter_path && (regexec(&mod_filter_path, path, 0, NULL, 0) != 0)) {
1224 log_debug("Path %s matched inclusion filter", path);
1225 return false;
1226 }
1227 return true;
1228 }
1229
1230 static int install_dependent_modules(struct kmod_list *modlist)
1231 {
1232 struct kmod_list *itr;
1233 struct kmod_module *mod;
1234 const char *path = NULL;
1235 const char *name = NULL;
1236 int ret = 0;
1237
1238 kmod_list_foreach(itr, modlist) {
1239 mod = kmod_module_get_module(itr);
1240 path = kmod_module_get_path(mod);
1241
1242 name = kmod_module_get_name(mod);
1243 if ((path == NULL) || (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0))) {
1244 kmod_module_unref(mod);
1245 continue;
1246 }
1247 ret = dracut_install(path, &path[kerneldirlen], false, false, true);
1248 if (ret == 0) {
1249 log_debug("dracut_install '%s' '%s' OK", path, &path[kerneldirlen]);
1250 install_firmware(mod);
1251 } else {
1252 log_error("dracut_install '%s' '%s' ERROR", path, &path[kerneldirlen]);
1253 }
1254 kmod_module_unref(mod);
1255 }
1256
1257 return ret;
1258 }
1259
1260 static int install_module(struct kmod_module *mod)
1261 {
1262 int ret = 0;
1263 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1264 _cleanup_kmod_module_unref_list_ struct kmod_list *modpre = NULL;
1265 _cleanup_kmod_module_unref_list_ struct kmod_list *modpost = NULL;
1266 const char *path = NULL;
1267 const char *name = NULL;
1268
1269 name = kmod_module_get_name(mod);
1270 if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
1271 log_debug("dracut_install '%s' is excluded", name);
1272 return 0;
1273 }
1274
1275 if (arg_hostonly && !check_hashmap(modules_loaded, name)) {
1276 log_debug("dracut_install '%s' not hostonly", name);
1277 return 0;
1278 }
1279
1280 path = kmod_module_get_path(mod);
1281 if (!path)
1282 return -ENOENT;
1283
1284 if (check_hashmap(items_failed, path))
1285 return -1;
1286
1287 if (check_hashmap(items, path))
1288 return 0;
1289
1290 if (!check_module_path(path) || !check_module_symbols(mod)) {
1291 log_debug("No symbol or path match for '%s'", path);
1292 return 1;
1293 }
1294
1295 log_debug("dracut_install '%s' '%s'", path, &path[kerneldirlen]);
1296
1297 ret = dracut_install(path, &path[kerneldirlen], false, false, true);
1298 if (ret == 0) {
1299 log_debug("dracut_install '%s' OK", kmod_module_get_name(mod));
1300 } else if (!arg_optional) {
1301 if (!arg_silent)
1302 log_error("dracut_install '%s' ERROR", kmod_module_get_name(mod));
1303 return ret;
1304 }
1305 install_firmware(mod);
1306
1307 modlist = kmod_module_get_dependencies(mod);
1308 ret = install_dependent_modules(modlist);
1309
1310 if (ret == 0) {
1311 ret = kmod_module_get_softdeps(mod, &modpre, &modpost);
1312 if (ret == 0)
1313 ret = install_dependent_modules(modpre);
1314 }
1315
1316 return ret;
1317 }
1318
1319 static int modalias_list(struct kmod_ctx *ctx)
1320 {
1321 int err;
1322 struct kmod_list *loaded_list = NULL;
1323 struct kmod_list *itr, *l;
1324 _cleanup_fts_close_ FTS *fts = NULL;
1325
1326 {
1327 char *paths[] = { "/sys/devices", NULL };
1328 fts = fts_open(paths, FTS_NOCHDIR|FTS_NOSTAT, NULL);
1329 }
1330 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1331 _cleanup_fclose_ FILE *f = NULL;
1332 _cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
1333 struct kmod_list *l;
1334
1335 int err;
1336
1337 char alias[2048];
1338 size_t len;
1339
1340 if (strncmp("modalias", ftsent->fts_name, 8) != 0)
1341 continue;
1342 if (!(f = fopen(ftsent->fts_accpath, "r")))
1343 continue;
1344
1345 if(!fgets(alias, sizeof(alias), f))
1346 continue;
1347
1348 len = strlen(alias);
1349
1350 if (len == 0)
1351 continue;
1352
1353 if (alias[len-1] == '\n')
1354 alias[len-1] = 0;
1355
1356 err = kmod_module_new_from_lookup(ctx, alias, &list);
1357 if (err < 0)
1358 continue;
1359
1360 kmod_list_foreach(l, list) {
1361 struct kmod_module *mod = kmod_module_get_module(l);
1362 char *name = strdup(kmod_module_get_name(mod));
1363 kmod_module_unref(mod);
1364 hashmap_put(modules_loaded, name, name);
1365 }
1366 }
1367
1368 err = kmod_module_new_from_loaded(ctx, &loaded_list);
1369 if (err < 0) {
1370 errno = err;
1371 log_error("Could not get list of loaded modules: %m. Switching to non-hostonly mode.");
1372 arg_hostonly = false;
1373 } else {
1374 kmod_list_foreach(itr, loaded_list) {
1375 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1376
1377 struct kmod_module *mod = kmod_module_get_module(itr);
1378 char *name = strdup(kmod_module_get_name(mod));
1379 hashmap_put(modules_loaded, name, name);
1380 kmod_module_unref(mod);
1381
1382 /* also put the modules from the new kernel in the hashmap,
1383 * which resolve the name as an alias, in case a kernel module is
1384 * renamed.
1385 */
1386 err = kmod_module_new_from_lookup(ctx, name, &modlist);
1387 if (err < 0)
1388 continue;
1389 if (!modlist)
1390 continue;
1391 kmod_list_foreach(l, modlist) {
1392 mod = kmod_module_get_module(l);
1393 char *name = strdup(kmod_module_get_name(mod));
1394 hashmap_put(modules_loaded, name, name);
1395 kmod_module_unref(mod);
1396 }
1397 }
1398 kmod_module_unref_list(loaded_list);
1399 }
1400 return 0;
1401 }
1402
1403 static int install_modules(int argc, char **argv)
1404 {
1405 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
1406 struct kmod_list *itr;
1407
1408 struct kmod_module *mod = NULL, *mod_o = NULL;
1409
1410 const char *abskpath = NULL;
1411 char *p;
1412 int i;
1413 int modinst = 0;
1414
1415 ctx = kmod_new(kerneldir, NULL);
1416 abskpath = kmod_get_dirname(ctx);
1417
1418 p = strstr(abskpath, "/lib/modules/");
1419 if (p != NULL)
1420 kerneldirlen = p - abskpath;
1421
1422 if (arg_hostonly) {
1423 char *modalias_file;
1424 modalias_file = getenv("DRACUT_KERNEL_MODALIASES");
1425
1426 if (modalias_file == NULL) {
1427 modalias_list(ctx);
1428 } else {
1429 _cleanup_fclose_ FILE *f = NULL;
1430 if ((f = fopen(modalias_file, "r"))) {
1431 char name[2048];
1432
1433 while (!feof(f)) {
1434 size_t len;
1435 char *dupname = NULL;
1436
1437 if(!(fgets(name, sizeof(name), f)))
1438 continue;
1439 len = strlen(name);
1440
1441 if (len == 0)
1442 continue;
1443
1444 if (name[len-1] == '\n')
1445 name[len-1] = 0;
1446
1447 log_debug("Adding module '%s' to hostonly module list", name);
1448 dupname = strdup(name);
1449 hashmap_put(modules_loaded, dupname, dupname);
1450 }
1451 }
1452 }
1453
1454 }
1455
1456 for (i = 0; i < argc; i++) {
1457 int r = 0;
1458 int ret = -1;
1459 log_debug("Handle module '%s'", argv[i]);
1460
1461 if (argv[i][0] == '/') {
1462 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1463 _cleanup_free_ const char *modname = NULL;
1464
1465 r = kmod_module_new_from_path(ctx, argv[i], &mod_o);
1466 if (r < 0) {
1467 log_debug("Failed to lookup modules path '%s': %m", argv[i]);
1468 if (!arg_optional)
1469 return -ENOENT;
1470 continue;
1471 }
1472 /* Check, if we have to load another module with that name instead */
1473 modname = strdup(kmod_module_get_name(mod_o));
1474
1475 if (!modname) {
1476 if (!arg_optional) {
1477 if (!arg_silent)
1478 log_error("Failed to get name for module '%s'", argv[i]);
1479 return -ENOENT;
1480 }
1481 log_info("Failed to get name for module '%s'", argv[i]);
1482 continue;
1483 }
1484
1485 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1486 kmod_module_unref(mod_o);
1487 mod_o = NULL;
1488
1489 if (r < 0) {
1490 if (!arg_optional) {
1491 if (!arg_silent)
1492 log_error("3 Failed to lookup alias '%s': %d", modname, r);
1493 return -ENOENT;
1494 }
1495 log_info("3 Failed to lookup alias '%s': %d", modname, r);
1496 continue;
1497 }
1498 if (!modlist) {
1499 if (!arg_optional) {
1500 if (!arg_silent)
1501 log_error("Failed to find module '%s' %s", modname, argv[i]);
1502 return -ENOENT;
1503 }
1504 log_info("Failed to find module '%s' %s", modname, argv[i]);
1505 continue;
1506 }
1507 kmod_list_foreach(itr, modlist) {
1508 mod = kmod_module_get_module(itr);
1509 r = install_module(mod);
1510 kmod_module_unref(mod);
1511 if ((r < 0) && !arg_optional) {
1512 if (!arg_silent)
1513 log_error("ERROR: installing module '%s'", modname);
1514 return -ENOENT;
1515 };
1516 ret = ( ret == 0 ? 0 : r );
1517 modinst = 1;
1518 }
1519 } else if (argv[i][0] == '=') {
1520 _cleanup_free_ char *path1 = NULL, *path2 = NULL, *path3 = NULL;
1521 _cleanup_fts_close_ FTS *fts = NULL;
1522
1523 log_debug("Handling =%s", &argv[i][1]);
1524 /* FIXME and add more paths*/
1525 r = asprintf(&path2, "%s/kernel/%s", kerneldir, &argv[i][1]);
1526 if (r < 0) {
1527 log_error("Out of memory!");
1528 exit(EXIT_FAILURE);
1529 }
1530
1531 r = asprintf(&path1, "%s/extra/%s", kerneldir, &argv[i][1]);
1532 if (r < 0) {
1533 log_error("Out of memory!");
1534 exit(EXIT_FAILURE);
1535 }
1536
1537 r = asprintf(&path3, "%s/updates/%s", kerneldir, &argv[i][1]);
1538 if (r < 0) {
1539 log_error("Out of memory!");
1540 exit(EXIT_FAILURE);
1541 }
1542
1543 {
1544 char *paths[] = { path1, path2, path3, NULL };
1545 fts = fts_open(paths, FTS_COMFOLLOW|FTS_NOCHDIR|FTS_NOSTAT|FTS_LOGICAL, NULL);
1546 }
1547
1548 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1549 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1550 _cleanup_free_ const char *modname = NULL;
1551
1552 if((ftsent->fts_info == FTS_D) && !check_module_path(ftsent->fts_accpath)) {
1553 fts_set(fts, ftsent, FTS_SKIP);
1554 log_debug("Skipping %s", ftsent->fts_accpath);
1555 continue;
1556 }
1557 if((ftsent->fts_info != FTS_F) && (ftsent->fts_info != FTS_SL)) {
1558 log_debug("Ignoring %s", ftsent->fts_accpath);
1559 continue;
1560 }
1561 log_debug("Handling %s", ftsent->fts_accpath);
1562 r = kmod_module_new_from_path(ctx, ftsent->fts_accpath, &mod_o);
1563 if (r < 0) {
1564 log_debug("Failed to lookup modules path '%s': %m",
1565 ftsent->fts_accpath);
1566 if (!arg_optional) {
1567 return -ENOENT;
1568 }
1569 continue;
1570 }
1571
1572 /* Check, if we have to load another module with that name instead */
1573 modname = strdup(kmod_module_get_name(mod_o));
1574
1575 if (!modname) {
1576 log_error("Failed to get name for module '%s'", ftsent->fts_accpath);
1577 if (!arg_optional) {
1578 return -ENOENT;
1579 }
1580 continue;
1581 }
1582 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1583 kmod_module_unref(mod_o);
1584 mod_o = NULL;
1585
1586 if (r < 0) {
1587 log_error("Failed to lookup alias '%s': %m", modname);
1588 if (!arg_optional) {
1589 return -ENOENT;
1590 }
1591 continue;
1592 }
1593
1594 if (!modlist) {
1595 log_error("Failed to find module '%s' %s", modname,
1596 ftsent->fts_accpath);
1597 if (!arg_optional) {
1598 return -ENOENT;
1599 }
1600 continue;
1601 }
1602 kmod_list_foreach(itr, modlist) {
1603 mod = kmod_module_get_module(itr);
1604 r = install_module(mod);
1605 kmod_module_unref(mod);
1606 if ((r < 0) && !arg_optional) {
1607 if (!arg_silent)
1608 log_error("ERROR: installing module '%s'", modname);
1609 return -ENOENT;
1610 };
1611 ret = ( ret == 0 ? 0 : r );
1612 modinst = 1;
1613 }
1614 }
1615 if (errno) {
1616 log_error("FTS ERROR: %m");
1617 }
1618 } else {
1619 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1620 char *modname = argv[i];
1621
1622 if (endswith(modname, ".ko")) {
1623 int len = strlen(modname);
1624 modname[len-3]=0;
1625 }
1626 if (endswith(modname, ".ko.xz") || endswith(modname, ".ko.gz")) {
1627 int len = strlen(modname);
1628 modname[len-6]=0;
1629 }
1630 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1631 if (r < 0) {
1632 if (!arg_optional) {
1633 if (!arg_silent)
1634 log_error("Failed to lookup alias '%s': %m", modname);
1635 return -ENOENT;
1636 }
1637 log_info("Failed to lookup alias '%s': %m", modname);
1638 continue;
1639 }
1640 if (!modlist) {
1641 if (!arg_optional) {
1642 if (!arg_silent)
1643 log_error("Failed to find module '%s'", modname);
1644 return -ENOENT;
1645 }
1646 log_info("Failed to find module '%s'", modname);
1647 continue;
1648 }
1649 kmod_list_foreach(itr, modlist) {
1650 mod = kmod_module_get_module(itr);
1651 r = install_module(mod);
1652 kmod_module_unref(mod);
1653 if ((r < 0) && !arg_optional) {
1654 if (!arg_silent)
1655 log_error("ERROR: installing '%s'", argv[i]);
1656 return -ENOENT;
1657 };
1658 ret = ( ret == 0 ? 0 : r );
1659 modinst = 1;
1660 }
1661 }
1662
1663 if ((modinst != 0) && (ret != 0) && (!arg_optional)) {
1664 if (!arg_silent)
1665 log_error("ERROR: installing '%s'", argv[i]);
1666 return EXIT_FAILURE;
1667 }
1668 }
1669
1670 return EXIT_SUCCESS;
1671 }
1672
1673 int main(int argc, char **argv)
1674 {
1675 int r;
1676 char *i;
1677 char *path = NULL;
1678
1679 r = parse_argv(argc, argv);
1680 if (r <= 0)
1681 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1682
1683 log_set_target(LOG_TARGET_CONSOLE);
1684 log_parse_environment();
1685
1686 if (arg_loglevel >= 0)
1687 log_set_max_level(arg_loglevel);
1688
1689 log_open();
1690
1691 modules_loaded = hashmap_new(string_hash_func, string_compare_func);
1692 if (arg_modalias) {
1693 Iterator i;
1694 char *name;
1695 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
1696 ctx = kmod_new(kerneldir, NULL);
1697
1698 modalias_list(ctx);
1699 HASHMAP_FOREACH(name, modules_loaded, i) {
1700 printf("%s\n", name);
1701 }
1702 exit(0);
1703 }
1704
1705 path = getenv("PATH");
1706
1707 if (path == NULL) {
1708 log_error("PATH is not set");
1709 exit(EXIT_FAILURE);
1710 }
1711
1712 log_debug("PATH=%s", path);
1713
1714 pathdirs = strv_split(path, ":");
1715
1716 umask(0022);
1717
1718 if (destrootdir == NULL || strlen(destrootdir) == 0) {
1719 destrootdir = getenv("DESTROOTDIR");
1720 if (destrootdir == NULL || strlen(destrootdir) == 0) {
1721 log_error("Environment DESTROOTDIR or argument -D is not set!");
1722 usage(EXIT_FAILURE);
1723 }
1724 destrootdir = strdup(destrootdir);
1725 }
1726
1727 if (strcmp(destrootdir, "/") == 0) {
1728 log_error("Environment DESTROOTDIR or argument -D is set to '/'!");
1729 usage(EXIT_FAILURE);
1730 }
1731
1732 i = destrootdir;
1733 destrootdir = realpath(destrootdir, NULL);
1734 if (!destrootdir) {
1735 log_error("Environment DESTROOTDIR or argument -D is set to '%s': %m", i);
1736 r = EXIT_FAILURE;
1737 goto finish;
1738 }
1739 free(i);
1740
1741 items = hashmap_new(string_hash_func, string_compare_func);
1742 items_failed = hashmap_new(string_hash_func, string_compare_func);
1743
1744 if (!items || !items_failed || !modules_loaded) {
1745 log_error("Out of memory");
1746 r = EXIT_FAILURE;
1747 goto finish;
1748 }
1749
1750 if (logdir) {
1751 int ret;
1752
1753 ret = asprintf(&logfile, "%s/%d.log", logdir, getpid());
1754 if (ret < 0) {
1755 log_error("Out of memory!");
1756 exit(EXIT_FAILURE);
1757 }
1758
1759 logfile_f = fopen(logfile, "a");
1760 if (logfile_f == NULL) {
1761 log_error("Could not open %s for logging: %m", logfile);
1762 r = EXIT_FAILURE;
1763 goto finish;
1764 }
1765 }
1766
1767 r = EXIT_SUCCESS;
1768
1769 if (((optind + 1) < argc) && (strcmp(argv[optind + 1], destrootdir) == 0)) {
1770 /* ugly hack for compat mode "inst src $destrootdir" */
1771 if ((optind + 2) == argc) {
1772 argc--;
1773 } else {
1774 /* ugly hack for compat mode "inst src $destrootdir dst" */
1775 if ((optind + 3) == argc) {
1776 argc--;
1777 argv[optind + 1] = argv[optind + 2];
1778 }
1779 }
1780 }
1781
1782 if (arg_module) {
1783 r = install_modules(argc - optind, &argv[optind]);
1784 } else if (arg_resolvelazy) {
1785 r = resolve_lazy(argc - optind, &argv[optind]);
1786 } else if (arg_all || (argc - optind > 2) || ((argc - optind) == 1)) {
1787 r = install_all(argc - optind, &argv[optind]);
1788 } else {
1789 /* simple "inst src dst" */
1790 r = install_one(argv[optind], argv[optind + 1]);
1791 }
1792
1793 if (arg_optional)
1794 r = EXIT_SUCCESS;
1795
1796 finish:
1797 if (logfile_f)
1798 fclose(logfile_f);
1799
1800 while ((i = hashmap_steal_first(modules_loaded)))
1801 item_free(i);
1802
1803 while ((i = hashmap_steal_first(items)))
1804 item_free(i);
1805
1806 while ((i = hashmap_steal_first(items_failed)))
1807 item_free(i);
1808
1809 hashmap_free(items);
1810 hashmap_free(items_failed);
1811 hashmap_free(modules_loaded);
1812
1813 free(destrootdir);
1814 strv_free(firmwaredirs);
1815 strv_free(pathdirs);
1816 return r;
1817 }