queue-fix.c
changeset 0 c045670f36e9
equal deleted inserted replaced
-1:000000000000 0:c045670f36e9
       
     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 }