static Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int i; Path *path; Walkqid *wq; UnixFd *ufd; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); fsclone(c, nc); ufd = c->aux; path = ufd->path; incref(&path->ref); wq->clone = nc; for(i=0; i<nname; i++){ ufd = nc->aux; replacepath(nc, path); if(fswalk1(nc, name[i]) < 0){ if(i == 0){ pathclose(path); cclose(nc); free(wq); error(Enonexist); } break; } path = addelem(path, name[i], nil); wq->qid[i] = nc->qid; } replacepath(nc, path); pathclose(path); if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq; }
int deliver_write_deliver(struct deliver_ctx *dctx, struct actitem *ti) { struct account *a = dctx->account; struct mail *m = dctx->mail; struct deliver_write_data *data = ti->data; char *path; FILE *f; path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home); if (path == NULL || *path == '\0') { if (path != NULL) xfree(path); log_warnx("%s: empty command", a->name); return (DELIVER_FAILURE); } if (data->append) { log_debug2("%s: appending to %s", a->name, path); f = fopen(path, "a"); } else { log_debug2("%s: writing to %s", a->name, path); f = fopen(path, "w"); } if (f == NULL) { log_warn("%s: %s: fopen", a->name, path); goto error; } if (fwrite(m->data, m->size, 1, f) != 1) { log_warn("%s: %s: fwrite", a->name, path); goto error; } if (fflush(f) != 0) { log_warn("%s: %s: fflush", a->name, path); goto error; } if (fsync(fileno(f)) != 0) { log_warn("%s: %s: fsync", a->name, path); goto error; } fclose(f); xfree(path); return (DELIVER_SUCCESS); error: xfree(path); return (DELIVER_FAILURE); }
int deliver_mbox_deliver(struct deliver_ctx *dctx, struct actitem *ti) { struct account *a = dctx->account; struct mail *m = dctx->mail; struct deliver_mbox_data *data = ti->data; char *path, *ptr, *lptr, *from = NULL; const char *msg; size_t len, llen; int fd, saved_errno; FILE *f; gzFile gzf; long long used; sigset_t set, oset; struct stat sb; f = gzf = NULL; fd = -1; path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home); if (path == NULL || *path == '\0') { log_warnx("%s: empty path", a->name); goto error; } if (data->compress) { len = strlen(path); if (len < 3 || strcmp(path + len - 3, ".gz") != 0) { path = xrealloc(path, 1, len + 4); strlcat(path, ".gz", len + 4); } } log_debug2("%s: saving to mbox %s", a->name, path); /* Save the mbox path. */ add_tag(&m->tags, "mbox_file", "%s", path); /* Check permissions and ownership. */ if (stat(path, &sb) != 0) { if (conf.no_create || errno != ENOENT) goto error_log; log_debug2("%s: creating %s", a->name, xdirname(path)); if (xmkpath(xdirname(path), -1, conf.file_group, DIRMODE) != 0) goto error_log; } else { if ((msg = checkmode(&sb, UMASK(FILEMODE))) != NULL) log_warnx("%s: %s: %s", a->name, path, msg); if ((msg = checkowner(&sb, -1)) != NULL) log_warnx("%s: %s: %s", a->name, path, msg); if ((msg = checkgroup(&sb, conf.file_group)) != NULL) log_warnx("%s: %s: %s", a->name, path, msg); } /* Create or open the mbox. */ used = 0; do { if (conf.no_create) fd = openlock(path, O_WRONLY|O_APPEND, conf.lock_types); else { fd = createlock(path, O_WRONLY|O_APPEND, -1, conf.file_group, FILEMODE, conf.lock_types); } if (fd == -1 && errno == EEXIST) fd = openlock(path, O_WRONLY|O_APPEND, conf.lock_types); if (fd == -1) { if (errno == EAGAIN) { if (locksleep(a->name, path, &used) != 0) goto error; continue; } goto error_log; } } while (fd < 0); /* Open gzFile or FILE * for writing. */ if (data->compress) { if ((gzf = gzdopen(fd, "a")) == NULL) { errno = ENOMEM; goto error_log; } } else { if ((f = fdopen(fd, "a")) == NULL) goto error_log; } /* * mboxes are a pain: if we are interrupted after this we risk * having written a partial mail. So, block SIGTERM until we're * done. */ sigemptyset(&set); sigaddset(&set, SIGTERM); if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) fatal("sigprocmask failed"); /* Write the from line. */ from = make_from(m, dctx->udata->name); if (deliver_mbox_write(f, gzf, from, strlen(from)) < 0) { xfree(from); goto error_unblock; } if (deliver_mbox_write(f, gzf, "\n", 1) < 0) { xfree(from); goto error_unblock; } log_debug3("%s: using from line: %s", a->name, from); xfree(from); /* Write the mail, escaping from lines. */ line_init(m, &ptr, &len); while (ptr != NULL) { if (ptr != m->data) { /* Skip leading >s. */ lptr = ptr; llen = len; while (*lptr == '>' && llen > 0) { lptr++; llen--; } if (llen >= 5 && strncmp(lptr, "From ", 5) == 0) { log_debug2("%s: quoting from line: %.*s", a->name, (int) len - 1, ptr); if (deliver_mbox_write(f, gzf, ">", 1) < 0) goto error_unblock; } } if (deliver_mbox_write(f, gzf, ptr, len) < 0) goto error_unblock; line_next(m, &ptr, &len); } /* Append newlines. */ if (m->data[m->size - 1] == '\n') { if (deliver_mbox_write(f, gzf, "\n", 1) < 0) goto error_unblock; } else { if (deliver_mbox_write(f, gzf, "\n\n", 2) < 0) goto error_unblock; } /* Flush buffers and sync. */ if (gzf == NULL) { if (fflush(f) != 0) goto error_unblock; } else { if (gzflush(gzf, Z_FINISH) != Z_OK) { errno = EIO; goto error_unblock; } } if (fsync(fd) != 0) goto error_unblock; if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) fatal("sigprocmask failed"); if (gzf != NULL) gzclose(gzf); if (f != NULL) fclose(f); closelock(fd, path, conf.lock_types); xfree(path); return (DELIVER_SUCCESS); error_unblock: saved_errno = errno; if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) fatal("sigprocmask failed"); errno = saved_errno; error_log: log_warn("%s: %s", a->name, path); error: if (gzf != NULL) gzclose(gzf); if (f != NULL) fclose(f); if (fd != -1) closelock(fd, path, conf.lock_types); if (path != NULL) xfree(path); return (DELIVER_FAILURE); }
int yylex(void) { int ch, value; char *path; struct replpath rp; /* Switch to new file. See comment in read_token below. */ if (lex_include) { while ((ch = lex_getc()) != EOF && isspace((u_char) ch)) ; if (ch != '"' && ch != '\'') yyerror("syntax error"); if (ch == '"') rp.str = read_string('"', 1); else rp.str = read_string('\'', 0); path = replacepath(&rp, parse_tags, NULL, NULL, conf.user_home); xfree(rp.str); include_start(path); lex_include = 0; } restart: while ((ch = lex_getc()) != EOF) { switch (ch) { case '#': /* Comment: discard until EOL. */ while ((ch = lex_getc()) != '\n' && ch != EOF) ; parse_file->line++; break; case '\'': yylval.string = read_string('\'', 0); value = STRING; goto out; case '"': yylval.string = read_string('"', 1); value = STRING; goto out; case '$': ch = lex_getc(); if (ch == '(') { yylval.string = read_command(); value = STRCOMMAND; goto out; } if (ch == '{' || isalnum((u_char) ch)) { yylval.string = read_macro('$', ch); value = STRMACRO; goto out; } yyerror("invalid macro name"); case '%': ch = lex_getc(); if (ch == '(') { yylval.string = read_command(); value = NUMCOMMAND; goto out; } if (ch == '{' || isalnum((u_char) ch)) { yylval.string = read_macro('%', ch); value = NUMMACRO; goto out; } yyerror("invalid macro name"); case '=': ch = lex_getc(); if (ch == '=') { value = TOKEQ; goto out; } lex_ungetc(ch); value = '='; goto out; case '!': ch = lex_getc(); if (ch == '=') { value = TOKNE; goto out; } lex_ungetc(ch); value = '!'; goto out; case '~': case '+': case '(': case ')': case ',': case '<': case '>': case '{': case '}': case '*': value = ch; goto out; case '\n': parse_file->line++; break; case ' ': case '\t': break; default: if (ch != '_' && ch != '-' && !isalnum((u_char) ch)) yyerror("unexpected character: %c", ch); if (isdigit((u_char) ch)) { yylval.number = read_number(ch); value = NUMBER; goto out; } value = read_token(ch); goto out; } } if (!include_finish()) goto restart; if (lex_ifdef != 0) yyerror("missing endif"); return (EOF); out: if (lex_skip) goto restart; return (value); }
int deliver_pipe_deliver(struct deliver_ctx *dctx, struct actitem *ti) { struct account *a = dctx->account; struct mail *m = dctx->mail; struct deliver_pipe_data *data = ti->data; char *s, *cause, *err; int status; struct cmd *cmd = NULL; char *lbuf; size_t llen; s = replacepath(&data->cmd, m->tags, m, &m->rml, dctx->udata->home); if (s == NULL || *s == '\0') { log_warnx("%s: empty command", a->name); goto error; } if (data->pipe) { log_debug2("%s: piping to \"%s\"", a->name, s); cmd = cmd_start(s, CMD_IN|CMD_ONCE, m->data, m->size, &cause); } else { log_debug2("%s: executing \"%s\"", a->name, s); cmd = cmd_start(s, 0, NULL, 0, &cause); } if (cmd == NULL) goto error_cause; log_debug3("%s: %s: started", a->name, s); llen = IO_LINESIZE; lbuf = xmalloc(llen); do { status = cmd_poll( cmd, NULL, &err, &lbuf, &llen, conf.timeout, &cause); if (status == -1) { xfree(lbuf); goto error_cause; } if (status == 0 && err != NULL) log_warnx("%s: %s: %s", a->name, s, err); } while (status == 0); status--; xfree(lbuf); if (status != 0) { log_warnx("%s: %s: command returned %d", a->name, s, status); goto error; } cmd_free(cmd); xfree(s); return (DELIVER_SUCCESS); error_cause: log_warnx("%s: %s: %s", a->name, s, cause); xfree(cause); error: if (cmd != NULL) cmd_free(cmd); if (s != NULL) xfree(s); return (DELIVER_FAILURE); }
void child_deliver_cmd_hook(pid_t pid, struct account *a, unused struct msg *msg, struct child_deliver_data *data, int *result) { struct mail_ctx *mctx = data->mctx; struct mail *m = data->mail; struct match_command_data *cmddata = data->cmddata; int flags, status, found = 0; char *s, *cause, *lbuf, *out, *err, tag[24]; size_t llen; struct cmd *cmd = NULL; struct rmlist rml; u_int i; /* If this is the parent, do nothing. */ if (pid != 0) { xfree(mctx); return; } /* Sort out the command. */ s = replacepath( &cmddata->cmd, m->tags, m, &m->rml, find_tag(m->tags, "home")); if (s == NULL || *s == '\0') { log_warnx("%s: empty command", a->name); goto error; } log_debug2("%s: %s: started (ret=%d re=%s)", a->name, s, cmddata->ret, cmddata->re.str == NULL ? "none" : cmddata->re.str); flags = CMD_ONCE; if (cmddata->pipe) flags |= CMD_IN; if (cmddata->re.str != NULL) flags |= CMD_OUT; cmd = cmd_start(s, flags, m->data, m->size, &cause); if (cmd == NULL) { log_warnx("%s: %s: %s", a->name, s, cause); goto error; } llen = IO_LINESIZE; lbuf = xmalloc(llen); for (;;) { /* Stop early if looking for regexp only. */ if (found && cmddata->ret == -1) { log_debug3("%s: %s: found. stopping early", a->name, s); status = 1; break; } status = cmd_poll( cmd, &out, &err, &lbuf, &llen, conf.timeout, &cause); if (status == -1) { log_warnx("%s: %s: %s", a->name, s, cause); goto error; } if (status != 0) break; if (err != NULL) log_warnx("%s: %s: %s", a->name, s, err); if (out == NULL) continue; log_debug3("%s: %s: out: %s", a->name, s, out); if (found) continue; found = re_string(&cmddata->re, out, &rml, &cause); if (found == -1) { log_warnx("%s: %s", a->name, cause); goto error; } if (found != 1) continue; /* Save the matches. */ if (!rml.valid) continue; for (i = 0; i < NPMATCH; i++) { if (!rml.list[i].valid) break; xsnprintf(tag, sizeof tag, "command%u", i); add_tag(&m->tags, tag, "%.*s", (int) (rml.list[i].eo - rml.list[i].so), out + rml.list[i].so); } } status--; log_debug2("%s: %s: returned %d, found %d", a->name, s, status, found); cmd_free(cmd); xfree(s); xfree(lbuf); status = cmddata->ret == status; if (cmddata->ret != -1 && cmddata->re.str != NULL) *result = (found && status) ? MATCH_TRUE : MATCH_FALSE; else if (cmddata->ret != -1 && cmddata->re.str == NULL) *result = status ? MATCH_TRUE : MATCH_FALSE; else if (cmddata->ret == -1 && cmddata->re.str != NULL) *result = found ? MATCH_TRUE : MATCH_FALSE; else *result = MATCH_ERROR; return; error: if (cause != NULL) xfree(cause); if (cmd != NULL) cmd_free(cmd); if (s != NULL) xfree(s); if (lbuf != NULL) xfree(lbuf); *result = MATCH_ERROR; }