Re: branch-1_4 maketemp cleanup

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Gary,

According to Gary V. Vaughan on 10/20/2006 8:29 PM:
> On 19 Oct 2006, at 18:00, Eric Blake wrote:
>>> Would it make sense to also implement a mkdtemp macro for head?
> 
> Sure, that seems like a great idea to me.

Done:

2006-10-21  Eric Blake  <[email protected]>

	* modules/m4.c (m4_make_temp): Change signature.
	(maketemp, mkstemp): Update callers.
	* modules/m4.h (m4_make_temp_func): New export.
	* modules/gnu.c (mkdtemp): New macro.
	* doc/m4.texinfo (Operation modes): Document interaction with
	--safer.
	(Mkdtemp): New node.
	* tests/builtins.at (mkdtemp): New test.
	(mkstemp): Check for umask effect.
	* NEWS: Document new builtin.

- --
Life is short - so eat dessert first!

Eric Blake             [email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD0DBQFFOpsk84KuGfSFAYARAvQFAJjKq92/c4a4ebU5twAwFarasj/+AJICFMj6
t6FYNAILngatiM1rB/aw
=94Qf
-----END PGP SIGNATURE-----

_______________________________________________
M4-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/m4-patches
m4.patch195 (text/plain, 12.6 KB)
Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.28
diff -u -p -r1.28 NEWS
--- NEWS	19 Oct 2006 23:13:45 -0000	1.28
+++ NEWS	21 Oct 2006 22:06:31 -0000
@@ -50,13 +50,17 @@ promoted to 2.0.
   the include path, rather than always searching `.' first.
 
 * New `--safer' command-line option cripples the potentially unsafe
-  macros `debugfile', `syscmd', `esyscmd', `maketemp', and `mkstemp'.
+  macros `debugfile', `esyscmd', `maketemp', `mkdtemp', `mkstemp', and
+  `syscmd'.
 
 * The `maketemp' builtin now always warns that it is obsolete, even in GNU
   mode where it uses the same secure algorithm as `mkstemp', because of
   the recommendation of POSIX to obsolete `maketemp' as inherently
   insecure when obeying POSIX.
 
+* New builtin `mkdtemp' parallels `mkstemp', but allows the creation of
+  temporary directories instead of files.
+
 * New `-b'/`--batch' command line option to force non-interactive mode.
   Also, in addition to `-e'/`--interactive' requesting interactive mode, m4
   now follows the lead of sh, and automatically enters interactive mode
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.70
diff -u -p -r1.70 m4.texinfo
--- doc/m4.texinfo	21 Oct 2006 15:23:56 -0000	1.70
+++ doc/m4.texinfo	21 Oct 2006 22:06:32 -0000
@@ -260,6 +260,7 @@ Macros for running shell commands
 * Esyscmd::                     Reading the output of commands
 * Sysval::                      Exit status
 * Mkstemp::                     Making temporary files
+* Mkdtemp::                     Making temporary directories
 
 Miscellaneous builtin macros
 
@@ -646,11 +647,11 @@ format and meaning of @var{RESYNTAX-SPEC
 
 @item --safer
 Cripple the builtins @code{maketemp}, @code{mkstemp} (@pxref{Mkstemp}),
-@code{debugfile} (@pxref{Debugfile}), @code{syscmd} (@pxref{Syscmd}),
-and @code{esyscmd} (@pxref{Esyscmd}), since they can perform potentially
-unsafe actions.  An attempt to use these macros will result in an error.
-This option is intended to make it safer to preprocess an input file of
-unknown origin.
+@code{mkdtemp} (@pxref{Mkdtemp}), @code{debugfile} (@pxref{Debugfile}),
+@code{syscmd} (@pxref{Syscmd}), and @code{esyscmd} (@pxref{Esyscmd}),
+since they can perform potentially unsafe actions.  An attempt to use
+these macros will result in an error.  This option is intended to make
+it safer to preprocess an input file of unknown origin.
 @end table
 
 @node Dynamic loading features
@@ -2078,6 +2079,7 @@ regular expression.
 
 The expansion of @code{renamesyms} is void.
 The macro @code{renamesyms} is recognized only with parameters.
+This macro was added in M4 2.0.
 @end deffn
 
 Here is an example that performs the same renaming as the
@@ -2302,6 +2304,7 @@ programs.
 
 When given arguments, @code{m4symbols} returns the sorted subset of the
 @var{names} currently defined, and silently ignores the rest.
+This macro was added in M4 2.0.
 @end deffn
 
 @example
@@ -5147,6 +5150,7 @@ commands from within @code{m4}.
 * Esyscmd::                     Reading the output of commands
 * Sysval::                      Exit status
 * Mkstemp::                     Making temporary files
+* Mkdtemp::                     Making temporary directories
 @end menu
 
 @node Platform macros
@@ -5403,6 +5407,81 @@ syscmd(`echo foo??????')dnl
 @result{}foo??????
 @end example
 
+@node Mkdtemp
+@section Making temporary directories
+
+@cindex temporary directory
+@cindex directories, temporary
+@cindex @acronym{GNU} extensions
+Commands specified to @code{syscmd} or @code{esyscmd} might need a
+temporary directory, for holding multiple temporary files; such a
+directory can be created with @code{mkdtemp}:
+
+@deffn {Builtin (gnu)} mkdtemp (@var{template})
+Expands to a name of a new, empty directory, made from the string
+@var{template}, which should end with the string @samp{XXXXXX}.  The six
+@samp{X} characters are then replaced with random characters matching
+the regular expression @samp{[a-zA-Z0-9._-]}, in order to make the name
+unique.  If fewer than six @samp{X} characters are found at the end of
+@code{template}, the result will be longer than the template.  The
+created directory will have access permissions as if by @kbd{chmod
+=rwx,go=}, meaning that the current umask of the @code{m4} process is
+taken into account, and at most only the current user can read, write,
+and search the directory.
+
+The expansion is void and an error issued if a temporary directory could
+not be created.
+
+When the @option{--safer} option (@pxref{Operation modes, Invoking m4})
+is in effect, @code{mkdtemp} results in an error, since otherwise an
+input file could perform a mild denial-of-service attack by filling up a
+disk with multiple directories.
+
+The macro @code{mkdtemp} is recognized only with parameters.
+This macro was added in M4 2.0.
+@end deffn
+
+If you try this next example, you will most likely get different output
+for the directory names, since the replacement characters are randomly
+chosen:
+
+@comment ignore
+@example
+$ @kbd{m4}
+mkdtemp(`/tmp/fooXXXXXX')
+@result{}/tmp/foo2h89Vo
+mkdtemp(`dir)
+@result{}dirrg079A
+@end example
+
+@comment options: --safer
+@comment status: 1
+@example
+$ @kbd{m4 --safer}
+mkdtemp(`/tmp/fooXXXXXX')
+@error{}m4:stdin:1: mkdtemp: disabled by --safer
+@result{}
+@end example
+
+Multiple calls with the same template will generate multiple
+directories.
+
+@example
+$ @kbd{m4}
+syscmd(`echo foo??????')dnl
+@result{}foo??????
+define(`dir1', mkdtemp(`fooXXXXXX'))dnl
+ifelse(esyscmd(`echo foo??????'), `foo??????', `no dir', `created')
+@result{}created
+define(`dir2', mkdtemp(`fooXXXXXX'))dnl
+ifelse(dir1, dir2, `same', `different directories')
+@result{}different directories
+syscmd(`rmdir 'dir1 dir2)
+@result{}
+sysval
+@result{}0
+@end example
+
 @node Miscellaneous
 @chapter Miscellaneous builtin macros
 
Index: modules/gnu.c
===================================================================
RCS file: /sources/m4/m4/modules/gnu.c,v
retrieving revision 1.64
diff -u -p -r1.64 gnu.c
--- modules/gnu.c	13 Oct 2006 16:46:47 -0000	1.64
+++ modules/gnu.c	21 Oct 2006 22:06:32 -0000
@@ -55,6 +55,7 @@
   BUILTIN (esyscmd,	false,	true,	true,	1,	1  )	\
   BUILTIN (format,	false,	true,	false,	1,	-1 )	\
   BUILTIN (indir,	true,	true,	false,	1,	-1 )	\
+  BUILTIN (mkdtemp,	false,	true,	false,	1,	1  )	\
   BUILTIN (patsubst,	false,	true,	true,	2,	4  )	\
   BUILTIN (regexp,	false,	true,	true,	2,	4  )	\
   BUILTIN (renamesyms,	false,	true,	false,	2,	3  )	\
@@ -570,6 +571,22 @@ M4BUILTIN_HANDLER (indir)
 }
 
 
+/* The builtin "mkdtemp" allows creation of temporary directories.  */
+
+/**
+ * mkdtemp(TEMPLATE)
+ **/
+M4BUILTIN_HANDLER (mkdtemp)
+{
+  M4_MODULE_IMPORT (m4, m4_make_temp);
+
+  if (m4_make_temp)
+    m4_make_temp (context, obs, M4ARG (0), M4ARG (1), true);
+  else
+    assert (!"Unable to import from m4 module");
+}
+
+
 /* Substitute all matches of a regexp occuring in a string.  Each match of
    the second argument (a regexp) in the first argument is changed to the
    third argument, with \& substituted by the matched text, and \N
Index: modules/m4.c
===================================================================
RCS file: /sources/m4/m4/modules/m4.c,v
retrieving revision 1.84
diff -u -p -r1.84 m4.c
--- modules/m4.c	19 Oct 2006 23:13:45 -0000	1.84
+++ modules/m4.c	21 Oct 2006 22:06:32 -0000
@@ -53,6 +53,8 @@ extern void m4_sysval_flush  (m4 *contex
 extern void m4_dump_symbols  (m4 *context, m4_dump_symbol_data *data, int argc,
 			      m4_symbol_value **argv, bool complain);
 extern const char *m4_expand_ranges (const char *s, m4_obstack *obs);
+extern void m4_make_temp     (m4 *context, m4_obstack *obs, const char *macro,
+			      const char *name, bool dir);
 
 /* Maintain each of the builtins implemented in this modules along
    with their details in a single table for easy maintenance.
@@ -673,17 +675,17 @@ M4BUILTIN_HANDLER (sinclude)
 /* Use the first argument as at template for a temporary file name.
    FIXME - should we add a mkdtemp builtin in the gnu module, then
    export this function as a helper to that?  */
-static void
-m4_make_temp (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv)
+void
+m4_make_temp (m4 *context, m4_obstack *obs, const char *macro,
+	      const char *name, bool dir)
 {
   int fd;
   int len;
   int i;
-  const char *name = M4ARG (1);
 
   if (m4_get_safer_opt (context))
     {
-      m4_error (context, 0, 0, _("%s: disabled by --safer"), M4ARG (0));
+      m4_error (context, 0, 0, _("%s: disabled by --safer"), macro);
       return;
     }
 
@@ -699,16 +701,25 @@ m4_make_temp (m4 *context, m4_obstack *o
     obstack_1grow (obs, 'X');
   obstack_1grow (obs, '\0');
 
+  /* Make the temporary object.  */
   errno = 0;
-  fd = mkstemp (obstack_base (obs));
+  if (dir)
+    fd = mkdtemp (obstack_base (obs)) ? 0 : -1;
+  else
+    fd = mkstemp (obstack_base (obs));
   if (fd < 0)
     {
-      m4_error (context, 0, errno, _("%s: cannot create tempfile `%s'"),
-		M4ARG (0), name);
+      /* This use of _() will need to change if xgettext ever changes
+	 its undocumented behavior of parsing both string options.  */
+
+      m4_error (context, 0, errno,
+		_(dir ? "%s: cannot create directory `%s'"
+		  : "%s: cannot create file `%s'"),
+		macro, name);
       obstack_free (obs, obstack_finish (obs));
     }
-  else
-     close (fd);
+  else if (! dir)
+    close (fd);
 }
 
 /* Use the first argument as at template for a temporary file name.  */
@@ -748,13 +759,13 @@ M4BUILTIN_HANDLER (maketemp)
 	}
     }
   else
