29#define WHO "qmail-qmaint"
56static void die_make(
char *name)
58 logmsg(
WHO,111,ERROR,B(
"Failed to make: ",name));
61static void die_check()
63 logmsg(
WHO,111,ERROR,
"Failed while checking directory structure. \nEnsure the given queue exists and you have permission to access it.");
68 logmsg(
WHO,110,ERROR,
"Out of memory.");
71static void err_unlink(
unsigned long id)
74 foo[fmt_ulong(
foo,
id)] = 0;
75 logmsg(
WHO,100,ERROR,B(
"trouble with unlinking #",
foo));
78static void err_chdir()
80 logmsg(
WHO,110,FATAL,
"unable to chdir");
89 if (getln(buffer_0,&
query,&
match,
'\n'))
return 0;
91 if (
query.s[0] ==
'y' ||
query.s[0] ==
'Y' ||
query.s[0] ==
'\n')
return 1;
97#define DIRS logmsg(WHO,0,WARN,"It looks like some directories don't exist, should I create them? (Y/n)")
98#define FILES logmsg(WHO,0,WARN,"It looks like some files don't exist, should I create them? (Y/n)")
100#define PERMS logmsg(WHO,0,WARN,B("It looks like permissions are wrong for ",name," should I fix them? (Y/n)"))
101#define CPERMS logmsg(WHO,0,WARN,B("Changing permissions: ",name," => ",pnum))
103#define OWNER logmsg(WHO,0,WARN,B("It looks like ownerships are wrong for ",name," should I fix them? (Y/n)"))
104#define COWNER logmsg(WHO,0,WARN,B("Changing ownership: ",name," => ",unum,"/",gnum))
106static int check_item(
char *name,
int uid,
int gid,
int perm,
char type,
int size)
118 strnum[fmt_uint(gnum,gid)] = 0;
123 if (stat(name,&st)) {
124 if (errno != ENOENT)
return -1;
126 DIRS;
if (!confirm())
return -1;
130 logmsg(
WHO,0,INFO,B(
"Creating directory: ",name));
131 if (mkdir(name,
perm)) die_make(name);
133 COWNER;
if (chown(name,
uid,gid)) die_make(name);
137 if (st.st_uid !=
uid || st.st_gid != gid) {
139 COWNER;
if (chown(name,
uid,gid)) die_make(name);
141 if ((st.st_mode & 07777) !=
perm) {
147 if (stat(name,&st))
return -1;
149 if (st.st_uid !=
uid || (st.st_gid != gid && gid != -1)) {
151 COWNER;
if (chown(name,
uid,gid)) die_make(name);
153 if ((st.st_mode & 07777) !=
perm) {
159 if (stat(name,&st)) {
160 if (errno != ENOENT)
return -1;
162 FILES;
if (!confirm())
return -1;
168 logmsg(
WHO,0,INFO,B(
"Creating: ",name,
" with size ",
num));
169 fd = open_trunc(name);
170 if (
fd == -1) die_make(name);
171 while (
size--) {
if (
write(
fd,
"",1)!=1) die_make(name); }
174 COWNER;
if (chown(name,
uid,gid)) die_make(name);
178 if (st.st_uid !=
uid || (st.st_gid != gid && gid != -1)) {
180 COWNER;
if (chown(name,
uid,gid)) die_make(name);
182 if ((st.st_mode & 07777) !=
perm) {
186 if (st.st_size !=
size) {
187 logmsg(
WHO,0,WARN,B(
"File ",name,
" has not the right size. I will not fix it, please investigate."));
191 if (stat(name,&st)) {
192 if (errno != ENOENT)
return -1;
194 FILES;
if (!confirm())
return -1;
198 logmsg(
WHO,INFO,0,B(
"Creating fifo: ",name));
201 COWNER;
if (chown(name,
uid,gid)) die_make(name);
205 if (st.st_uid !=
uid || (st.st_gid != gid && gid != -1)) {
207 COWNER;
if (chown(name,
uid,gid)) die_make(name);
209 if ((st.st_mode & 07777) !=
perm) {
219static int check_files(
char * directory,
int uid,
int gid,
int perm)
224 dir = opendir(directory);
227 while ((
d = readdir(dir))) {
228 if (
d->d_name[0] ==
'.')
continue;
233 if (check_item(
temp_filename.s,
uid,gid,perm,
'f',0)) { closedir(dir);
return -1; }
239static void warn_files(
char * directory)
245 dir = opendir(directory);
248 while ((
d = readdir(dir))) {
249 if (
d->d_name[0] ==
'.')
continue;
257 logmsg(
WHO,0,WARN,B(
"Found files in ",directory,
" that shouldn't be there. I will not remove them. You should consider checking it out."));
260static int check_splits(
char * directory,
int dir_uid,
int dir_gid,
int dir_perm,
int file_gid,
int file_perm)
274 if (check_item(
temp_dirname.s,dir_uid,dir_gid,dir_perm,
'd',0))
return -1;
279 while ((
d = readdir(dir))) {
280 if (
d->d_name[0] ==
'.')
continue;
285 if (check_item(
temp_filename.s,dir_uid,file_gid,file_perm,
'f',0)) { closedir(dir);
return -1; }
293static int rename_mess(
char *dir,
char *part,
char *new_part,
char *old_filename,
char *new_filename)
297 logmsg(
WHO,0,INFO,
"It looks like some files need to be renamed, should I rename them? (Y/n)\n");
298 if (!confirm())
return -1;
320 if (errno != ENOENT)
return -1;
333 i = fmt_str(s,
" Date: "); len += i;
if (s) s += i;
340 if (!stralloc_ready(&
birth_date,datefmt(FMT_LEN,when)))
return 0;
345static int cleanup_dkim()
353 if (chdir(
"queue/dkim") == -1)
return 0;
367 while ((
d = readdir(dir))) {
368 if (
d->d_name[0] ==
'.')
continue;
375 date_make(st.st_mtime);
390static int fix_part(
char *part)
395 char inode[FMT_ULONG];
396 char new_part[FMT_ULONG];
397 unsigned int old_inode;
398 unsigned int part_num;
399 unsigned int correct_part_num;
401 scan_uint(part,&part_num);
411 while ((
d = readdir(dir))) {
412 if (
d->d_name[0] ==
'.')
continue;
422 scan_uint(
d->d_name,&old_inode);
423 correct_part_num = st.st_ino %
split_num;
424 if (st.st_ino != old_inode || part_num != correct_part_num) {
426 inode[fmt_ulong(inode,st.st_ino)] = 0;
427 new_part[fmt_ulong(new_part,correct_part_num)] = 0;
428 if (rename_mess(
"dkim/",part,new_part,
d->d_name,inode)) { closedir(dir);
return -1; }
429 if (rename_mess(
"mess/",part,new_part,
d->d_name,inode)) { closedir(dir);
return -1; }
430 if (rename_mess(
"info/",part,new_part,
d->d_name,inode)) { closedir(dir);
return -1; }
431 if (rename_mess(
"local/",part,new_part,
d->d_name,inode)) { closedir(dir);
return -1; }
432 if (rename_mess(
"remote/",part,new_part,
d->d_name,inode)) { closedir(dir);
return -1; }
433 if (rename_mess(
"todo/",part,new_part,
d->d_name,inode)) { closedir(dir);
return -1; }
434 if (rename_mess(
"intd/",part,new_part,
d->d_name,inode)) { closedir(dir);
return -1; }
436 if (rename_mess(
"bounce",
"",
"",
d->d_name,inode)) { closedir(dir);
return -1; }
444static int fix_names()
454 if (fix_part(
strnum))
return -1;
460static int check_dirs()
554static void fnmake_local(
unsigned long id) {
fn.len =
fmtqfn(
fn.s,
"local/",
id,1); }
555static void fnmake_remote(
unsigned long id) {
fn.len =
fmtqfn(
fn.s,
"remote/",
id,1); }
556static void fnmake_mess(
unsigned long id) {
fn.len =
fmtqfn(
fn.s,
"mess/",
id,1); }
557static void fnmake_dkim(
unsigned long id) {
fn.len =
fmtqfn(
fn.s,
"dkim/",
id,1); }
558static void fnmake_info(
unsigned long id) {
fn.len =
fmtqfn(
fn.s,
"info/",
id,1); }
559static void fnmake_bounce(
unsigned long id) {
fn.len =
fmtqfn(
fn.s,
"bounce/",
id,0); }
561static void warn_unlink(
unsigned long id)
564 foo[fmt_ulong(
foo,
id)] = 0;
565 logmsg(
WHO,99,WARN,B(
"no such file to unlink #",
foo));
568static int delete_msg(
unsigned long id)
574 if (chdir(
"queue") == -1) err_chdir();
579 if (stat(
fn.s,&st) == -1) err_unlink(
id);
581 if (!bounce && unlink(
fn.s) == -1)
582 if (errno != ENOENT) err_unlink(
id);
586 if (unlink(
fn.s) == -1)
587 if (errno != ENOENT) err_unlink(
id);
591 if (!stat(
fn.s,&st)) { warn_unlink(
id);
return 1; }
592 if (unlink(
fn.s) == -1)
593 if (errno != ENOENT) err_unlink(
id);
598 if (unlink(
fn.s) == -1)
599 if (errno != ENOENT) err_unlink(
id);
603 if (unlink(
fn.s) == -1)
604 if (errno != ENOENT) err_unlink(
id);
609int main(
int argc,
char *
const *argv)
612 unsigned long id = 0;
617 if (!str_diff(argv[1],
"-i")) {
619 }
else if (!str_diff(argv[1],
"-d")) {
620 if (!argv[2]) logmsg(
WHO,111,USAGE,
"qmail-qmaint [-i] || [-d messid] || [-D]");
623 scan_ulong(
mess,&
id);
624 }
else if (!str_diff(argv[1],
"-D")) {
627 logmsg(
WHO,111,USAGE,
"qmail-qmaint [-i] || [-d messid] || [-D]");
633 logmsg(
WHO,0,INFO,B(
"Checking s/qmail queue at: ",
auto_queue,
"/queue/"));
645 if (check_dirs()) die_check();
649 logmsg(
WHO,0,INFO,B(
"file ",
mess,
" from queue deleted."));
653 logmsg(
WHO,0,INFO,B(
strnum,
" DKIM staging files from queue deleted."));
655 if (fix_names()) die_check();
657 logmsg(
WHO,0,INFO,
"done.");
unsigned int date822fmt(char *s, struct datetime *dt)
void datetime_tai(struct datetime *dt, datetime_sec t)
int stralloc_copys(stralloc *, char const *)
int rename(const char *, const char *)
int fifo_make(char *fn, int mode)
unsigned int fmtqfn(char *s, char *dirslash, unsigned long id, int flagsplit)
void perm(char *prefix1, char *prefix2, char *prefix3, char *file, int type, int uid, int gid, int mode)