changeset 334:0a3a4868fd3c

-d option for mlmmj-maintd to work on all listdirs below the specified one
author mmj
date Sat, 11 Sep 2004 08:48:42 +1000
parents d70614c2d99e
children 64540601d8a8
files ChangeLog VERSION man/mlmmj-maintd.1 src/mlmmj-maintd.c
diffstat 4 files changed, 177 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Sep 10 17:15:44 2004 +1000
+++ b/ChangeLog	Sat Sep 11 08:48:42 2004 +1000
@@ -1,3 +1,5 @@
+ o Implement -d option for mlmmj-maintd to be able to supply it with a directory
+   containing several listdirs, where mlmmj-maintd then will run maintenance
  o Chown option and a fix for mlmmj-make-ml.sh. Thanks Ingo Lameter
 1.0.0
  o Replace index() with strchr()
--- a/VERSION	Fri Sep 10 17:15:44 2004 +1000
+++ b/VERSION	Sat Sep 11 08:48:42 2004 +1000
@@ -1,1 +1,1 @@
-1.0.0
+1.0.1
--- a/man/mlmmj-maintd.1	Fri Sep 10 17:15:44 2004 +1000
+++ b/man/mlmmj-maintd.1	Sat Sep 11 08:48:42 2004 +1000
@@ -3,7 +3,9 @@
 mlmmj-maintd \- maintenance for mlmmj maintained lists
 .SH SYNOPSIS
 .B mlmmj-maintd
-\fI-L /path/to/listdir \fR[\fI-F\fR]
+[\fI-F\fR] \fI[-d\fR | \fI-L\fR] /path/to/dir
+.HP
+\fB\-d\fR: Full path to directory with lists
 .HP
 \fB\-L\fR: Full path to list directory
 .HP
@@ -15,6 +17,12 @@
 requests for e.g. subscription, resend list mails and clean up leftover files
 etc.
 
+If a directory containing several lists exists, the \fB\-d\fR can be used to
+specify this, making mlmmj-maintd perform a maintenance run in every listdir
+below the specified one.
+
+Only either \fB\-d\fR or \fB\-L\fR can be specified at the same time.
+
 It will run as a daemon, unless the \fB\-F\fR switch is specified, in which
 case it just runs once.  The \fB\-F\fR  option should be used when one wants to
 avoid running another daemon, and use e.g. cron to control it instead. In case
@@ -23,10 +31,6 @@
 
 .LP
 0 */2 * * * /usr/bin/mlmmj-maintd -F -L /path/to/list
-.SH BUGS
-It's not yet possible to tell mlmmj-maintd to perform maintenance on all
-lists (directories) in a directory yet. It's a high priority TODO item, so
-expect it soonish.
 .SH AUTHORS
 This manual page was written by the following persons:
 .HP
