diff --git a/usr.bin/mktemp/mktemp.c b/usr.bin/mktemp/mktemp.c index 6f5b21ce70d5..226084fefb49 100644 --- a/usr.bin/mktemp/mktemp.c +++ b/usr.bin/mktemp/mktemp.c @@ -1,202 +1,208 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * This program was originally written long ago, originally for a non * BSD-like OS without mkstemp(). It's been modified over the years * to use mkstemp() rather than the original O_CREAT|O_EXCL/fstat/lstat * etc style hacks. * A cleanup, misc options and mkdtemp() calls were added to try and work * more like the OpenBSD version - which was first to publish the interface. */ #include #include #include #include #include #include #include #include #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ static void usage(void); static const struct option long_opts[] = { {"directory", no_argument, NULL, 'd'}, {"tmpdir", optional_argument, NULL, 'p'}, {"quiet", no_argument, NULL, 'q'}, {"dry-run", no_argument, NULL, 'u'}, {NULL, no_argument, NULL, 0}, }; int main(int argc, char **argv) { int c, fd, ret; const char *prefix, *tmpdir; char *name; int dflag, qflag, tflag, uflag; bool prefer_tmpdir; ret = dflag = qflag = tflag = uflag = 0; prefer_tmpdir = true; prefix = "mktemp"; name = NULL; tmpdir = NULL; while ((c = getopt_long(argc, argv, "dp:qt:u", long_opts, NULL)) != -1) switch (c) { case 'd': dflag++; break; case 'p': tmpdir = optarg; if (tmpdir == NULL || *tmpdir == '\0') tmpdir = getenv("TMPDIR"); + + /* + * We've already done the necessary environment + * fallback, skip the later one. + */ + prefer_tmpdir = false; break; case 'q': qflag++; break; case 't': prefix = optarg; tflag++; break; case 'u': uflag++; break; default: usage(); } argc -= optind; argv += optind; if (!tflag && argc < 1) { tflag = 1; prefix = "tmp"; /* * For this implied -t mode, we actually want to swap the usual * order of precedence: -p, then TMPDIR, then /tmp. */ prefer_tmpdir = false; } if (tflag) { const char *envtmp; size_t len; envtmp = NULL; /* * $TMPDIR preferred over `-p` if specified, for compatibility. */ if (prefer_tmpdir || tmpdir == NULL) envtmp = getenv("TMPDIR"); if (envtmp != NULL) tmpdir = envtmp; if (tmpdir == NULL) tmpdir = _PATH_TMP; len = strlen(tmpdir); if (len > 0 && tmpdir[len - 1] == '/') asprintf(&name, "%s%s.XXXXXXXXXX", tmpdir, prefix); else asprintf(&name, "%s/%s.XXXXXXXXXX", tmpdir, prefix); /* if this fails, the program is in big trouble already */ if (name == NULL) { if (qflag) return (1); else errx(1, "cannot generate template"); } } /* generate all requested files */ while (name != NULL || argc > 0) { if (name == NULL) { if (!tflag && tmpdir != NULL) asprintf(&name, "%s/%s", tmpdir, argv[0]); else name = strdup(argv[0]); if (name == NULL) err(1, "%s", argv[0]); argv++; argc--; } if (dflag) { if (mkdtemp(name) == NULL) { ret = 1; if (!qflag) warn("mkdtemp failed on %s", name); } else { printf("%s\n", name); if (uflag) rmdir(name); } } else { fd = mkstemp(name); if (fd < 0) { ret = 1; if (!qflag) warn("mkstemp failed on %s", name); } else { close(fd); if (uflag) unlink(name); printf("%s\n", name); } } if (name) free(name); name = NULL; } return (ret); } static void usage(void) { fprintf(stderr, "usage: mktemp [-d] [-p tmpdir] [-q] [-t prefix] [-u] template " "...\n"); fprintf(stderr, " mktemp [-d] [-p tmpdir] [-q] [-u] -t prefix \n"); exit (1); } diff --git a/usr.bin/mktemp/tests/mktemp_test.sh b/usr.bin/mktemp/tests/mktemp_test.sh index 60555f1b561b..505c60536b34 100755 --- a/usr.bin/mktemp/tests/mktemp_test.sh +++ b/usr.bin/mktemp/tests/mktemp_test.sh @@ -1,132 +1,132 @@ # # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2022 Klara Systems # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ atf_test_case tmpdir_env tmpdir_env_body() { tmpdir="$PWD" atf_check -o match:"^$tmpdir/foo\..+$" \ env TMPDIR="$tmpdir" mktemp -t foo } atf_test_case tmpdir_pflag tmpdir_pflag_body() { mkdir tmp_p tmp_env tmpdir="$PWD/tmp_env" export TMPDIR="$tmpdir" pflag="$PWD/tmp_p" # Basic usage: just -p specified atf_check -o match:"^$pflag/tmp\..+$" \ env -u TMPDIR mktemp -p "$pflag" atf_check -o match:"^$pflag/tmp\..+$" \ env TMPDIR="$tmpdir" mktemp -p "$pflag" # -p with a list of names atf_check -o ignore env -u TMPDIR mktemp -p "$pflag" x y z atf_check test -f "$pflag/x" atf_check test -f "$pflag/y" atf_check test -f "$pflag/z" # Checking --tmpdir usage, which should defer to $TMPDIR followed by # /tmp with no value specified. atf_check -o match:"^/tmp/foo\..+$" \ env -u TMPDIR mktemp --tmpdir -t foo atf_check -o match:"^$tmpdir/foo\..+$" \ env TMPDIR="$tmpdir" mktemp --tmpdir -t foo # Finally, combined -p -t atf_check -o match:"^$pflag/foo\..+$" \ env -u TMPDIR mktemp -p "$pflag" -t foo - atf_check -o match:"^$tmpdir/foo\..+$" \ + atf_check -o match:"^$pflag/foo\..+$" \ env TMPDIR="$tmpdir" mktemp -p "$pflag" -t foo } atf_test_case tmpdir_pflag_dir tmpdir_pflag_dir_body() { tmpdir="$PWD" atf_check -o save:tmpname \ env -u TMPDIR mktemp -d -p "$tmpdir" -t foo # Better diagnostics when using -o match: + cat rather than grep. atf_check -o match:"^$tmpdir/foo\..+$" cat tmpname cdir=$(cat tmpname) atf_check test -d "$cdir" atf_check -o match:"^$tmpdir/footmp$" \ env -u TMPDIR mktemp -d -p "$tmpdir" footmp atf_check test -d "$tmpdir/footmp" } atf_test_case tmpdir_pflag_noarg tmpdir_pflag_noarg_body() { # Without -t, this time; this introduces $TMPDIR without having to use # it. tmpdir="$PWD" atf_check -o save:tmpname \ env TMPDIR="$tmpdir" mktemp --tmpdir foo.XXXXXXXX atf_check -o match:"^$tmpdir/foo\..+$" cat tmpname # An empty string gets the same treatment. atf_check -o save:tmpname \ env TMPDIR="$tmpdir" mktemp -p '' foo.XXXXXXXX atf_check -o match:"^$tmpdir/foo\..+$" cat tmpname } atf_test_case tmpdir_tflag_oneslash tmpdir_tflag_oneslash_body() { tmpdir="$PWD" # Provided a trailing slash, we shouldn't end up with two trailing # slashes. atf_check -o save:tmpname \ env TMPDIR="$tmpdir/" mktemp -t foo atf_check -o match:"^$tmpdir/foo\..+$" cat tmpname } atf_init_test_cases() { atf_add_test_case tmpdir_env atf_add_test_case tmpdir_pflag atf_add_test_case tmpdir_pflag_dir atf_add_test_case tmpdir_pflag_noarg atf_add_test_case tmpdir_tflag_oneslash }