-    m4_make_temp (context, obs, argc, argv);
+    m4_make_temp (context, obs, M4ARG (0), M4ARG (1), false);
 }
 
 /* Use the first argument as a template for a temporary file name.  */
 M4BUILTIN_HANDLER (mkstemp)
 {
-  m4_make_temp (context, obs, argc, argv);
+  m4_make_temp (context, obs, M4ARG (0), M4ARG (1), false);
 }
 
 /* Print all arguments on standard error.  */
Index: modules/m4.h
===================================================================
RCS file: /sources/m4/m4/modules/m4.h,v
retrieving revision 1.6
diff -u -p -r1.6 m4.h
--- modules/m4.h	1 May 2005 11:10:05 -0000	1.6
+++ modules/m4.h	21 Oct 2006 22:06:32 -0000
@@ -1,5 +1,5 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -39,8 +39,11 @@ typedef struct
 typedef void m4_sysval_flush_func (m4 *context);
 typedef void m4_set_sysval_func (int value);
 typedef void m4_dump_symbols_func (m4 *context, m4_dump_symbol_data *data,
-		int argc, m4_symbol_value **argv, bool complain);
-typedef const char *m4_expand_ranges_func  (const char *s, m4_obstack *obs);
+				   int argc, m4_symbol_value **argv,
+				   bool complain);
+typedef const char *m4_expand_ranges_func (const char *s, m4_obstack *obs);
+typedef void m4_make_temp_func (m4 *context, m4_obstack *obs,
+				const char *macro, const char *name, bool dir);
 
 END_C_DECLS
 
