1 /* dracut-install.c -- install files and executables
3 Copyright (C) 2012 Harald Hoyer
4 Copyright (C) 2012 Red Hat, Inc. All rights reserved.
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.
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.
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/>.
20 #define PROGRAM_VERSION_STRING "2"
25 #undef _FILE_OFFSET_BITS
37 #include <sys/types.h>
40 #include <sys/ioctl.h>
44 #include <sys/utsname.h>
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;
84 static int dracut_install(const char *src
, const char *dst
, bool isdir
, bool resolvedeps
, bool hashdst
);
87 static inline void kmod_module_unrefp(struct kmod_module
**p
) {
89 kmod_module_unref(*p
);
91 #define _cleanup_kmod_module_unref_ _cleanup_(kmod_module_unrefp)
93 static inline void kmod_module_unref_listp(struct kmod_list
**p
) {
95 kmod_module_unref_list(*p
);
97 #define _cleanup_kmod_module_unref_list_ _cleanup_(kmod_module_unref_listp)
99 static inline void kmod_module_info_free_listp(struct kmod_list
**p
) {
101 kmod_module_info_free_list(*p
);
103 #define _cleanup_kmod_module_info_free_list_ _cleanup_(kmod_module_info_free_listp)
105 static inline void kmod_unrefp(struct kmod_ctx
**p
) {
108 #define _cleanup_kmod_unref_ _cleanup_(kmod_unrefp)
110 static inline void kmod_module_dependency_symbols_free_listp(struct kmod_list
**p
) {
112 kmod_module_dependency_symbols_free_list(*p
);
114 #define _cleanup_kmod_module_dependency_symbols_free_list_ _cleanup_(kmod_module_dependency_symbols_free_listp)
116 static inline void fts_closep(FTS
**p
) {
120 #define _cleanup_fts_close_ _cleanup_(fts_closep)
124 static size_t dir_len(char const *file
)
131 /* Strip the basename and any redundant slashes before it. */
132 for (length
= strlen(file
) - 1; 0 < length
; length
--)
133 if (file
[length
] == '/' && file
[length
- 1] != '/')
138 static char *convert_abs_rel(const char *from
, const char *target
)
140 /* we use the 4*MAXPATHLEN, which should not overrun */
141 char relative_from
[MAXPATHLEN
* 4];
142 _cleanup_free_
char *realtarget
= NULL
;
143 _cleanup_free_
char *target_dir_p
= NULL
, *realpath_p
= NULL
;
144 const char *realfrom
= from
;
145 size_t level
= 0, fromlevel
= 0, targetlevel
= 0;
147 size_t i
, rl
, dirlen
;
150 target_dir_p
= strdup(target
);
154 dirlen
= dir_len(target_dir_p
);
155 target_dir_p
[dirlen
] = '\0';
156 realpath_p
= realpath(target_dir_p
, NULL
);
158 if (realpath_p
== NULL
) {
159 log_warning("convert_abs_rel(): target '%s' directory has no realpath.", target
);
163 /* dir_len() skips double /'s e.g. //lib64, so we can't skip just one
164 * character - need to skip all leading /'s */
166 for (i
= dirlen
+ 1; i
< rl
; ++i
)
167 if (target_dir_p
[i
] != '/')
169 ret
= asprintf(&realtarget
, "%s/%s", realpath_p
, &target_dir_p
[i
]);
171 log_error("Out of memory!");
175 /* now calculate the relative path from <from> to <target> and
176 store it in <relative_from>
178 relative_from
[0] = 0;
181 /* count the pathname elements of realtarget */
182 for (targetlevel
= 0, i
= 0; realtarget
[i
]; i
++)
183 if (realtarget
[i
] == '/')
186 /* count the pathname elements of realfrom */
187 for (fromlevel
= 0, i
= 0; realfrom
[i
]; i
++)
188 if (realfrom
[i
] == '/')
191 /* count the pathname elements, which are common for both paths */
192 for (level
= 0, i
= 0; realtarget
[i
] && (realtarget
[i
] == realfrom
[i
]); i
++)
193 if (realtarget
[i
] == '/')
196 /* add "../" to the relative_from path, until the common pathname is
198 for (i
= level
; i
< targetlevel
; i
++) {
200 relative_from
[rl
++] = '/';
201 relative_from
[rl
++] = '.';
202 relative_from
[rl
++] = '.';
205 /* set l to the next uncommon pathname element in realfrom */
206 for (l
= 1, i
= 1; i
< level
; i
++)
207 for (l
++; realfrom
[l
] && realfrom
[l
] != '/'; l
++) ;
211 /* append the uncommon rest of realfrom to the relative_from path */
212 for (i
= level
; i
<= fromlevel
; i
++) {
214 relative_from
[rl
++] = '/';
215 while (realfrom
[l
] && realfrom
[l
] != '/')
216 relative_from
[rl
++] = realfrom
[l
++];
220 relative_from
[rl
] = 0;
221 return strdup(relative_from
);
224 static int ln_r(const char *src
, const char *dst
)
227 _cleanup_free_
const char *points_to
= convert_abs_rel(src
, dst
);
229 log_info("ln -s '%s' '%s'", points_to
, dst
);
230 ret
= symlink(points_to
, dst
);
233 log_error("ERROR: ln -s '%s' '%s': %m", points_to
, dst
);
240 /* Perform the O(1) btrfs clone operation, if possible.
241 Upon success, return 0. Otherwise, return -1 and set errno. */
242 static inline int clone_file(int dest_fd
, int src_fd
)
244 #undef BTRFS_IOCTL_MAGIC
245 #define BTRFS_IOCTL_MAGIC 0x94
246 #undef BTRFS_IOC_CLONE
247 #define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int)
248 return ioctl(dest_fd
, BTRFS_IOC_CLONE
, src_fd
);
251 static bool use_clone
= true;
253 static int cp(const char *src
, const char *dst
)
260 _cleanup_close_
int dest_desc
= -1, source_desc
= -1;
262 if (lstat(src
, &sb
) != 0)
265 if (S_ISLNK(sb
.st_mode
))
268 source_desc
= open(src
, O_RDONLY
| O_CLOEXEC
);
273 open(dst
, O_WRONLY
| O_CREAT
| O_EXCL
| O_CLOEXEC
,
274 (sb
.st_mode
) & (S_ISUID
| S_ISGID
| S_ISVTX
| S_IRWXU
| S_IRWXG
| S_IRWXO
));
280 ret
= clone_file(dest_desc
, source_desc
);
283 struct timeval tv
[2];
284 if (fchown(dest_desc
, sb
.st_uid
, sb
.st_gid
) != 0)
285 if(fchown(dest_desc
, (uid_t
) - 1, sb
.st_gid
) != 0) {
287 log_error("Failed to chown %s: %m", dst
);
289 log_info("Failed to chown %s: %m", dst
);
292 tv
[0].tv_sec
= sb
.st_atime
;
294 tv
[1].tv_sec
= sb
.st_mtime
;
296 futimes(dest_desc
, tv
);
301 /* clone did not work, remove the file */
303 /* do not try clone again */
311 execlp("cp", "cp", "--reflink=auto", "--sparse=auto", "--preserve=mode,xattr,timestamps", "-fL", src
, dst
,
314 execlp("cp", "cp", "--reflink=auto", "--sparse=auto", "--preserve=mode,timestamps", "-fL", src
, dst
,
319 while (waitpid(pid
, &ret
, 0) < 0) {
320 if (errno
!= EINTR
) {
323 log_error("Failed: cp --reflink=auto --sparse=auto --preserve=mode,xattr,timestamps -fL %s %s", src
,
326 log_error("Failed: cp --reflink=auto --sparse=auto --preserve=mode,timestamps -fL %s %s", src
,
331 log_debug("cp ret = %d", ret
);
335 static int library_install(const char *src
, const char *lib
)
337 _cleanup_free_
char *p
= NULL
;
338 _cleanup_free_
char *pdir
= NULL
, *ppdir
= NULL
, *clib
= NULL
;
344 r
= dracut_install(p
, p
, false, false, true);
346 log_error("ERROR: failed to install '%s' for '%s'", p
, src
);
348 log_debug("Lib install: '%s'", p
);
351 /* also install lib.so for lib.so.* files */
352 q
= strstr(p
, ".so.");
356 /* ignore errors for base lib symlink */
357 if (dracut_install(p
, p
, false, false, true) == 0)
358 log_debug("Lib install: '%s'", p
);
361 /* Also try to install the same library from one directory above.
362 This fixes the case, where only the HWCAP lib would be installed
363 # ldconfig -p|grep -F libc.so
364 libc.so.6 (libc6,64bit, hwcap: 0x0000001000000000, OS ABI: Linux 2.6.32) => /lib64/power6/libc.so.6
365 libc.so.6 (libc6,64bit, hwcap: 0x0000000000000200, OS ABI: Linux 2.6.32) => /lib64/power6x/libc.so.6
366 libc.so.6 (libc6,64bit, OS ABI: Linux 2.6.32) => /lib64/libc.so.6
377 ppdir
= dirname(pdir
);
381 ppdir
= strdup(ppdir
);
385 clib
= strjoin(ppdir
, "/", basename(p
), NULL
);
386 if (dracut_install(clib
, clib
, false, false, true) == 0)
387 log_debug("Lib install: '%s'", clib
);
388 /* also install lib.so for lib.so.* files */
389 q
= strstr(clib
, ".so.");
393 /* ignore errors for base lib symlink */
394 if (dracut_install(clib
, clib
, false, false, true) == 0)
395 log_debug("Lib install: '%s'", p
);
401 static int resolve_deps(const char *src
)
405 _cleanup_free_
char *buf
= NULL
;
406 size_t linesize
= LINE_MAX
;
407 _cleanup_pclose_
FILE *fptr
= NULL
;
408 _cleanup_free_
char *cmd
= NULL
;
410 buf
= malloc(LINE_MAX
);
414 if (strstr(src
, ".so") == 0) {
415 _cleanup_close_
int fd
= -1;
416 fd
= open(src
, O_RDONLY
| O_CLOEXEC
);
420 ret
= read(fd
, buf
, LINE_MAX
);
424 buf
[LINE_MAX
- 1] = '\0';
425 if (buf
[0] == '#' && buf
[1] == '!') {
426 /* we have a shebang */
428 for (p
= &buf
[2]; *p
&& isspace(*p
); p
++) ;
429 for (q
= p
; *q
&& (!isspace(*q
)); q
++) ;
431 log_debug("Script install: '%s'", p
);
432 ret
= dracut_install(p
, p
, false, true, false);
434 log_error("ERROR: failed to install '%s'", p
);
440 ret
= asprintf(&cmd
, "ldd %s 2>&1", src
);
442 log_error("Out of memory!");
448 fptr
= popen(cmd
, "r");
450 while (!feof(fptr
)) {
453 if (getline(&buf
, &linesize
, fptr
) <= 0)
456 log_debug("ldd: '%s'", buf
);
458 if (strstr(buf
, "you do not have execution permission")) {
459 log_error("%s", buf
);
465 if (strstr(buf
, "Not a valid dynamic program"))
469 if (strstr(buf
, "cannot execute binary file"))
472 if (strstr(buf
, "not a dynamic executable"))
475 if (strstr(buf
, "loader cannot load itself"))
478 if (strstr(buf
, "not regular file"))
481 if (strstr(buf
, "cannot read header"))
484 if (strstr(buf
, destrootdir
))
487 p
= strchr(buf
, '/');
491 for (q
= p
; *q
&& *q
!= ' ' && *q
!= '\n'; q
++) ;
494 ret
+= library_install(src
, p
);
502 /* Install ".<filename>.hmac" file for FIPS self-checks */
503 static int hmac_install(const char *src
, const char *dst
, const char *hmacpath
)
505 _cleanup_free_
char *srcpath
= strdup(src
);
506 _cleanup_free_
char *dstpath
= strdup(dst
);
507 _cleanup_free_
char *srchmacname
= NULL
;
508 _cleanup_free_
char *dsthmacname
= NULL
;
511 if (!(srcpath
&& dstpath
))
514 size_t dlen
= dir_len(src
);
516 if (endswith(src
, ".hmac"))
520 hmac_install(src
, dst
, "/lib/fipscheck");
521 hmac_install(src
, dst
, "/lib64/fipscheck");
522 hmac_install(src
, dst
, "/lib/hmaccalc");
523 hmac_install(src
, dst
, "/lib64/hmaccalc");
526 srcpath
[dlen
] = '\0';
527 dstpath
[dir_len(dst
)] = '\0';
529 ret
= asprintf(&srchmacname
, "%s/%s.hmac", hmacpath
, &src
[dlen
+ 1]);
531 log_error("Out of memory!");
535 ret
= asprintf(&dsthmacname
, "%s/%s.hmac", hmacpath
, &src
[dlen
+ 1]);
537 log_error("Out of memory!");
541 ret
= asprintf(&srchmacname
, "%s/.%s.hmac", srcpath
, &src
[dlen
+ 1]);
543 log_error("Out of memory!");
547 ret
= asprintf(&dsthmacname
, "%s/.%s.hmac", dstpath
, &src
[dlen
+ 1]);
549 log_error("Out of memory!");
553 log_debug("hmac cp '%s' '%s')", srchmacname
, dsthmacname
);
554 dracut_install(srchmacname
, dsthmacname
, false, false, true);
558 void mark_hostonly(const char *path
)
560 _cleanup_free_
char *fulldstpath
= NULL
;
561 _cleanup_fclose_
FILE *f
= NULL
;
564 ret
= asprintf(&fulldstpath
, "%s/lib/dracut/hostonly-files", destrootdir
);
566 log_error("Out of memory!");
570 f
= fopen(fulldstpath
, "a");
573 log_error("Could not open '%s' for writing.", fulldstpath
);
577 fprintf(f
, "%s\n", path
);
580 void dracut_log_cp(const char *path
)
583 ret
= fprintf(logfile_f
, "%s\n", path
);
585 log_error("Could not append '%s' to logfile '%s': %m", path
, logfile
);
588 static bool check_hashmap(Hashmap
*hm
, const char *item
)
591 existing
= hashmap_get(hm
, item
);
593 if (strcmp(existing
, item
) == 0) {
600 static int dracut_install(const char *src
, const char *dst
, bool isdir
, bool resolvedeps
, bool hashdst
)
603 _cleanup_free_
char *fulldstpath
= NULL
;
604 _cleanup_free_
char *fulldstdir
= NULL
;
606 bool src_exists
= true;
609 log_debug("dracut_install('%s', '%s')", src
, dst
);
611 if (check_hashmap(items_failed
, src
)) {
612 log_debug("hash hit items_failed for '%s'", src
);
616 if (hashdst
&& check_hashmap(items
, dst
)) {
617 log_debug("hash hit items for '%s'", dst
);
621 if (lstat(src
, &sb
) < 0) {
625 hashmap_put(items_failed
, i
, i
);
626 /* src does not exist */
635 hashmap_put(items
, i
, i
);
637 ret
= asprintf(&fulldstpath
, "%s/%s", destrootdir
, (dst
[0]=='/' ? (dst
+1) : dst
));
639 log_error("Out of memory!");
643 ret
= stat(fulldstpath
, &sb
);
645 if (ret
!= 0 && (errno
!= ENOENT
)) {
646 log_error("ERROR: stat '%s': %m", fulldstpath
);
651 if (resolvedeps
&& S_ISREG(sb
.st_mode
) && (sb
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))) {
652 log_debug("'%s' already exists, but checking for any deps", fulldstpath
);
653 ret
= resolve_deps(src
);
655 log_debug("'%s' already exists", fulldstpath
);
657 /* dst does already exist */
661 /* check destination directory */
662 fulldstdir
= strdup(fulldstpath
);
663 fulldstdir
[dir_len(fulldstdir
)] = '\0';
665 ret
= stat(fulldstdir
, &db
);
668 _cleanup_free_
char *dname
= NULL
;
670 if (errno
!= ENOENT
) {
671 log_error("ERROR: stat '%s': %m", fulldstdir
);
674 /* create destination directory */
675 log_debug("dest dir '%s' does not exist", fulldstdir
);
680 dname
[dir_len(dname
)] = '\0';
681 ret
= dracut_install(dname
, dname
, true, false, true);
684 log_error("ERROR: failed to create directory '%s'", fulldstdir
);
689 if (isdir
&& !src_exists
) {
690 log_info("mkdir '%s'", fulldstpath
);
691 ret
= mkdir(fulldstpath
, 0755);
695 /* ready to install src */
697 if (S_ISDIR(sb
.st_mode
)) {
698 log_info("mkdir '%s'", fulldstpath
);
699 ret
= mkdir(fulldstpath
, sb
.st_mode
| S_IWUSR
);
703 if (S_ISLNK(sb
.st_mode
)) {
704 _cleanup_free_
char *abspath
= NULL
;
706 abspath
= realpath(src
, NULL
);
711 if (dracut_install(abspath
, abspath
, false, resolvedeps
, hashdst
)) {
712 log_debug("'%s' install error", abspath
);
716 if (lstat(abspath
, &sb
) != 0) {
717 log_debug("lstat '%s': %m", abspath
);
721 if (lstat(fulldstpath
, &sb
) != 0) {
722 _cleanup_free_
char *absdestpath
= NULL
;
724 ret
= asprintf(&absdestpath
, "%s/%s", destrootdir
, (abspath
[0]=='/' ? (abspath
+1) : abspath
));
726 log_error("Out of memory!");
730 ln_r(absdestpath
, fulldstpath
);
734 /* copy .hmac files also */
735 hmac_install(src
, dst
, NULL
);
741 if (sb
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) {
743 ret
+= resolve_deps(src
);
745 /* copy .hmac files also */
746 hmac_install(src
, dst
, NULL
);
750 log_debug("dracut_install ret = %d", ret
);
751 log_info("cp '%s' '%s'", src
, fulldstpath
);
753 if (arg_hostonly
&& !arg_module
)
756 ret
+= cp(src
, fulldstpath
);
757 if (ret
== 0 && logfile_f
)
760 log_debug("dracut_install ret = %d", ret
);
765 static void item_free(char *i
)
771 static void usage(int status
)
774 printf("Usage: %s -D DESTROOTDIR [OPTION]... -a SOURCE...\n"
775 "or: %s -D DESTROOTDIR [OPTION]... SOURCE DEST\n"
776 "or: %s -D DESTROOTDIR [OPTION]... -m KERNELMODULE [KERNELMODULE …]\n"
778 "Install SOURCE to DEST in DESTROOTDIR with all needed dependencies.\n"
780 " KERNELMODULE can have the format:\n"
781 " <absolute path> with a leading /\n"
782 " =<kernel subdir>[/<kernel subdir>…] like '=drivers/hid'\n"
785 " -D --destrootdir Install all files to DESTROOTDIR as the root\n"
786 " -a --all Install all SOURCE arguments to DESTROOTDIR\n"
787 " -o --optional If SOURCE does not exist, do not fail\n"
788 " -d --dir SOURCE is a directory\n"
789 " -l --ldd Also install shebang executables and libraries\n"
790 " -L --logdir <DIR> Log files, which were installed from the host to <DIR>\n"
791 " -R --resolvelazy Only install shebang executables and libraries\n"
792 " for all SOURCE files\n"
793 " -H --hostonly Mark all SOURCE files as hostonly\n\n"
794 " -f --fips Also install all '.SOURCE.hmac' files\n"
796 " --module,-m Install kernel modules, instead of files\n"
797 " --kerneldir Specify the kernel module directory\n"
798 " --firmwaredirs Specify the firmware directory search path with : separation\n"
799 " --silent Don't display error messages for kernel module install\n"
800 " --modalias Only generate module list from /sys/devices modalias list\n"
801 " -o --optional If kernel module does not exist, do not fail\n"
802 " -p --mod-filter-path Filter kernel modules by path regexp\n"
803 " -P --mod-filter-nopath Exclude kernel modules by path regexp\n"
804 " -s --mod-filter-symbol Filter kernel modules by symbol regexp\n"
805 " -S --mod-filter-nosymbol Exclude kernel modules by symbol regexp\n"
806 " -N --mod-filter-noname Exclude kernel modules by name regexp\n"
808 " -v --verbose Show more output\n"
809 " --debug Show debug output\n"
810 " --version Show package version\n"
811 " -h --help Show this help\n"
813 program_invocation_short_name
, program_invocation_short_name
,
814 program_invocation_short_name
);
818 static int parse_argv(int argc
, char *argv
[])
831 static struct option
const options
[] = {
832 {"help", no_argument
, NULL
, 'h'},
833 {"version", no_argument
, NULL
, ARG_VERSION
},
834 {"dir", no_argument
, NULL
, 'd'},
835 {"debug", no_argument
, NULL
, ARG_DEBUG
},
836 {"verbose", no_argument
, NULL
, 'v'},
837 {"ldd", no_argument
, NULL
, 'l'},
838 {"resolvelazy", no_argument
, NULL
, 'R'},
839 {"optional", no_argument
, NULL
, 'o'},
840 {"hostonly", no_argument
, NULL
, 'H'},
841 {"all", no_argument
, NULL
, 'a'},
842 {"module", no_argument
, NULL
, 'm'},
843 {"fips", no_argument
, NULL
, 'f'},
844 {"destrootdir", required_argument
, NULL
, 'D'},
845 {"logdir", required_argument
, NULL
, 'L'},
846 {"mod-filter-path", required_argument
, NULL
, 'p'},
847 {"mod-filter-nopath", required_argument
, NULL
, 'P'},
848 {"mod-filter-symbol", required_argument
, NULL
, 's'},
849 {"mod-filter-nosymbol", required_argument
, NULL
, 'S'},
850 {"mod-filter-noname", required_argument
, NULL
, 'N'},
851 {"modalias", no_argument
, NULL
, ARG_MODALIAS
},
852 {"silent", no_argument
, NULL
, ARG_SILENT
},
853 {"kerneldir", required_argument
, NULL
, ARG_KERNELDIR
},
854 {"firmwaredirs", required_argument
, NULL
, ARG_FIRMWAREDIRS
},
858 while ((c
= getopt_long(argc
, argv
, "madfhlL:oD:HRp:P:s:S:N:", options
, NULL
)) != -1) {
861 puts(PROGRAM_VERSION_STRING
);
864 arg_createdir
= true;
867 arg_loglevel
= LOG_DEBUG
;
877 arg_loglevel
= LOG_INFO
;
883 arg_resolvedeps
= true;
886 arg_resolvelazy
= true;
895 destrootdir
= strdup(optarg
);
898 if (regcomp(&mod_filter_path
, optarg
, REG_NOSUB
|REG_EXTENDED
) != 0) {
899 log_error("Module path filter %s is not a regular expression", optarg
);
902 arg_mod_filter_path
= true;
905 if (regcomp(&mod_filter_nopath
, optarg
, REG_NOSUB
|REG_EXTENDED
) != 0) {
906 log_error("Module path filter %s is not a regular expression", optarg
);
909 arg_mod_filter_nopath
= true;
912 if (regcomp(&mod_filter_symbol
, optarg
, REG_NOSUB
|REG_EXTENDED
) != 0) {
913 log_error("Module symbol filter %s is not a regular expression", optarg
);
916 arg_mod_filter_symbol
= true;
919 if (regcomp(&mod_filter_nosymbol
, optarg
, REG_NOSUB
|REG_EXTENDED
) != 0) {
920 log_error("Module symbol filter %s is not a regular expression", optarg
);
923 arg_mod_filter_nosymbol
= true;
926 if (regcomp(&mod_filter_noname
, optarg
, REG_NOSUB
|REG_EXTENDED
) != 0) {
927 log_error("Module symbol filter %s is not a regular expression", optarg
);
930 arg_mod_filter_noname
= true;
933 logdir
= strdup(optarg
);
936 kerneldir
= strdup(optarg
);
938 case ARG_FIRMWAREDIRS
:
939 firmwaredirs
= strv_split(optarg
, ":");
958 kerneldir
= strdup(buf
.version
);
969 path
= getenv("DRACUT_FIRMWARE_PATH");
972 log_error("Environment variable DRACUT_FIRMWARE_PATH is not set");
976 log_debug("DRACUT_FIRMWARE_PATH=%s", path
);
978 firmwaredirs
= strv_split(path
, ":");
982 if (!optind
|| optind
== argc
) {
983 log_error("No SOURCE argument given");
990 static int resolve_lazy(int argc
, char **argv
)
993 size_t destrootdirlen
= strlen(destrootdir
);
996 for (i
= 0; i
< argc
; i
++) {
997 const char *src
= argv
[i
];
1001 log_debug("resolve_deps('%s')", src
);
1003 if (strstr(src
, destrootdir
)) {
1004 p
= &argv
[i
][destrootdirlen
];
1007 existing
= hashmap_get(items
, p
);
1009 if (strcmp(existing
, p
) == 0)
1014 hashmap_put(items
, item
, item
);
1016 ret
+= resolve_deps(src
);
1021 static char **find_binary(const char *src
)
1025 char *newsrc
= NULL
;
1027 STRV_FOREACH(q
, pathdirs
) {
1031 r
= asprintf(&newsrc
, "%s/%s", *q
, src
);
1033 log_error("Out of memory!");
1037 if (stat(newsrc
, &sb
) != 0) {
1038 log_debug("stat(%s) != 0", newsrc
);
1044 strv_push(&ret
, newsrc
);
1049 STRV_FOREACH(q
, ret
) {
1050 log_debug("find_binary(%s) == %s", src
, *q
);
1057 static int install_one(const char *src
, const char *dst
)
1059 int r
= EXIT_SUCCESS
;
1062 if (strchr(src
, '/') == NULL
) {
1063 char **p
= find_binary(src
);
1066 STRV_FOREACH(q
, p
) {
1068 log_debug("dracut_install '%s' '%s'", newsrc
, dst
);
1069 ret
= dracut_install(newsrc
, dst
, arg_createdir
, arg_resolvedeps
, true);
1071 log_debug("dracut_install '%s' '%s' OK", newsrc
, dst
);
1079 ret
= dracut_install(src
, dst
, arg_createdir
, arg_resolvedeps
, true);
1082 if ((ret
!= 0) && (!arg_optional
)) {
1083 log_error("ERROR: installing '%s' to '%s'", src
, dst
);
1090 static int install_all(int argc
, char **argv
)
1092 int r
= EXIT_SUCCESS
;
1094 for (i
= 0; i
< argc
; i
++) {
1096 log_debug("Handle '%s'", argv
[i
]);
1098 if (strchr(argv
[i
], '/') == NULL
) {
1099 char **p
= find_binary(argv
[i
]);
1102 STRV_FOREACH(q
, p
) {
1104 log_debug("dracut_install '%s'", newsrc
);
1105 ret
= dracut_install(newsrc
, newsrc
, arg_createdir
, arg_resolvedeps
, true);
1107 log_debug("dracut_install '%s' OK", newsrc
);
1116 _cleanup_free_
char *dest
= strdup(argv
[i
]);
1117 ret
= dracut_install(argv
[i
], dest
, arg_createdir
, arg_resolvedeps
, true);
1120 if ((ret
!= 0) && (!arg_optional
)) {
1121 log_error("ERROR: installing '%s'", argv
[i
]);
1128 static int install_firmware(struct kmod_module
*mod
)
1130 struct kmod_list
*l
;
1131 _cleanup_kmod_module_info_free_list_
struct kmod_list
*list
= NULL
;
1136 ret
= kmod_module_get_info(mod
, &list
);
1138 log_error("could not get modinfo from '%s': %s\n",
1139 kmod_module_get_name(mod
), strerror(-ret
));
1142 kmod_list_foreach(l
, list
) {
1143 const char *key
= kmod_module_info_get_key(l
);
1144 const char *value
= NULL
;
1146 if (!streq("firmware", key
))
1149 value
= kmod_module_info_get_value(l
);
1150 log_debug("Firmware %s", value
);
1152 STRV_FOREACH(q
, firmwaredirs
) {
1153 _cleanup_free_
char *fwpath
= NULL
;
1157 r
= asprintf(&fwpath
, "%s/%s", *q
, value
);
1159 log_error("Out of memory!");
1163 if (stat(fwpath
, &sb
) != 0) {
1164 log_debug("stat(%s) != 0", fwpath
);
1168 ret
= dracut_install(fwpath
, fwpath
, false, false, true);
1170 log_debug("dracut_install '%s' OK", fwpath
);
1174 log_info("Possible missing firmware %s for kernel module %s", value
, kmod_module_get_name(mod
));
1180 static bool check_module_symbols(struct kmod_module
*mod
)
1182 struct kmod_list
*itr
;
1183 _cleanup_kmod_module_dependency_symbols_free_list_
struct kmod_list
*deplist
= NULL
;
1185 if (!arg_mod_filter_symbol
&& !arg_mod_filter_nosymbol
)
1188 if (kmod_module_get_dependency_symbols(mod
, &deplist
) < 0) {
1189 log_debug("kmod_module_get_dependency_symbols failed");
1190 if (arg_mod_filter_symbol
)
1195 if (arg_mod_filter_nosymbol
) {
1196 kmod_list_foreach(itr
, deplist
) {
1197 const char *symbol
= kmod_module_symbol_get_symbol(itr
);
1198 // log_debug("Checking symbol %s", symbol);
1199 if (regexec(&mod_filter_nosymbol
, symbol
, 0, NULL
, 0) == 0) {
1200 log_debug("Module %s: symbol %s matched exclusion filter", kmod_module_get_name(mod
), symbol
);
1206 if (arg_mod_filter_symbol
) {
1207 kmod_list_foreach(itr
, deplist
) {
1208 const char *symbol
= kmod_module_dependency_symbol_get_symbol(itr
);
1209 // log_debug("Checking symbol %s", symbol);
1210 if (regexec(&mod_filter_symbol
, symbol
, 0, NULL
, 0) == 0) {
1211 log_debug("Module %s: symbol %s matched inclusion filter", kmod_module_get_name(mod
), symbol
);
1221 static bool check_module_path(const char *path
)
1223 if (arg_mod_filter_nopath
&& (regexec(&mod_filter_nopath
, path
, 0, NULL
, 0) == 0)) {
1224 log_debug("Path %s matched exclusion filter", path
);
1228 if (arg_mod_filter_path
&& (regexec(&mod_filter_path
, path
, 0, NULL
, 0) != 0)) {
1229 log_debug("Path %s matched inclusion filter", path
);
1235 static int install_dependent_modules(struct kmod_list
*modlist
)
1237 struct kmod_list
*itr
;
1238 const char *path
= NULL
;
1239 const char *name
= NULL
;
1242 kmod_list_foreach(itr
, modlist
) {
1243 _cleanup_kmod_module_unref_
struct kmod_module
*mod
= NULL
;
1244 mod
= kmod_module_get_module(itr
);
1245 path
= kmod_module_get_path(mod
);
1247 if (check_hashmap(items_failed
, path
))
1250 if (check_hashmap(items
, path
)) {
1254 name
= kmod_module_get_name(mod
);
1256 if ((path
== NULL
) || (arg_mod_filter_noname
&& (regexec(&mod_filter_noname
, name
, 0, NULL
, 0) == 0))) {
1260 ret
= dracut_install(path
, &path
[kerneldirlen
], false, false, true);
1262 _cleanup_kmod_module_unref_list_
struct kmod_list
*modlist
= NULL
;
1263 _cleanup_kmod_module_unref_list_
struct kmod_list
*modpre
= NULL
;
1264 _cleanup_kmod_module_unref_list_
struct kmod_list
*modpost
= NULL
;
1265 log_debug("dracut_install '%s' '%s' OK", path
, &path
[kerneldirlen
]);
1266 install_firmware(mod
);
1267 modlist
= kmod_module_get_dependencies(mod
);
1268 ret
= install_dependent_modules(modlist
);
1270 ret
= kmod_module_get_softdeps(mod
, &modpre
, &modpost
);
1272 ret
= install_dependent_modules(modpre
);
1275 log_error("dracut_install '%s' '%s' ERROR", path
, &path
[kerneldirlen
]);
1282 static int install_module(struct kmod_module
*mod
)
1285 _cleanup_kmod_module_unref_list_
struct kmod_list
*modlist
= NULL
;
1286 _cleanup_kmod_module_unref_list_
struct kmod_list
*modpre
= NULL
;
1287 _cleanup_kmod_module_unref_list_
struct kmod_list
*modpost
= NULL
;
1288 const char *path
= NULL
;
1289 const char *name
= NULL
;
1291 name
= kmod_module_get_name(mod
);
1292 if (arg_mod_filter_noname
&& (regexec(&mod_filter_noname
, name
, 0, NULL
, 0) == 0)) {
1293 log_debug("dracut_install '%s' is excluded", name
);
1297 if (arg_hostonly
&& !check_hashmap(modules_loaded
, name
)) {
1298 log_debug("dracut_install '%s' not hostonly", name
);
1302 path
= kmod_module_get_path(mod
);
1306 if (check_hashmap(items_failed
, path
))
1309 if (check_hashmap(items
, path
))
1312 if (!check_module_path(path
) || !check_module_symbols(mod
)) {
1313 log_debug("No symbol or path match for '%s'", path
);
1317 log_debug("dracut_install '%s' '%s'", path
, &path
[kerneldirlen
]);
1319 ret
= dracut_install(path
, &path
[kerneldirlen
], false, false, true);
1321 log_debug("dracut_install '%s' OK", kmod_module_get_name(mod
));
1322 } else if (!arg_optional
) {
1324 log_error("dracut_install '%s' ERROR", kmod_module_get_name(mod
));
1327 install_firmware(mod
);
1329 modlist
= kmod_module_get_dependencies(mod
);
1330 ret
= install_dependent_modules(modlist
);
1333 ret
= kmod_module_get_softdeps(mod
, &modpre
, &modpost
);
1335 ret
= install_dependent_modules(modpre
);
1341 static int modalias_list(struct kmod_ctx
*ctx
)
1344 struct kmod_list
*loaded_list
= NULL
;
1345 struct kmod_list
*itr
, *l
;
1346 _cleanup_fts_close_ FTS
*fts
= NULL
;
1349 char *paths
[] = { "/sys/devices", NULL
};
1350 fts
= fts_open(paths
, FTS_NOCHDIR
|FTS_NOSTAT
, NULL
);
1352 for (FTSENT
*ftsent
= fts_read(fts
); ftsent
!= NULL
; ftsent
= fts_read(fts
)) {
1353 _cleanup_fclose_
FILE *f
= NULL
;
1354 _cleanup_kmod_module_unref_list_
struct kmod_list
*list
= NULL
;
1355 struct kmod_list
*l
;
1362 if (strncmp("modalias", ftsent
->fts_name
, 8) != 0)
1364 if (!(f
= fopen(ftsent
->fts_accpath
, "r")))
1367 if(!fgets(alias
, sizeof(alias
), f
))
1370 len
= strlen(alias
);
1375 if (alias
[len
-1] == '\n')
1378 err
= kmod_module_new_from_lookup(ctx
, alias
, &list
);
1382 kmod_list_foreach(l
, list
) {
1383 struct kmod_module
*mod
= kmod_module_get_module(l
);
1384 char *name
= strdup(kmod_module_get_name(mod
));
1385 kmod_module_unref(mod
);
1386 hashmap_put(modules_loaded
, name
, name
);
1390 err
= kmod_module_new_from_loaded(ctx
, &loaded_list
);
1393 log_error("Could not get list of loaded modules: %m. Switching to non-hostonly mode.");
1394 arg_hostonly
= false;
1396 kmod_list_foreach(itr
, loaded_list
) {
1397 _cleanup_kmod_module_unref_list_
struct kmod_list
*modlist
= NULL
;
1399 struct kmod_module
*mod
= kmod_module_get_module(itr
);
1400 char *name
= strdup(kmod_module_get_name(mod
));
1401 hashmap_put(modules_loaded
, name
, name
);
1402 kmod_module_unref(mod
);
1404 /* also put the modules from the new kernel in the hashmap,
1405 * which resolve the name as an alias, in case a kernel module is
1408 err
= kmod_module_new_from_lookup(ctx
, name
, &modlist
);
1413 kmod_list_foreach(l
, modlist
) {
1414 mod
= kmod_module_get_module(l
);
1415 char *name
= strdup(kmod_module_get_name(mod
));
1416 hashmap_put(modules_loaded
, name
, name
);
1417 kmod_module_unref(mod
);
1420 kmod_module_unref_list(loaded_list
);
1425 static int install_modules(int argc
, char **argv
)
1427 _cleanup_kmod_unref_
struct kmod_ctx
*ctx
= NULL
;
1428 struct kmod_list
*itr
;
1430 struct kmod_module
*mod
= NULL
, *mod_o
= NULL
;
1432 const char *abskpath
= NULL
;
1437 ctx
= kmod_new(kerneldir
, NULL
);
1438 abskpath
= kmod_get_dirname(ctx
);
1440 p
= strstr(abskpath
, "/lib/modules/");
1442 kerneldirlen
= p
- abskpath
;
1445 char *modalias_file
;
1446 modalias_file
= getenv("DRACUT_KERNEL_MODALIASES");
1448 if (modalias_file
== NULL
) {
1451 _cleanup_fclose_
FILE *f
= NULL
;
1452 if ((f
= fopen(modalias_file
, "r"))) {
1457 char *dupname
= NULL
;
1459 if(!(fgets(name
, sizeof(name
), f
)))
1466 if (name
[len
-1] == '\n')
1469 log_debug("Adding module '%s' to hostonly module list", name
);
1470 dupname
= strdup(name
);
1471 hashmap_put(modules_loaded
, dupname
, dupname
);
1478 for (i
= 0; i
< argc
; i
++) {
1481 log_debug("Handle module '%s'", argv
[i
]);
1483 if (argv
[i
][0] == '/') {
1484 _cleanup_kmod_module_unref_list_
struct kmod_list
*modlist
= NULL
;
1485 _cleanup_free_
const char *modname
= NULL
;
1487 r
= kmod_module_new_from_path(ctx
, argv
[i
], &mod_o
);
1489 log_debug("Failed to lookup modules path '%s': %m", argv
[i
]);
1494 /* Check, if we have to load another module with that name instead */
1495 modname
= strdup(kmod_module_get_name(mod_o
));
1498 if (!arg_optional
) {
1500 log_error("Failed to get name for module '%s'", argv
[i
]);
1503 log_info("Failed to get name for module '%s'", argv
[i
]);
1507 r
= kmod_module_new_from_lookup(ctx
, modname
, &modlist
);
1508 kmod_module_unref(mod_o
);
1512 if (!arg_optional
) {
1514 log_error("3 Failed to lookup alias '%s': %d", modname
, r
);
1517 log_info("3 Failed to lookup alias '%s': %d", modname
, r
);
1521 if (!arg_optional
) {
1523 log_error("Failed to find module '%s' %s", modname
, argv
[i
]);
1526 log_info("Failed to find module '%s' %s", modname
, argv
[i
]);
1529 kmod_list_foreach(itr
, modlist
) {
1530 mod
= kmod_module_get_module(itr
);
1531 r
= install_module(mod
);
1532 kmod_module_unref(mod
);
1533 if ((r
< 0) && !arg_optional
) {
1535 log_error("ERROR: installing module '%s'", modname
);
1538 ret
= ( ret
== 0 ? 0 : r
);
1541 } else if (argv
[i
][0] == '=') {
1542 _cleanup_free_
char *path1
= NULL
, *path2
= NULL
, *path3
= NULL
;
1543 _cleanup_fts_close_ FTS
*fts
= NULL
;
1545 log_debug("Handling =%s", &argv
[i
][1]);
1546 /* FIXME and add more paths*/
1547 r
= asprintf(&path2
, "%s/kernel/%s", kerneldir
, &argv
[i
][1]);
1549 log_error("Out of memory!");
1553 r
= asprintf(&path1
, "%s/extra/%s", kerneldir
, &argv
[i
][1]);
1555 log_error("Out of memory!");
1559 r
= asprintf(&path3
, "%s/updates/%s", kerneldir
, &argv
[i
][1]);
1561 log_error("Out of memory!");
1566 char *paths
[] = { path1
, path2
, path3
, NULL
};
1567 fts
= fts_open(paths
, FTS_COMFOLLOW
|FTS_NOCHDIR
|FTS_NOSTAT
|FTS_LOGICAL
, NULL
);
1570 for (FTSENT
*ftsent
= fts_read(fts
); ftsent
!= NULL
; ftsent
= fts_read(fts
)) {
1571 _cleanup_kmod_module_unref_list_
struct kmod_list
*modlist
= NULL
;
1572 _cleanup_free_
const char *modname
= NULL
;
1574 if((ftsent
->fts_info
== FTS_D
) && !check_module_path(ftsent
->fts_accpath
)) {
1575 fts_set(fts
, ftsent
, FTS_SKIP
);
1576 log_debug("Skipping %s", ftsent
->fts_accpath
);
1579 if((ftsent
->fts_info
!= FTS_F
) && (ftsent
->fts_info
!= FTS_SL
)) {
1580 log_debug("Ignoring %s", ftsent
->fts_accpath
);
1583 log_debug("Handling %s", ftsent
->fts_accpath
);
1584 r
= kmod_module_new_from_path(ctx
, ftsent
->fts_accpath
, &mod_o
);
1586 log_debug("Failed to lookup modules path '%s': %m",
1587 ftsent
->fts_accpath
);
1588 if (!arg_optional
) {
1594 /* Check, if we have to load another module with that name instead */
1595 modname
= strdup(kmod_module_get_name(mod_o
));
1598 log_error("Failed to get name for module '%s'", ftsent
->fts_accpath
);
1599 if (!arg_optional
) {
1604 r
= kmod_module_new_from_lookup(ctx
, modname
, &modlist
);
1605 kmod_module_unref(mod_o
);
1609 log_error("Failed to lookup alias '%s': %m", modname
);
1610 if (!arg_optional
) {
1617 log_error("Failed to find module '%s' %s", modname
,
1618 ftsent
->fts_accpath
);
1619 if (!arg_optional
) {
1624 kmod_list_foreach(itr
, modlist
) {
1625 mod
= kmod_module_get_module(itr
);
1626 r
= install_module(mod
);
1627 kmod_module_unref(mod
);
1628 if ((r
< 0) && !arg_optional
) {
1630 log_error("ERROR: installing module '%s'", modname
);
1633 ret
= ( ret
== 0 ? 0 : r
);
1638 log_error("FTS ERROR: %m");
1641 _cleanup_kmod_module_unref_list_
struct kmod_list
*modlist
= NULL
;
1642 char *modname
= argv
[i
];
1644 if (endswith(modname
, ".ko")) {
1645 int len
= strlen(modname
);
1648 if (endswith(modname
, ".ko.xz") || endswith(modname
, ".ko.gz")) {
1649 int len
= strlen(modname
);
1652 r
= kmod_module_new_from_lookup(ctx
, modname
, &modlist
);
1654 if (!arg_optional
) {
1656 log_error("Failed to lookup alias '%s': %m", modname
);
1659 log_info("Failed to lookup alias '%s': %m", modname
);
1663 if (!arg_optional
) {
1665 log_error("Failed to find module '%s'", modname
);
1668 log_info("Failed to find module '%s'", modname
);
1671 kmod_list_foreach(itr
, modlist
) {
1672 mod
= kmod_module_get_module(itr
);
1673 r
= install_module(mod
);
1674 kmod_module_unref(mod
);
1675 if ((r
< 0) && !arg_optional
) {
1677 log_error("ERROR: installing '%s'", argv
[i
]);
1680 ret
= ( ret
== 0 ? 0 : r
);
1685 if ((modinst
!= 0) && (ret
!= 0) && (!arg_optional
)) {
1687 log_error("ERROR: installing '%s'", argv
[i
]);
1688 return EXIT_FAILURE
;
1692 return EXIT_SUCCESS
;
1695 int main(int argc
, char **argv
)
1701 r
= parse_argv(argc
, argv
);
1703 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;
1705 log_set_target(LOG_TARGET_CONSOLE
);
1706 log_parse_environment();
1708 if (arg_loglevel
>= 0)
1709 log_set_max_level(arg_loglevel
);
1713 modules_loaded
= hashmap_new(string_hash_func
, string_compare_func
);
1717 _cleanup_kmod_unref_
struct kmod_ctx
*ctx
= NULL
;
1718 ctx
= kmod_new(kerneldir
, NULL
);
1721 HASHMAP_FOREACH(name
, modules_loaded
, i
) {
1722 printf("%s\n", name
);
1727 path
= getenv("PATH");
1730 log_error("PATH is not set");
1734 log_debug("PATH=%s", path
);
1736 pathdirs
= strv_split(path
, ":");
1740 if (destrootdir
== NULL
|| strlen(destrootdir
) == 0) {
1741 destrootdir
= getenv("DESTROOTDIR");
1742 if (destrootdir
== NULL
|| strlen(destrootdir
) == 0) {
1743 log_error("Environment DESTROOTDIR or argument -D is not set!");
1744 usage(EXIT_FAILURE
);
1746 destrootdir
= strdup(destrootdir
);
1749 if (strcmp(destrootdir
, "/") == 0) {
1750 log_error("Environment DESTROOTDIR or argument -D is set to '/'!");
1751 usage(EXIT_FAILURE
);
1755 destrootdir
= realpath(destrootdir
, NULL
);
1757 log_error("Environment DESTROOTDIR or argument -D is set to '%s': %m", i
);
1763 items
= hashmap_new(string_hash_func
, string_compare_func
);
1764 items_failed
= hashmap_new(string_hash_func
, string_compare_func
);
1766 if (!items
|| !items_failed
|| !modules_loaded
) {
1767 log_error("Out of memory");
1775 ret
= asprintf(&logfile
, "%s/%d.log", logdir
, getpid());
1777 log_error("Out of memory!");
1781 logfile_f
= fopen(logfile
, "a");
1782 if (logfile_f
== NULL
) {
1783 log_error("Could not open %s for logging: %m", logfile
);
1791 if (((optind
+ 1) < argc
) && (strcmp(argv
[optind
+ 1], destrootdir
) == 0)) {
1792 /* ugly hack for compat mode "inst src $destrootdir" */
1793 if ((optind
+ 2) == argc
) {
1796 /* ugly hack for compat mode "inst src $destrootdir dst" */
1797 if ((optind
+ 3) == argc
) {
1799 argv
[optind
+ 1] = argv
[optind
+ 2];
1805 r
= install_modules(argc
- optind
, &argv
[optind
]);
1806 } else if (arg_resolvelazy
) {
1807 r
= resolve_lazy(argc
- optind
, &argv
[optind
]);
1808 } else if (arg_all
|| (argc
- optind
> 2) || ((argc
- optind
) == 1)) {
1809 r
= install_all(argc
- optind
, &argv
[optind
]);
1811 /* simple "inst src dst" */
1812 r
= install_one(argv
[optind
], argv
[optind
+ 1]);
1822 while ((i
= hashmap_steal_first(modules_loaded
)))
1825 while ((i
= hashmap_steal_first(items
)))
1828 while ((i
= hashmap_steal_first(items_failed
)))
1831 hashmap_free(items
);
1832 hashmap_free(items_failed
);
1833 hashmap_free(modules_loaded
);
1836 strv_free(firmwaredirs
);
1837 strv_free(pathdirs
);