m4: Mkstemp

 
 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 the quoted 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 or quoting the expansion, 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 expansion is void and an error issued if a temporary file could
      not be created.
 
      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:
 
      $ m4
      define(`tmp', `oops')
      =>
      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',
 ⇒Invoking m4 Limits control.), 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.  Also, as of M4 1.4.11, the secure implementation
 quotes the resulting file name, so that you are guaranteed to know what
 file was created even if the random file name happens to match an
 existing macro.  Notice that this example is careful to use 'defn' to
 avoid unintended expansion of 'foo'.
 
      $ m4
      define(`foo', `errprint(`oops')')
      =>
      syscmd(`rm -f foo-??????')sysval
      =>0
      define(`file1', maketemp(`foo-XXXXXX'))dnl
      ifelse(esyscmd(`echo \` foo-?????? \''), ` foo-?????? ',
             `no file', `created')
      =>created
      define(`file2', maketemp(`foo-XX'))dnl
      define(`file3', mkstemp(`foo-XXXXXX'))dnl
      ifelse(len(defn(`file1')), len(defn(`file2')),
             `same length', `different')
      =>same length
      ifelse(defn(`file1'), defn(`file2'), `same', `different file')
      =>different file
      ifelse(defn(`file2'), defn(`file3'), `same', `different file')
      =>different file
      ifelse(defn(`file1'), defn(`file3'), `same', `different file')
      =>different file
      syscmd(`rm 'defn(`file1') defn(`file2') defn(`file3'))
      =>
      sysval
      =>0