mktemp: add -p/--tmpdir argument
This matches other mktemp implementations, including OpenBSD and GNU. The -p option can be used to provide a tmpdir prefix for specified templates. Precedence works out like so: -t flag: - $TMPDIR - -p directory - /tmp Implied -t flag (no arguments or only -d flag): - -p directory - $TMPDIR - /tmp Some tests have been added for mktemp(1) in the process. Reviewed by: imp (earlier version), wosch Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D37121
This commit is contained in:
parent
cfc57d7dbe
commit
ac6f924e1c
@ -1060,6 +1060,8 @@
|
||||
..
|
||||
mkimg
|
||||
..
|
||||
mktemp
|
||||
..
|
||||
ncal
|
||||
..
|
||||
opensm
|
||||
|
@ -1,7 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <src.opts.mk>
|
||||
|
||||
PACKAGE= runtime
|
||||
|
||||
PROG= mktemp
|
||||
|
||||
HAS_TESTS=
|
||||
SUBDIR.${MK_TESTS}+= tests
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -37,12 +37,14 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl d
|
||||
.Op Fl p Ar tmpdir
|
||||
.Op Fl q
|
||||
.Op Fl t Ar prefix
|
||||
.Op Fl u
|
||||
.Ar template ...
|
||||
.Nm
|
||||
.Op Fl d
|
||||
.Op Fl p Ar tmpdir
|
||||
.Op Fl q
|
||||
.Op Fl u
|
||||
.Fl t Ar prefix
|
||||
@ -91,10 +93,20 @@ will generate a template string based on the
|
||||
and the
|
||||
.Ev TMPDIR
|
||||
environment variable if set.
|
||||
The default location if
|
||||
If the
|
||||
.Fl p
|
||||
option is set, then the given
|
||||
.Ar tmpdir
|
||||
will be used if the
|
||||
.Ev TMPDIR
|
||||
is not set is
|
||||
.Pa /tmp .
|
||||
environment variable is not set.
|
||||
Finally,
|
||||
.Pa /tmp
|
||||
will be used if neither
|
||||
.Ev TMPDIR
|
||||
or
|
||||
.Fl p
|
||||
are set and used.
|
||||
Care should
|
||||
be taken to ensure that it is appropriate to use an environment variable
|
||||
potentially supplied by the user.
|
||||
@ -134,6 +146,23 @@ The available options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl d , Fl -directory
|
||||
Make a directory instead of a file.
|
||||
.It Fl p Ar tmpdir , Fl -tmpdir Ns Oo = Ns Ar tmpdir Oc
|
||||
Use
|
||||
.Ar tmpdir
|
||||
for the
|
||||
.Fl t
|
||||
flag if the
|
||||
.Ev TMPDIR
|
||||
environment variable is not set.
|
||||
Additionally, any provided
|
||||
.Ar template
|
||||
arguments will be interpreted relative to the path specified as
|
||||
.Ar tmpdir .
|
||||
If
|
||||
.Ar tmpdir
|
||||
is either empty or omitted, then the
|
||||
.Ev TMPDIR
|
||||
environment variable will be used.
|
||||
.It Fl q , Fl -quiet
|
||||
Fail silently if an error occurs.
|
||||
This is useful if
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <paths.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -53,6 +54,7 @@ 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},
|
||||
@ -62,21 +64,29 @@ int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c, fd, ret;
|
||||
char *tmpdir;
|
||||
const char *prefix;
|
||||
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, "dqt:u", long_opts, NULL)) != -1)
|
||||
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");
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
qflag++;
|
||||
break;
|
||||
@ -100,10 +110,26 @@ main(int argc, char **argv)
|
||||
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) {
|
||||
tmpdir = getenv("TMPDIR");
|
||||
const char *envtmp;
|
||||
|
||||
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)
|
||||
asprintf(&name, "%s%s.XXXXXXXXXX", _PATH_TMP, prefix);
|
||||
else
|
||||
@ -120,7 +146,12 @@ main(int argc, char **argv)
|
||||
/* generate all requested files */
|
||||
while (name != NULL || argc > 0) {
|
||||
if (name == NULL) {
|
||||
name = strdup(argv[0]);
|
||||
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--;
|
||||
}
|
||||
@ -159,8 +190,9 @@ static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: mktemp [-d] [-q] [-t prefix] [-u] template ...\n");
|
||||
"usage: mktemp [-d] [-p tmpdir] [-q] [-t prefix] [-u] template "
|
||||
"...\n");
|
||||
fprintf(stderr,
|
||||
" mktemp [-d] [-q] [-u] -t prefix \n");
|
||||
" mktemp [-d] [-p tmpdir] [-q] [-u] -t prefix \n");
|
||||
exit (1);
|
||||
}
|
||||
|
7
usr.bin/mktemp/tests/Makefile
Normal file
7
usr.bin/mktemp/tests/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PACKAGE= tests
|
||||
|
||||
ATF_TESTS_SH+= mktemp_test
|
||||
|
||||
.include <bsd.test.mk>
|
118
usr.bin/mktemp/tests/mktemp_test.sh
Executable file
118
usr.bin/mktemp/tests/mktemp_test.sh
Executable file
@ -0,0 +1,118 @@
|
||||
#
|
||||
# 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\..+$" \
|
||||
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_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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user