Previous: Sysval, Up: Shell commands


13.5 Making temporary files

Commands specified to syscmd or esyscmd might need a temporary file, for output or for some other purpose. There is a builtin macro, mkstemp, for making a temporary file:

— Builtin: mkstemp (template)
— Builtin: maketemp (template)

Expands to a name of a new, empty file, made from the string template, which should end with the string `XXXXXX'. The six `X' characters are then replaced with random characters matching the regular expression `[a-zA-Z0-9._-]', in order to make the file name unique. If fewer than six `X' characters are found at the end of template, the result will be longer than the template. The created file will have access permissions as if by chmod =rw,go=, meaning that the current umask of the m4 process is taken into account, and at most only the current user can read and write the file.

The traditional behavior, standardized by POSIX, is that maketemp merely replaces the trailing `X' with the process id, without creating a file, and without ensuring that the resulting string is a unique file name. In part, this means that using the same template twice in the same input file will result in the same expansion. This behavior is a security hole, as it is very easy for another process to guess the name that will be generated, and thus interfere with a subsequent use of syscmd trying to manipulate that file name. Hence, POSIX has recommended that all new implementations of m4 provide the secure mkstemp builtin, and that users of m4 check for its existence.

The macros mkstemp and maketemp are recognized only with parameters.

If you try this next example, you will most likely get different output for the two file names, since the replacement characters are randomly chosen:

     maketemp(`/tmp/fooXXXXXX')
     =>/tmp/fooa07346
     ifdef(`mkstemp', `define(`maketemp', defn(`mkstemp'))',
           `define(`mkstemp', defn(`maketemp'))dnl
     errprint(`warning: potentially insecure maketemp implementation
     ')')
     =>
     mkstemp(`doc')
     =>docQv83Uw

Unless you use the --traditional command line option (or -G, see Invoking m4), the GNU version of maketemp is secure. This means that using the same template to multiple calls will generate multiple files. However, we recommend that you use the new mkstemp macro, introduced in GNU M4 1.4.8, which is secure even in traditional mode.

     syscmd(`echo foo??????')dnl
     =>foo??????
     define(`file1', maketemp(`fooXXXXXX'))dnl
     ifelse(esyscmd(`echo foo??????'), `foo??????', `no file', `created')
     =>created
     define(`file2', maketemp(`fooXX'))dnl
     define(`file3', mkstemp(`fooXXXXXX'))dnl
     ifelse(len(file1), len(file2), `same length', `different')
     =>same length
     ifelse(file1, file2, `same', `different file')
     =>different file
     ifelse(file2, file3, `same', `different file')
     =>different file
     ifelse(file1, file3, `same', `different file')
     =>different file
     syscmd(`rm 'file1 file2 file3)
     =>
     sysval
     =>0