Index: tests/builtins.at
===================================================================
RCS file: /sources/m4/m4/tests/builtins.at,v
retrieving revision 1.25
diff -u -p -r1.25 builtins.at
--- tests/builtins.at	19 Oct 2006 23:13:45 -0000	1.25
+++ tests/builtins.at	21 Oct 2006 22:06:32 -0000
@@ -495,6 +495,32 @@ AT_CHECK_M4([indir.m4], 0, expout)
 AT_CLEANUP
 
 
+## ------- ##
+## mkdtemp ##
+## ------- ##
+
+AT_SETUP([mkdtemp])
+
+dnl Check that on error, the expansion is void
+AT_DATA([[in]],
+[[mkdtemp(`no_such_dir/m4-fooXXXXXX')
+]])
+AT_CHECK_M4([in], [1], [[
+]], [[m4:in:1: mkdtemp: cannot create directory `no_such_dir/m4-fooXXXXXX': No such file or directory
+]])
+
+dnl Check that umask has an effect
+AT_DATA([[in]],
+[[substr(esyscmd(`ls -ld 'mkdtemp(`m4-fooXXXXXX')), `0', `10')
+]])
+AT_CHECK([m4 < in], [0], [[drwx------
+]])
+AT_CHECK([umask 700; m4 < in], [0], [[d---------
+]])
+
+AT_CLEANUP
+
+
 ## -------- ##
 ## maketemp ##
 ## -------- ##
@@ -506,7 +532,16 @@ AT_DATA([[in]],
 [[mkstemp(`no_such_dir/m4-fooXXXXXX')
 ]])
 AT_CHECK_M4([in], [1], [[
-]], [[m4:in:1: mkstemp: cannot create tempfile `no_such_dir/m4-fooXXXXXX': No such file or directory
+]], [[m4:in:1: mkstemp: cannot create file `no_such_dir/m4-fooXXXXXX': No such file or directory
+]])
+
+dnl Check that umask has an effect
+AT_DATA([[in]],
+[[substr(esyscmd(`ls -ld 'mkstemp(`m4-fooXXXXXX')), `0', `10')
+]])
+AT_CHECK([m4 < in], [0], [[-rw-------
+]])
+AT_CHECK([umask 700; m4 < in], [0], [[----------
 ]])
 
 dnl Check for Solaris compatibility of maketemp.  Hopefully the pid is
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.