]> diplodocus.org Git - nmh/blob - uip/mkstemp.c
lock_file.c: close(2) file descriptor on failure, avoiding leak.
[nmh] / uip / mkstemp.c
1 /* mkstemp.c -- create a temporary file
2 *
3 * This code is Copyright (c) 2014 by the authors of nmh.
4 * See the COPYRIGHT file in the root directory of the nmh
5 * distribution for complete copyright information.
6 */
7
8 /* define NMH to 0 to remove dependencies on nmh. */
9 #ifndef NMH
10 # define NMH 1
11 #endif /* ! NMH */
12
13 #ifdef HAVE_CONFIG_H
14 # include <config.h>
15 #endif /* HAVE_CONFIG_H */
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <stdbool.h>
19 #include <string.h>
20 #include <stdio.h>
21
22 #if ! defined HAVE_MKSTEMPS
23 # define HAVE_MKSTEMPS 0
24 #endif /* ! HAVE_MKSTEMPS */
25
26 static char *build_template(const char *, const char *, const char *);
27 static void process_args(int, char **, const char **, const char **, const char **);
28
29 /*
30 * Use a template of the form:
31 * [directory/][prefix]XXXXXX[suffix]
32 * where some of those named components might be null. suffix is only
33 * supported if HAVE_MKSTEMPS.
34 */
35
36 int
37 main(int argc, char *argv[]) {
38 const char *directory = "", *prefix = "", *suffix = "";
39 size_t suffix_len;
40 int fd;
41 char *template;
42
43 process_args(argc, argv, &directory, &prefix, &suffix);
44 if ((template = build_template(directory, prefix, suffix)) == NULL) {
45 return 1;
46 }
47
48 if ((suffix_len = strlen(suffix)) > 0) {
49 # if HAVE_MKSTEMPS
50 if ((fd = mkstemps(template, suffix_len)) < 0) { perror("mkstemps"); }
51 # else /* ! HAVE_MKSTEMPS */
52 fd = 0;
53 # endif /* ! HAVE_MKSTEMPS */
54 } else {
55 if ((fd = mkstemp(template)) < 0) { perror("mkstemp"); }
56 }
57
58 if (fd >= 0) {
59 (void) puts(template);
60 (void) close(fd);
61 }
62
63 free(template);
64
65 return fd >= 0 ? 0 : 1;
66 }
67
68
69 static char *
70 build_template(const char *directory, const char *prefix, const char *suffix) {
71 const char pattern[] = "XXXXXX";
72 size_t len, directory_len, pathsep_len, prefix_len, suffix_len;
73 char *template;
74
75 directory_len = strlen(directory);
76 if (directory_len > 0) {
77 pathsep_len = 1;
78 if (directory[directory_len - 1] == '/') {
79 /* Will insert a '/' separately, so truncate the one provided
80 in the directory name. */
81 --directory_len;
82 }
83 } else {
84 pathsep_len = 0;
85 }
86 prefix_len = strlen(prefix);
87 suffix_len = strlen(suffix);
88 /* sizeof pattern includes its final NULL, so don't add another. */
89 len = directory_len + pathsep_len + prefix_len + sizeof pattern +
90 suffix_len;
91
92 if ((template = malloc(len))) {
93 char *tp = template;
94
95 (void) strncpy(tp, directory, directory_len);
96 tp += directory_len;
97
98 if (pathsep_len == 1) { *tp++ = '/'; }
99
100 (void) strncpy(tp, prefix, prefix_len);
101 tp += prefix_len;
102
103 (void) strncpy(tp, pattern, sizeof pattern - 1);
104 tp += sizeof pattern - 1;
105
106 (void) strncpy(tp, suffix, suffix_len);
107 /* tp += suffix_len; */
108
109 template[len-1] = '\0';
110
111 return template;
112 }
113
114 perror("malloc");
115 return NULL;
116 }
117
118
119 #if NMH
120 #include <h/mh.h>
121 #include <h/utils.h>
122
123 #if HAVE_MKSTEMPS
124 # define MHFIXMSG_SWITCHES \
125 X("directory", 0, DIRECTORYSW) \
126 X("prefix", 0, PREFIXSW) \
127 X("suffix", 0, SUFFIXSW) \
128 X("version", 0, VERSIONSW) \
129 X("help", 0, HELPSW)
130 #else /* ! HAVE_MKSTEMPS */
131 # define MHFIXMSG_SWITCHES \
132 X("directory", 0, DIRECTORYSW) \
133 X("prefix", 0, PREFIXSW) \
134 X("version", 0, VERSIONSW) \
135 X("help", 0, HELPSW)
136 #endif /* ! HAVE_MKSTEMPS */
137
138 #define X(sw, minchars, id) id,
139 DEFINE_SWITCH_ENUM(MHFIXMSG);
140 #undef X
141
142 #define X(sw, minchars, id) { sw, minchars, id },
143 DEFINE_SWITCH_ARRAY(MHFIXMSG, switches);
144 #undef X
145
146 static void
147 process_args(int argc, char **argv, const char **directory,
148 const char **prefix, const char **suffix) {
149 char **argp, **arguments, *cp, buf[100];
150 # if ! HAVE_MKSTEMPS
151 NMH_UNUSED(suffix);
152 # endif /* ! HAVE_MKSTEMPS */
153
154 if (nmh_init(argv[0], 2)) { done(1); }
155 arguments = getarguments (invo_name, argc, argv, 1);
156 argp = arguments;
157
158 /*
159 * Parse arguments
160 */
161 while ((cp = *argp++)) {
162 if (*cp == '-') {
163 switch (smatch(++cp, switches)) {
164 case AMBIGSW:
165 ambigsw(cp, switches);
166 done(1);
167 case UNKWNSW:
168 inform("-%s unknown", cp);
169 (void) snprintf(buf, sizeof buf, "%s [switches]", invo_name);
170 print_help(buf, switches, 1);
171 done(1);
172 case HELPSW:
173 (void) snprintf(buf, sizeof buf, "%s [switches]", invo_name);
174 print_help(buf, switches, 1);
175 done(OK);
176 case VERSIONSW:
177 print_version(invo_name);
178 done(OK);
179
180 case DIRECTORYSW:
181 /* Allow the directory to start with '-'. */
182 if ((cp = *argp++) == NULL) {
183 adios(NULL, "missing argument to %s", argp[-2]);
184 }
185 *directory = cp;
186 continue;
187
188 case PREFIXSW:
189 /* Allow the prefix to start with '-'. */
190 if ((cp = *argp++) == NULL) {
191 adios(NULL, "missing argument to %s", argp[-2]);
192 }
193 *prefix = cp;
194 continue;
195
196 # if HAVE_MKSTEMPS
197 case SUFFIXSW:
198 /* Allow the suffix to start with '-'. */
199 if ((cp = *argp++) == NULL) {
200 adios(NULL, "missing argument to %s", argp[-2]);
201 }
202 *suffix = cp;
203 continue;
204 # endif /* HAVE_MKSTEMPS */
205 }
206 }
207 }
208 }
209 #else /* ! NMH */
210 static void
211 process_args(int argc, char **argv, const char **directory,
212 const char **prefix, const char **suffix) {
213 # if HAVE_MKSTEMPS
214 const char usage[] =
215 "usage: %s [-h] [-d directory] [-p prefix] [-s suffix]\n";
216 const char optstring[] = "d:hp:s:";
217 # else /* ! HAVE_MKSTEMPS */
218 const char usage[] = "usage: %s [-h] [-d directory] [-p prefix]\n";
219 const char optstring[] = "d:hp:";
220 # endif /* ! HAVE_MKSTEMPS */
221 int opt;
222
223 while ((opt = getopt(argc, argv, optstring)) != -1) {
224 switch (opt) {
225 case 'd':
226 *directory = optarg;
227 break;
228 case 'p':
229 *prefix = optarg;
230 break;
231 case 's':
232 *suffix = optarg;
233 break;
234 case 'h':
235 (void) printf(usage, argv[0]);
236 exit(0);
237 default:
238 (void) fprintf(stderr, usage, argv[0]);
239 exit(1);
240 }
241 }
242 }
243 #endif /* ! NMH */