]> diplodocus.org Git - nmh/commitdiff
Added mkstemp(1), wrapper around mkstemp(3)/mkstemps(3), to
authorDavid Levine <levinedl@acm.org>
Mon, 3 Mar 2014 04:38:57 +0000 (22:38 -0600)
committerDavid Levine <levinedl@acm.org>
Mon, 3 Mar 2014 04:38:57 +0000 (22:38 -0600)
auxexec, for use by mhmail.

.gitignore
Makefile.am
man/mkstemp.man [new file with mode: 0644]
test/mkstemp/test-mkstemp [new file with mode: 0755]
uip/mhmail
uip/mkstemp.c [new file with mode: 0644]

index 743853bd5bf2af6b63d27bc9225d9260f30f0a44..b8e0d4685dc4bcfdd05b4e2fb958273a227d6995 100644 (file)
@@ -79,6 +79,7 @@ a.out.dSYM/
 /uip/mhshow
 /uip/mhstore
 /uip/mhtest
 /uip/mhshow
 /uip/mhstore
 /uip/mhtest
+/uip/mkstemp
 /uip/msgchk
 /uip/msh
 /uip/new
 /uip/msgchk
 /uip/msh
 /uip/new
index ef35190922e4df587c9282a4128b253828dede9b..587dfb84ddede043bef78b16e9e05664e1f53ca9 100644 (file)
@@ -76,8 +76,8 @@ TESTS = test/ali/test-ali test/anno/test-anno \
        test/mhshow/test-charset test/mhshow/test-textcharset \
        test/mhshow/test-cte-binary test/mhshow/test-qp \
        test/mhshow/test-subpart test/mhshow/test-msg-buffer-boundaries \
        test/mhshow/test-charset test/mhshow/test-textcharset \
        test/mhshow/test-cte-binary test/mhshow/test-qp \
        test/mhshow/test-subpart test/mhshow/test-msg-buffer-boundaries \
-       test/mhstore/test-mhstore test/new/test-basic \
-       test/pick/test-pick test/pick/test-stderr \
+       test/mhstore/test-mhstore test/mkstemp/test-mkstemp \
+       test/new/test-basic test/pick/test-pick test/pick/test-stderr \
        test/post/test-post-aliases test/post/test-post-basic \
        test/post/test-post-multiple test/post/test-post-bcc \
        test/post/test-post-dcc test/post/test-post-fcc \
        test/post/test-post-aliases test/post/test-post-basic \
        test/post/test-post-multiple test/post/test-post-bcc \
        test/post/test-post-dcc test/post/test-post-fcc \
@@ -150,9 +150,9 @@ bin_SCRIPTS = uip/mhmail etc/sendfiles
 ##
 ## This is all programs that get installed in the "lib" directory
 ##
 ##
 ## This is all programs that get installed in the "lib" directory
 ##
-auxexec_PROGRAMS = uip/ap uip/conflict uip/dp uip/fmtdump uip/mhl uip/post \
-                  uip/rcvdist uip/rcvpack uip/rcvstore uip/rcvtty uip/slocal \
-                  uip/viamail uip/mhtest
+auxexec_PROGRAMS = uip/ap uip/conflict uip/dp uip/fmtdump uip/mhl uip/mkstemp \
+                  uip/post uip/rcvdist uip/rcvpack uip/rcvstore uip/rcvtty \
+                  uip/slocal uip/viamail uip/mhtest
 
 auxexec_SCRIPTS = uip/spost
 
 
 auxexec_SCRIPTS = uip/spost
 
@@ -228,8 +228,8 @@ man_MANS = man/ali.1 man/anno.1 man/ap.8 man/burst.1 man/comp.1 \
           man/mh-format.5 man/mh-mail.5 man/mh-profile.5 man/mh_profile.5 \
           man/mh-sequence.5 man/mh-tailor.5 man/mhbuild.1 man/mhfixmsg.1 \
           man/mhl.1 man/mhlist.1 man/mhmail.1 man/mhn.1 man/mhparam.1 \
           man/mh-format.5 man/mh-mail.5 man/mh-profile.5 man/mh_profile.5 \
           man/mh-sequence.5 man/mh-tailor.5 man/mhbuild.1 man/mhfixmsg.1 \
           man/mhl.1 man/mhlist.1 man/mhmail.1 man/mhn.1 man/mhparam.1 \
