/** * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/" * * Returns the count of host records that were moved. * * Note that if any error occurs during this process, some monitor * records may be left in the "sm" directory. */ unsigned int nsm_retire_monitored_hosts(void) { unsigned int count = 0; struct dirent *de; char *path; DIR *dir; path = nsm_make_pathname(NSM_MONITOR_DIR); if (path == NULL) { xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR); return count; } dir = opendir(path); free(path); if (dir == NULL) { xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m"); return count; } while ((de = readdir(dir)) != NULL) { char *src, *dst; if (de->d_type != (unsigned char)DT_REG) continue; if (de->d_name[0] == '.') continue; src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name); if (src == NULL) { xlog_warn("Bad monitor file name, skipping"); continue; } dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name); if (dst == NULL) { free(src); xlog_warn("Bad notify file name, skipping"); continue; } if (rename(src, dst) == -1) xlog_warn("Failed to rename %s -> %s: %m", src, dst); else { xlog(D_GENERAL, "Retired record for mon_name %s", de->d_name); count++; } free(dst); free(src); } (void)closedir(dir); return count; }
/** * nsm_insert_monitored_host - write callback data for one host to disk * @hostname: C string containing a hostname * @sap: sockaddr containing NLM callback address * @mon: SM_MON arguments to save * * Returns true if successful, otherwise false if some error occurs. */ _Bool nsm_insert_monitored_host(const char *hostname, const struct sockaddr *sap, const struct mon *m) { static char buf[LINELEN + 1 + SM_MAXSTRLEN + 2]; char *path; _Bool result = false; ssize_t len; size_t size; int fd; path = nsm_make_record_pathname(NSM_MONITOR_DIR, hostname); if (path == NULL) { xlog(L_ERROR, "Failed to insert: bad monitor hostname '%s'", hostname); return false; } size = nsm_create_monitor_record(buf, sizeof(buf), sap, m); if (size == 0) { xlog(L_ERROR, "Failed to insert: record too long"); goto out; } /* * If exclusive create fails, we're adding a new line to an * existing file. */ fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_SYNC, S_IRUSR | S_IWUSR); if (fd == -1) { if (errno != EEXIST) { xlog(L_ERROR, "Failed to insert: creating %s: %m", path); goto out; } result = nsm_append_monitored_host(path, buf); goto out; } result = true; len = write(fd, buf, size); if (exact_error_check(len, size)) { xlog_warn("Failed to insert: writing %s: %m", path); (void)unlink(path); result = false; } if (close(fd) == -1) { xlog(L_ERROR, "Failed to insert: closing %s: %m", path); (void)unlink(path); result = false; } out: free(path); return result; }
/* * Given a filename, reads data from a file under "directory" * and invokes @func so caller can populate their in-core * database with this data. */ static unsigned int nsm_load_host(const char *directory, const char *filename, nsm_populate_t func) { char buf[LINELEN + 1 + SM_MAXSTRLEN + 2]; unsigned int result = 0; struct stat stb; char *path; FILE *f; path = nsm_make_record_pathname(directory, filename); if (path == NULL) goto out_err; if (lstat(path, &stb) == -1) { xlog(L_ERROR, "Failed to stat %s: %m", path); goto out_freepath; } if (!S_ISREG(stb.st_mode)) { xlog(D_GENERAL, "Skipping non-regular file %s", path); goto out_freepath; } f = fopen(path, "r"); if (f == NULL) { xlog(L_ERROR, "Failed to open %s: %m", path); goto out_freepath; } while (fgets(buf, (int)sizeof(buf), f) != NULL) { buf[sizeof(buf) - 1] = '\0'; result += nsm_read_line(filename, stb.st_mtime, buf, func); } if (result == 0) xlog(L_ERROR, "Failed to read monitor data from %s", path); (void)fclose(f); out_freepath: free(path); out_err: return result; }
/** * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/" * * Returns the count of host records that were moved. * * Note that if any error occurs during this process, some monitor * records may be left in the "sm" directory. */ unsigned int nsm_retire_monitored_hosts(void) { unsigned int count = 0; struct dirent *de; char *path; DIR *dir; path = nsm_make_pathname(NSM_MONITOR_DIR); if (path == NULL) { xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR); return count; } dir = opendir(path); free(path); if (dir == NULL) { xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m"); return count; } while ((de = readdir(dir)) != NULL) { char *src, *dst; struct stat stb; if (de->d_name[0] == '.') continue; src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name); if (src == NULL) { xlog_warn("Bad monitor file name, skipping"); continue; } /* NB: not all file systems fill in d_type correctly */ if (lstat(src, &stb) == -1) { xlog_warn("Bad monitor file %s, skipping: %m", de->d_name); free(src); continue; } if (!S_ISREG(stb.st_mode)) { xlog(D_GENERAL, "Skipping non-regular file %s", de->d_name); free(src); continue; } dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name); if (dst == NULL) { free(src); xlog_warn("Bad notify file name, skipping"); continue; } if (rename(src, dst) == -1) xlog_warn("Failed to rename %s -> %s: %m", src, dst); else { xlog(D_GENERAL, "Retired record for mon_name %s", de->d_name); count++; } free(dst); free(src); } (void)closedir(dir); return count; }
static void nsm_delete_host(const char *directory, const char *hostname, const char *mon_name, const char *my_name) { char line[LINELEN + 1 + SM_MAXSTRLEN + 2]; char *outbuf = NULL; struct stat stb; char *path, *next; size_t remaining; FILE *f; path = nsm_make_record_pathname(directory, hostname); if (path == NULL) { xlog(L_ERROR, "Bad filename, not deleting"); return; } if (stat(path, &stb) == -1) { xlog(L_ERROR, "Failed to delete: " "could not stat original file %s: %m", path); goto out; } remaining = (size_t)stb.st_size + 1; outbuf = malloc(remaining); if (outbuf == NULL) { xlog(L_ERROR, "Failed to delete: no memory"); goto out; } f = fopen(path, "r"); if (f == NULL) { xlog(L_ERROR, "Failed to delete: " "could not open original file %s: %m", path); goto out; } /* * Walk the records in the file, and copy the non-matching * ones to our output buffer. */ next = outbuf; while (fgets(line, (int)sizeof(line), f) != NULL) { struct sockaddr_in sin; struct mon m; size_t len; if (!nsm_parse_line(line, &sin, &m)) { xlog(L_ERROR, "Failed to delete: " "could not parse original file %s", path); (void)fclose(f); goto out; } if (strcmp(mon_name, m.mon_id.mon_name) == 0 && strcmp(my_name, m.mon_id.my_id.my_name) == 0) continue; /* nsm_parse_line destroys the contents of line[], so * reconstruct the copy in our output buffer. */ len = nsm_create_monitor_record(next, remaining, (struct sockaddr *)(char *)&sin, &m); if (len == 0) { xlog(L_ERROR, "Failed to delete: " "could not construct output record"); (void)fclose(f); goto out; } next += len; remaining -= len; } (void)fclose(f); /* * If nothing was copied when we're done, then unlink the file. * Otherwise, atomically update the contents of the file. */ if (next != outbuf) { if (!nsm_atomic_write(path, outbuf, strlen(outbuf))) xlog(L_ERROR, "Failed to delete: " "could not write new file %s: %m", path); } else { if (unlink(path) == -1) xlog(L_ERROR, "Failed to delete: " "could not unlink file %s: %m", path); } out: free(outbuf); free(path); }