|
1 /* |
|
2 queue-fix 1.4 |
|
3 by Eric Huss |
|
4 e-huss@netmeridian.com |
|
5 |
|
6 reconstructs qmail's queue |
|
7 */ |
|
8 #include <stdio.h> |
|
9 #include <sys/stat.h> |
|
10 #include <pwd.h> |
|
11 #include <grp.h> |
|
12 #include "stralloc.h" |
|
13 #include "direntry.h" |
|
14 #include "fmt.h" |
|
15 #include "error.h" |
|
16 #include "subfd.h" |
|
17 #include "getln.h" |
|
18 #include "str.h" |
|
19 #include "open.h" |
|
20 #include "fifo.h" |
|
21 #include "scan.h" |
|
22 |
|
23 /*change this to your qmail's conf-split value*/ |
|
24 #define SPLIT_NUM 23 |
|
25 |
|
26 stralloc queue_dir = {0}; /*the root queue dir with trailing slash*/ |
|
27 stralloc check_dir = {0}; /*the current directory being checked*/ |
|
28 stralloc temp_filename = {0}; /*temporary used for checking individuals*/ |
|
29 stralloc temp_dirname = {0}; /*temporary used for checking individuals*/ |
|
30 stralloc old_name = {0}; /*used in rename*/ |
|
31 stralloc new_name = {0}; /*used in rename*/ |
|
32 stralloc mess_dir = {0}; /*used for renaming in mess dir*/ |
|
33 stralloc query = {0}; /*used in interactive query function*/ |
|
34 |
|
35 char name_num[FMT_ULONG]; |
|
36 int flag_interactive=0; |
|
37 int flag_doit=1; |
|
38 int flag_dircreate=0; |
|
39 int flag_filecreate=0; |
|
40 int flag_permfix=0; |
|
41 int flag_namefix=0; |
|
42 int flag_unlink=0; |
|
43 |
|
44 int qmailq_uid; |
|
45 int qmails_uid; |
|
46 int qmailr_uid; |
|
47 int qmail_gid; |
|
48 |
|
49 void die_make(char * name) |
|
50 { |
|
51 printf("Failed to make %s\n" |
|
52 "\nExiting...\n\n",name); |
|
53 exit(1); |
|
54 } |
|
55 |
|
56 void die_user(char * user) |
|
57 { |
|
58 printf("Failed to determine the uid of %s\n" |
|
59 "\nExiting...\n\n",user); |
|
60 exit(1); |
|
61 } |
|
62 |
|
63 void die_group(char * group) |
|
64 { |
|
65 printf("Failed to determine the gid of %s\n" |
|
66 "\nExiting...\n\n",group); |
|
67 exit(1); |
|
68 } |
|
69 |
|
70 void die_args() |
|
71 { |
|
72 printf("Invalid arguments.\n" |
|
73 "queue-fix [-i | -N] queue_dir\n" |
|
74 "\nExiting...\n\n"); |
|
75 exit(1); |
|
76 } |
|
77 |
|
78 void die_check() |
|
79 { |
|
80 printf("Failed while checking directory structure.\n" |
|
81 "Make sure the given queue exists and you have permission to access it.\n" |
|
82 "\nExiting...\n\n"); |
|
83 exit(1); |
|
84 } |
|
85 |
|
86 void die_recon() |
|
87 { |
|
88 printf("Failed to reconstruct queue.\n" |
|
89 "Make sure the queue exists and you have permission to modify it.\n" |
|
90 "\nExiting...\n\n"); |
|
91 exit(1); |
|
92 } |
|
93 |
|
94 void die_nomem() |
|
95 { |
|
96 printf("Hmm.. Out of memory\n" |
|
97 "\nExiting...\n\n"); |
|
98 exit(1); |
|
99 } |
|
100 |
|
101 void die_rerun() |
|
102 { |
|
103 printf(".tmp files exist in the queue.\n" |
|
104 "queue-fix may have abnormally terminated in a previous run.\n" |
|
105 "The queue must be manually cleaned of the .tmp files.\n" |
|
106 "\nExiting...\n\n"); |
|
107 exit(1); |
|
108 } |
|
109 |
|
110 /*returns 1==yes, 0==no*/ |
|
111 int confirm() |
|
112 { |
|
113 int match; |
|
114 |
|
115 if(getln(subfdinsmall,&query,&match,'\n')) return 0; |
|
116 if(!match) return 0; |
|
117 if(query.s[0]=='y' || query.s[0]=='Y' || query.s[0]=='\n') return 1; |
|
118 return 0; |
|
119 } |
|
120 |
|
121 /*gid may be -1 on files for "unknown*/ |
|
122 int check_item(char * name,int uid,int gid,int perm,char type,int size) |
|
123 { |
|
124 struct stat st; |
|
125 int fd; |
|
126 |
|
127 /*check for existence and proper credentials*/ |
|
128 switch(type) { |
|
129 case 'd': /*directory*/ |
|
130 if(stat(name,&st)) { |
|
131 if(errno!=error_noent) return -1; |
|
132 if(!flag_dircreate && flag_interactive) { |
|
133 printf("It looks like some directories don't exist, should I create them? (Y/n)\n"); |
|
134 if(!confirm()) return -1; |
|
135 flag_dircreate = 1; |
|
136 } |
|
137 /*create it*/ |
|
138 printf("Creating directory [%s]\n",name); |
|
139 if(flag_doit) if(mkdir(name,perm)) die_make(name); |
|
140 printf("Changing permissions of [%s] to [%o]\n",name,perm); |
|
141 if(flag_doit) if(chmod(name,perm)) die_make(name); |
|
142 printf("Changing ownership of [%s] to uid %u gid %u\n",name,uid,gid); |
|
143 if(flag_doit) if(chown(name,uid,gid)) die_make(name); |
|
144 return 0; |
|
145 } |
|
146 /*check the values*/ |
|
147 if(st.st_uid!=uid || st.st_gid!=gid) { |
|
148 if(!flag_permfix && flag_interactive) { |
|
149 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
150 if(!confirm()) return -1; |
|
151 flag_permfix = 1; |
|
152 } |
|
153 /*fix it*/ |
|
154 printf("Changing ownership of [%s] to uid %u gid %u\n",name,uid,gid); |
|
155 if(flag_doit) if(chown(name,uid,gid)) die_make(name); |
|
156 } |
|
157 if((st.st_mode & 07777) != perm) { |
|
158 if(!flag_permfix && flag_interactive) { |
|
159 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
160 if(!confirm()) return -1; |
|
161 flag_permfix = 1; |
|
162 } |
|
163 /*fix it*/ |
|
164 printf("Changing permissions of [%s] to [%o]\n",name,perm); |
|
165 if(flag_doit) if(chmod(name,perm)) die_make(name); |
|
166 } |
|
167 return 0; |
|
168 case 'f': /*regular file*/ |
|
169 if(stat(name,&st)) return -1; |
|
170 /*check the values*/ |
|
171 if(st.st_uid!=uid || (st.st_gid!=gid && gid!=-1)) { |
|
172 if(!flag_permfix && flag_interactive) { |
|
173 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
174 if(!confirm()) return -1; |
|
175 flag_permfix = 1; |
|
176 } |
|
177 /*fix it*/ |
|
178 printf("Changing ownership of [%s] to uid %u gid %u\n",name,uid,gid); |
|
179 if(flag_doit) if(chown(name,uid,gid)) die_make(name); |
|
180 } |
|
181 if((st.st_mode & 07777) != perm) { |
|
182 if(!flag_permfix && flag_interactive) { |
|
183 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
184 if(!confirm()) return -1; |
|
185 flag_permfix = 1; |
|
186 } |
|
187 /*fix it*/ |
|
188 printf("Changing permissions of [%s] to [%o]\n",name,perm); |
|
189 if(flag_doit) if(chmod(name,perm)) die_make(name); |
|
190 } |
|
191 return 0; |
|
192 case 'z': /*regular file with a size*/ |
|
193 if(stat(name,&st)) { |
|
194 if(errno!=error_noent) return -1; |
|
195 if(!flag_filecreate && flag_interactive) { |
|
196 printf("It looks like some files don't exist, should I create them? (Y/n)\n"); |
|
197 if(!confirm()) return -1; |
|
198 flag_filecreate = 1; |
|
199 } |
|
200 /*create it*/ |
|
201 printf("Creating [%s] with size [%u]\n",name,size); |
|
202 if(flag_doit) { |
|
203 fd = open_trunc(name); |
|
204 if(fd==-1) die_make(name); |
|
205 while(size--) { |
|
206 if(write(fd,"",1)!=1) die_make(name); |
|
207 } |
|
208 close(fd); |
|
209 } |
|
210 |
|
211 printf("Changing permissions of [%s] to [%o]\n",name,perm); |
|
212 if(flag_doit) if(chmod(name,perm)) die_make(name); |
|
213 printf("Changing ownership of [%s] to uid %u gid %u\n",name,uid,gid); |
|
214 if(flag_doit) if(chown(name,uid,gid)) die_make(name); |
|
215 return 0; |
|
216 } |
|
217 /*check the values*/ |
|
218 if(st.st_uid!=uid || (st.st_gid!=gid && gid!=-1)) { |
|
219 if(!flag_permfix && flag_interactive) { |
|
220 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
221 if(!confirm()) return -1; |
|
222 flag_permfix = 1; |
|
223 } |
|
224 /*fix it*/ |
|
225 printf("Changing ownership of [%s] to uid %u gid %u\n",name,uid,gid); |
|
226 if(flag_doit) if(chown(name,uid,gid)) die_make(name); |
|
227 } |
|
228 if((st.st_mode & 07777) != perm) { |
|
229 if(!flag_permfix && flag_interactive) { |
|
230 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
231 if(!confirm()) return -1; |
|
232 flag_permfix = 1; |
|
233 } |
|
234 /*fix it*/ |
|
235 printf("Changing permissions of [%s] to [%o]\n",name,perm); |
|
236 if(flag_doit) if(chmod(name,perm)) die_make(name); |
|
237 } |
|
238 if(st.st_size!=size) { |
|
239 printf("%s is not the right size. I will not fix it, please investigate.\n",name); |
|
240 } |
|
241 return 0; |
|
242 case 'p': /*a named pipe*/ |
|
243 if(stat(name,&st)) { |
|
244 if(errno!=error_noent) return -1; |
|
245 if(!flag_filecreate && flag_interactive) { |
|
246 printf("It looks like some files don't exist, should I create them? (Y/n)\n"); |
|
247 if(!confirm()) return -1; |
|
248 flag_filecreate = 1; |
|
249 } |
|
250 /*create it*/ |
|
251 printf("Creating fifo [%s]\n",name); |
|
252 if(flag_doit) if(fifo_make(name,perm)) die_make(name); |
|
253 printf("Changing permissions of [%s] to [%o]\n",name,perm); |
|
254 if(flag_doit) if(chmod(name,perm)) die_make(name); |
|
255 printf("Changing ownership of [%s] to uid %u gid %u\n",name,uid,gid); |
|
256 if(flag_doit) if(chown(name,uid,gid)) die_make(name); |
|
257 return 0; |
|
258 } |
|
259 /*check the values*/ |
|
260 if(st.st_uid!=uid || (st.st_gid!=gid && gid!=-1)) { |
|
261 if(!flag_permfix && flag_interactive) { |
|
262 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
263 if(!confirm()) return -1; |
|
264 flag_permfix = 1; |
|
265 } |
|
266 /*fix it*/ |
|
267 printf("Changing ownership of [%s] to uid %u gid %u\n",name,uid,gid); |
|
268 if(flag_doit) if(chown(name,uid,gid)) die_make(name); |
|
269 } |
|
270 if((st.st_mode & 07777) != perm) { |
|
271 if(!flag_permfix && flag_interactive) { |
|
272 printf("It looks like some permissions are wrong, should I fix them? (Y/n)\n"); |
|
273 if(!confirm()) return -1; |
|
274 flag_permfix = 1; |
|
275 } |
|
276 /*fix it*/ |
|
277 printf("Changing permissions of [%s] to [%o]\n",name,perm); |
|
278 if(flag_doit) if(chmod(name,perm)) die_make(name); |
|
279 } |
|
280 return 0; |
|
281 } /*end switch*/ |
|
282 |
|
283 return 0; |
|
284 } |
|
285 |
|
286 int check_files(char * directory, int uid, int gid, int perm) |
|
287 { |
|
288 DIR * dir; |
|
289 direntry * d; |
|
290 |
|
291 dir = opendir(directory); |
|
292 if(!dir) return -1; |
|
293 while((d = readdir(dir))) { |
|
294 if(d->d_name[0]=='.') continue; |
|
295 if(!stralloc_copys(&temp_filename,directory)) die_nomem(); |
|
296 if(!stralloc_append(&temp_filename,"/")) die_nomem(); |
|
297 if(!stralloc_cats(&temp_filename,d->d_name)) die_nomem(); |
|
298 if(!stralloc_0(&temp_filename)) die_nomem(); |
|
299 if(check_item(temp_filename.s,uid,gid,perm,'f',0)) { closedir(dir); return -1; } |
|
300 } |
|
301 closedir(dir); |
|
302 return 0; |
|
303 } |
|
304 |
|
305 void warn_files(char * directory) |
|
306 { |
|
307 DIR * dir; |
|
308 direntry * d; |
|
309 int found = 0; |
|
310 |
|
311 dir = opendir(directory); |
|
312 if(!dir) return; |
|
313 |
|
314 while((d = readdir(dir))) { |
|
315 if(d->d_name[0]=='.') continue; |
|
316 found = 1; |
|
317 break; |
|
318 } |
|
319 |
|
320 closedir(dir); |
|
321 |
|
322 if(found) { |
|
323 printf("Found files in %s that shouldn't be there.\n" |
|
324 "I will not remove them. You should consider checking it out.\n\n",directory); |
|
325 } |
|
326 } |
|
327 |
|
328 int check_splits(char * directory, int dir_uid, int dir_gid, int dir_perm, |
|
329 int file_gid, int file_perm) |
|
330 { |
|
331 DIR * dir; |
|
332 direntry * d; |
|
333 int i; |
|
334 |
|
335 for(i=0;i<SPLIT_NUM;i++) { |
|
336 name_num[fmt_ulong(name_num,i)]=0; |
|
337 if(!stralloc_copys(&temp_dirname,directory)) die_nomem(); |
|
338 if(!stralloc_append(&temp_dirname,"/")) die_nomem(); |
|
339 if(!stralloc_cats(&temp_dirname,name_num)) die_nomem(); |
|
340 if(!stralloc_0(&temp_dirname)) die_nomem(); |
|
341 /*check the split dir*/ |
|
342 if(check_item(temp_dirname.s,dir_uid,dir_gid,dir_perm,'d',0)) return -1; |
|
343 /*check its contents*/ |
|
344 dir = opendir(temp_dirname.s); |
|
345 if(!dir) return -1; |
|
346 while((d = readdir(dir))) { |
|
347 if(d->d_name[0]=='.') continue; |
|
348 if(!stralloc_copy(&temp_filename,&temp_dirname)) die_nomem(); |
|
349 temp_filename.len--; /*remove NUL*/ |
|
350 if(!stralloc_append(&temp_filename,"/")) die_nomem(); |
|
351 if(!stralloc_cats(&temp_filename,d->d_name)) die_nomem(); |
|
352 if(!stralloc_0(&temp_filename)) die_nomem(); |
|
353 if(check_item(temp_filename.s,dir_uid,file_gid,file_perm,'f',0)) { closedir(dir); return -1; } |
|
354 } |
|
355 closedir(dir); |
|
356 } /*end for*/ |
|
357 return 0; |
|
358 } |
|
359 |
|
360 int rename_mess(char * dir, char * part, char * new_part, char * old_filename, char * new_filename) |
|
361 { |
|
362 struct stat st; |
|
363 |
|
364 if(flag_interactive && !flag_namefix) { |
|
365 printf("It looks like some files need to be renamed, should I rename them? (Y/n)\n"); |
|
366 if(!confirm()) return -1; |
|
367 flag_namefix = 1; |
|
368 } |
|
369 /*prepare the old filename*/ |
|
370 if(!stralloc_copy(&old_name,&queue_dir)) die_nomem(); |
|
371 if(!stralloc_cats(&old_name,dir)) die_nomem(); |
|
372 if(!stralloc_cats(&old_name,part)) die_nomem(); |
|
373 if(!stralloc_append(&old_name,"/")) die_nomem(); |
|
374 if(!stralloc_cats(&old_name,old_filename)) die_nomem(); |
|
375 if(!stralloc_0(&old_name)) die_nomem(); |
|
376 |
|
377 /*prepare the new filename*/ |
|
378 if(!stralloc_copy(&new_name,&queue_dir)) die_nomem(); |
|
379 if(!stralloc_cats(&new_name,dir)) die_nomem(); |
|
380 if(!stralloc_cats(&new_name,new_part)) die_nomem(); |
|
381 if(!stralloc_append(&new_name,"/")) die_nomem(); |
|
382 if(!stralloc_cats(&new_name,new_filename)) die_nomem(); |
|
383 if(!stralloc_0(&new_name)) die_nomem(); |
|
384 |
|
385 /*check if destination exists*/ |
|
386 if(stat(new_name.s,&st)==0) { |
|
387 /*it exists*/ |
|
388 new_name.len--; /*remove NUL*/ |
|
389 /*append an extension to prevent name clash*/ |
|
390 if(!stralloc_cats(&new_name,".tmp")) die_nomem(); |
|
391 if(!stralloc_0(&new_name)) die_nomem(); |
|
392 /*do a double check for collision*/ |
|
393 if(stat(new_name.s,&st)==0) die_rerun(); |
|
394 } |
|
395 |
|
396 printf("Renaming [%s] to [%s]\n",old_name.s,new_name.s); |
|
397 if(flag_doit) { |
|
398 if(rename(old_name.s,new_name.s)) { |
|
399 if(errno!=error_noent) { |
|
400 return -1; |
|
401 } |
|
402 } |
|
403 } |
|
404 return 0; |
|
405 } |
|
406 |
|
407 int fix_part(char * part,int part_num) |
|
408 { |
|
409 DIR * dir; |
|
410 direntry * d; |
|
411 struct stat st; |
|
412 char inode[FMT_ULONG]; |
|
413 char new_part[FMT_ULONG]; |
|
414 int old_inode; |
|
415 int correct_part_num; |
|
416 |
|
417 if(!stralloc_copy(&mess_dir,&queue_dir)) die_nomem(); |
|
418 if(!stralloc_cats(&mess_dir,"mess/")) die_nomem(); |
|
419 if(!stralloc_cats(&mess_dir,part)) die_nomem(); |
|
420 if(!stralloc_0(&mess_dir)) die_nomem(); |
|
421 |
|
422 dir = opendir(mess_dir.s); |
|
423 if(!dir) return -1; |
|
424 |
|
425 while((d = readdir(dir))) { |
|
426 if(d->d_name[0]=='.') continue; |
|
427 /*check from mess*/ |
|
428 if(!stralloc_copy(&temp_filename,&mess_dir)) die_nomem(); |
|
429 temp_filename.len--; /*remove NUL*/ |
|
430 if(!stralloc_append(&temp_filename,"/")) die_nomem(); |
|
431 if(!stralloc_cats(&temp_filename,d->d_name)) die_nomem(); |
|
432 if(!stralloc_0(&temp_filename)) die_nomem(); |
|
433 if(stat(temp_filename.s,&st)) { closedir(dir); return -1; } |
|
434 |
|
435 /*check that filename==inode number*/ |
|
436 /*check that inode%auto_split==part_num*/ |
|
437 scan_ulong(d->d_name,&old_inode); |
|
438 correct_part_num = st.st_ino % SPLIT_NUM; |
|
439 if(st.st_ino != old_inode || |
|
440 part_num!=correct_part_num) { |
|
441 /*rename*/ |
|
442 inode[fmt_ulong(inode,st.st_ino)]=0; |
|
443 new_part[fmt_ulong(new_part,correct_part_num)]=0; |
|
444 if(rename_mess("mess/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } |
|
445 if(rename_mess("info/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } |
|
446 if(rename_mess("local/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } |
|
447 if(rename_mess("remote/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } |
|
448 |
|
449 if(rename_mess("intd","","",d->d_name,inode)) { closedir(dir); return -1; } |
|
450 if(rename_mess("todo","","",d->d_name,inode)) { closedir(dir); return -1; } |
|
451 if(rename_mess("bounce","","",d->d_name,inode)) { closedir(dir); return -1; } |
|
452 } |
|
453 } |
|
454 |
|
455 closedir(dir); |
|
456 return 0; |
|
457 } |
|
458 |
|
459 int clean_tmp(char * directory, char * part) |
|
460 { |
|
461 DIR * dir; |
|
462 direntry * d; |
|
463 struct stat st; |
|
464 int length; |
|
465 |
|
466 if(!stralloc_copy(&mess_dir,&queue_dir)) die_nomem(); |
|
467 if(!stralloc_cats(&mess_dir,directory)) die_nomem(); |
|
468 if(!stralloc_cats(&mess_dir,part)) die_nomem(); |
|
469 if(!stralloc_0(&mess_dir)) die_nomem(); |
|
470 |
|
471 dir = opendir(mess_dir.s); |
|
472 if(!dir) return -1; |
|
473 |
|
474 while((d = readdir(dir))) { |
|
475 if(d->d_name[0]=='.') continue; |
|
476 |
|
477 /*check for tmp extension*/ |
|
478 length = str_len(d->d_name); |
|
479 if(length>4) { |
|
480 if(str_equal(d->d_name+length-4,".tmp")) { |
|
481 /*remove the extension*/ |
|
482 if(!stralloc_copys(&temp_filename,d->d_name)) die_nomem(); |
|
483 temp_filename.len-=4; |
|
484 if(!stralloc_0(&temp_filename)) die_nomem(); |
|
485 |
|
486 if(rename_mess(directory,part,part,d->d_name,temp_filename.s)) { closedir(dir); return -1; } |
|
487 } |
|
488 } |
|
489 } |
|
490 |
|
491 closedir(dir); |
|
492 return 0; |
|
493 } |
|
494 |
|
495 int fix_names() |
|
496 { |
|
497 int i; |
|
498 |
|
499 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
500 if(!stralloc_cats(&check_dir,"mess")) die_nomem(); |
|
501 if(!stralloc_0(&check_dir)) die_nomem(); |
|
502 |
|
503 /*make the filenames match their inode*/ |
|
504 for(i=0;i<SPLIT_NUM;i++) { |
|
505 name_num[fmt_ulong(name_num,i)]=0; |
|
506 if(fix_part(name_num,i)) return -1; |
|
507 } |
|
508 |
|
509 /*clean up any tmp files*/ |
|
510 for(i=0;i<SPLIT_NUM;i++) { |
|
511 name_num[fmt_ulong(name_num,i)]=0; |
|
512 if(clean_tmp("mess/",name_num)) return -1; |
|
513 if(clean_tmp("info/",name_num)) return -1; |
|
514 if(clean_tmp("local/",name_num)) return -1; |
|
515 if(clean_tmp("remote/",name_num)) return -1; |
|
516 } |
|
517 if(clean_tmp("intd","")) return -1; |
|
518 if(clean_tmp("todo","")) return -1; |
|
519 if(clean_tmp("bounce","")) return -1; |
|
520 |
|
521 return 0; |
|
522 } |
|
523 |
|
524 int check_dirs() |
|
525 { |
|
526 /*check root existence*/ |
|
527 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
528 if(!stralloc_0(&check_dir)) die_nomem(); |
|
529 if(check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; |
|
530 |
|
531 /*check the big 4*/ |
|
532 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
533 if(!stralloc_cats(&check_dir,"info")) die_nomem(); |
|
534 if(!stralloc_0(&check_dir)) die_nomem(); |
|
535 if(check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; |
|
536 if(check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1; |
|
537 |
|
538 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
539 if(!stralloc_cats(&check_dir,"mess")) die_nomem(); |
|
540 if(!stralloc_0(&check_dir)) die_nomem(); |
|
541 if(check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; |
|
542 if(check_splits(check_dir.s,qmailq_uid,qmail_gid,0750,-1,0644)) return -1; |
|
543 |
|
544 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
545 if(!stralloc_cats(&check_dir,"remote")) die_nomem(); |
|
546 if(!stralloc_0(&check_dir)) die_nomem(); |
|
547 if(check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; |
|
548 if(check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1; |
|
549 |
|
550 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
551 if(!stralloc_cats(&check_dir,"local")) die_nomem(); |
|
552 if(!stralloc_0(&check_dir)) die_nomem(); |
|
553 if(check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; |
|
554 if(check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1; |
|
555 |
|
556 /*check the others*/ |
|
557 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
558 if(!stralloc_cats(&check_dir,"todo")) die_nomem(); |
|
559 if(!stralloc_0(&check_dir)) die_nomem(); |
|
560 if(check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; |
|
561 if(check_files(check_dir.s,qmailq_uid,-1,0644)) return -1; |
|
562 |
|
563 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
564 if(!stralloc_cats(&check_dir,"intd")) die_nomem(); |
|
565 if(!stralloc_0(&check_dir)) die_nomem(); |
|
566 if(check_item(check_dir.s,qmailq_uid,qmail_gid,0700,'d',0)) return -1; |
|
567 if(check_files(check_dir.s,qmailq_uid,-1,0644)) return -1; |
|
568 |
|
569 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
570 if(!stralloc_cats(&check_dir,"bounce")) die_nomem(); |
|
571 if(!stralloc_0(&check_dir)) die_nomem(); |
|
572 if(check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; |
|
573 if(check_files(check_dir.s,qmails_uid,qmail_gid,0600)) return -1; |
|
574 |
|
575 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
576 if(!stralloc_cats(&check_dir,"pid")) die_nomem(); |
|
577 if(!stralloc_0(&check_dir)) die_nomem(); |
|
578 if(check_item(check_dir.s,qmailq_uid,qmail_gid,0700,'d',0)) return -1; |
|
579 warn_files(check_dir.s); |
|
580 |
|
581 /*lock has special files that must exist*/ |
|
582 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
583 if(!stralloc_cats(&check_dir,"lock")) die_nomem(); |
|
584 if(!stralloc_0(&check_dir)) die_nomem(); |
|
585 if(check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; |
|
586 |
|
587 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
588 if(!stralloc_cats(&check_dir,"lock/sendmutex")) die_nomem(); |
|
589 if(!stralloc_0(&check_dir)) die_nomem(); |
|
590 if(check_item(check_dir.s,qmails_uid,qmail_gid,0600,'z',0)) return -1; |
|
591 |
|
592 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
593 if(!stralloc_cats(&check_dir,"lock/tcpto")) die_nomem(); |
|
594 if(!stralloc_0(&check_dir)) die_nomem(); |
|
595 if(check_item(check_dir.s,qmailr_uid,qmail_gid,0644,'z',1024)) return -1; |
|
596 |
|
597 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
598 if(!stralloc_cats(&check_dir,"lock/trigger")) die_nomem(); |
|
599 if(!stralloc_0(&check_dir)) die_nomem(); |
|
600 if(check_item(check_dir.s,qmails_uid,qmail_gid,0622,'p',0)) return -1; |
|
601 |
|
602 return 0; |
|
603 } |
|
604 |
|
605 int check_strays(char * directory) |
|
606 { |
|
607 DIR * dir; |
|
608 direntry * d; |
|
609 struct stat st; |
|
610 int inode; |
|
611 int part; |
|
612 char new_part[FMT_ULONG]; |
|
613 |
|
614 dir = opendir(directory); |
|
615 if(!dir) return -1; |
|
616 |
|
617 while((d = readdir(dir))) { |
|
618 if(d->d_name[0]=='.') continue; |
|
619 |
|
620 scan_ulong(d->d_name,&inode); |
|
621 part = inode % SPLIT_NUM; |
|
622 new_part[fmt_ulong(new_part,part)]=0; |
|
623 |
|
624 /*check for corresponding entry in mess dir*/ |
|
625 if(!stralloc_copy(&mess_dir,&queue_dir)) die_nomem(); |
|
626 if(!stralloc_cats(&mess_dir,"mess/")) die_nomem(); |
|
627 if(!stralloc_cats(&mess_dir,new_part)) die_nomem(); |
|
628 if(!stralloc_append(&mess_dir,"/")) die_nomem(); |
|
629 if(!stralloc_cats(&mess_dir,d->d_name)) die_nomem(); |
|
630 if(!stralloc_0(&mess_dir)) die_nomem(); |
|
631 |
|
632 if(stat(mess_dir.s,&st)) { |
|
633 /*failed to find in mess*/ |
|
634 if(flag_interactive && !flag_unlink) { |
|
635 printf("There are some stray files in %s\n",directory); |
|
636 printf("Should I remove them? (Y/n)\n"); |
|
637 if(!confirm()) { |
|
638 closedir(dir); |
|
639 return -1; |
|
640 } |
|
641 flag_unlink = 1; |
|
642 } |
|
643 if(!stralloc_copys(&temp_filename,directory)) die_nomem(); |
|
644 if(!stralloc_append(&temp_filename,"/")) die_nomem(); |
|
645 if(!stralloc_cats(&temp_filename,d->d_name)) die_nomem(); |
|
646 if(!stralloc_0(&temp_filename)) die_nomem(); |
|
647 |
|
648 printf("Unlinking [%s]\n",temp_filename.s); |
|
649 if(flag_doit) if(unlink(temp_filename.s)==-1) { closedir(dir); return -1; } |
|
650 } |
|
651 } |
|
652 |
|
653 closedir(dir); |
|
654 return 0; |
|
655 } |
|
656 |
|
657 int check_stray_parts() |
|
658 { |
|
659 int i; |
|
660 |
|
661 for(i=0;i<SPLIT_NUM;i++) { |
|
662 name_num[fmt_ulong(name_num,i)]=0; |
|
663 if(!stralloc_copy(&temp_dirname,&check_dir)) die_nomem(); |
|
664 if(!stralloc_append(&temp_dirname,"/")) die_nomem(); |
|
665 if(!stralloc_cats(&temp_dirname,name_num)) die_nomem(); |
|
666 if(!stralloc_0(&temp_dirname)) die_nomem(); |
|
667 /*check this dir for strays*/ |
|
668 if(check_strays(temp_dirname.s)) return -1; |
|
669 } |
|
670 return 0; |
|
671 } |
|
672 |
|
673 int find_strays() |
|
674 { |
|
675 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
676 if(!stralloc_cats(&check_dir,"info")) die_nomem(); |
|
677 if(check_stray_parts()) return -1; |
|
678 |
|
679 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
680 if(!stralloc_cats(&check_dir,"local")) die_nomem(); |
|
681 if(check_stray_parts()) return -1; |
|
682 |
|
683 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
684 if(!stralloc_cats(&check_dir,"remote")) die_nomem(); |
|
685 if(check_stray_parts()) return -1; |
|
686 |
|
687 |
|
688 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
689 if(!stralloc_cats(&check_dir,"todo")) die_nomem(); |
|
690 if(!stralloc_0(&check_dir)) die_nomem(); |
|
691 if(check_strays(check_dir.s)) return -1; |
|
692 |
|
693 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
694 if(!stralloc_cats(&check_dir,"intd")) die_nomem(); |
|
695 if(!stralloc_0(&check_dir)) die_nomem(); |
|
696 if(check_strays(check_dir.s)) return -1; |
|
697 |
|
698 if(!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); |
|
699 if(!stralloc_cats(&check_dir,"bounce")) die_nomem(); |
|
700 if(!stralloc_0(&check_dir)) die_nomem(); |
|
701 if(check_strays(check_dir.s)) return -1; |
|
702 |
|
703 return 0; |
|
704 } |
|
705 |
|
706 int main(int argc, char ** argv) |
|
707 { |
|
708 struct passwd * pw; |
|
709 struct group * gr; |
|
710 |
|
711 if(argc<2 || !argv[1] || !argv[1][0]) { |
|
712 die_args(); |
|
713 } |
|
714 |
|
715 if(str_diff(argv[1],"-i")==0) { |
|
716 flag_interactive = 1; |
|
717 argv++; |
|
718 if(!argv[1] || !argv[1][0]) die_args(); |
|
719 } else if(str_diff(argv[1],"-N")==0) { |
|
720 printf("Running in test mode, no changes will be made.\n"); |
|
721 flag_doit = 0; |
|
722 argv++; |
|
723 if(!argv[1] || !argv[1][0]) die_args(); |
|
724 } |
|
725 |
|
726 if(!stralloc_copys(&queue_dir,argv[1])) die_nomem(); |
|
727 if(queue_dir.s[queue_dir.len-1]!='/') { |
|
728 if(!stralloc_append(&queue_dir,"/")) die_nomem(); |
|
729 } |
|
730 |
|
731 /*prepare the uid and gid*/ |
|
732 pw = getpwnam("qmailq"); |
|
733 if(!pw) die_user("qmailq"); |
|
734 qmailq_uid = pw->pw_uid; |
|
735 |
|
736 pw = getpwnam("qmails"); |
|
737 if(!pw) die_user("qmails"); |
|
738 qmails_uid = pw->pw_uid; |
|
739 |
|
740 pw = getpwnam("qmailr"); |
|
741 if(!pw) die_user("qmailr"); |
|
742 qmailr_uid = pw->pw_uid; |
|
743 |
|
744 gr = getgrnam("qmail"); |
|
745 if(!gr) die_group("qmail"); |
|
746 qmail_gid = gr->gr_gid; |
|
747 |
|
748 /*check that all the proper directories exist with proper credentials*/ |
|
749 if(check_dirs()) die_check(); |
|
750 /*rename inode filenames*/ |
|
751 if(fix_names()) die_check(); |
|
752 /*check for stray files*/ |
|
753 if(find_strays()) die_check(); |
|
754 |
|
755 printf("queue-fix finished...\n"); |
|
756 return 0; |
|
757 } |