From: Baptiste Daroussin Date: Wed, 8 Dec 2021 09:19:28 +0000 (+0100) Subject: unsubscribe: move the code for reusability X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=be25a4f17ae7b9b7294aef0d577e69f981d9573f;p=thirdparty%2Fmlmmj.git unsubscribe: move the code for reusability --- diff --git a/include/subscriberfuncs.h b/include/subscriberfuncs.h index fc63576c..6e7e4939 100644 --- a/include/subscriberfuncs.h +++ b/include/subscriberfuncs.h @@ -33,5 +33,6 @@ enum subtype is_subbed(struct mlmmj_list *list, const char *address, int both); int open_subscriber_directory(struct mlmmj_list *list, enum subtype typesub, const char **subdir); void change_uid(struct mlmmj_list *list); char *lowercase(const char *address); +void unsubscribe(struct mlmmj_list *list, const char *address, enum subtype typesub, enum subreason reasonsub); #endif /* SUBSCRIBERFUNC_H */ diff --git a/src/mlmmj-unsub.c b/src/mlmmj-unsub.c index e6e6a013..48827056 100644 --- a/src/mlmmj-unsub.c +++ b/src/mlmmj-unsub.c @@ -217,46 +217,6 @@ static void generate_unsubconfirm(struct mlmmj_list *list, const char *subaddr, exit(EXIT_FAILURE); } -static ssize_t unsubscribe(int subreadfd, int subwritefd, const char *address) -{ - off_t suboff = find_subscriber(subreadfd, address); - struct stat st; - char *inmap; - size_t len = strlen(address) + 1; /* + 1 for the '\n' */ - ssize_t writeres = 0, written = 0; - - if(suboff == -1) - return -1; /* Did not find subscriber */ - - if(fstat(subreadfd, &st) < 0) { - log_error(LOG_ARGS, "Could not stat subreadfd"); - return -1; - } - - if((inmap = mmap(0, st.st_size, PROT_READ, MAP_SHARED, - subreadfd, 0)) == MAP_FAILED) { - log_error(LOG_ARGS, "Could not mmap subreadfd"); - return -1; - } - - if(suboff > 0) { - writeres = dprintf(subwritefd, "%.*s", (int)suboff, inmap); - if(writeres < 0) - return -1; - } - written += writeres; - - writeres = dprintf(subwritefd, "%.*s", (int)(st.st_size - len - suboff), - inmap + len + suboff); - if(writeres < 0) - return -1; - - written += writeres; - - munmap(inmap, st.st_size); - - return written; -} static void print_help(const char *prg) { @@ -308,112 +268,6 @@ static void generate_notsubscribed(struct mlmmj_list *list, const char *subaddr, exit(EXIT_FAILURE); } -static void unsubscribe_type(struct mlmmj_list *list, - char *address, - enum subtype typesub, enum subreason reasonsub) { - const char *subdir; - char *sublockname; - char *subwritename; - int subread, subwrite, sublockfd; - int groupwritable = 0; - int unsubres; - struct stat st; - DIR *subddir; - struct dirent *dp; - off_t suboff; - int subdirfd; - - subdirfd = open_subscriber_directory(list, typesub, &subdir); - if (fstat(subdirfd, &st) == 0) { - if(st.st_mode & S_IWGRP) { - groupwritable = S_IRGRP|S_IWGRP; - umask(S_IWOTH); - } - } - - if((subddir = fdopendir(subdirfd)) == NULL) { - log_error(LOG_ARGS, "Could not opendir(%s/%s)", - list->dir, subdir); - exit(EXIT_FAILURE); - } - - while((dp = readdir(subddir)) != NULL) { - if(!strcmp(dp->d_name, ".")) - continue; - if(!strcmp(dp->d_name, "..")) - continue; - - subread = openat(subdirfd, dp->d_name, O_RDWR|O_EXLOCK); - if(subread == -1) - continue; - - suboff = find_subscriber(subread, address); - if(suboff == -1) { - close(subread); - continue; - } - - /* create a .name.lock file and aquire the lock */ - myasprintf(&sublockname, ".%s.lock", dp->d_name); - sublockfd = open(sublockname, O_RDWR | O_CREAT | O_EXLOCK, - S_IRUSR | S_IWUSR); - if (sublockfd < 0) { - log_error(LOG_ARGS, "Error opening lock file %s/%s/%s", - list->dir, subdir, sublockname); - myfree(sublockname); - continue; - } - - myasprintf(&subwritename, "%s.new", dp->d_name); - subwrite = openat(subdirfd, subwritename, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, - S_IRUSR | S_IWUSR | groupwritable); - if(subwrite == -1){ - log_error(LOG_ARGS, "Could not open '%s/%s/%s'", - list->dir, subdir, subwritename); - close(subread); - close(sublockfd); - myfree(subwritename); - myfree(sublockname); - continue; - } - - unsubres = unsubscribe(subread, subwrite, address); - if(unsubres < 0) { - close(subread); - close(subwrite); - close(sublockfd); - unlink(subwritename); - myfree(subwritename); - myfree(sublockname); - continue; - } - - if(unsubres > 0) { - if(renameat(subdirfd, subwritename, subdirfd, dp->d_name) < 0) { - log_error(LOG_ARGS, - "Could not rename '%s' to '%s'", - subwritename, dp->d_name); - close(subread); - close(subwrite); - myfree(subwritename); - continue; - } - } else { /* unsubres == 0, no subscribers left */ - unlinkat(subdirfd, subwritename, 0); - } - - close(subread); - close(subwrite); - close(sublockfd); - myfree(subwritename); - unlinkat(subdirfd, sublockname, 0); - myfree(sublockname); - - } - - closedir(subddir); -} - int main(int argc, char **argv) { int opt; @@ -543,11 +397,11 @@ int main(int argc, char **argv) generate_unsubconfirm(&list, address, typesub, reasonsub); if (typesub == SUB_ALL) { - unsubscribe_type(&list, address, SUB_NORMAL, reasonsub); - unsubscribe_type(&list, address, SUB_DIGEST, reasonsub); - unsubscribe_type(&list, address, SUB_NOMAIL, reasonsub); + unsubscribe(&list, address, SUB_NORMAL, reasonsub); + unsubscribe(&list, address, SUB_DIGEST, reasonsub); + unsubscribe(&list, address, SUB_NOMAIL, reasonsub); } else { - unsubscribe_type(&list, address, typesub, reasonsub); + unsubscribe(&list, address, typesub, reasonsub); } if(confirmunsub) { diff --git a/src/subscriberfuncs.c b/src/subscriberfuncs.c index 8f2709ed..89198d95 100644 --- a/src/subscriberfuncs.c +++ b/src/subscriberfuncs.c @@ -237,3 +237,151 @@ lowercase(const char *address) return (loweraddress); } +static ssize_t +real_unsubscribe(int subreadfd, int subwritefd, const char *address) +{ + off_t suboff = find_subscriber(subreadfd, address); + struct stat st; + char *inmap; + size_t len = strlen(address) + 1; /* + 1 for the '\n' */ + ssize_t writeres = 0, written = 0; + + if(suboff == -1) + return -1; /* Did not find subscriber */ + + if(fstat(subreadfd, &st) < 0) { + log_error(LOG_ARGS, "Could not stat subreadfd"); + return -1; + } + + if((inmap = mmap(0, st.st_size, PROT_READ, MAP_SHARED, + subreadfd, 0)) == MAP_FAILED) { + log_error(LOG_ARGS, "Could not mmap subreadfd"); + return -1; + } + + if(suboff > 0) { + writeres = dprintf(subwritefd, "%.*s", (int)suboff, inmap); + if(writeres < 0) + return -1; + } + written += writeres; + + writeres = dprintf(subwritefd, "%.*s", (int)(st.st_size - len - suboff), + inmap + len + suboff); + if(writeres < 0) + return -1; + + written += writeres; + + munmap(inmap, st.st_size); + + return written; +} +void +unsubscribe(struct mlmmj_list *list, const char *address, enum subtype typesub, + enum subreason reasonsub) +{ + + const char *subdir; + char *sublockname; + char *subwritename; + int subread, subwrite, sublockfd; + int groupwritable = 0; + int unsubres; + struct stat st; + DIR *subddir; + struct dirent *dp; + off_t suboff; + int subdirfd; + + subdirfd = open_subscriber_directory(list, typesub, &subdir); + if (fstat(subdirfd, &st) == 0) { + if(st.st_mode & S_IWGRP) { + groupwritable = S_IRGRP|S_IWGRP; + umask(S_IWOTH); + } + } + + if((subddir = fdopendir(subdirfd)) == NULL) { + log_error(LOG_ARGS, "Could not opendir(%s/%s)", + list->dir, subdir); + exit(EXIT_FAILURE); + } + + while((dp = readdir(subddir)) != NULL) { + if(!strcmp(dp->d_name, ".")) + continue; + if(!strcmp(dp->d_name, "..")) + continue; + + subread = openat(subdirfd, dp->d_name, O_RDWR|O_EXLOCK); + if(subread == -1) + continue; + + suboff = find_subscriber(subread, address); + if(suboff == -1) { + close(subread); + continue; + } + + /* create a .name.lock file and aquire the lock */ + myasprintf(&sublockname, ".%s.lock", dp->d_name); + sublockfd = open(sublockname, O_RDWR | O_CREAT | O_EXLOCK, + S_IRUSR | S_IWUSR); + if (sublockfd < 0) { + log_error(LOG_ARGS, "Error opening lock file %s/%s/%s", + list->dir, subdir, sublockname); + myfree(sublockname); + continue; + } + + myasprintf(&subwritename, "%s.new", dp->d_name); + subwrite = openat(subdirfd, subwritename, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, + S_IRUSR | S_IWUSR | groupwritable); + if(subwrite == -1){ + log_error(LOG_ARGS, "Could not open '%s/%s/%s'", + list->dir, subdir, subwritename); + close(subread); + close(sublockfd); + myfree(subwritename); + myfree(sublockname); + continue; + } + + unsubres = real_unsubscribe(subread, subwrite, address); + if(unsubres < 0) { + close(subread); + close(subwrite); + close(sublockfd); + unlink(subwritename); + myfree(subwritename); + myfree(sublockname); + continue; + } + + if(unsubres > 0) { + if(renameat(subdirfd, subwritename, subdirfd, dp->d_name) < 0) { + log_error(LOG_ARGS, + "Could not rename '%s' to '%s'", + subwritename, dp->d_name); + close(subread); + close(subwrite); + myfree(subwritename); + continue; + } + } else { /* unsubres == 0, no subscribers left */ + unlinkat(subdirfd, subwritename, 0); + } + + close(subread); + close(subwrite); + close(sublockfd); + myfree(subwritename); + unlinkat(subdirfd, sublockname, 0); + myfree(sublockname); + + } + + closedir(subddir); +}