diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c --- a/sbin/reboot/reboot.c +++ b/sbin/reboot/reboot.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -113,13 +114,19 @@ static void write_nextboot(const char *fn, const char *env, bool force) { + char dir[PATH_MAX], *dirp, tmp[PATH_MAX]; FILE *fp; struct statfs sfs; + int tmpfd; bool supported = false; bool zfs = false; - if (statfs("/boot", &sfs) != 0) - err(1, "statfs /boot"); + if (strlcpy(dir, fn, sizeof(dir)) >= sizeof(dir)) + errx(1, "Path too long %s", fn); + dirp = dirname(dir); + + if (statfs(dirp, &sfs) != 0) + err(1, "statfs %s", dirp); if (strcmp(sfs.f_fstypename, "ufs") == 0) { /* * Only UFS supports the full nextboot protocol. @@ -138,21 +145,37 @@ zfsbootcfg(sfs.f_mntfromname, force); } - fp = fopen(fn, "w"); + if (strlcpy(tmp, fn, sizeof(tmp)) >= sizeof(tmp)) + errx(1, "Path too long %s", fn); + if (strlcat(tmp, ".XXXXXX", sizeof(tmp)) >= sizeof(tmp)) + errx(1, "Path too long %s", fn); + tmpfd = mkstemp(tmp); + if (tmpfd == -1) + err(1, "mkstemp %s", tmp); + + fp = fdopen(tmpfd, "w"); if (fp == NULL) - E("Can't create %s", fn); + err(1, "fdopen %s", fn); - if (fprintf(fp,"%s%s", + if (fprintf(fp, "%s%s", supported ? "nextboot_enable=\"YES\"\n" : "", env != NULL ? env : "") < 0) { int e; e = errno; - fclose(fp); - if (unlink(fn)) - warn("unlink %s", fn); - errno = e; - E("Can't write %s", fn); + if (unlink(tmp)) + warn("unlink %s", tmp); + errc(1, e, "Can't write %s", tmp); + } + if (fsync(fileno(fp)) != 0) + warn("fsync %s", fn); + if (rename(tmp, fn) != 0) { + int e; + + e = errno; + if (unlink(tmp)) + warn("unlink %s", tmp); + errc(1, e, "rename %s to %s", tmp, fn); } fclose(fp); }