void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream) { QMGR_QUEUE *queue; QMGR_ENTRY *entry; /* * Find out if this delivery process is really available. Once elected, * the delivery process is supposed to express its happiness. If there is * a problem, wipe the pending deliveries for this transport. This * routine runs in response to an external event, so it does not run * while some other queue manipulation is happening. */ if (qmgr_deliver_initial_reply(stream) != 0) { qmgr_transport_throttle(transport, "mail transport unavailable"); qmgr_defer_transport(transport, transport->reason); (void) vstream_fclose(stream); return; } /* * Find a suitable queue entry. Things may have changed since this * transport was allocated. If no suitable entry is found, * unceremoniously disconnect from the delivery process. The delivery * agent request reading routine is prepared for the queue manager to * change its mind for no apparent reason. */ if ((queue = qmgr_queue_select(transport)) == 0 || (entry = qmgr_entry_select(queue)) == 0) { (void) vstream_fclose(stream); return; } /* * Send the queue file info and recipient info to the delivery process. * If there is a problem, wipe the pending deliveries for this transport. * This routine runs in response to an external event, so it does not run * while some other queue manipulation is happening. */ if (qmgr_deliver_send_request(entry, stream) < 0) { qmgr_entry_unselect(queue, entry); qmgr_transport_throttle(transport, "mail transport unavailable"); qmgr_defer_transport(transport, transport->reason); /* warning: entry and queue may be dangling pointers here */ (void) vstream_fclose(stream); return; } /* * If we get this far, go wait for the delivery status report. */ qmgr_deliver_concurrency++; entry->stream = stream; event_enable_read(vstream_fileno(stream), qmgr_deliver_update, (char *) entry); /* * Guard against broken systems. */ event_request_timer(qmgr_deliver_abort, (char *) entry, var_daemon_timeout); }
static int deliver_message(DELIVER_REQUEST *request) { const char *myname = "deliver_message"; VSTREAM *src; int result = 0; int status; RECIPIENT *rcpt; int nrcpt; DSN_SPLIT dp; DSN dsn; if (msg_verbose) msg_info("deliver_message: from %s", request->sender); /* * Sanity checks. */ if (request->nexthop[0] == 0) msg_fatal("empty nexthop hostname"); if (request->rcpt_list.len <= 0) msg_fatal("recipient count: %d", request->rcpt_list.len); /* * Open the queue file. Opening the file can fail for a variety of * reasons, such as the system running out of resources. Instead of * throwing away mail, we're raising a fatal error which forces the mail * system to back off, and retry later. */ src = mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0); if (src == 0) msg_fatal("%s: open %s %s: %m", myname, request->queue_name, request->queue_id); if (msg_verbose) msg_info("%s: file %s", myname, VSTREAM_PATH(src)); /* * Discard all recipients. */ #define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS(request->flags) dsn_split(&dp, "2.0.0", request->nexthop); (void) DSN_SIMPLE(&dsn, DSN_STATUS(dp.dsn), dp.text); for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) { rcpt = request->rcpt_list.info + nrcpt; status = sent(BOUNCE_FLAGS(request), request->queue_id, &request->msg_stats, rcpt, "none", &dsn); if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(src, rcpt->offset); result |= status; } /* * Clean up. */ if (vstream_fclose(src)) msg_warn("close %s %s: %m", request->queue_name, request->queue_id); return (result); }
static int deliver_message(DELIVER_REQUEST *request) { char *myname = "deliver_message"; VSTREAM *src; int result = 0; int status; RECIPIENT *rcpt; int nrcpt; if (msg_verbose) msg_info("deliver_message: from %s", request->sender); /* * Sanity checks. */ if (request->nexthop[0] == 0) msg_fatal("empty nexthop hostname"); if (request->rcpt_list.len <= 0) msg_fatal("recipient count: %d", request->rcpt_list.len); /* * Open the queue file. Opening the file can fail for a variety of * reasons, such as the system running out of resources. Instead of * throwing away mail, we're raising a fatal error which forces the mail * system to back off, and retry later. */ src = mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0); if (src == 0) msg_fatal("%s: open %s %s: %m", myname, request->queue_name, request->queue_id); if (msg_verbose) msg_info("%s: file %s", myname, VSTREAM_PATH(src)); /* * Bounce all recipients. */ #define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS(request->flags) for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) { rcpt = request->rcpt_list.info + nrcpt; if (rcpt->offset >= 0) { status = bounce_append(BOUNCE_FLAGS(request), request->queue_id, rcpt->orig_addr, rcpt->address, rcpt->offset, "none", request->arrival_time, "%s", request->nexthop); if (status == 0) deliver_completed(src, rcpt->offset); result |= status; } } /* * Clean up. */ if (vstream_fclose(src)) msg_warn("close %s %s: %m", request->queue_name, request->queue_id); return (result); }
static void close_session(SESSION *session) { event_disable_readwrite(vstream_fileno(session->stream)); vstream_fclose(session->stream); session->stream = 0; start_another(session); }
void load_file(const char *path, LOAD_FILE_FN action, void *context) { VSTREAM *fp; struct stat st; time_t before; time_t after; /* * Read the file again if it is hot. This may result in reading a partial * parameter name or missing end marker when a file changes in the middle * of a read. */ for (before = time((time_t *) 0); /* see below */ ; before = after) { if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) msg_fatal("open %s: %m", path); action(fp, context); if (fstat(vstream_fileno(fp), &st) < 0) msg_fatal("fstat %s: %m", path); if (vstream_ferror(fp) || vstream_fclose(fp)) msg_fatal("read %s: %m", path); after = time((time_t *) 0); if (st.st_mtime < before - 1 || st.st_mtime > after) break; if (msg_verbose) msg_info("pausing to let %s cool down", path); doze(300000); } }
int edit_file_close(EDIT_FILE *ep) { VSTREAM *fp = ep->tmp_fp; int fd = vstream_fileno(fp); int saved_errno; /* * The rename/unlock portion of the protocol is relatively simple. The * only things that really matter here are that we change permissions as * late as possible, and that we rename the file to its final pathname * before we lose the exclusive lock. * * Applications that are concerned about maximal safety should protect the * edit_file_close() call with sigdelay() and sigresume() calls. It is * not safe for us to call these functions directly, because the calls do * not nest. It is also not nice to force every caller to run with * interrupts turned off. */ if (vstream_fflush(fp) < 0 || fchmod(fd, ep->final_mode) < 0 #ifdef HAS_FSYNC || fsync(fd) < 0 #endif || rename(ep->tmp_path, ep->final_path) < 0) { saved_errno = errno; edit_file_cleanup(ep); errno = saved_errno; return (VSTREAM_EOF); } else { (void) vstream_fclose(ep->tmp_fp); EDIT_FILE_FREE(ep); return (0); } }
int dict_load_file_xt(const char *dict_name, const char *path) { VSTREAM *fp; struct stat st; time_t before; time_t after; /* * Read the file again if it is hot. This may result in reading a partial * parameter name when a file changes in the middle of a read. */ for (before = time((time_t *) 0); /* see below */ ; before = after) { if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) return (0); dict_load_fp(dict_name, fp); if (fstat(vstream_fileno(fp), &st) < 0) msg_fatal("fstat %s: %m", path); if (vstream_ferror(fp) || vstream_fclose(fp)) msg_fatal("read %s: %m", path); after = time((time_t *) 0); if (st.st_mtime < before - 1 || st.st_mtime > after) break; if (msg_verbose > 1) msg_info("pausing to let %s cool down", path); doze(300000); } return (1); }
void smtpd_proxy_free(SMTPD_STATE *state) { SMTPD_PROXY *proxy = state->proxy; /* * Clean up. */ if (proxy->service_stream != 0) (void) smtpd_proxy_close(state); if (proxy->request != 0) vstring_free(proxy->request); if (proxy->reply != 0) vstring_free(proxy->reply); myfree((char *) proxy); state->proxy = 0; /* * Reuse the replay logfile if possible. For security reasons we must * truncate the replay logfile before reuse. For performance reasons we * should truncate the replay logfile immediately after the end of a mail * transaction. We truncate the file here, and enforce the security * guarantee by requiring that no I/O happens before the file is reused. */ if (smtpd_proxy_replay_stream == 0) return; if (vstream_ferror(smtpd_proxy_replay_stream)) { /* Errors are already reported. */ (void) vstream_fclose(smtpd_proxy_replay_stream); smtpd_proxy_replay_stream = 0; return; } /* Flush output from aborted transaction before truncating the file!! */ if (vstream_fseek(smtpd_proxy_replay_stream, (off_t) 0, SEEK_SET) < 0) { msg_warn("seek before-queue filter speed-adjust log: %m"); (void) vstream_fclose(smtpd_proxy_replay_stream); smtpd_proxy_replay_stream = 0; return; } if (ftruncate(vstream_fileno(smtpd_proxy_replay_stream), (off_t) 0) < 0) { msg_warn("truncate before-queue filter speed-adjust log: %m"); (void) vstream_fclose(smtpd_proxy_replay_stream); smtpd_proxy_replay_stream = 0; return; } }
void pcf_read_master(int fail_on_open_error) { const char *myname = "pcf_read_master"; char *path; VSTRING *buf; VSTREAM *fp; const char *err; int entry_count = 0; int line_count; int last_line = 0; /* * Sanity check. */ if (pcf_master_table != 0) msg_panic("%s: master table is already initialized", myname); /* * Get the location of master.cf. */ if (var_config_dir == 0) pcf_set_config_dir(); path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0); /* * Initialize the in-memory master table. */ pcf_master_table = (PCF_MASTER_ENT *) mymalloc(sizeof(*pcf_master_table)); /* * Skip blank lines and comment lines. Degrade gracefully if master.cf is * not available, and master.cf is not the primary target. */ if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) { if (fail_on_open_error) msg_fatal("open %s: %m", path); msg_warn("open %s: %m", path); } else { buf = vstring_alloc(100); while (readllines(buf, fp, &last_line, &line_count) != 0) { pcf_master_table = (PCF_MASTER_ENT *) myrealloc((void *) pcf_master_table, (entry_count + 2) * sizeof(*pcf_master_table)); if ((err = pcf_parse_master_entry(pcf_master_table + entry_count, STR(buf))) != 0) msg_fatal("file %s: line %d: %s", path, line_count, err); entry_count += 1; } vstream_fclose(fp); vstring_free(buf); } /* * Null-terminate the master table and clean up. */ pcf_master_table[entry_count].argv = 0; myfree(path); }
static void quit_done(int unused_event, char *context) { SESSION *session = (SESSION *) context; (void) response(session->stream, buffer); event_disable_readwrite(vstream_fileno(session->stream)); vstream_fclose(session->stream); session->stream = 0; start_another(session); }
DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags) { DICT_CIDR *dict_cidr; VSTREAM *map_fp; VSTRING *line_buffer = vstring_alloc(100); VSTRING *why = vstring_alloc(100); DICT_CIDR_ENTRY *rule; DICT_CIDR_ENTRY *last_rule = 0; int lineno = 0; /* * Sanity checks. */ if (open_flags != O_RDONLY) msg_fatal("%s:%s map requires O_RDONLY access mode", DICT_TYPE_CIDR, mapname); /* * XXX Eliminate unnecessary queries by setting a flag that says "this * map matches network addresses only". */ dict_cidr = (DICT_CIDR *) dict_alloc(DICT_TYPE_CIDR, mapname, sizeof(*dict_cidr)); dict_cidr->dict.lookup = dict_cidr_lookup; dict_cidr->dict.close = dict_cidr_close; dict_cidr->dict.flags = dict_flags | DICT_FLAG_PATTERN; dict_cidr->head = 0; if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0) msg_fatal("open %s: %m", mapname); while (readlline(line_buffer, map_fp, &lineno)) { rule = dict_cidr_parse_rule(vstring_str(line_buffer), why); if (rule == 0) { msg_warn("cidr map %s, line %d: %s: skipping this rule", mapname, lineno, vstring_str(why)); continue; } if (last_rule == 0) dict_cidr->head = rule; else last_rule->cidr_info.next = &(rule->cidr_info); last_rule = rule; } /* * Clean up. */ if (vstream_fclose(map_fp)) msg_fatal("cidr map %s: read error: %m", mapname); vstring_free(line_buffer); vstring_free(why); return (DICT_DEBUG (&dict_cidr->dict)); }
void edit_file_cleanup(EDIT_FILE *ep) { /* * Don't touch the file after we lose the exclusive lock! */ if (unlink(ep->tmp_path) < 0 && errno != ENOENT) msg_fatal("unlink %s: %m", ep->tmp_path); (void) vstream_fclose(ep->tmp_fp); EDIT_FILE_FREE(ep); }
static void xsasl_dovecot_server_disconnect(XSASL_DOVECOT_SERVER_IMPL *xp) { if (xp->sasl_stream) { (void) vstream_fclose(xp->sasl_stream); xp->sasl_stream = 0; } if (xp->mechanism_list) { xsasl_dovecot_server_mech_free(xp->mechanism_list); xp->mechanism_list = 0; } }
static void dict_tcp_close(DICT *dict) { DICT_TCP *dict_tcp = (DICT_TCP *) dict; if (dict_tcp->fp) (void) vstream_fclose(dict_tcp->fp); if (dict_tcp->raw_buf) vstring_free(dict_tcp->raw_buf); if (dict_tcp->hex_buf) vstring_free(dict_tcp->hex_buf); dict_free(dict); }
main(void) { VSTRING *vp = vstring_alloc(1); VSTREAM *fp; if ((fp = vstream_fopen(TEXT_VSTREAM, O_RDONLY, 0)) == 0) msg_fatal("open %s: %m", TEXT_VSTREAM); while (vstring_fgets(vp, fp)) vstream_fprintf(VSTREAM_OUT, "%s", vstring_str(vp)); vstream_fclose(fp); vstream_fflush(VSTREAM_OUT); vstring_free(vp); }
void event_server_disconnect(VSTREAM *stream) { if (msg_verbose) msg_info("connection closed fd %d", vstream_fileno(stream)); if (event_server_pre_disconn) event_server_pre_disconn(stream, event_server_name, event_server_argv); (void) vstream_fclose(stream); client_count--; /* Avoid integer wrap-around in a persistent process. */ if (use_count < INT_MAX) use_count++; if (client_count == 0 && var_idle_limit > 0) event_request_timer(event_server_timeout, (char *) 0, var_idle_limit); }
void end_master_ent() { const char *myname = "end_master_ent"; if (master_fp == 0) msg_panic("%s: configuration file not open", myname); if (vstream_fclose(master_fp) != 0) msg_fatal("%s: close configuration file: %m", myname); master_fp = 0; if (master_disable == 0) msg_panic("%s: no service disable list", myname); match_service_free(master_disable); master_disable = 0; }
static void fail_connect(SESSION *session) { if (session->connect_count-- == 1) msg_fatal("connect: %m"); msg_warn("connect: %m"); event_disable_readwrite(vstream_fileno(session->stream)); vstream_fclose(session->stream); session->stream = 0; #ifdef MISSING_USLEEP doze(10); #else usleep(10); #endif start_connect(session); }
static int flush_add_path(const char *path, const char *queue_id) { const char *myname = "flush_add_path"; VSTREAM *log; /* * Sanity check. */ if (!mail_queue_id_ok(path)) return (FLUSH_STAT_BAD); /* * Open the logfile or bust. */ if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path, O_CREAT | O_APPEND | O_WRONLY, 0600)) == 0) msg_fatal("%s: open fast flush logfile %s: %m", myname, path); /* * We must lock the logfile, so that we don't lose information due to * concurrent access. If the lock takes too long, the Postfix watchdog * will eventually take care of the problem, but it will take a while. */ if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) msg_fatal("%s: lock fast flush logfile %s: %m", myname, path); /* * Append the queue ID. With 15 bits of microsecond time, a queue ID is * not recycled often enough for false hits to be a problem. If it does, * then we could add other signature information, such as the file size * in bytes. */ vstream_fprintf(log, "%s\n", queue_id); if (vstream_fflush(log)) msg_warn("write fast flush logfile %s: %m", path); /* * Clean up. */ if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("%s: unlock fast flush logfile %s: %m", myname, path); if (vstream_fclose(log) != 0) msg_warn("write fast flush logfile %s: %m", path); return (FLUSH_STAT_OK); }
static VSTREAM *safe_open_create(const char *path, int flags, int mode, struct stat * st, uid_t user, uid_t group, VSTRING *why) { VSTREAM *fp; /* * Create a non-existing file. This relies on O_CREAT | O_EXCL to not * follow symbolic links. */ if ((fp = vstream_fopen(path, flags | (O_CREAT | O_EXCL), mode)) == 0) { vstring_sprintf(why, "cannot create file exclusively: %m"); return (0); } /* * Optionally change ownership after creating a new file. If there is a * problem we should not attempt to delete the file. Something else may * have opened the file in the mean time. */ #define CHANGE_OWNER(user, group) (user != (uid_t) -1 || group != (gid_t) -1) if (CHANGE_OWNER(user, group) && fchown(vstream_fileno(fp), user, group) < 0) { msg_warn("%s: cannot change file ownership: %m", path); } /* * Optionally look up the file attributes. */ if (st != 0 && fstat(vstream_fileno(fp), st) < 0) msg_fatal("%s: bad open file status: %m", path); /* * We are almost there... */ else { return (fp); } /* * End up here in case of trouble. */ vstream_fclose(fp); return (0); }
int forward_finish(DELIVER_REQUEST *request, DELIVER_ATTR attr, int cancel) { HTABLE_INFO **dt_list; HTABLE_INFO **dt; HTABLE_INFO **sn_list; HTABLE_INFO **sn; HTABLE *table_snd; char *delivered; char *sender; FORWARD_INFO *info; int status = cancel; /* * Sanity checks. */ if (forward_dt == 0) msg_panic("forward_finish: missing forward_init call"); /* * Walk over all delivered-to header addresses and over each envelope * sender address. */ for (dt = dt_list = htable_list(forward_dt); *dt; dt++) { delivered = dt[0]->key; table_snd = (HTABLE *) dt[0]->value; for (sn = sn_list = htable_list(table_snd); *sn; sn++) { sender = sn[0]->key; info = (FORWARD_INFO *) sn[0]->value; if (status == 0) status |= forward_send(info, request, attr, delivered); if (msg_verbose) msg_info("forward_finish: delivered %s sender %s status %d", delivered, sender, status); (void) vstream_fclose(info->cleanup); myfree(info->queue_id); myfree((void *) info); } myfree((void *) sn_list); htable_free(table_snd, (void (*) (void *)) 0); } myfree((void *) dt_list); htable_free(forward_dt, (void (*) (void *)) 0); forward_dt = 0; return (status); }
void smtp_session_free(SMTP_SESSION *session) { #ifdef USE_TLS if (session->stream) { vstream_fflush(session->stream); if (session->tls_context) tls_client_stop(smtp_tls_ctx, session->stream, var_smtp_starttls_tmout, 0, session->tls_context); } if (session->tls_protocols) myfree(session->tls_protocols); if (session->tls_grade) myfree(session->tls_grade); if (session->tls_exclusions) vstring_free(session->tls_exclusions); if (session->tls_matchargv) argv_free(session->tls_matchargv); #endif if (session->stream) vstream_fclose(session->stream); myfree(session->dest); myfree(session->host); myfree(session->addr); myfree(session->namaddr); myfree(session->namaddrport); if (session->helo) myfree(session->helo); vstring_free(session->buffer); vstring_free(session->scratch); vstring_free(session->scratch2); if (session->history) smtp_chat_reset(session); if (session->mime_state) mime_state_free(session->mime_state); #ifdef USE_SASL_AUTH smtp_sasl_cleanup(session); #endif debug_peer_restore(); myfree((char *) session); }
VSTREAM *open_lock(const char *path, int flags, int mode, VSTRING *why) { VSTREAM *fp; /* * Carefully create or open the file, and lock it down. Some systems * don't have the O_LOCK open() flag, or the flag does not do what we * want, so we roll our own lock. */ if ((fp = safe_open(path, flags, mode, (struct stat *) 0, -1, -1, why)) == 0) return (0); if (myflock(vstream_fileno(fp), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) < 0) { vstring_sprintf(why, "unable to set exclusive lock: %m"); vstream_fclose(fp); return (0); } return (fp); }
void smtpd_proxy_close(SMTPD_STATE *state) { SMTPD_PROXY *proxy = state->proxy; /* * Specify SMTPD_PROX_WANT_NONE so that the server reply will not clobber * the END-OF-DATA reply. */ if (proxy->service_stream != 0) { if (vstream_feof(proxy->service_stream) == 0 && vstream_ferror(proxy->service_stream) == 0) (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, SMTPD_CMD_QUIT); (void) vstream_fclose(proxy->service_stream); if (proxy->stream == proxy->service_stream) proxy->stream = 0; proxy->service_stream = 0; } }
static void single_server_wakeup(int fd, HTABLE *attr) { VSTREAM *stream; char *tmp; /* * If the accept() succeeds, be sure to disable non-blocking I/O, because * the application is supposed to be single-threaded. Notice the master * of our (un)availability to service connection requests. Commit suicide * when the master process disconnected from us. Don't drop the already * accepted client request after "postfix reload"; that would be rude. */ if (msg_verbose) msg_info("connection established"); non_blocking(fd, BLOCKING); close_on_exec(fd, CLOSE_ON_EXEC); stream = vstream_fdopen(fd, O_RDWR); tmp = concatenate(single_server_name, " socket", (char *) 0); vstream_control(stream, CA_VSTREAM_CTL_PATH(tmp), CA_VSTREAM_CTL_CONTEXT((void *) attr), CA_VSTREAM_CTL_END); myfree(tmp); timed_ipc_setup(stream); if (master_notify(var_pid, single_server_generation, MASTER_STAT_TAKEN) < 0) /* void */ ; if (single_server_in_flow_delay && mail_flow_get(1) < 0) doze(var_in_flow_delay * 1000000); single_server_service(stream, single_server_name, single_server_argv); (void) vstream_fclose(stream); if (master_notify(var_pid, single_server_generation, MASTER_STAT_AVAIL) < 0) single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT); if (msg_verbose) msg_info("connection closed"); /* Avoid integer wrap-around in a persistent process. */ if (use_count < INT_MAX) use_count++; if (var_idle_limit > 0) event_request_timer(single_server_timeout, (void *) 0, var_idle_limit); if (attr) htable_free(attr, myfree); }
static void clnt_stream_close(CLNT_STREAM *clnt_stream) { /* * Sanity check. */ if (clnt_stream->vstream == 0) msg_panic("clnt_stream_close: stream is closed"); /* * Be sure to disable read and timer events. */ if (msg_verbose) msg_info("%s stream disconnect", clnt_stream->service); event_disable_readwrite(vstream_fileno(clnt_stream->vstream)); event_cancel_timer(clnt_stream_event, (void *) clnt_stream); event_cancel_timer(clnt_stream_ttl_event, (void *) clnt_stream); (void) vstream_fclose(clnt_stream->vstream); clnt_stream->vstream = 0; }
void mail_conf_checkdir(const char *config_dir) { VSTRING *buf; VSTREAM *fp; char *path; char *name; char *value; char *cp; int found = 0; /* * If running set-[ug]id, require that a non-default configuration * directory name is blessed as a bona fide configuration directory in * the default main.cf file. */ path = concatenate(DEF_CONFIG_DIR, "/", "main.cf", (char *) 0); if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) msg_fatal("open file %s: %m", path); buf = vstring_alloc(1); while (found == 0 && readlline(buf, fp, (int *) 0)) { if (split_nameval(vstring_str(buf), &name, &value) == 0 && (strcmp(name, VAR_CONFIG_DIRS) == 0 || strcmp(name, VAR_MULTI_CONF_DIRS) == 0)) { while (found == 0 && (cp = mystrtok(&value, CHARS_COMMA_SP)) != 0) if (strcmp(cp, config_dir) == 0) found = 1; } } if (vstream_fclose(fp)) msg_fatal("read file %s: %m", path); vstring_free(buf); if (found == 0) { msg_error("unauthorized configuration directory name: %s", config_dir); msg_fatal("specify \"%s = %s\" or \"%s = %s\" in %s", VAR_CONFIG_DIRS, config_dir, VAR_MULTI_CONF_DIRS, config_dir, path); } myfree(path); }
int post_mail_fclose(VSTREAM *cleanup) { int status = 0; /* * Send the message end marker only when there were no errors. */ if (vstream_ferror(cleanup) != 0) { status = CLEANUP_STAT_WRITE; } else { rec_fputs(cleanup, REC_TYPE_XTRA, ""); rec_fputs(cleanup, REC_TYPE_END, ""); if (vstream_fflush(cleanup) || attr_scan(cleanup, ATTR_FLAG_MISSING, ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, ATTR_TYPE_END) != 1) status = CLEANUP_STAT_WRITE; } (void) vstream_fclose(cleanup); return (status); }
static void receive_reply(int unused_event, char *context) { SESSION *session = (SESSION *) context; int except; /* * Prepare for disaster. */ if ((except = vstream_setjmp(session->stream)) != 0) msg_fatal("%s while receiving server reply", exception_text(except)); /* * Receive and process the server reply. */ netstring_get(session->stream, buffer, var_line_limit); if (msg_verbose) vstream_printf("<< %.*s\n", (int) LEN(buffer), STR(buffer)); if (STR(buffer)[0] != QMQP_STAT_OK) msg_fatal("%s error: %.*s", STR(buffer)[0] == QMQP_STAT_RETRY ? "recoverable" : STR(buffer)[0] == QMQP_STAT_HARD ? "unrecoverable" : "unknown", (int) LEN(buffer) - 1, STR(buffer) + 1); /* * Update the optional running counter. */ if (count) { counter++; vstream_printf("%d\r", counter); vstream_fflush(VSTREAM_OUT); } /* * Finish this session. QMQP sends only one message per session. */ event_disable_readwrite(vstream_fileno(session->stream)); vstream_fclose(session->stream); session->stream = 0; start_another(session); }
static void deliver_request_free(DELIVER_REQUEST *request) { if (request->fp) vstream_fclose(request->fp); if (request->queue_name) myfree(request->queue_name); if (request->queue_id) myfree(request->queue_id); if (request->nexthop) myfree(request->nexthop); if (request->encoding) myfree(request->encoding); if (request->sender) myfree(request->sender); recipient_list_free(&request->rcpt_list); if (request->hop_status) dsn_free(request->hop_status); if (request->client_name) myfree(request->client_name); if (request->client_addr) myfree(request->client_addr); if (request->client_port) myfree(request->client_port); if (request->client_proto) myfree(request->client_proto); if (request->client_helo) myfree(request->client_helo); if (request->sasl_method) myfree(request->sasl_method); if (request->sasl_username) myfree(request->sasl_username); if (request->sasl_sender) myfree(request->sasl_sender); if (request->rewrite_context) myfree(request->rewrite_context); if (request->dsn_envid) myfree(request->dsn_envid); myfree((char *) request); }