/* * clear_pool_dir.c - Part of AFD, an automatic file distribution program. * Copyright (c) 1998 - 2022 Deutscher Wetterdienst (DWD), * Holger Kiehl * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "afddefs.h" DESCR__S_M3 /* ** NAME ** clear_pool_dir - moves files left in the pool directory back ** to their original directories ** ** SYNOPSIS ** void clear_pool_dir(void) ** ** DESCRIPTION ** The function clear_pool_dir() tries to moves files back to ** their original directories from the pool directory that have ** been left after a crash. If it cannot determine the original ** directory or this directory simply does not exist, these files ** will be deleted. ** ** RETURN VALUES ** None. ** ** AUTHOR ** H.Kiehl ** ** HISTORY ** 14.05.1998 H.Kiehl Created ** 28.08.2003 H.Kiehl Adapted to CRC-32 directory ID's. ** 21.01.2009 H.Kiehl No need to open DIR_NAME_FILE twice. ** 03.09.2013 H.Kiehl When we move files back report this to system log. ** */ DESCR__E_M3 #include /* sprintf() */ #include /* malloc(), free() */ #include /* strcpy(), strerror() */ #include /* isdigit() */ #include /* stat(), S_ISREG() */ #include /* read(), close(), rmdir(), R_OK ... */ #include /* opendir(), closedir(), readdir(), */ /* DIR, struct dirent */ #ifdef HAVE_FCNTL_H # include #endif #include #include "amgdefs.h" /* External global variables. */ extern int *no_of_dir_names; extern struct dir_name_buf *dnb; extern char *p_work_dir; /* Local function prototypes. */ static int get_source_dir(char *, char *, unsigned int *); static void move_files_back(char *, char *); /*########################## clear_pool_dir() ##########################*/ void clear_pool_dir(void) { char pool_dir[MAX_PATH_LENGTH], orig_dir[MAX_PATH_LENGTH]; #ifdef HAVE_STATX struct statx stat_buf; #else struct stat stat_buf; #endif (void)snprintf(pool_dir, MAX_PATH_LENGTH, "%s%s%s", p_work_dir, AFD_FILE_DIR, AFD_TMP_DIR); #ifdef HAVE_STATX if (statx(0, pool_dir, AT_STATX_SYNC_AS_STAT, 0, &stat_buf) == -1) #else if (stat(pool_dir, &stat_buf) == -1) #endif { system_log(WARN_SIGN, __FILE__, __LINE__, #ifdef HAVE_STATX "Failed to statx() %s : %s", #else "Failed to stat() %s : %s", #endif pool_dir, strerror(errno)); } else { DIR *dp; if ((dp = opendir(pool_dir)) == NULL) { system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to opendir() %s : %s", pool_dir, strerror(errno)); } else { int dnb_fd; unsigned int dir_id; char *work_ptr; struct dirent *p_dir; work_ptr = pool_dir + strlen(pool_dir); *(work_ptr++) = '/'; *work_ptr = '\0'; if (dnb == NULL) { size_t size = (DIR_NAME_BUF_SIZE * sizeof(struct dir_name_buf)) + AFD_WORD_OFFSET; char dir_name_file[MAX_PATH_LENGTH], *p_dir_buf; /* * Map to the directory name database. */ (void)strcpy(dir_name_file, p_work_dir); (void)strcat(dir_name_file, FIFO_DIR); (void)strcat(dir_name_file, DIR_NAME_FILE); if ((p_dir_buf = attach_buf(dir_name_file, &dnb_fd, &size, NULL, FILE_MODE, NO)) == (caddr_t) -1) { system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to mmap() to %s : %s", dir_name_file, strerror(errno)); (void)close(dnb_fd); (void)closedir(dp); return; } no_of_dir_names = (int *)p_dir_buf; p_dir_buf += AFD_WORD_OFFSET; dnb = (struct dir_name_buf *)p_dir_buf; } errno = 0; while ((p_dir = readdir(dp)) != NULL) { if (p_dir->d_name[0] == '.') { continue; } (void)strcpy(work_ptr, p_dir->d_name); #ifdef MULTI_FS_SUPPORT # ifdef HAVE_STATX if ((statx(0, pool_dir, AT_STATX_SYNC_AS_STAT | AT_SYMLINK_NOFOLLOW, STATX_MODE, &stat_buf) != -1) && (S_ISLNK(stat_buf.stx_mode) == 0)) # else if ((lstat(pool_dir, &stat_buf) != -1) && (S_ISLNK(stat_buf.st_mode) == 0)) # endif { #endif if (get_source_dir(p_dir->d_name, orig_dir, &dir_id) == INCORRECT) { /* Remove it, no matter what it is. */ #ifdef _DELETE_LOG remove_pool_directory(pool_dir, dir_id); #else (void)rec_rmdir(pool_dir); #endif } else { move_files_back(pool_dir, orig_dir); } #ifdef MULTI_FS_SUPPORT } #endif errno = 0; } if (errno) { system_log(ERROR_SIGN, __FILE__, __LINE__, "Could not readdir() %s : %s", pool_dir, strerror(errno)); } if (closedir(dp) == -1) { system_log(ERROR_SIGN, __FILE__, __LINE__, "Could not close directory %s : %s", pool_dir, strerror(errno)); } } } return; } /*+++++++++++++++++++++++++++ get_source_dir() ++++++++++++++++++++++++++*/ static int get_source_dir(char *dir_name, char *orig_dir, unsigned int *dir_id) { register int i = 0; *dir_id = 0; while ((dir_name[i] != '\0') && (dir_name[i] != '_')) { if (isxdigit((int)dir_name[i]) == 0) { system_log(WARN_SIGN, __FILE__, __LINE__, "Unable to determine the diretory ID for `%s'.", dir_name); return(INCORRECT); } i++; } if (dir_name[i] == '_') { i++; while ((dir_name[i] != '\0') && (dir_name[i] != '_')) { if (isxdigit((int)dir_name[i]) == 0) { system_log(WARN_SIGN, __FILE__, __LINE__, "Unable to determine the diretory ID for `%s'.", dir_name); return(INCORRECT); } i++; } if (dir_name[i] == '_') { i++; while ((dir_name[i] != '\0') && (dir_name[i] != '_')) { if (isxdigit((int)dir_name[i]) == 0) { system_log(WARN_SIGN, __FILE__, __LINE__, "Unable to determine the diretory ID for `%s'.", dir_name); return(INCORRECT); } i++; } if (dir_name[i] == '_') { int start; start = ++i; while (dir_name[i] != '\0') { if (isxdigit((int)dir_name[i]) == 0) { system_log(WARN_SIGN, __FILE__, __LINE__, "Unable to determine the diretory ID for `%s'.", dir_name); return(INCORRECT); } i++; } errno = 0; *dir_id = (unsigned int)strtoul(&dir_name[start], (char **)NULL, 16); if (errno == ERANGE) { system_log(WARN_SIGN, __FILE__, __LINE__, "Unable to determine the diretory ID for `%s'.", dir_name); return(INCORRECT); } for (i = 0; i < *no_of_dir_names; i++) { if (*dir_id == dnb[i].dir_id) { /* * Before we say this is it, check if it still does * exist! */ if (eaccess(dnb[i].dir_name, R_OK | W_OK | X_OK) == -1) { system_log(INFO_SIGN, __FILE__, __LINE__, "Cannot move files back to %s : %s", dnb[i].dir_name, strerror(errno)); return(INCORRECT); } (void)strcpy(orig_dir, dnb[i].dir_name); return(SUCCESS); } } } /* if (dir_name[i] == '_') */ } /* if (dir_name[i] == '_') */ } /* if (dir_name[i] == '_') */ return(INCORRECT); } /*+++++++++++++++++++++++++++ move_files_back() +++++++++++++++++++++++++*/ static void move_files_back(char *pool_dir, char *orig_dir) { DIR *dp; if ((dp = opendir(pool_dir)) == NULL) { system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to opendir() %s : %s", pool_dir, strerror(errno)); } else { int ret; unsigned int files_moved = 0; char *orig_ptr, *pool_ptr; struct dirent *p_dir; pool_ptr = pool_dir + strlen(pool_dir); if (*(pool_ptr - 1) != '/') { *(pool_ptr++) = '/'; } orig_ptr = orig_dir + strlen(orig_dir); if (*(orig_ptr - 1) != '/') { *(orig_ptr++) = '/'; } errno = 0; while ((p_dir = readdir(dp)) != NULL) { if (p_dir->d_name[0] == '.') { continue; } (void)strcpy(pool_ptr, p_dir->d_name); (void)strcpy(orig_ptr, p_dir->d_name); if (((ret = move_file(pool_dir, orig_dir)) < 0) || (ret == 2)) { system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to move_file() %s to %s : %s [%d]", pool_dir, orig_dir, strerror(errno), ret); } else { files_moved++; } errno = 0; } *pool_ptr = '\0'; *orig_ptr = '\0'; if (errno) { system_log(ERROR_SIGN, __FILE__, __LINE__, "Could not readdir() %s : %s", pool_dir, strerror(errno)); } if (closedir(dp) == -1) { system_log(ERROR_SIGN, __FILE__, __LINE__, "Could not close directory %s : %s", pool_dir, strerror(errno)); } /* * After all files have been moved back to their original * directory, remove the directory from the pool directory. */ if (rmdir(pool_dir) == -1) { if ((errno == ENOTEMPTY) || (errno == EEXIST)) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Hmm. Directory %s is not empty?! Will remove it!", pool_dir); (void)rec_rmdir(pool_dir); } else { system_log(WARN_SIGN, __FILE__, __LINE__, "Could not remove directory %s : %s", pool_dir, strerror(errno)); } } system_log(DEBUG_SIGN, __FILE__, __LINE__, "Moved %u files back to %s", files_moved, orig_dir); } return; }