--- a/src/mlmmj-maintd.c	Fri Sep 10 17:15:44 2004 +1000
+++ b/src/mlmmj-maintd.c	Sat Sep 11 08:48:42 2004 +1000
@@ -47,8 +47,11 @@
 
 static void print_help(const char *prg)
 {
-	printf("Usage: %s -L /path/to/listdir [-F]\n"
-	       " -L: Full path to list directory\n"
+	printf("Usage: %s [-L | -d] /path/to/dir [-F]\n"
+	       " -d: Full path to directory with listdirs\n"
+	       "     Use this to run maintenance on all list directories\n"
+	       "     in that directory.\n"
+	       " -L: Full path to one list directory\n"
 	       " -F: Don't fork, performing one maintenance run only.\n"
 	       "     This option should be used when one wants to\n"
 	       "     avoid running another daemon, and use e.g."
@@ -737,99 +740,50 @@
 	return 0;
 }
 
-int main(int argc, char **argv)
+void do_maintenance(const char *listdir, const char *mlmmjsend,
+		    const char *mlmmjbounce, const char *mlmmjunsub)
 {
-	int opt, daemonize = 1;
-	char *bindir, *listdir = NULL, *mlmmjsend, *mlmmjbounce, *mlmmjunsub;
-	char *logstr, *logname, *random;
+	char *random, *logname, *logstr;
 	struct stat st;
-	uid_t uid;
-
-	CHECKFULLPATH(argv[0]);
-
-	log_set_name(argv[0]);
+	int maintdlogfd;
+	uid_t uid = getuid();
 
-	while ((opt = getopt(argc, argv, "hFVL:")) != -1) {
-		switch(opt) {
-		case 'F':
-			daemonize = 0;
-			break;
-		case 'L':
-			listdir = optarg;
-			break;
-		case 'h':
-			print_help(argv[0]);
-			break;
-		case 'V':
-			print_version(argv[0]);
-			exit(0);
-		}
+	if(!listdir)
+		return;
+	
+	if(stat(listdir, &st) < 0) {
+		log_error(LOG_ARGS, "Could not stat(%s) "
+				    "No maintenance run performed.", listdir);
+		return;
 	}
 
-	if(listdir == NULL) {
-		fprintf(stderr, "You have to specify -L\n");
-		fprintf(stderr, "%s -h for help\n", argv[0]);
-		exit(EXIT_FAILURE);
+	if(uid == 0) { /* We're root. Do something about it.*/
+		if(setuid(st.st_uid) < 0) {
+			log_error(LOG_ARGS, "Could not setuid listdir owner.");
+			return;
+		}
+	} else if(uid != st.st_uid) {
+		log_error(LOG_ARGS,
+				"User ID not equal to the ID of %s. No "
+				"maintenance run performed.", listdir);
+		return;
 	}
 
 	if(chdir(listdir) < 0) {
-		log_error(LOG_ARGS, "Could not chdir(%s), exiting. "
-				    "No maintenance performed.", listdir);
-		exit(EXIT_FAILURE);
+		log_error(LOG_ARGS, "Could not chdir(%s). "
+				    "No maintenance run performed.", listdir);
+		return;
 	}
 
-	/* sanity check since maintd should be invoked as root so it can
-	 * setuid or as the owner of listdir */
-
-	if(listdir) {
-		if(stat(listdir, &st) == 0) {
-			uid = getuid();
-			if(uid && uid != st.st_uid) {
-				log_error(LOG_ARGS,
-					"Have to invoke either as root "
-					"or as the user owning listdir");
-				writen(STDERR_FILENO,
-					"Have to invoke either as root "
-					"or as the user owning listdir\n", 60);
-				exit(EXIT_FAILURE);
-			}
-		} else {
-			log_error(LOG_ARGS, "Could not stat %s", listdir);
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	if(uid == 0) { /* We're root. chown the logfile and setuid */
-		chown(logname, st.st_uid, st.st_gid);
-
-		if(setuid(st.st_uid) < 0) {
-			log_error(LOG_ARGS, "Could not setuid listdir owner");
-			exit(EXIT_FAILURE);
-		}
-	}
-	
-	bindir = mydirname(argv[0]);
-	mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
-	mlmmjbounce = concatstr(2, bindir, "/mlmmj-bounce");
-	mlmmjunsub = concatstr(2, bindir, "/mlmmj-unsub");
-	myfree(bindir);
-
-	if(daemonize && (mydaemon(listdir) < 0)) {
-		log_error(LOG_ARGS, "Could not daemonize. Only one "
-				"maintenance run will be done.");
-		daemonize = 0;
-	}
-
-	for(;;) {
 		random = random_str();
 		logname = concatstr(3, listdir, "/maintdlog-", random);
 		myfree(random);
-		maintdlogfd = open(logname, O_WRONLY|O_EXCL|O_CREAT,
-					S_IRUSR|S_IWUSR);
+
+	maintdlogfd = open(logname, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR|S_IWUSR);
 		if(maintdlogfd < 0) {
+		log_error(LOG_ARGS, "Could not open %s", logname);
 			myfree(logname);
-			log_error(LOG_ARGS, "Could not open maintenance logfile");
-			exit(EXIT_FAILURE);
+		return;
 		}
 	
 		WRITEMAINTLOG4(3, "clean_moderation(", listdir, ");\n");
@@ -864,15 +818,134 @@
 		probe_bouncers(listdir, mlmmjbounce);
 
 		close(maintdlogfd);
+
 		logstr = concatstr(3, listdir, "/", MAINTD_LOGFILE);
+
 		if(rename(logname, logstr) < 0)
 			log_error(LOG_ARGS, "Could not rename(%s,%s)",
 						logname, logstr);
 
 		myfree(logname);
 		myfree(logstr);
+}
 
-		if(daemonize == 0)
+int main(int argc, char **argv)
+{
+	int opt, daemonize = 1, ret;
+	char *bindir, *listdir = NULL, *mlmmjsend, *mlmmjbounce, *mlmmjunsub;
+	char *dirlists = NULL, *s;
+	struct stat st;
+	struct dirent *dp;
+	DIR *dirp;
+
+	CHECKFULLPATH(argv[0]);
+
+	log_set_name(argv[0]);
+
+	while ((opt = getopt(argc, argv, "hFVLd:")) != -1) {
+		switch(opt) {
+		case 'd':
+			dirlists = optarg;
+			break;
+		case 'F':
+			daemonize = 0;
+			break;
+		case 'L':
+			listdir = optarg;
+			break;
+		case 'h':
+			print_help(argv[0]);
+			break;
+		case 'V':
+			print_version(argv[0]);
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	if(listdir == NULL && dirlists == NULL) {
+		fprintf(stderr, "You have to specify -d or -L\n");
+		fprintf(stderr, "%s -h for help\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+	
+	if(listdir && dirlists) {
+		fprintf(stderr, "You have to specify either -d or -L\n");
+		fprintf(stderr, "%s -h for help\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	bindir = mydirname(argv[0]);
+	mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
+	mlmmjbounce = concatstr(2, bindir, "/mlmmj-bounce");
+	mlmmjunsub = concatstr(2, bindir, "/mlmmj-unsub");
+	myfree(bindir);
+
+	if(daemonize) {
+		if(listdir)
+			ret = mydaemon(listdir);
+		else
+			ret = mydaemon(dirlists);
+	}
+
+	if(daemonize && ret < 0) {
+		log_error(LOG_ARGS, "Could not daemonize. Only one "
+				"maintenance run will be done.");
+		daemonize = 0;
+	}
+
+	while(1) {
+		if(listdir) {
+			do_maintenance(listdir, mlmmjsend, mlmmjbounce,
+					mlmmjunsub);
+			continue;
+		}
+
+		if((dirp = opendir(dirlists)) == NULL) {
+			log_error(LOG_ARGS, "Could not opendir(%s).",
+					dirlists);
+			myfree(mlmmjbounce);
+			myfree(mlmmjsend);
+			myfree(mlmmjunsub);
+			exit(EXIT_FAILURE);
+		}
+
+		while((dp = readdir(dirp)) != NULL) {
+			if((strcmp(dp->d_name, "..") == 0) ||
+					(strcmp(dp->d_name, ".") == 0))
+				continue;
+			
+			listdir = concatstr(3, dirlists, "/", dp->d_name);
+
+			if(stat(listdir, &st) < 0) {
+				log_error(LOG_ARGS, "Could not stat(%s)",
+						listdir);
+				myfree(listdir);
+				continue;
+			}
+
+			if(!S_ISDIR(st.st_mode)) {
+				myfree(listdir);
+				continue;
+			}
+
+			s = concatstr(2, listdir, "/control/listaddress");
+			ret = stat(s, &st);
+			myfree(s);
+
+			if(ret < 0) { /* If ret < 0 it's not a listdir */
+				myfree(listdir);
+				continue;
+			}
+
+			do_maintenance(listdir, mlmmjsend, mlmmjbounce,
+					mlmmjunsub);
+
+			myfree(listdir);
+		}
+
+		closedir(dirp);
+
+		if(!daemonize)
 			break;
 		else
 			sleep(MAINTD_SLEEP);