-          man/mhpath.1 man/mhshow.1 man/mhstore.1 man/msgchk.1 man/msh.1 \
-          man/mts.conf.5 man/new.1 man/next.1 man/nmh.7 man/packf.1 \
+          man/mhpath.1 man/mhshow.1 man/mhstore.1 man/mkstemp.1 man/msgchk.1 \
+          man/msh.1 man/mts.conf.5 man/new.1 man/next.1 man/nmh.7 man/packf.1 \
           man/pick.1 man/post.8 man/prev.1 man/prompter.1 man/rcvdist.1 \
           man/rcvpack.1 man/rcvstore.1 man/rcvtty.1 man/refile.1 \
           man/repl.1 man/rmf.1 man/rmm.1 man/scan.1 man/send.1 \
           man/pick.1 man/post.8 man/prev.1 man/prompter.1 man/rcvdist.1 \
           man/rcvpack.1 man/rcvstore.1 man/rcvtty.1 man/refile.1 \
           man/repl.1 man/rmf.1 man/rmm.1 man/scan.1 man/send.1 \
@@ -249,8 +249,8 @@ man_SRCS = man/ali.man man/anno.man man/ap.man man/burst.man man/comp.man \
           man/mh_profile.man man/mh-sequence.man man/mh-tailor.man \
           man/mhbuild.man man/mhfixmsg.man man/mhl.man man/mhlist.man \
           man/mhmail.man man/mhn.man man/mhparam.man man/mhpath.man \
           man/mh_profile.man man/mh-sequence.man man/mh-tailor.man \
           man/mhbuild.man man/mhfixmsg.man man/mhl.man man/mhlist.man \
           man/mhmail.man man/mhn.man man/mhparam.man man/mhpath.man \
-          man/mhshow.man man/mhstore.man man/msgchk.man man/msh.man \
-          man/mts.conf.man man/new.man man/next.man man/nmh.man \
+          man/mhshow.man man/mhstore.man man/mkstemp.man man/msgchk.man \
+          man/msh.man man/mts.conf.man man/new.man man/next.man man/nmh.man \
           man/packf.man man/pick.man man/post.man man/prev.man \
           man/prompter.man man/rcvdist.man man/rcvpack.man \
           man/rcvstore.man man/rcvtty.man man/refile.man man/repl.man \
           man/packf.man man/pick.man man/post.man man/prev.man \
           man/prompter.man man/rcvdist.man man/rcvpack.man \
           man/rcvstore.man man/rcvtty.man man/refile.man man/repl.man \
@@ -432,6 +432,9 @@ uip_mhtest_SOURCES = uip/mhtest.c uip/mhparse.c uip/mhcachesbr.c \
                     uip/md5.c
 uip_mhtest_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
 
                     uip/md5.c
 uip_mhtest_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
 
+uip_mkstemp_SOURCES = uip/mkstemp.c
+uip_mkstemp_LDADD = $(LDADD) $(POSTLINK)
+
 uip_post_SOURCES = uip/post.c uip/aliasbr.c
 uip_post_LDADD = mts/libmts.a $(LDADD) $(SASLLIB) $(TLSLIB) $(POSTLINK)
 
 uip_post_SOURCES = uip/post.c uip/aliasbr.c
 uip_post_LDADD = mts/libmts.a $(LDADD) $(SASLLIB) $(TLSLIB) $(POSTLINK)
 
