/* * handle_extra_workdirs.c - Part of AFD, an automatic file distribution * program. * Copyright (c) 2015 - 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 ** handle_extra_workdirs - set of functions to handle the extra work ** dirs from AFD_CONFIG ** ** SYNOPSIS ** void get_extra_work_dirs(char *afd_config_buffer, ** int *no_of_extra_work_dirs, ** struct extra_work_dirs **ewl, ** int create) ** void delete_stale_extra_work_dir_links(int no_of_extra_work_dirs ** struct extra_work_dirs **ewl) ** void free_extra_work_dirs(int no_of_extra_work_dirs, ** struct extra_work_dirs **ewl) ** ** DESCRIPTION ** ** RETURN VALUES ** ** AUTHOR ** H.Kiehl ** ** HISTORY ** 04.11.2015 H.Kiehl Created ** 17.02.2018 H.Kiehl Handle case when there is no AFD_CONFIG. ** */ DESCR__E_M3 #include #include #include #include #ifdef HAVE_STATX # include /* makedev() */ # include /* Definition of AT_* constants */ #endif #include #include /* opendir(), closedir(), readdir(), */ /* DIR, struct dirent */ #include /* unlink() */ #include #include /* External global definitions. */ extern char *p_work_dir; /* Local function prototypes. */ static void scan_old_links(int, struct extra_work_dirs *, char *, int); /*####################### get_extra_work_dirs() #########################*/ void get_extra_work_dirs(char *afd_config_buffer, int *no_of_extra_work_dirs, struct extra_work_dirs **ewl, int create) { char afd_file_dir[MAX_PATH_LENGTH], *buffer = NULL, linkpath[MAX_PATH_LENGTH], *ptr, value[MAX_ADD_LOCKED_FILES_LENGTH]; #ifdef HAVE_STATX struct statx stat_buf; #else struct stat stat_buf; #endif if (afd_config_buffer == NULL) { char config_file[MAX_PATH_LENGTH]; (void)snprintf(config_file, MAX_PATH_LENGTH, "%s%s%s", p_work_dir, ETC_DIR, AFD_CONFIG_FILE); if (eaccess(config_file, F_OK) == 0) { off_t bytes_read; if ((bytes_read = read_file_no_cr(config_file, &buffer, YES, __FILE__, __LINE__)) != INCORRECT) { if (bytes_read < 6) { /* Forget it, there is nothing meaningful in it. */ free(buffer); buffer = NULL; } } } } else { buffer = afd_config_buffer; } if (buffer != NULL) { ptr = buffer; *no_of_extra_work_dirs = 1; while ((ptr = get_definition(ptr, EXTRA_WORK_DIR_DEF, value, MAX_PATH_LENGTH)) != NULL) { (*no_of_extra_work_dirs)++; } } if ((*ewl = malloc(*no_of_extra_work_dirs * sizeof(struct extra_work_dirs))) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), *no_of_extra_work_dirs * sizeof(struct extra_work_dirs), strerror(errno)); exit(INCORRECT); } /* First insert the default from AFD_WORK_DIR environment variable. */ (void)strcpy(afd_file_dir, p_work_dir); (void)strcat(afd_file_dir, AFD_FILE_DIR); #ifdef HAVE_STATX if (statx(0, afd_file_dir, AT_STATX_SYNC_AS_STAT, 0, &stat_buf) == -1) #else if (stat(afd_file_dir, &stat_buf) == -1) #endif { system_log(FATAL_SIGN, __FILE__, __LINE__, #ifdef HAVE_STATX _("Failed to statx() `%s' : %s"), #else _("Failed to stat() `%s' : %s"), #endif afd_file_dir, strerror(errno)); exit(INCORRECT); } (*ewl)[0].dir_name_length = strlen(p_work_dir); if (((*ewl)[0].dir_name = malloc((*ewl)[0].dir_name_length + 1)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), (*ewl)[0].dir_name_length, strerror(errno)); exit(INCORRECT); } (void)memcpy((*ewl)[0].dir_name, p_work_dir, (*ewl)[0].dir_name_length + 1); #ifdef HAVE_STATX (*ewl)[0].dev = makedev(stat_buf.stx_dev_major, stat_buf.stx_dev_minor); #else (*ewl)[0].dev = stat_buf.st_dev; #endif if (((*ewl)[0].afd_file_dir = malloc(MAX_PATH_LENGTH)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), MAX_PATH_LENGTH, strerror(errno)); exit(INCORRECT); } (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s/%x", p_work_dir, AFD_ARCHIVE_DIR, (unsigned int)(*ewl)[0].dev); (void)snprintf((*ewl)[0].afd_file_dir, MAX_PATH_LENGTH, "%s%s", p_work_dir, AFD_ARCHIVE_DIR); if (symlink((*ewl)[0].afd_file_dir, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp((*ewl)[0].afd_file_dir, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, (*ewl)[0].afd_file_dir, resolved_path); } if (symlink((*ewl)[0].afd_file_dir, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].afd_file_dir, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].afd_file_dir, strerror(errno)); exit(INCORRECT); } } (*ewl)[0].afd_file_dir_length = (*ewl)[0].dir_name_length + AFD_FILE_DIR_LENGTH; (void)memcpy((*ewl)[0].afd_file_dir, afd_file_dir, (*ewl)[0].afd_file_dir_length + 1); if (((*ewl)[0].outgoing_file_dir = malloc(MAX_PATH_LENGTH)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), MAX_PATH_LENGTH, strerror(errno)); exit(INCORRECT); } (*ewl)[0].outgoing_file_dir_length = (*ewl)[0].afd_file_dir_length + OUTGOING_DIR_LENGTH; (void)strcpy((*ewl)[0].outgoing_file_dir, (*ewl)[0].afd_file_dir); (void)strcpy((*ewl)[0].outgoing_file_dir + (*ewl)[0].afd_file_dir_length, OUTGOING_DIR); if (((*ewl)[0].time_dir = malloc(MAX_PATH_LENGTH)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), MAX_PATH_LENGTH, strerror(errno)); exit(INCORRECT); } (*ewl)[0].time_dir_length = (*ewl)[0].afd_file_dir_length + AFD_TIME_DIR_LENGTH; (void)strcpy((*ewl)[0].time_dir, (*ewl)[0].afd_file_dir); (void)strcpy((*ewl)[0].time_dir + (*ewl)[0].afd_file_dir_length, AFD_TIME_DIR); (*ewl)[0].p_time_dir_id = (*ewl)[0].time_dir + (*ewl)[0].time_dir_length + 1; (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s%s/%x", p_work_dir, AFD_FILE_DIR, AFD_TMP_DIR, (unsigned int)(*ewl)[0].dev); (void)snprintf((*ewl)[0].afd_file_dir + (*ewl)[0].afd_file_dir_length, MAX_INT_HEX_LENGTH, "%s", AFD_TMP_DIR); if (symlink((*ewl)[0].afd_file_dir, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp((*ewl)[0].afd_file_dir, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, (*ewl)[0].afd_file_dir, resolved_path); } if (symlink((*ewl)[0].afd_file_dir, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].afd_file_dir, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].afd_file_dir, strerror(errno)); exit(INCORRECT); } } (*ewl)[0].afd_file_dir[(*ewl)[0].afd_file_dir_length] = '\0'; (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s%s/%x", p_work_dir, AFD_FILE_DIR, OUTGOING_DIR, (unsigned int)(*ewl)[0].dev); if (symlink((*ewl)[0].outgoing_file_dir, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp((*ewl)[0].outgoing_file_dir, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, (*ewl)[0].outgoing_file_dir, resolved_path); } if (symlink((*ewl)[0].outgoing_file_dir, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].outgoing_file_dir, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].outgoing_file_dir, strerror(errno)); exit(INCORRECT); } } (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s%s/%x", p_work_dir, AFD_FILE_DIR, AFD_TIME_DIR, (unsigned int)(*ewl)[0].dev); if (symlink((*ewl)[0].time_dir, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp((*ewl)[0].time_dir, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, (*ewl)[0].time_dir, resolved_path); } if (symlink((*ewl)[0].time_dir, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].time_dir, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[0].time_dir, strerror(errno)); exit(INCORRECT); } } *((*ewl)[0].time_dir + (*ewl)[0].time_dir_length) = '/'; *((*ewl)[0].time_dir + (*ewl)[0].time_dir_length + 1) = '\0'; if (*no_of_extra_work_dirs > 1) { int i, length, ret; char created_path[MAX_PATH_LENGTH], *error_ptr, *ewdp, new_path[MAX_PATH_LENGTH]; ewdp = buffer; for (i = 1; i < *no_of_extra_work_dirs; i++) { ewdp = get_definition(ewdp, EXTRA_WORK_DIR_DEF, value, MAX_PATH_LENGTH); if (value[0] != '/') { char *p_path, user[MAX_USER_NAME_LENGTH + 1]; if (value[0] == '~') { if (value[1] == '/') { p_path = &value[2]; user[0] = '\0'; } else { int j = 0; p_path = &value[1]; while ((*(p_path + j) != '/') && (*(p_path + j) != '\0') && (j < MAX_USER_NAME_LENGTH)) { user[j] = *(p_path + j); j++; } if (j >= MAX_USER_NAME_LENGTH) { system_log(WARN_SIGN, __FILE__, __LINE__, _("User name to long for %s definition %s. User name may be %d bytes long."), EXTRA_WORK_DIR_DEF, value, MAX_USER_NAME_LENGTH); } user[j] = '\0'; } (void)expand_path(user, p_path); length = strlen(p_path); (void)memmove(value, p_path, length + 1); } else { char tmp_config_file[MAX_PATH_LENGTH]; (void)strcpy(tmp_config_file, value); length = snprintf(value, MAX_PATH_LENGTH, "%s%s/%s", p_work_dir, AFD_FILE_DIR, tmp_config_file); } } else { length = strlen(value); } /* Check create file directory. */ (void)memcpy(new_path, value, length + 1); if ((ret = check_create_path(new_path, DIR_MODE, &error_ptr, create, YES, created_path)) == CREATED_DIR) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Created extra directory `%s' [%s]", new_path, created_path); } else if (ret == NO_ACCESS) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot access directory `%s' or create a subdirectory in it.", new_path); } else if (ret == MKDIR_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot create directory `%s'.", new_path); } else if (ret == STAT_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to stat() `%s'.", new_path); } else if (ret == ALLOC_ERROR) { system_log(FATAL_SIGN, __FILE__, __LINE__, "Could not realloc() memory : %s", strerror(errno)); exit(INCORRECT); } if ((ret == SUCCESS) || (ret == CREATED_DIR)) { #ifdef HAVE_STATX if (statx(0, new_path, AT_STATX_SYNC_AS_STAT, 0, &stat_buf) == -1) #else if (stat(new_path, &stat_buf) == -1) #endif { system_log(WARN_SIGN, __FILE__, __LINE__, #ifdef HAVE_STATX "Unable to statx() `%s' : %s. Will ignore this directory.", #else "Unable to stat() `%s' : %s. Will ignore this directory.", #endif new_path, strerror(errno)); (*ewl)[i].dev = 0; (*ewl)[i].dir_name = NULL; (*ewl)[i].dir_name_length = 0; (*ewl)[i].afd_file_dir = NULL; (*ewl)[i].afd_file_dir_length = 0; (*ewl)[i].outgoing_file_dir = NULL; (*ewl)[i].outgoing_file_dir_length = 0; (*ewl)[i].time_dir = NULL; (*ewl)[i].time_dir_length = 0; } else { if (((*ewl)[i].dir_name = malloc(length + 1)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), length + 1, strerror(errno)); exit(INCORRECT); } (void)memcpy((*ewl)[i].dir_name, new_path, length + 1); (*ewl)[i].dir_name_length = length; #ifdef HAVE_STATX (*ewl)[i].dev = makedev(stat_buf.stx_dev_major, stat_buf.stx_dev_minor); #else (*ewl)[i].dev = stat_buf.st_dev; #endif ptr = new_path + length; (void)strcpy(ptr, AFD_ARCHIVE_DIR); if ((ret = check_create_path(new_path, DIR_MODE, &error_ptr, create, YES, created_path)) == CREATED_DIR) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Created extra directory `%s' [%s]", new_path, created_path); } else if (ret == NO_ACCESS) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot access directory `%s' or create a subdirectory in it.", new_path); } else if (ret == MKDIR_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot create directory `%s'.", new_path); } else if (ret == STAT_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to stat() `%s'.", new_path); } else if (ret == ALLOC_ERROR) { system_log(FATAL_SIGN, __FILE__, __LINE__, "Could not realloc() memory : %s", strerror(errno)); exit(INCORRECT); } if ((ret == SUCCESS) || (ret == CREATED_DIR)) { (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s/%x", p_work_dir, AFD_ARCHIVE_DIR, (unsigned int)(*ewl)[i].dev); if (symlink(new_path, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp(new_path, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, new_path, resolved_path); } if (symlink(new_path, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, new_path, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, new_path, strerror(errno)); exit(INCORRECT); } } (void)strcpy(ptr, AFD_FILE_DIR); if ((ret = check_create_path(new_path, DIR_MODE, &error_ptr, create, YES, created_path)) == CREATED_DIR) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Created extra directory `%s' [%s]", new_path, created_path); } else if (ret == NO_ACCESS) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot access directory `%s' or create a subdirectory in it.", new_path); } else if (ret == MKDIR_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot create directory `%s'.", new_path); } else if (ret == STAT_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to stat() `%s'.", new_path); } else if (ret == ALLOC_ERROR) { system_log(FATAL_SIGN, __FILE__, __LINE__, "Could not realloc() memory : %s", strerror(errno)); exit(INCORRECT); } if ((ret == SUCCESS) || (ret == CREATED_DIR)) { if (((*ewl)[i].afd_file_dir = malloc(MAX_PATH_LENGTH)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), MAX_PATH_LENGTH, strerror(errno)); exit(INCORRECT); } (*ewl)[i].afd_file_dir_length = length + AFD_FILE_DIR_LENGTH; (void)memcpy((*ewl)[i].afd_file_dir, new_path, (*ewl)[i].afd_file_dir_length + 1); /* Check create pool directory. */ ptr += AFD_FILE_DIR_LENGTH; (void)strcpy(ptr, AFD_TMP_DIR); if ((ret = check_create_path(new_path, DIR_MODE, &error_ptr, create, YES, created_path)) == CREATED_DIR) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Created extra directory `%s' [%s]", new_path, created_path); } else if (ret == NO_ACCESS) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot access directory `%s' or create a subdirectory in it.", new_path); } else if (ret == MKDIR_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot create directory `%s'.", new_path); } else if (ret == STAT_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to stat() `%s'.", new_path); } else if (ret == ALLOC_ERROR) { system_log(FATAL_SIGN, __FILE__, __LINE__, "Could not realloc() memory : %s", strerror(errno)); exit(INCORRECT); } if ((ret == SUCCESS) || (ret == CREATED_DIR)) { (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s%s/%x", p_work_dir, AFD_FILE_DIR, AFD_TMP_DIR, (unsigned int)(*ewl)[i].dev); if (symlink(new_path, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp(new_path, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, new_path, resolved_path); } if (symlink(new_path, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, new_path, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, new_path, strerror(errno)); exit(INCORRECT); } } /* Check create outgoing_file_dir. */ (void)strcpy(ptr, OUTGOING_DIR); if ((ret = check_create_path(new_path, DIR_MODE, &error_ptr, create, YES, created_path)) == CREATED_DIR) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Created extra directory `%s' [%s]", new_path, created_path); } else if (ret == NO_ACCESS) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot access directory `%s' or create a subdirectory in it.", new_path); } else if (ret == MKDIR_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot create directory `%s'.", new_path); } else if (ret == STAT_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to stat() `%s'.", new_path); } else if (ret == ALLOC_ERROR) { system_log(FATAL_SIGN, __FILE__, __LINE__, "Could not realloc() memory : %s", strerror(errno)); exit(INCORRECT); } if ((ret == SUCCESS) || (ret == CREATED_DIR)) { if (((*ewl)[i].outgoing_file_dir = malloc(MAX_PATH_LENGTH)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), MAX_PATH_LENGTH, strerror(errno)); exit(INCORRECT); } (*ewl)[i].outgoing_file_dir_length = length + AFD_FILE_DIR_LENGTH + OUTGOING_DIR_LENGTH; (void)memcpy((*ewl)[i].outgoing_file_dir, new_path, (*ewl)[i].outgoing_file_dir_length + 1); (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s%s/%x", p_work_dir, AFD_FILE_DIR, OUTGOING_DIR, (unsigned int)(*ewl)[i].dev); if (symlink((*ewl)[i].outgoing_file_dir, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp((*ewl)[i].outgoing_file_dir, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, (*ewl)[i].outgoing_file_dir, resolved_path); } if (symlink((*ewl)[i].outgoing_file_dir, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[i].outgoing_file_dir, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[i].outgoing_file_dir, strerror(errno)); exit(INCORRECT); } } /* Check create time_dir. */ (void)strcpy(ptr, AFD_TIME_DIR); if ((ret = check_create_path(new_path, DIR_MODE, &error_ptr, create, YES, created_path)) == CREATED_DIR) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Created extra directory `%s' [%s]", new_path, created_path); } else if (ret == NO_ACCESS) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot access directory `%s' or create a subdirectory in it.", new_path); } else if (ret == MKDIR_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot create directory `%s'.", new_path); } else if (ret == STAT_ERROR) { if (error_ptr != NULL) { *error_ptr = '\0'; } system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to stat() `%s'.", new_path); } else if (ret == ALLOC_ERROR) { system_log(FATAL_SIGN, __FILE__, __LINE__, "Could not realloc() memory : %s", strerror(errno)); exit(INCORRECT); } if ((ret == SUCCESS) || (ret == CREATED_DIR)) { if (((*ewl)[i].time_dir = malloc(MAX_PATH_LENGTH)) == NULL) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to malloc() %d bytes : %s"), MAX_PATH_LENGTH, strerror(errno)); exit(INCORRECT); } (*ewl)[i].time_dir_length = length + AFD_FILE_DIR_LENGTH + AFD_TIME_DIR_LENGTH; (void)memcpy((*ewl)[i].time_dir, new_path, (*ewl)[i].time_dir_length + 1); (*ewl)[i].p_time_dir_id = (*ewl)[i].time_dir + (*ewl)[i].time_dir_length + 1; (void)snprintf(linkpath, MAX_PATH_LENGTH, "%s%s%s/%x", p_work_dir, AFD_FILE_DIR, AFD_TIME_DIR, (unsigned int)(*ewl)[i].dev); if (symlink((*ewl)[i].time_dir, linkpath) == -1) { if (errno == EEXIST) { char *resolved_path; if ((resolved_path = realpath(linkpath, NULL)) == NULL) { if (errno != ENOENT) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to get realpath() of `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } } if ((resolved_path == NULL) || (strcmp((*ewl)[i].time_dir, resolved_path) != 0)) { if (unlink(linkpath) != 0) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to unlink() `%s' : %s"), linkpath, strerror(errno)); exit(INCORRECT); } if (resolved_path == NULL) { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s'", linkpath); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Deleted wrong link `%s' [%s != %s]", linkpath, (*ewl)[i].time_dir, resolved_path); } if (symlink((*ewl)[i].time_dir, linkpath) == -1) { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[i].time_dir, strerror(errno)); exit(INCORRECT); } } free(resolved_path); } else { system_log(FATAL_SIGN, __FILE__, __LINE__, _("Failed to symlink() `%s' to `%s' : %s"), linkpath, (*ewl)[i].time_dir, strerror(errno)); exit(INCORRECT); } } *((*ewl)[i].time_dir + (*ewl)[i].time_dir_length) = '/'; *((*ewl)[i].time_dir + (*ewl)[i].time_dir_length + 1) = '\0'; } else { (*ewl)[i].time_dir = NULL; (*ewl)[i].time_dir_length = 0; } } else { (*ewl)[i].outgoing_file_dir = NULL; (*ewl)[i].outgoing_file_dir_length = 0; (*ewl)[i].time_dir = NULL; (*ewl)[i].time_dir_length = 0; } } else { (*ewl)[i].afd_file_dir = NULL; (*ewl)[i].afd_file_dir_length = 0; (*ewl)[i].outgoing_file_dir = NULL; (*ewl)[i].outgoing_file_dir_length = 0; (*ewl)[i].time_dir = NULL; (*ewl)[i].time_dir_length = 0; } } else { (*ewl)[i].afd_file_dir = NULL; (*ewl)[i].afd_file_dir_length = 0; (*ewl)[i].outgoing_file_dir = NULL; (*ewl)[i].outgoing_file_dir_length = 0; (*ewl)[i].time_dir = NULL; (*ewl)[i].time_dir_length = 0; } } else { free((*ewl)[i].dir_name); (*ewl)[i].dir_name = NULL; (*ewl)[i].dir_name_length = 0; (*ewl)[i].afd_file_dir = NULL; (*ewl)[i].afd_file_dir_length = 0; (*ewl)[i].outgoing_file_dir = NULL; (*ewl)[i].outgoing_file_dir_length = 0; (*ewl)[i].time_dir = NULL; (*ewl)[i].time_dir_length = 0; } } } else { (*ewl)[i].dir_name = NULL; (*ewl)[i].dir_name_length = 0; (*ewl)[i].dev = 0; (*ewl)[i].afd_file_dir = NULL; (*ewl)[i].afd_file_dir_length = 0; (*ewl)[i].outgoing_file_dir = NULL; (*ewl)[i].outgoing_file_dir_length = 0; (*ewl)[i].time_dir = NULL; (*ewl)[i].time_dir_length = 0; } } } if (afd_config_buffer == NULL) { free(buffer); } return; } /*############### delete_stale_extra_work_dir_links() ###################*/ void delete_stale_extra_work_dir_links(int no_of_extra_work_dirs, struct extra_work_dirs *ewl) { char search_dir[MAX_PATH_LENGTH]; /* Handle archive dir. */ (void)memcpy(search_dir, ewl[0].dir_name, ewl[0].dir_name_length); (void)memcpy(search_dir + ewl[0].dir_name_length, AFD_ARCHIVE_DIR, AFD_ARCHIVE_DIR_LENGTH); *(search_dir + ewl[0].dir_name_length + AFD_ARCHIVE_DIR_LENGTH) = '\0'; scan_old_links(no_of_extra_work_dirs, ewl, search_dir, ewl[0].dir_name_length + AFD_ARCHIVE_DIR_LENGTH); /* Handle files/pool dir. */ (void)memcpy(search_dir + ewl[0].dir_name_length, AFD_FILE_DIR, AFD_FILE_DIR_LENGTH); (void)memcpy(search_dir + ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH, AFD_TMP_DIR, AFD_TMP_DIR_LENGTH); *(search_dir + ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH + AFD_TMP_DIR_LENGTH) = '\0'; scan_old_links(no_of_extra_work_dirs, ewl, search_dir, ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH + AFD_TMP_DIR_LENGTH); /* Handle files/outgoing dir. */ (void)memcpy(search_dir + ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH, OUTGOING_DIR, OUTGOING_DIR_LENGTH); *(search_dir + ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH + OUTGOING_DIR_LENGTH) = '\0'; scan_old_links(no_of_extra_work_dirs, ewl, search_dir, ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH + OUTGOING_DIR_LENGTH); /* Handle files/time dir. */ (void)memcpy(search_dir + ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH, AFD_TIME_DIR, AFD_TIME_DIR_LENGTH); *(search_dir + ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH + AFD_TIME_DIR_LENGTH) = '\0'; scan_old_links(no_of_extra_work_dirs, ewl, search_dir, ewl[0].dir_name_length + AFD_FILE_DIR_LENGTH + AFD_TIME_DIR_LENGTH); return; } /*++++++++++++++++++++++++++ scan_old_links() +++++++++++++++++++++++++++*/ static void scan_old_links(int no_of_extra_work_dirs, struct extra_work_dirs *ewl, char *search_dir, int search_dir_length) { DIR *dp; struct dirent *p_dir; #ifdef HAVE_STATX struct statx stat_buf; #else struct stat stat_buf; #endif if ((dp = opendir(search_dir)) == NULL) { system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot opendir() `%s' : %s", search_dir, strerror(errno)); return; } *(search_dir + search_dir_length) = '/'; while ((p_dir = readdir(dp)) != NULL) { if (p_dir->d_name[0] == '.') { continue; } (void)strcpy(search_dir + search_dir_length + 1, p_dir->d_name); #ifdef HAVE_STATX if (statx(0, search_dir, AT_STATX_SYNC_AS_STAT | AT_SYMLINK_NOFOLLOW, STATX_MODE, &stat_buf) != -1) #else if (lstat(search_dir, &stat_buf) != -1) #endif { /* Only check symbolic links! */ #ifdef HAVE_STATX if (S_ISLNK(stat_buf.stx_mode)) #else if (S_ISLNK(stat_buf.st_mode)) #endif { int gotcha = NO, i; unsigned int job_id; job_id = (unsigned int)strtoul(p_dir->d_name, (char **)NULL, 16); for (i = 0; i < no_of_extra_work_dirs; i++) { if (job_id == (unsigned int)ewl[i].dev) { gotcha = YES; break; } } if (gotcha == NO) { if (unlink(search_dir) == -1) { system_log(WARN_SIGN, __FILE__, __LINE__, "Failed to remove stale link `%s'.", search_dir); } else { system_log(DEBUG_SIGN, __FILE__, __LINE__, "Removed stale link `%s'.", search_dir); } } } } } *(search_dir + search_dir_length) = '\0'; if (closedir(dp) == -1) { system_log(WARN_SIGN, __FILE__, __LINE__, "Cannot closedir() `%s' : %s", search_dir, strerror(errno)); } return; } /*###################### free_extra_work_dirs() #########################*/ void free_extra_work_dirs(int no_of_extra_work_dirs, struct extra_work_dirs **ewl) { int i; for (i = 0; i < no_of_extra_work_dirs; i++) { free((*ewl)[i].dir_name); free((*ewl)[i].time_dir); free((*ewl)[i].afd_file_dir); free((*ewl)[i].outgoing_file_dir); } free(*ewl); *ewl = NULL; return; }