m4: Mkstemp
1
1 13.5 Making temporary files
1 ===========================
1
1 Commands specified to 'syscmd' or 'esyscmd' might need a temporary file,
1 for output or for some other purpose. There is a builtin macro,
1 'mkstemp', for making a temporary file:
1
1 -- Builtin: mkstemp (TEMPLATE)
1 -- Builtin: maketemp (TEMPLATE)
1 Expands to the quoted name of a new, empty file, made from the
1 string TEMPLATE, which should end with the string 'XXXXXX'. The
1 six 'X' characters are then replaced with random characters
1 matching the regular expression '[a-zA-Z0-9._-]', in order to make
1 the file name unique. If fewer than six 'X' characters are found
1 at the end of 'template', the result will be longer than the
1 template. The created file will have access permissions as if by
1 'chmod =rw,go=', meaning that the current umask of the 'm4' process
1 is taken into account, and at most only the current user can read
1 and write the file.
1
1 The traditional behavior, standardized by POSIX, is that 'maketemp'
1 merely replaces the trailing 'X' with the process id, without
1 creating a file or quoting the expansion, and without ensuring that
1 the resulting string is a unique file name. In part, this means
1 that using the same TEMPLATE twice in the same input file will
1 result in the same expansion. This behavior is a security hole, as
1 it is very easy for another process to guess the name that will be
1 generated, and thus interfere with a subsequent use of 'syscmd'
1 trying to manipulate that file name. Hence, POSIX has recommended
1 that all new implementations of 'm4' provide the secure 'mkstemp'
1 builtin, and that users of 'm4' check for its existence.
1
1 The expansion is void and an error issued if a temporary file could
1 not be created.
1
1 The macros 'mkstemp' and 'maketemp' are recognized only with
1 parameters.
1
1 If you try this next example, you will most likely get different
1 output for the two file names, since the replacement characters are
1 randomly chosen:
1
1 $ m4
1 define(`tmp', `oops')
1 =>
1 maketemp(`/tmp/fooXXXXXX')
1 =>/tmp/fooa07346
1 ifdef(`mkstemp', `define(`maketemp', defn(`mkstemp'))',
1 `define(`mkstemp', defn(`maketemp'))dnl
1 errprint(`warning: potentially insecure maketemp implementation
1 ')')
1 =>
1 mkstemp(`doc')
1 =>docQv83Uw
1
1 Unless you use the '--traditional' command line option (or '-G',
1 ⇒Invoking m4 Limits control.), the GNU version of 'maketemp' is
1 secure. This means that using the same template to multiple calls will
1 generate multiple files. However, we recommend that you use the new
1 'mkstemp' macro, introduced in GNU M4 1.4.8, which is secure even in
1 traditional mode. Also, as of M4 1.4.11, the secure implementation
1 quotes the resulting file name, so that you are guaranteed to know what
1 file was created even if the random file name happens to match an
1 existing macro. Notice that this example is careful to use 'defn' to
1 avoid unintended expansion of 'foo'.
1
1 $ m4
1 define(`foo', `errprint(`oops')')
1 =>
1 syscmd(`rm -f foo-??????')sysval
1 =>0
1 define(`file1', maketemp(`foo-XXXXXX'))dnl
1 ifelse(esyscmd(`echo \` foo-?????? \''), ` foo-?????? ',
1 `no file', `created')
1 =>created
1 define(`file2', maketemp(`foo-XX'))dnl
1 define(`file3', mkstemp(`foo-XXXXXX'))dnl
1 ifelse(len(defn(`file1')), len(defn(`file2')),
1 `same length', `different')
1 =>same length
1 ifelse(defn(`file1'), defn(`file2'), `same', `different file')
1 =>different file
1 ifelse(defn(`file2'), defn(`file3'), `same', `different file')
1 =>different file
1 ifelse(defn(`file1'), defn(`file3'), `same', `different file')
1 =>different file
1 syscmd(`rm 'defn(`file1') defn(`file2') defn(`file3'))
1 =>
1 sysval
1 =>0
1