]>
diplodocus.org Git - mdeliver/blob - mdeliver.c
a91ca99b00416ee9bba7c1b9ebd6e71f075024ce
1 /* mdeliver.c -- Deliver a message to a Maildir.
5 * This program is in the public domain.
22 #if !defined(HOST_NAME_MAX)
23 #if defined MAXHOSTNAMELEN
24 #define HOST_NAME_MAX MAXHOSTNAMELEN
26 #define HOST_NAME_MAX 64
30 /* holds 2^128 - 1 in decimal, plus '\0' */
33 /* 1 for '\0', 4 for "tmp/", HOST_NAME_MAX for the hostname, and two
34 * LEN_ULONGs for time and pid. */
35 #define TMPNAMLEN 1 + 4 + HOST_NAME_MAX + LEN_ULONG + LEN_ULONG
37 static char rcsid
[] = "$Id$";
39 /* Write all of buf, even if write(2) is interrupted. */
41 full_write(int fd
, const char *buf
, size_t nbytes
)
45 /* Loop until nbytes of buf have been written. */
47 /* Keep trying until write succeeds without interruption. */
49 r
= write(fd
, buf
+ w
, nbytes
- w
);
50 } while (r
< 0 && errno
== EINTR
);
63 deliver(char *maildir
, char *newfn
)
65 char fn
[TMPNAMLEN
], host
[HOST_NAME_MAX
+ 1];
66 char *buildfn
; /* used to build up the fn */
75 if (chdir(maildir
) != 0) {
76 err(EX_TEMPFAIL
, "Failed chdir(%s)", maildir
);
80 gethostname(host
, sizeof(host
));
82 for (try = 0; ; try++) {
86 buildfn
= fn
+ sprintf(fn
, "tmp/");
87 buildfn
+= strftime(buildfn
, LEN_ULONG
+ 1, "%s.", t
);
88 buildfn
+= snprintf(buildfn
, LEN_ULONG
+ 1, "%d.", pid
);
89 buildfn
+= sprintf(buildfn
, "%s", host
);
91 if (stat(fn
, &statbuf
) != 0) {
92 if (errno
== ENOENT
) {
98 errx(EX_TEMPFAIL
, "Attempted filename exists.");
104 fd
= open(fn
, O_WRONLY
| O_EXCL
| O_CREAT
, 0644);
106 err(EX_TEMPFAIL
, "Failed open(%s)", fn
);
109 /* From this point, we have a tmp file, so if someting fails we
110 * must try to unlink it before bombing. */
112 while ((r
= read(STDIN_FILENO
, buf
, BUFSIZ
)) > 0) {
113 if (full_write(fd
, buf
, r
) != r
) {
115 err(EX_TEMPFAIL
, "Failed write(%s)", fn
);
121 err(EX_TEMPFAIL
, "Failed fsync(%s)", fn
);
125 err(EX_TEMPFAIL
, "Failed close(%s)", fn
);
129 memcpy(newfn
, "new", 3);
131 if (rename(fn
, newfn
) != 0) {
133 err(EX_TEMPFAIL
, "Failed rename(%s, new)", fn
);
138 main(int argc
, char *argv
[])
140 char newfn
[TMPNAMLEN
];
146 if (argv
[1] && argv
[1][0] == '-' && argv
[1][1] == 'v') {
151 deliver("Maildir", newfn
);
154 if ((pid
= fork()) > 0) {
156 } else if (pid
== 0) {
159 execv(argv
[0], argv
);
165 /* If we got here fork or exec failed, so try to write an
166 * error message where later mail processors can find it. We
167 * really can't do anything about it if this fails. */
168 memcpy(newfn
, "err", 3);
169 fd
= open(newfn
, O_WRONLY
| O_EXCL
| O_CREAT
, 0644);
170 errfile
= fdopen(fd
, "w");
172 fprintf(errfile
, "%s:%d\n", fail
, errno
);
176 /* Always return 0 because deliver exits if it fails, and if it
177 * succeeds we cannot return a failure code to the MTA. */