#include "common.h" typedef struct Qfile Qfile; struct Qfile { Qfile *next; char *name; char *tname; } *files; char *user; int isnone; int copy(Qfile*); void usage(void) { fprint(2, "usage: qer [-f file] [-q dir] q-root description reply-to arg-list\n"); exits("usage"); } void error(char *f, char *a) { char err[Errlen+1]; char buf[256]; rerrstr(err, sizeof(err)); snprint(buf, sizeof(buf), f, a); fprint(2, "qer: %s: %s\n", buf, err); exits(buf); } void main(int argc, char**argv) { Dir *dir; String *f, *c; int fd; char file[1024]; char buf[1024]; long n; char *cp, *qdir; int i; Qfile *q, **l; l = &files; qdir = 0; ARGBEGIN { case 'f': q = malloc(sizeof(Qfile)); q->name = ARGF(); q->next = *l; *l = q; break; case 'q': qdir = ARGF(); if(qdir == 0) usage(); break; default: usage(); } ARGEND; if(argc < 3) usage(); user = getuser(); isnone = (qdir != 0) || (strcmp(user, "none") == 0); if(qdir == 0) { qdir = user; if(qdir == 0) error("unknown user", 0); } snprint(file, sizeof(file), "%s/%s", argv[0], qdir); /* * data file name */ f = s_copy(file); s_append(f, "/D.XXXXXX"); mktemp(s_to_c(f)); cp = utfrrune(s_to_c(f), '/'); cp++; /* * create directory and data file. once the data file * exists, runq won't remove the directory */ fd = -1; for(i = 0; i < 10; i++){ int perm; dir = dirstat(file); if(dir == nil){ perm = isnone?0777:0775; if(sysmkdir(file, perm) < 0) continue; } else { if((dir->qid.type&QTDIR)==0) error("not a directory %s", file); } perm = isnone?0664:0660; fd = create(s_to_c(f), OWRITE, perm); if(fd >= 0) break; sleep(250); } if(fd < 0) error("creating data file %s", s_to_c(f)); /* * copy over associated files */ if(files){ *cp = 'F'; for(q = files; q; q = q->next){ q->tname = strdup(s_to_c(f)); if(copy(q) < 0) error("copying %s to queue", q->name); (*cp)++; } } /* * copy in the data file */ i = 0; while((n = read(0, buf, sizeof(buf)-1)) > 0){ if(i++ == 0 && strncmp(buf, "From", 4) != 0){ buf[n] = 0; syslog(0, "smtp", "qer usys data starts with %-40.40s\n", buf); } if(write(fd, buf, n) != n) error("writing data file %s", s_to_c(f)); } /* if(n < 0) error("reading input"); */ close(fd); /* * create control file */ *cp = 'C'; fd = syscreatelocked(s_to_c(f), OWRITE, 0664); if(fd < 0) error("creating control file %s", s_to_c(f)); c = s_new(); for(i = 1; i < argc; i++){ s_append(c, argv[i]); s_append(c, " "); } for(q = files; q; q = q->next){ s_append(c, q->tname); s_append(c, " "); } s_append(c, "\n"); if(write(fd, s_to_c(c), strlen(s_to_c(c))) < 0) { sysunlockfile(fd); error("writing control file %s", s_to_c(f)); } sysunlockfile(fd); exits(0); } int copy(Qfile *q) { int from, to, n; char buf[4096]; from = open(q->name, OREAD); if(from < 0) return -1; to = create(q->tname, OWRITE, 0660); if(to < 0){ close(from); return -1; } for(;;){ n = read(from, buf, sizeof(buf)); if(n <= 0) break; n = write(to, buf, n); if(n < 0) break; } close(to); close(from); return n; }