diff --git a/man/mkstemp.man b/man/mkstemp.man
new file mode 100644 (file)
index 0000000..1df5fd6
--- /dev/null
@@ -0,0 +1,81 @@
+.TH MKSTEMP %manext1% "March 2, 2014" "%nmhversion%"
+.\"
+.\" %nmhwarning%
+.\"
+.SH NAME
+mkstemp \- create a temporary file
+.SH SYNOPSIS
+.HP 5
+.na
+.B %libdir%/mkstemp
+.RB [ \-directory
+.IR directory ]
+.RB [ \-prefix
+.IR prefix ]
+.RB [ \-suffix
+.IR suffix ]
+.RB [ \-version ]
+.RB [ \-help ]
+.ad
+.SH DESCRIPTION
+.B mkstemp
+creates a temporary file using
+.IR mkstemp (3),
+or if the
+.B \-suffix
+switch is available and used,
+.IR mkstemps (3).
+The file name identifies a unique, newly created file, and always
+contains 6 characters that appear to be random.
+.PP
+The
+.B \-directory
+switch specifies a
+.I directory
+in which to create the file.
+.PP
+The
+.B \-prefix
+switch specifies an initial part, before the 6 characters, of the file
+name.
+.PP
+The
+.B \-suffix
+switch is only supported on platforms that provide the
+.IR mkstemps (3)
+library function.  It specifies a
+.I suffix
+to appear after the 6 characters; if it should begin with a special
+character such as a period, that must be explicit in
+.IR suffix .
+.PP
+Unlike arguments to most switches of other
+.B nmh
+commands, the arguments to
+.B mkstemp
+switches can begin with a dash.
+.SH "EXIT STATUS"
+If
+.B mkstemp
+successfully creates the temporary file, it prints the file name on
+standard output and exits with status 0.  On failure, it prints a
+diagnostic message on standard error and exits with status -1.
+.SH "PROFILE COMPONENTS"
+None
+.SH "SEE ALSO"
+.IR mkstemp (3),
+.IR mkstemps (3)
+.SH DEFAULTS
+.PD 0
+.TP 14
+\-directory
+current directory
+.TP
+\-prefix
+none
+.TP
+\-suffix
+none
+.PD
+.SH CONTEXT
+None
diff --git a/test/mkstemp/test-mkstemp b/test/mkstemp/test-mkstemp
new file mode 100755 (executable)
index 0000000..3894936
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+##################################
+#
+# Test creation of temporary file.
+#
+##################################
+
+set -e
+
+if test -z "${MH_OBJ_DIR}"; then
+    srcdir=`dirname "$0"`/../..
+    MH_OBJ_DIR=`cd "$srcdir" && pwd`; export MH_OBJ_DIR
+fi
+
+. "$MH_OBJ_DIR/test/common.sh"
+
+setup_test
+
+expected="$MH_TEST_DIR"/$$.expected
+actual="$MH_TEST_DIR"/$$.actual
+
+mkstemp="${MH_LIB_DIR}/mkstemp"
+
+cd "$MHTMPDIR"
+
+
+# check -help
+cat >$expected <<'EOF'
+Usage: mkstemp [switches]
+  switches are:
+  -directory
+  -prefix
+  -suffix
+  -version
+  -help
+EOF
+
+$mkstemp -h >$actual 2>&1
+check $expected $actual
+
+
+# check -version
+# Verified same behavior as compiled mhmail.
+case `$mkstemp -v` in
+  mkstemp\ --*) ;;
+  *          ) printf '%s: mkstemp -v generated unexpected output\n' "$0" >&2
+               failed=`expr ${failed:-0} + 1`;;
+esac
+
+
+# check with no switches
+tmpfile=`$mkstemp`
+if [ -f "$tmpfile" ]; then
+    rm "$tmpfile"
+else
+    failed=1
+fi
+
+
+# check -directory
+tmpfile=`$mkstemp -directory "$MHTMPDIR"`
+[ -f "$tmpfile" ]  &&  rm "$tmpfile"  ||  failed=`expr ${failed:-0} + 1`
+check_tmpfile=`echo $tmpfile | grep "^$MHTMPDIR/......$" >/dev/null`
+run_test `echo $check_tmpfile` ''
+
+
+# check -prefix
+tmpfile=`$mkstemp -prefix mkstemptest`
+[ -f "$tmpfile" ]  &&  rm "$tmpfile"  ||  failed=`expr ${failed:-0} + 1`
+check_tmpfile=`echo $tmpfile | grep '^mkstemptest......$' >/dev/null`
+run_test `echo $check_tmpfile` ''
+
+
+# check -suffix
+tmpfile=`$mkstemp -suffix .txt`
+[ -f "$tmpfile" ]  &&  rm "$tmpfile"  ||  failed=`expr ${failed:-0} + 1`
+check_tmpfile=`echo $tmpfile | grep '^......\.txt$' >/dev/null`
+run_test `echo $check_tmpfile` ''
+
+
+exit $failed
index ffc51298d2c619120eb2048a331f89be9b8ddeb0..b9dc0ddd2eb32c8e2ed6c096a84b9e81f7d9f66e 100755 (executable)
@@ -215,9 +215,11 @@ fi
 #### .orig file, so it will remove them, too.
 umask 077
 tmpdir="${MHTMPDIR:-${TMPDIR:-`$nmhbindir/mhpath +`}}"
 #### .orig file, so it will remove them, too.
 umask 077
 tmpdir="${MHTMPDIR:-${TMPDIR:-`$nmhbindir/mhpath +`}}"
-tmpfile="$tmpdir/mhmail$$"
+tmpfilename=`cd "$tmpdir"  &&  "${nmhlibdir}/mkstemp" -p mhmail`
+[ $? -ne 0 ]  &&  die "mhmail: failed to create temporary file in $tmpdir"
+tmpfile="$tmpdir/$tmpfilename"
 backup_char=`"$nmhbindir"/mhparam sbackup`
 backup_char=`"$nmhbindir"/mhparam sbackup`
