int DotLock::attemptlock(const char *templock, const char *finallock) { Mio mio; Buffer b; static Buffer errbuf; if (mio.Open(templock, O_CREAT | O_WRONLY, 0644) < 0) { errbuf="Unable to create a dot-lock at "; errbuf += (const char *)templock; errbuf += ".\n"; errbuf += '\0'; throw (const char *)errbuf; } b.append( (unsigned long)getpid() ); b += '\n'; if (mio.write((const char *)b, b.Length()) < 0 || mio.flush() < 0) { mio.Close(); unlink(templock); throw "Unable to write to a dot-lock."; } mio.Close(); if (mio.errflag()) { unlink(templock); throw "Unable to close a dot-lock."; } try { struct stat buf; if (link(templock, finallock) < 0) ; /* ignored */ int rc=stat(templock, &buf); if (rc == 0 && buf.st_nlink == 2) { name(finallock); unlink(templock); return (0); } unlink(templock); } catch (...) { unlink(templock); throw; } return (-1); }
int delivery(const char *mailbox) { FormatMbox format_mbox; if (format_mbox.HasMsg()) return (0); DeliverDotLock dotlock; Buffer b; if ( *mailbox == '!' || *mailbox == '|' ) { Buffer cmdbuf; if (*mailbox == '!') { b="SENDMAIL"; const char *sendmail=GetVarStr(b); cmdbuf=sendmail; cmdbuf += " -f '' "; cmdbuf += mailbox+1; } else cmdbuf= mailbox+1; cmdbuf += '\0'; if (VerboseLevel() > 0) merr << "maildrop: Delivering to |" << (const char *)cmdbuf << "\n"; PipeFds pipe; if (pipe.Pipe()) throw "Cannot create pipe."; pid_t pid=fork(); if (pid < 0) throw "Cannot fork."; if (pid == 0) { pipe.close1(); dup2(pipe.fds[0], 0); pipe.close0(); try { subshell(cmdbuf); } catch (const char *p) { if (write(2, p, strlen(p)) < 0 || write(2, "\n", 1) < 0) ; /* ignored */ _exit(100); } #if NEED_NONCONST_EXCEPTIONS catch (char *p) { if (write(2, p, strlen(p)) < 0 || write(2, "\n", 1) < 0) ; /* ignored */ _exit(100); } #endif catch (...) { _exit(100); } } Mio pipemio; pipe.close0(); pipemio.fd(pipe.fds[1]); pipe.fds[1]= -1; format_mbox.Init(0); int rc=format_mbox.DeliverTo(pipemio); int wait_stat; while (wait(&wait_stat) != pid) ; if (wait_stat == 0) rc=0; log(mailbox, rc || wait_stat, format_mbox); { Buffer name, val; if (rc) wait_stat= -1; else wait_stat= WIFEXITED(wait_stat) ? WEXITSTATUS(wait_stat):-1; val.append( (unsigned long)wait_stat); name="EXITCODE"; SetVar(name, val); } if (rc) return (-1); } else if (Maildir::IsMaildir(mailbox)) { Maildir deliver_maildir; Mio deliver_file; if ( deliver_maildir.MaildirOpen(mailbox, deliver_file, maildrop.msgptr->MessageSize()) < 0) { #if HAVE_COURIER throw 75; #else throw 77; #endif } format_mbox.Init(0); if (format_mbox.DeliverTo(deliver_file)) { log(mailbox, -1, format_mbox); return (-1); } deliver_maildir.MaildirSave(); log(mailbox, 0, format_mbox); } else // Delivering to a mailbox (hopefully) { if (VerboseLevel() > 0) merr << "maildrop: Delivering to " << mailbox << "\n"; #if USE_DOTLOCK dotlock.LockMailbox(mailbox); #endif struct stat stat_buf; Mio mio; Buffer name_buf; name_buf="UMASK"; const char *um=GetVarStr(name_buf); unsigned int umask_val=077; sscanf(um, "%o", &umask_val); umask_val=umask(umask_val); if (mio.Open(mailbox, O_CREAT | O_WRONLY, 0666) < 0) { umask_val=umask(umask_val); throw "Unable to open mailbox."; } umask_val=umask(umask_val); if (fstat(mio.fd(), &stat_buf) < 0) throw "Unable to open mailbox."; #if USE_FLOCK if (VerboseLevel() > 4) merr << "maildrop: Flock()ing " << mailbox << ".\n"; FileLock::do_filelock(mio.fd()); #endif if (S_ISREG(stat_buf.st_mode)) { if (mio.seek(0L, SEEK_END) < 0) throw "Seek error on mailbox."; dotlock.trap_truncate(mio.fd(), stat_buf.st_size); } if (VerboseLevel() > 4) merr << "maildrop: Appending to " << mailbox << ".\n"; try { format_mbox.Init(1); if ((stat_buf.st_size > 0 && mio.write( #if CRLF_TERM "\r\n", 2 #else "\n", 1 #endif ) < 0) || format_mbox.DeliverTo(mio)) { dotlock.truncate(); log(mailbox, -1, format_mbox); return (-1); } } catch (...) { dotlock.truncate(); log(mailbox, -1, format_mbox); throw; } log(mailbox, 0, format_mbox); } if (VerboseLevel() > 4) merr << "maildrop: Delivery complete.\n"; return (0); }