I've noticed this before, but it was brought up again as I was answering "How to move directory into a directory with the same name?":
The mktemp
utility on macOS does not behave the same as the utility of the same name on Linux or BSD (or least OpenBSD) with respect to the TMPDIR
environment variable.
To create a temporary file in the current directory, I can usually say
tmdfile=$(TMPDIR=. mktemp)
or
tmpfile=$(TMPDIR=$PWD mktemp)
(and similarly for a temporary directory with mktemp -d
).
On macOS, I will have to force the utility to use the current directory by giving it an actual template, as in
tmpfile=(mktemp ./tmp.XXXXXXXX)
because using the more convenient tmpfile=$(TMPDIR=. mktemp)
would ignore the TMPDIR
variable and create the file under /var/folders/qg/s5jp5ffx2p1fxv0hy2l_p3hm0000gn/T
or in a similarly named directory.
The manual for mktemp
on macOS mentions that
If the
-t prefix
option is given,mktemp
will generate a template string based on the prefix and
the_CS_DARWIN_USER_TEMP_DIR
configuration variable if available. Fallback locations if
_CS_DARWIN_USER_TEMP_DIR
is not available areTMPDIR
and/tmp
.
On my system, _CS_DARWIN_USER_TEMP_DIR
appears to be unset:
$ getconf _CS_DARWIN_USER_TEMP_DIR
getconf: no such configuration parameter `_CS_DARWIN_USER_TEMP_DIR'
but e.g.
tmpfile=$(TMPDIR=. mktemp -t hello)
still creates a file under /var/folders/.../
(also when using $PWD
in place of .
).
I'm noticing that
$ getconf DARWIN_USER_TEMP_DIR
/var/folders/qg/s5jp5ffx2p1fxv0hy2l_p3hm0000gn/T/
but this doesn't help me much as I wouldn't know how to change this value.
The macOS mktemp
utility is said to come from FreeBSD, which in turn got it from OpenBSD (which must have been quite a while ago).
Question:
Is this a bug (or omission) in the macOS implementation of mktemp
? How do I change the DARWIN_USER_TEMP_DIR
value (or _CS_DARWIN_USER_TEMP_DIR
mentioned by the manual) from within a script (I would ideally want to unset it so that $TMPDIR
takes precedence)?
Best Answer
This is your Darwin user local directory. Its name is simply a modified base 32 encoding of the concatenation your MacOS User UUID and your MacOS (BSD) user ID. The first two letters of the encoding are used as a "bucket" system to attempt to keep directory sizes low. Those two characters are the encoded first 10 bits of the User UUID, because in base 32 one digit is of course 5 bits.
Its subdirectories are your user local temp and user local cache directories. Their names used to be
-Caches-
and-Tmp-
but those have been shortened toC
andT
. It should be apparent that all of these names are fixed and unchangeable, unless you are willing to change your user ID or user UUID.When an application calls
confstr(_CS_DARWIN_USER_TEMP_DIR,…)
, the C library first tries to ensure that you have a user local directory, then tries to ensure that you have a user local temp directory within it.Ensuring that you have a user local directory is non-trivial, because you do not have write access to
/var/folders
. So there is adirhelper
Mach launch dæmon that runs with superuser privileges and that securely creates these directories, responding to Mach IPC calls from applications from within the implementation ofconfstr()
in their C libraries. You do have write access to the user local directory (once created) and so the C libraries justmkdir()
its children directly if they do not already exist.If this succeeeds, the
mktemp
program never looks at the value of theTMPDIR
environment variable, because the fallback inmktemp
's code is from callingconfstr()
to callinggetenv()
not the other way around.confstr(_CS_DARWIN_USER_TEMP_DIR,…)
will almost always succeed. Its failure modes are things like thedirhelper
launch dæmon not being able to be run, or the attempt to create theT
subdirectory failing with an error other than that the directory already exists.You could put something other than a directory as
T
, but this will be regularly cleaned up by thedirhelper
launch dæmon, which is also what deletes stuff in/var/folders
. Disabling thedirhelper
launch dæmon will cause problems of its own, not the least of which will be/var/folders
not getting cleaned. Denying yourself write permission on your user local directory will potentially interfere with all other uses of it, it being used for more than just aT
subdirectory.Your best option (aside from supplying a template) is to make
T
a symbolic link, but this is still far from good because it will of course affect all running applications of yours that might, at the very same instant, be wanting to create a temporary file.Neither
DARWIN_USER_TEMP_DIR
nor_CS_DARWIN_USER_TEMP_DIR
are variable names. They are names, for thegetconf
utility and for theconfstr()
library function, of a configuration string.