-tmpfilebackup="'$tmpdir'/${backup_char}mhmail$$*"
+tmpfilebackup="$tmpdir/${backup_char}${tmpfilename}*"
 tmpfileresent=
 
 message_file=
 tmpfileresent=
 
 message_file=
@@ -234,7 +236,8 @@ else
     #### When resending with send, tmpfile will just contain the
     #### Resent- header fields.  "$tmpfileresent" will contain
     #### the message that is being resent.
     #### When resending with send, tmpfile will just contain the
     #### Resent- header fields.  "$tmpfileresent" will contain
     #### the message that is being resent.
-    tmpfileresent="$tmpdir/mhmail-resent$$"
+    tmpfileresent=`"${nmhlibdir}/mkstemp" -d "$tmpdir" -p mhmail-resent`
+    [ $? -ne 0 ]  &&  die "mhmail: failed to create temporary file in $tmpdir"
     mhdist=1; export mhdist
     mhaltmsg=$tmpfileresent; export mhaltmsg
     message_file="$tmpfileresent"
     mhdist=1; export mhdist
     mhaltmsg=$tmpfileresent; export mhaltmsg
     message_file="$tmpfileresent"
diff --git a/uip/mkstemp.c b/uip/mkstemp.c
new file mode 100644 (file)
index 0000000..16ddf64
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * mkstemp.c -- create a temporary file
+ *
+ * This code is Copyright (c) 2014 by the authors of nmh.
+ * See the COPYRIGHT file in the root directory of the nmh
+ * distribution for complete copyright information.
+ */
+
+/* define NMH to 0 to remove dependencies on nmh. */
+#ifndef NMH
+#   define NMH 1
+#endif /* ! NMH */
+
+#ifdef HAVE_CONFIG_H
+#   include <config.h>
+#endif /* HAVE_CONFIG_H */
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#if ! defined HAVE_MKSTEMPS
+#   define HAVE_MKSTEMPS 0
+#endif /* ! HAVE_MKSTEMPS */
+
+char *build_template(const char *, const char *, const char *);
+void process_args(int, char **, const char **, const char **, const char **);
+
+/*
+ * Use a template of the form:
+ *     [directory/][prefix]XXXXXX[suffix]
+ * where some of those named components might be null.  suffix is only
+ * supported if HAVE_MKSTEMPS.
+ */
+
+int
+main(int argc, char *argv[]) {
+    const char *directory = "", *prefix = "", *suffix = "";
+    size_t suffix_len;
+    int fd;
+    char *template;
+
+    process_args(argc, argv, &directory, &prefix, &suffix);
+    if ((template = build_template(directory, prefix, suffix)) == NULL) {
+        return -1;
+    }
+
+    if ((suffix_len = strlen(suffix)) > 0) {
+#       if HAVE_MKSTEMPS
+        if ((fd = mkstemps(template, suffix_len)) < 0) { perror("mkstemps"); }
+#       endif /* HAVE_MKSTEMPS */
+    } else {
+        if ((fd = mkstemp(template)) < 0) { perror("mkstemp"); }
+    }
+
+    if (fd >= 0) {
+        (void) puts(template);
+        (void) close(fd);
+    }
+
+    free(template);
+
+    return fd >= 0  ?  0  :  -1;
+}
+
+
+char *
+build_template(const char *directory, const char *prefix, const char *suffix) {
+    const char pattern[] = "XXXXXX";
+    size_t len, directory_len, pathsep_len, prefix_len, suffix_len;
+    char *template;
+
+    directory_len = strlen(directory);
+    if (directory_len > 0) {
+        pathsep_len = 1;
+        if (directory[directory_len - 1] == '/') {
+            /* Will insert a '/' separately, so truncate the one provided
+               in the directory name. */
+            --directory_len;
+        }
+    } else {
+        pathsep_len = 0;
+    }
+    prefix_len = strlen(prefix);
+    suffix_len = strlen(suffix);
+    /* sizeof pattern includes its final NULL, so don't add another. */
+    len = directory_len  +  pathsep_len  +  prefix_len  +   sizeof pattern  +
+        suffix_len;
+
+    if ((template = malloc(len))) {
+        char *tp = template;
+
+        (void) strncpy(tp, directory, directory_len);
+        tp += directory_len;
+
+        if (pathsep_len == 1) { *tp++ = '/'; }
+
+        (void) strncpy(tp, prefix, prefix_len);
+        tp += prefix_len;
+
+        (void) strncpy(tp, pattern, sizeof pattern - 1);
+        tp += sizeof pattern - 1;
+
+        (void) strncpy(tp, suffix, suffix_len);
+        tp += suffix_len;
+
+        template[len-1] = '\0';
+
+        return template;
+    } else {
+        perror("malloc");
+        return NULL;
+    }
+}
+
+
+#if NMH
+#include <h/mh.h>
+
+#if HAVE_MKSTEMPS
+#   define MHFIXMSG_SWITCHES \
+    X("directory", 0, DIRECTORYSW) \
+    X("prefix", 0, PREFIXSW) \
+    X("suffix", 0, SUFFIXSW) \
+    X("version", 0, VERSIONSW) \
+    X("help", 0, HELPSW)
+#else  /* ! HAVE_MKSTEMPS */
+#   define MHFIXMSG_SWITCHES \
+    X("directory", 0, DIRECTORYSW) \
+    X("prefix", 0, PREFIXSW) \
+    X("version", 0, VERSIONSW) \
+    X("help", 0, HELPSW)
+#endif /* ! HAVE_MKSTEMPS */
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(MHFIXMSG);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(MHFIXMSG, switches);
+#undef X
+
+void
+process_args(int argc, char **argv, const char **directory,
+             const char **prefix, const char **suffix) {
+    char **argp, **arguments, *cp, buf[100];
+#   if ! HAVE_MKSTEMPS
+    NMH_UNUSED(suffix);
+#   endif /* ! HAVE_MKSTEMPS */
+
+    if (nmh_init(argv[0], 1)) { done(NOTOK); }
+    arguments = getarguments (invo_name, argc, argv, 1);
+    argp = arguments;
+
+    /*
+     * Parse arguments
+     */
+    while ((cp = *argp++)) {
+        if (*cp == '-') {
+            switch (smatch(++cp, switches)) {
+            case AMBIGSW:
+                ambigsw(cp, switches);
+                done(NOTOK);
+            case UNKWNSW:
+                advise (NULL, "-%s unknown", cp);
+                (void) snprintf(buf, sizeof buf, "%s [switches]", invo_name);
+                print_help(buf, switches, 1);
+                done(NOTOK);
+            case HELPSW:
+                (void) snprintf(buf, sizeof buf, "%s [switches]", invo_name);
+                print_help(buf, switches, 1);
+                done(OK);
+            case VERSIONSW:
+                print_version(invo_name);
+                done(OK);
+
+            case DIRECTORYSW:
+                /* Allow the directory to start with '-'. */
+                if ((cp = *argp++) == NULL) {
+                    adios(NULL, "missing argument to %s", argp[-2]);
+                }
+                *directory = cp;
+                continue;
+
+            case PREFIXSW:
+                /* Allow the prefix to start with '-'. */
+                if ((cp = *argp++) == NULL) {
+                    adios(NULL, "missing argument to %s", argp[-2]);
+                }
+                *prefix = cp;
+                continue;
+
+#           if HAVE_MKSTEMPS
+            case SUFFIXSW:
+                /* Allow the suffix to start with '-'. */
+                if ((cp = *argp++) == NULL) {
+                    adios(NULL, "missing argument to %s", argp[-2]);
+                }
+                *suffix = cp;
+                continue;
+#           endif /* HAVE_MKSTEMPS */
+            }
+        }
+    }
+}
+#else  /* ! NMH */
+void
+process_args(int argc, char **argv, const char **directory,
+             const char **prefix, const char **suffix) {
+#   if HAVE_MKSTEMPS
+    const char usage[] =
+        "usage: %s [-h] [-d directory] [-p prefix] [-s suffix]\n";
+    const char optstring[] = "d:hp:s:";
+#   else  /* ! HAVE_MKSTEMPS */
+    const char usage[] = "usage: %s [-h] [-d directory] [-p prefix]\n";
+    const char optstring[] = "d:hp:";
+#   endif /* ! HAVE_MKSTEMPS */
+    int opt;
+
+    while ((opt = getopt(argc, argv, optstring)) != -1) {
+        switch (opt) {
+        case 'd':
+            *directory = optarg;
+            break;
+        case 'p':
+            *prefix = optarg;
+            break;
+        case 's':
+            *suffix = optarg;
+            break;
+        case 'h':
+            (void) printf(usage, argv[0]);
+            exit(0);
+        default:
+            (void) fprintf(stderr, usage, argv[0]);
+            exit(-1);
+        }
+    }
+}
+#endif /* ! NMH */