trail.c revision 285830
199461Sobrien/*- 299461Sobrien * Copyright (c) 2012 The FreeBSD Foundation 399461Sobrien * All rights reserved. 499461Sobrien * 599461Sobrien * This software was developed by Pawel Jakub Dawidek under sponsorship from 699461Sobrien * the FreeBSD Foundation. 799461Sobrien * 892828Sobrien * Redistribution and use in source and binary forms, with or without 992828Sobrien * modification, are permitted provided that the following conditions 1092828Sobrien * are met: 1192828Sobrien * 1. Redistributions of source code must retain the above copyright 1291041Sobrien * notice, this list of conditions and the following disclaimer. 1391041Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1491041Sobrien * notice, this list of conditions and the following disclaimer in the 1591041Sobrien * documentation and/or other materials provided with the distribution. 1691041Sobrien * 1791041Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1891041Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1991041Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2091041Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2191041Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2291041Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2391041Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2491041Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2591041Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2691041Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2791041Sobrien * SUCH DAMAGE. 2891041Sobrien * 2991041Sobrien * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/trail.c#3 $ 3091041Sobrien */ 3189857Sobrien 3278828Sobrien#include <config/config.h> 3389857Sobrien 3489857Sobrien#include <sys/param.h> 3578828Sobrien#include <sys/stat.h> 3689857Sobrien 3778828Sobrien#include <dirent.h> 3889857Sobrien#include <errno.h> 3978828Sobrien#include <fcntl.h> 4089857Sobrien#include <stdbool.h> 4178828Sobrien#include <stdint.h> 4289857Sobrien#include <stdlib.h> 4389857Sobrien#include <string.h> 4478828Sobrien#include <unistd.h> 4589857Sobrien 4678828Sobrien#include <compat/compat.h> 4789857Sobrien#ifndef HAVE_STRLCPY 4889857Sobrien#include <compat/strlcpy.h> 4989857Sobrien#endif 5089857Sobrien#ifndef HAVE_FACCESSAT 5189857Sobrien#include "faccessat.h" 5289857Sobrien#endif 5389857Sobrien#ifndef HAVE_FSTATAT 5489857Sobrien#include "fstatat.h" 5589857Sobrien#endif 5678828Sobrien#ifndef HAVE_OPENAT 5789857Sobrien#include "openat.h" 5889857Sobrien#endif 5989857Sobrien#ifndef HAVE_UNLINKAT 6089857Sobrien#include "unlinkat.h" 6189857Sobrien#endif 6289857Sobrien 6389857Sobrien#include "pjdlog.h" 6489857Sobrien#include "trail.h" 6589857Sobrien 6689857Sobrien#define TRAIL_MAGIC 0x79a11 6789857Sobrienstruct trail { 6889857Sobrien int tr_magic; 6989857Sobrien /* Path usually to /var/audit/dist/ directory. */ 7089857Sobrien char tr_dirname[PATH_MAX]; 7189857Sobrien /* Descriptor to td_dirname directory. */ 7289857Sobrien DIR *tr_dirfp; 7389857Sobrien /* Path to audit trail file. */ 7489857Sobrien char tr_filename[PATH_MAX]; 7589857Sobrien /* Descriptor to audit trail file. */ 7689857Sobrien int tr_filefd; 7789857Sobrien}; 7889857Sobrien 7989857Sobrien#define HALF_LEN 14 8089857Sobrien 8189857Sobrienbool 8289857Sobrientrail_is_not_terminated(const char *filename) 8389857Sobrien{ 8489857Sobrien 8589857Sobrien return (strcmp(filename + HALF_LEN, ".not_terminated") == 0); 8689857Sobrien} 8789857Sobrien 8889857Sobrienbool 8989857Sobrientrail_is_crash_recovery(const char *filename) 9089857Sobrien{ 9189857Sobrien 9289857Sobrien return (strcmp(filename + HALF_LEN, ".crash_recovery") == 0); 9389857Sobrien} 9489857Sobrien 9589857Sobrienstruct trail * 9689857Sobrientrail_new(const char *dirname, bool create) 9789857Sobrien{ 9889857Sobrien struct trail *trail; 9989857Sobrien 10089857Sobrien trail = calloc(1, sizeof(*trail)); 10189857Sobrien 10289857Sobrien if (strlcpy(trail->tr_dirname, dirname, sizeof(trail->tr_dirname)) >= 10389857Sobrien sizeof(trail->tr_dirname)) { 10489857Sobrien free(trail); 10589857Sobrien pjdlog_error("Directory name too long (\"%s\").", dirname); 10689857Sobrien errno = ENAMETOOLONG; 10789857Sobrien return (NULL); 10889857Sobrien } 10989857Sobrien trail->tr_dirfp = opendir(dirname); 11089857Sobrien if (trail->tr_dirfp == NULL) { 11189857Sobrien if (create && errno == ENOENT) { 11289857Sobrien if (mkdir(dirname, 0700) == -1) { 11389857Sobrien pjdlog_errno(LOG_ERR, 11489857Sobrien "Unable to create directory \"%s\"", 11589857Sobrien dirname); 11689857Sobrien free(trail); 11789857Sobrien return (NULL); 11889857Sobrien } 11989857Sobrien /* TODO: Set directory ownership. */ 12089857Sobrien } else { 12189857Sobrien pjdlog_errno(LOG_ERR, 12289857Sobrien "Unable to open directory \"%s\"", 12389857Sobrien dirname); 12489857Sobrien free(trail); 12589857Sobrien return (NULL); 12689857Sobrien } 12789857Sobrien trail->tr_dirfp = opendir(dirname); 12889857Sobrien if (trail->tr_dirfp == NULL) { 12989857Sobrien pjdlog_errno(LOG_ERR, 13089857Sobrien "Unable to open directory \"%s\"", 13189857Sobrien dirname); 13289857Sobrien free(trail); 13389857Sobrien return (NULL); 13489857Sobrien } 13589857Sobrien } 13689857Sobrien trail->tr_filefd = -1; 13789857Sobrien trail->tr_magic = TRAIL_MAGIC; 13889857Sobrien return (trail); 13989857Sobrien} 14089857Sobrien 14189857Sobrienvoid 14289857Sobrientrail_free(struct trail *trail) 14389857Sobrien{ 14489857Sobrien 14589857Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 14689857Sobrien 14789857Sobrien if (trail->tr_filefd != -1) 14889857Sobrien trail_close(trail); 14989857Sobrien closedir(trail->tr_dirfp); 15089857Sobrien bzero(trail, sizeof(*trail)); 15191041Sobrien trail->tr_magic = 0; 15291041Sobrien trail->tr_filefd = -1; 15391041Sobrien free(trail); 15491041Sobrien} 15591041Sobrien 15691041Sobrienstatic uint8_t 15789857Sobrientrail_type(DIR *dirfp, const char *filename) 15889857Sobrien{ 15989857Sobrien struct stat sb; 16089857Sobrien int dfd; 16189857Sobrien 16291041Sobrien PJDLOG_ASSERT(dirfp != NULL); 16391041Sobrien 16491041Sobrien dfd = dirfd(dirfp); 16591041Sobrien PJDLOG_ASSERT(dfd >= 0); 16691041Sobrien if (fstatat(dfd, filename, &sb, AT_SYMLINK_NOFOLLOW) == -1) { 16791041Sobrien pjdlog_errno(LOG_ERR, "Unable to stat \"%s\"", filename); 16891041Sobrien return (DT_UNKNOWN); 16991041Sobrien } 17091041Sobrien return (IFTODT(sb.st_mode)); 17189857Sobrien} 17289857Sobrien 17389857Sobrien/* 17489857Sobrien * Find trail file by first part of the name in case it was renamed. 17589857Sobrien * First part of the trail file name never changes, but trail file 17689857Sobrien * can be renamed when hosts are disconnected from .not_terminated 17789857Sobrien * to .[0-9]{14} or to .crash_recovery. 17889857Sobrien */ 17989857Sobrienstatic bool 18089857Sobrientrail_find(struct trail *trail) 18189857Sobrien{ 18289857Sobrien struct dirent *dp; 18389857Sobrien 18489857Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 18589857Sobrien PJDLOG_ASSERT(trail_is_not_terminated(trail->tr_filename)); 18689857Sobrien 18789857Sobrien rewinddir(trail->tr_dirfp); 18889857Sobrien while ((dp = readdir(trail->tr_dirfp)) != NULL) { 18989857Sobrien if (strncmp(dp->d_name, trail->tr_filename, HALF_LEN + 1) == 0) 19089857Sobrien break; 19189857Sobrien } 19289857Sobrien if (dp == NULL) 19389857Sobrien return (false); 19489857Sobrien PJDLOG_VERIFY(strlcpy(trail->tr_filename, dp->d_name, 19589857Sobrien sizeof(trail->tr_filename)) < sizeof(trail->tr_filename)); 19678828Sobrien return (true); 19778828Sobrien} 19878828Sobrien 19978828Sobrien/* 20078828Sobrien * Open the given trail file and move pointer at the given offset, as this is 20178828Sobrien * where receiver finished the last time. 20278828Sobrien * If the file doesn't exist or the given offset is equal to the file size, 20378828Sobrien * move to the next trail file. 20478828Sobrien */ 20578828Sobrienvoid 20678828Sobrientrail_start(struct trail *trail, const char *filename, off_t offset) 20789857Sobrien{ 20889857Sobrien struct stat sb; 20989857Sobrien int dfd, fd; 21089857Sobrien 21189857Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 21277298Sobrien 21377298Sobrien PJDLOG_VERIFY(strlcpy(trail->tr_filename, filename, 21477298Sobrien sizeof(trail->tr_filename)) < sizeof(trail->tr_filename)); 21577298Sobrien trail->tr_filefd = -1; 21677298Sobrien 21789857Sobrien if (trail->tr_filename[0] == '\0') { 21889857Sobrien PJDLOG_ASSERT(offset == 0); 21989857Sobrien trail_next(trail); 22089857Sobrien return; 22189857Sobrien } 22289857Sobrien 22389857Sobrien dfd = dirfd(trail->tr_dirfp); 22489857Sobrien PJDLOG_ASSERT(dfd >= 0); 22577298Sobrienagain: 22677298Sobrien fd = openat(dfd, trail->tr_filename, O_RDONLY); 22777298Sobrien if (fd == -1) { 22877298Sobrien if (errno == ENOENT && 22977298Sobrien trail_is_not_terminated(trail->tr_filename) && 23077298Sobrien trail_find(trail)) { 23177298Sobrien /* File was renamed. Retry with new name. */ 23277298Sobrien pjdlog_debug(1, 23389857Sobrien "Trail file was renamed since last connection to \"%s/%s\".", 23477298Sobrien trail->tr_dirname, trail->tr_filename); 23589857Sobrien goto again; 23689857Sobrien } else if (errno == ENOENT) { 23789857Sobrien /* File disappeared. */ 23889857Sobrien pjdlog_debug(1, "File \"%s/%s\" doesn't exist.", 23989857Sobrien trail->tr_dirname, trail->tr_filename); 24089857Sobrien } else { 24189857Sobrien pjdlog_errno(LOG_ERR, 24289857Sobrien "Unable to open file \"%s/%s\", skipping", 24389857Sobrien trail->tr_dirname, trail->tr_filename); 24477298Sobrien } 24577298Sobrien trail_next(trail); 24677298Sobrien return; 24789857Sobrien } 24889857Sobrien if (fstat(fd, &sb) == -1) { 24989857Sobrien pjdlog_errno(LOG_ERR, 25089857Sobrien "Unable to stat file \"%s/%s\", skipping", 25189857Sobrien trail->tr_dirname, trail->tr_filename); 25289857Sobrien close(fd); 25389857Sobrien trail_next(trail); 25489857Sobrien return; 25589857Sobrien } 25689857Sobrien if (!S_ISREG(sb.st_mode)) { 25789857Sobrien pjdlog_warning("File \"%s/%s\" is not a regular file, skipping.", 25889857Sobrien trail->tr_dirname, trail->tr_filename); 25989857Sobrien close(fd); 26089857Sobrien trail_next(trail); 26189857Sobrien return; 26277298Sobrien } 26377298Sobrien /* 26477298Sobrien * We continue sending requested file if: 26577298Sobrien * 1. It is not fully sent yet, or 26677298Sobrien * 2. It is fully sent, but is not terminated, so new data can be 26777298Sobrien * appended still, or 26877298Sobrien * 3. It is fully sent but file name has changed. 26977298Sobrien * 27077298Sobrien * Note that we are fine if our .not_terminated or .crash_recovery file 27177298Sobrien * is smaller than the one on the receiver side, as it is possible that 27277298Sobrien * more data was send to the receiver than was safely stored on disk. 27389857Sobrien * We accept .not_terminated only because auditdistd can start before 27477298Sobrien * auditd manage to rename it to .crash_recovery. 27577298Sobrien */ 27677298Sobrien if (offset < sb.st_size || 27777298Sobrien (offset >= sb.st_size && 27877298Sobrien trail_is_not_terminated(trail->tr_filename)) || 27977298Sobrien (offset >= sb.st_size && trail_is_not_terminated(filename) && 28077298Sobrien trail_is_crash_recovery(trail->tr_filename))) { 28177298Sobrien /* File was not fully send. Let's finish it. */ 28277298Sobrien if (lseek(fd, offset, SEEK_SET) == -1) { 28377298Sobrien pjdlog_errno(LOG_ERR, 28477298Sobrien "Unable to move to offset %jd within file \"%s/%s\", skipping", 28577298Sobrien (intmax_t)offset, trail->tr_dirname, 28677298Sobrien trail->tr_filename); 28777298Sobrien close(fd); 28877298Sobrien trail_next(trail); 28977298Sobrien return; 29077298Sobrien } 29177298Sobrien if (!trail_is_crash_recovery(trail->tr_filename)) { 29277298Sobrien pjdlog_debug(1, 29377298Sobrien "Restarting file \"%s/%s\" at offset %jd.", 29477298Sobrien trail->tr_dirname, trail->tr_filename, 29577298Sobrien (intmax_t)offset); 29677298Sobrien } 29777298Sobrien trail->tr_filefd = fd; 29877298Sobrien return; 29977298Sobrien } 30077298Sobrien close(fd); 30177298Sobrien if (offset > sb.st_size) { 30277298Sobrien pjdlog_warning("File \"%s/%s\" shrinked, removing it.", 30377298Sobrien trail->tr_dirname, trail->tr_filename); 30477298Sobrien } else { 30577298Sobrien pjdlog_debug(1, "File \"%s/%s\" is already sent, removing it.", 30677298Sobrien trail->tr_dirname, trail->tr_filename); 30777298Sobrien } 30877298Sobrien /* Entire file is already sent or it shirnked, we can remove it. */ 30977298Sobrien if (unlinkat(dfd, trail->tr_filename, 0) == -1) { 31077298Sobrien pjdlog_errno(LOG_WARNING, "Unable to remove file \"%s/%s\"", 31177298Sobrien trail->tr_dirname, trail->tr_filename); 31277298Sobrien } 31377298Sobrien trail_next(trail); 31477298Sobrien} 31577298Sobrien 31677298Sobrien/* 31777298Sobrien * Set next file in the trail->tr_dirname directory and open it for reading. 31877298Sobrien */ 31977298Sobrienvoid 32077298Sobrientrail_next(struct trail *trail) 32177298Sobrien{ 32277298Sobrien char curfile[PATH_MAX]; 32377298Sobrien struct dirent *dp; 32477298Sobrien int dfd; 32577298Sobrien 32677298Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 32777298Sobrien PJDLOG_ASSERT(trail->tr_filefd == -1); 32889857Sobrien 32977298Sobrienagain: 33077298Sobrien curfile[0] = '\0'; 33177298Sobrien 33277298Sobrien rewinddir(trail->tr_dirfp); 33377298Sobrien while ((dp = readdir(trail->tr_dirfp)) != NULL) { 33477298Sobrien if (dp->d_name[0] < '0' || dp->d_name[0] > '9') 33577298Sobrien continue; 33677298Sobrien if (dp->d_type == DT_UNKNOWN) 33777298Sobrien dp->d_type = trail_type(trail->tr_dirfp, dp->d_name); 33877298Sobrien /* We are only interested in regular files, skip the rest. */ 33977298Sobrien if (dp->d_type != DT_REG) { 34077298Sobrien pjdlog_debug(1, 34177298Sobrien "File \"%s/%s\" is not a regular file, skipping.", 34277298Sobrien trail->tr_dirname, dp->d_name); 34377298Sobrien continue; 34477298Sobrien } 34577298Sobrien /* Skip all files "greater" than curfile. */ 34677298Sobrien if (curfile[0] != '\0' && strcmp(dp->d_name, curfile) > 0) 34777298Sobrien continue; 34877298Sobrien /* Skip all files "smaller" than the current trail_filename. */ 34977298Sobrien if (trail->tr_filename[0] != '\0' && 35077298Sobrien strcmp(dp->d_name, trail->tr_filename) <= 0) { 35177298Sobrien continue; 35277298Sobrien } 35389857Sobrien PJDLOG_VERIFY(strlcpy(curfile, dp->d_name, sizeof(curfile)) < 35477298Sobrien sizeof(curfile)); 35577298Sobrien } 35677298Sobrien if (curfile[0] == '\0') { 35777298Sobrien /* 35877298Sobrien * There are no new trail files, so we return. 35977298Sobrien * We don't clear trail_filename string, to know where to 36077298Sobrien * start when new file appears. 36189857Sobrien */ 36277298Sobrien PJDLOG_ASSERT(trail->tr_filefd == -1); 36377298Sobrien pjdlog_debug(1, "No new trail files."); 36477298Sobrien return; 36577298Sobrien } 36677298Sobrien PJDLOG_VERIFY(strlcpy(trail->tr_filename, curfile, 36777298Sobrien sizeof(trail->tr_filename)) < sizeof(trail->tr_filename)); 36877298Sobrien dfd = dirfd(trail->tr_dirfp); 36977298Sobrien PJDLOG_ASSERT(dfd >= 0); 37077298Sobrien trail->tr_filefd = openat(dfd, trail->tr_filename, O_RDONLY); 37177298Sobrien if (trail->tr_filefd == -1) { 37277298Sobrien pjdlog_errno(LOG_ERR, 37377298Sobrien "Unable to open file \"%s/%s\", skipping", 37477298Sobrien trail->tr_dirname, trail->tr_filename); 37589857Sobrien goto again; 37677298Sobrien } 37777298Sobrien pjdlog_debug(1, "Found next trail file: \"%s/%s\".", trail->tr_dirname, 37889857Sobrien trail->tr_filename); 37977298Sobrien} 38077298Sobrien 38177298Sobrien/* 38289857Sobrien * Close current trial file. 38377298Sobrien */ 38489857Sobrienvoid 38589857Sobrientrail_close(struct trail *trail) 38677298Sobrien{ 38789857Sobrien 38889857Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 38989857Sobrien PJDLOG_ASSERT(trail->tr_filefd >= 0); 39077298Sobrien PJDLOG_ASSERT(trail->tr_filename[0] != '\0'); 39177298Sobrien 39277298Sobrien PJDLOG_VERIFY(close(trail->tr_filefd) == 0); 39377298Sobrien trail->tr_filefd = -1; 39477298Sobrien} 39577298Sobrien 39677298Sobrien/* 39777298Sobrien * Reset trail state. Used when connection is disconnected and we will 39877298Sobrien * need to start over after reconnect. Trail needs to be already closed. 39977298Sobrien */ 40077298Sobrienvoid 40177298Sobrientrail_reset(struct trail *trail) 40277298Sobrien{ 40377298Sobrien 40478828Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 40578828Sobrien PJDLOG_ASSERT(trail->tr_filefd == -1); 40678828Sobrien 40778828Sobrien trail->tr_filename[0] = '\0'; 40877298Sobrien} 40977298Sobrien 41077298Sobrien/* 41177298Sobrien * Unlink current trial file. 41277298Sobrien */ 41377298Sobrienvoid 41477298Sobrientrail_unlink(struct trail *trail, const char *filename) 41577298Sobrien{ 41677298Sobrien int dfd; 41777298Sobrien 41878828Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 41978828Sobrien PJDLOG_ASSERT(filename != NULL); 42078828Sobrien PJDLOG_ASSERT(filename[0] != '\0'); 42178828Sobrien 42278828Sobrien dfd = dirfd(trail->tr_dirfp); 42378828Sobrien PJDLOG_ASSERT(dfd >= 0); 42478828Sobrien 42578828Sobrien if (unlinkat(dfd, filename, 0) == -1) { 42678828Sobrien pjdlog_errno(LOG_ERR, "Unable to remove \"%s/%s\"", 42778828Sobrien trail->tr_dirname, filename); 42878828Sobrien } else { 42978828Sobrien pjdlog_debug(1, "Trail file \"%s/%s\" removed.", 43078828Sobrien trail->tr_dirname, filename); 43178828Sobrien } 43278828Sobrien} 43378828Sobrien 43478828Sobrien/* 43578828Sobrien * Return true if we should switch to next trail file. 43678828Sobrien * We don't switch if our file name ends with ".not_terminated" and it 43778828Sobrien * exists (ie. wasn't renamed). 43878828Sobrien */ 43978828Sobrienbool 44078828Sobrientrail_switch(struct trail *trail) 44177298Sobrien{ 44277298Sobrien char filename[PATH_MAX]; 44377298Sobrien int fd; 44477298Sobrien 44577298Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 44677298Sobrien PJDLOG_ASSERT(trail->tr_filefd >= 0); 44777298Sobrien 44877298Sobrien if (!trail_is_not_terminated(trail->tr_filename)) 44977298Sobrien return (true); 45077298Sobrien fd = dirfd(trail->tr_dirfp); 45177298Sobrien PJDLOG_ASSERT(fd >= 0); 45277298Sobrien if (faccessat(fd, trail->tr_filename, F_OK, 0) == 0) 45377298Sobrien return (false); 45477298Sobrien if (errno != ENOENT) { 45577298Sobrien pjdlog_errno(LOG_ERR, "Unable to access file \"%s/%s\"", 45677298Sobrien trail->tr_dirname, trail->tr_filename); 45777298Sobrien } 45877298Sobrien strlcpy(filename, trail->tr_filename, sizeof(filename)); 45977298Sobrien if (!trail_find(trail)) { 46077298Sobrien pjdlog_error("Trail file \"%s/%s\" disappeared.", 46177298Sobrien trail->tr_dirname, trail->tr_filename); 46277298Sobrien return (true); 46377298Sobrien } 46477298Sobrien pjdlog_debug(1, "Trail file \"%s/%s\" was renamed to \"%s/%s\".", 46577298Sobrien trail->tr_dirname, filename, trail->tr_dirname, 46677298Sobrien trail->tr_filename); 46777298Sobrien return (true); 46877298Sobrien} 46977298Sobrien 47061843Sobrienconst char * 47161843Sobrientrail_filename(const struct trail *trail) 47261843Sobrien{ 47361843Sobrien 47477298Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 47561843Sobrien 47677298Sobrien return (trail->tr_filename); 47761843Sobrien} 47877298Sobrien 47977298Sobrienint 48077298Sobrientrail_filefd(const struct trail *trail) 48177298Sobrien{ 48277298Sobrien 48377298Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 48477298Sobrien 48577298Sobrien return (trail->tr_filefd); 48677298Sobrien} 48777298Sobrien 48877298Sobrienint 48977298Sobrientrail_dirfd(const struct trail *trail) 49077298Sobrien{ 49177298Sobrien 49277298Sobrien PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 49377298Sobrien 49477298Sobrien return (dirfd(trail->tr_dirfp)); 49577298Sobrien} 49661843Sobrien 49761843Sobrien/* 49861843Sobrien * Find the last file in the directory opened under dirfp. 49977298Sobrien */ 50061843Sobrienvoid 50177298Sobrientrail_last(DIR *dirfp, char *filename, size_t filenamesize) 50261843Sobrien{ 50377298Sobrien char curfile[PATH_MAX]; 50477298Sobrien struct dirent *dp; 50577298Sobrien 50677298Sobrien PJDLOG_ASSERT(dirfp != NULL); 50777298Sobrien 50877298Sobrien curfile[0] = '\0'; 50977298Sobrien 51077298Sobrien rewinddir(dirfp); 51177298Sobrien while ((dp = readdir(dirfp)) != NULL) { 51277298Sobrien if (dp->d_name[0] < '0' || dp->d_name[0] > '9') 51377298Sobrien continue; 51477298Sobrien if (dp->d_type == DT_UNKNOWN) 51577298Sobrien dp->d_type = trail_type(dirfp, dp->d_name); 51677298Sobrien /* We are only interested in regular files, skip the rest. */ 51777298Sobrien if (dp->d_type != DT_REG) 51877298Sobrien continue; 51977298Sobrien /* Skip all files "greater" than curfile. */ 52077298Sobrien if (curfile[0] != '\0' && strcmp(dp->d_name, curfile) < 0) 52177298Sobrien continue; 52277298Sobrien PJDLOG_VERIFY(strlcpy(curfile, dp->d_name, sizeof(curfile)) < 52377298Sobrien sizeof(curfile)); 52477298Sobrien } 52577298Sobrien if (curfile[0] == '\0') { 52677298Sobrien /* 52760484Sobrien * There are no trail files, so we return. 52860484Sobrien */ 52960484Sobrien pjdlog_debug(1, "No trail files."); 53060484Sobrien bzero(filename, filenamesize); 53160484Sobrien return; 53260484Sobrien } 53360484Sobrien PJDLOG_VERIFY(strlcpy(filename, curfile, filenamesize) < filenamesize); 53460484Sobrien pjdlog_debug(1, "Found the most recent trail file: \"%s\".", filename); 53560484Sobrien} 53660484Sobrien 53760484Sobrien/* 53860484Sobrien * Check if the given file name is a valid audit trail file name. 53960484Sobrien * Possible names: 54060484Sobrien * 20120106132657.20120106132805 54160484Sobrien * 20120106132657.not_terminated 54260484Sobrien * 20120106132657.crash_recovery 54360484Sobrien * If two names are given, check if the first name can be renamed 54460484Sobrien * to the second name. When renaming, first part of the name has 54560484Sobrien * to be identical and only the following renames are valid: 54660484Sobrien * 20120106132657.not_terminated -> 20120106132657.20120106132805 54760484Sobrien * 20120106132657.not_terminated -> 20120106132657.crash_recovery 54860484Sobrien */ 54960484Sobrienbool 55060484Sobrientrail_validate_name(const char *srcname, const char *dstname) 55160484Sobrien{ 55260484Sobrien int i; 55360484Sobrien 55460484Sobrien PJDLOG_ASSERT(srcname != NULL); 55560484Sobrien 55660484Sobrien if (strlen(srcname) != 2 * HALF_LEN + 1) 55760484Sobrien return (false); 55860484Sobrien if (srcname[HALF_LEN] != '.') 55960484Sobrien return (false); 56060484Sobrien for (i = 0; i < HALF_LEN; i++) { 56160484Sobrien if (srcname[i] < '0' || srcname[i] > '9') 56260484Sobrien return (false); 56360484Sobrien } 56460484Sobrien for (i = HALF_LEN + 1; i < 2 * HALF_LEN - 1; i++) { 56560484Sobrien if (srcname[i] < '0' || srcname[i] > '9') 56660484Sobrien break; 56760484Sobrien } 56860484Sobrien if (i < 2 * HALF_LEN - 1 && 56989857Sobrien strcmp(srcname + HALF_LEN + 1, "not_terminated") != 0 && 57060484Sobrien strcmp(srcname + HALF_LEN + 1, "crash_recovery") != 0) { 57160484Sobrien return (false); 57260484Sobrien } 57360484Sobrien 57460484Sobrien if (dstname == NULL) 57560484Sobrien return (true); 57660484Sobrien 57760484Sobrien /* We tolarate if both names are identical. */ 57878828Sobrien if (strcmp(srcname, dstname) == 0) 57978828Sobrien return (true); 58078828Sobrien 58178828Sobrien /* We can only rename not_terminated files. */ 58278828Sobrien if (strcmp(srcname + HALF_LEN + 1, "not_terminated") != 0) 58360484Sobrien return (false); 58460484Sobrien if (strlen(dstname) != 2 * HALF_LEN + 1) 58560484Sobrien return (false); 58660484Sobrien if (strncmp(srcname, dstname, HALF_LEN + 1) != 0) 58760484Sobrien return (false); 58860484Sobrien for (i = HALF_LEN + 1; i < 2 * HALF_LEN - 1; i++) { 58960484Sobrien if (dstname[i] < '0' || dstname[i] > '9') 59060484Sobrien break; 59160484Sobrien } 59260484Sobrien if (i < 2 * HALF_LEN - 1 && 59360484Sobrien strcmp(dstname + HALF_LEN + 1, "crash_recovery") != 0) { 59460484Sobrien return (false); 59560484Sobrien } 59660484Sobrien 59760484Sobrien return (true); 59860484Sobrien} 59960484Sobrien 60060484Sobrienint 60160484Sobrientrail_name_compare(const char *name0, const char *name1) 60260484Sobrien{ 60360484Sobrien int ret; 60460484Sobrien 60560484Sobrien ret = strcmp(name0, name1); 60660484Sobrien if (ret == 0) 60760484Sobrien return (TRAIL_IDENTICAL); 60860484Sobrien if (strncmp(name0, name1, HALF_LEN + 1) == 0) 60960484Sobrien return (TRAIL_RENAMED); 61060484Sobrien return (ret < 0 ? TRAIL_OLDER : TRAIL_NEWER); 61160484Sobrien} 61260484Sobrien