Index: usr.sbin/kldxref/kldxref.c =================================================================== --- usr.sbin/kldxref/kldxref.c +++ usr.sbin/kldxref/kldxref.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -657,6 +658,41 @@ return (fdopen(fd, "w+")); } +/* + * Copy an existing file identified by its path to the path specified. The + * destination is first truncated if it already exists. On error, a warning + * is written to stderr with the details and the function returns false. + */ +static bool +copyfile(const char *src, const char *dst) +{ + int copy_result, src_fd, dst_fd; + + src_fd = open(src, O_RDONLY); + if (src_fd < 0) { + warn("can't open %s", src); + return (false); + } + dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC); + if (dst_fd < 0) { + warn("can't create %s", dst); + close(src_fd); + return (false); + } + + while ((copy_result = copy_file_range(src_fd, NULL, dst_fd, NULL, + SSIZE_MAX, 0)) > 0) { + /* Continue until the entirety of the source has been copied */ + } + if (copy_result < 0) { + warn("can't copy %s to %s", src, dst); + } + + close(src_fd); + close(dst_fd); + return (copy_result == 0); +} + static char xrefname[MAXPATHLEN], tempname[MAXPATHLEN]; static void @@ -732,7 +768,21 @@ fclose(fxref); fxref = NULL; if (reccnt != 0) { - rename(tempname, xrefname); + if (rename(tempname, xrefname) != 0) { + /* handle src/dst being on a different filesystems */ + if (errno == EXDEV) { + /* + * copyfile reports its own errors and we don't + * abort in case of copy failure, both so we + * can keep trying to create other hint files + * and so we can perform the required cleanup. + */ + copyfile(tempname, xrefname); + } else { + warn("can't rename %s to %s", xrefname, tempname); + } + unlink(tempname); + } } else { /* didn't find any entry, ignore this file */ unlink(tempname);