*/
#include <TargetConditionals.h>
-
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <xpc/private.h>
#define _PATH_WALL "/usr/bin/wall"
-#define NOTIFY_PATH_SERVICE "com.apple.system.notify.service.path:0x87:"
#define MY_ID "asl_action"
-/* XXX add to asl.h */
-#define ASL_KEY_MODULE "ASLModule"
-
#define MAX_FAILURES 5
#define ACTION_STATUS_ERROR -1
#define IDLE_CLOSE 300
+#define PRIVATE_FLAG_NO_CLOSE 0x00000001 /* File or Store is closed by a cancellation handler */
+
+#define DST_CLOSE_CHECKPOINT 0
+#define DST_CLOSE_DELETED 1
+#define DST_CLOSE_ERROR 2
+#define DST_CLOSE_IDLE 3
+#define DST_CLOSE_SHUTDOWN 4
+static const char *why_str[] =
+{
+ "checkpoint",
+ "deleted",
+ "error",
+ "idle",
+ "shutdown"
+};
+
#define forever for(;;)
static dispatch_queue_t asl_action_queue;
static time_t sweep_time = 0;
#if TARGET_OS_EMBEDDED
+#ifndef CRASH_MOVER_SERVICE
+#define CRASH_MOVER_SERVICE "com.apple.crash_mover"
+#endif
static dispatch_queue_t crashlog_queue;
-static dispatch_source_t crashlog_sentinel_src;
-static int crashlog_sentinel_fd = -1;
static time_t crashmover_state = 0;
static int crashmover_token = -1;
#endif
-typedef struct store_data
+typedef struct asl_file_data
+{
+ uint64_t next_id;
+ asl_file_t *aslfile;
+ time_t last_time;
+ uint32_t flags;
+ uint32_t pending;
+ dispatch_source_t monitor;
+} asl_action_asl_file_data_t;
+
+typedef struct asl_store_data
{
- asl_file_t *store;
FILE *storedata;
+ asl_file_t *aslfile;
uint64_t next_id;
time_t last_time;
+ uint32_t flags;
+ uint32_t pending;
uint32_t p_year;
uint32_t p_month;
uint32_t p_day;
- dispatch_source_t monitor;
-} asl_action_store_data_t;
+ dispatch_source_t storedata_monitor;
+ dispatch_source_t aslfile_monitor;
+} asl_action_asl_store_data_t;
typedef struct file_data
{
int fd;
- uint32_t last_hash;
- uint32_t last_count;
+ uint32_t flags;
time_t last_time;
+ uint32_t last_count;
+ uint32_t last_hash;
+ uint32_t pending;
char *last_msg;
dispatch_source_t dup_timer;
dispatch_source_t monitor;
static int action_asl_store_count;
static bool store_has_logged;
-extern void db_save_message(aslmsg m);
+extern void db_save_message(asl_msg_t *m);
/* forward */
static int _act_file_checkpoint_all(uint32_t force);
static void _asl_action_post_process_rule(asl_out_module_t *m, asl_out_rule_t *r);
static void _asl_action_close_idle_files(time_t idle_time);
+static void _act_dst_close(asl_out_rule_t *r, int why);
static void
_act_out_set_param(asl_out_module_t *m, char *x, bool eval)
if (intval == 0) m->flags &= ~MODULE_FLAG_ENABLED;
else m->flags|= MODULE_FLAG_ENABLED;
+ free_string_list(l);
return;
}
else if (!strcasecmp(l[0], "disable"))
if (intval != 0) m->flags &= ~MODULE_FLAG_ENABLED;
else m->flags|= MODULE_FLAG_ENABLED;
+ free_string_list(l);
return;
}
}
static void
-_act_broadcast(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_broadcast(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
#if !TARGET_OS_EMBEDDED
FILE *pw;
if (strcmp(m->name, ASL_MODULE_NAME)) return;
val = r->options;
- if (val == NULL) val = asl_get(msg, ASL_KEY_MSG);
+ if (val == NULL) val = asl_msg_get_val_for_key(msg, ASL_KEY_MSG);
if (val == NULL) return;
pw = popen(_PATH_WALL, "w");
}
static void
-_act_access_control(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_set_key(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
+{
+ /* Placeholder */
+}
+
+static void
+_act_unset_key(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
+{
+ /* Placeholder */
+}
+
+static void
+_act_access_control(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
int32_t ruid, rgid;
char *p;
rgid = atoi(p);
}
- if (ruid != -1) asl_set(msg, ASL_KEY_READ_UID, r->options);
+ if (ruid != -1) asl_msg_set_key_val(msg, ASL_KEY_READ_UID, r->options);
if (p != NULL)
{
- if (rgid != -1) asl_set(msg, ASL_KEY_READ_GID, p);
+ if (rgid != -1) asl_msg_set_key_val(msg, ASL_KEY_READ_GID, p);
p--;
*p = ' ';
}
#if TARGET_OS_EMBEDDED
static void
-_crashlog_sentinel_init(void)
+_crashlog_queue_check(void)
+{
+ /*
+ * Check whether the crashlog queue has been suspended for too long.
+ * We allow the crashlog quque to be suspended for 60 seconds.
+ * After that, we start logging again. This prevents syslogd from
+ * filling memory due to a suspended queue. CrashMover really shoud
+ * take no more than a second or two to finish.
+ */
+ if (crashmover_state == 0) return;
+ if ((time(NULL) - crashmover_state) <= 60) return;
+
+ asldebug("CrashMover timeout: resuming crashlog queue\n");
+ dispatch_resume(crashlog_queue);
+ crashmover_state = 0;
+}
+#endif
+
+/*
+ * cover routine for asl_out_dst_file_create_open()
+ */
+static int
+_act_file_create_open(asl_out_dst_data_t *dst)
+{
+ return asl_out_dst_file_create_open(dst, NULL);
+}
+
+/*
+ * Checks and creates (if required) a directory for an ASL data store.
+ */
+static int
+_asl_dir_create(asl_out_rule_t *r)
{
- char path[MAXPATHLEN];
+ struct stat sb;
+ int status;
+
+ memset(&sb, 0, sizeof(struct stat));
+ status = stat(r->dst->path, &sb);
+ if (status == 0)
+ {
+ /* Store path must be a directory */
+ if (!S_ISDIR(sb.st_mode))
+ {
+ asldebug("_asl_dir_create: expected a directory at path %s\n", r->dst->path);
+ return -1;
+ }
+ }
+ else if (errno == ENOENT)
+ {
+ /* Directory doesn't exists - try to create it */
+ status = asl_out_mkpath(global.asl_out_module, r);
+ if (status != 0)
+ {
+ asldebug("_asl_dir_create: asl_out_mkpath failed: %s\n", r->dst->path);
+ return -1;
+ }
+ }
+ else
+ {
+ /* Unexpected stat error */
+ asldebug("_asl_dir_create: stat error %s\n", strerror(errno));
+ return -1;
+ }
- if (crashlog_sentinel_src != NULL) return;
+ return 0;
+}
- snprintf(path, sizeof(path), "%s/com.apple.asl.%ld", _PATH_CRASHREPORTER, time(NULL));
+/*
+ * Close an ASL Directory StoreData file
+ * - cancel the dispatch source for the file
+ */
+static void
+_asl_dir_storedata_close(asl_out_rule_t *r)
+{
+ asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private;
+ if (as_data->storedata == NULL) return;
- crashlog_sentinel_fd = open(path, O_WRONLY | O_CREAT);
- if (crashlog_sentinel_fd < 0)
+ if (as_data->storedata_monitor == NULL)
+ {
+ /*
+ * This should never happen, but _asl_dir_storedata_open allows
+ * dispatch_source_create to fail silently. If there is no dispatch
+ * source, we just close the file.
+ */
+ asldebug("close ASL storedata fd %d\n", fileno(as_data->storedata));
+ fclose(as_data->storedata);
+ }
+ else
+ {
+ /*
+ * The storedata_monitor cancel handler will close the file.
+ */
+ dispatch_source_cancel(as_data->storedata_monitor);
+ dispatch_release(as_data->storedata_monitor);
+
+ }
+
+ asldebug("_asl_dir_storedata_close %p\n", as_data->storedata);
+ as_data->storedata = NULL;
+}
+
+/*
+ * Open an ASL Directory StoreData file
+ * - check directory existance and create it if necessary
+ * - check for StoreData file and create it (with given xid) if necessary.
+ * - create a dispatch source to watch for StoreData file deletion
+ */
+static int
+_asl_dir_storedata_open(asl_out_rule_t *r, uint64_t xid)
+{
+ struct stat sb;
+ int status;
+ char dstpath[MAXPATHLEN];
+
+ asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private;
+ if (as_data->storedata != NULL) return 0;
+
+ status = _asl_dir_create(r);
+ if (status != 0)
+ {
+ asldebug("_asl_dir_storedata_open: No directory at path %s\n", r->dst->path);
+ return -1;
+ }
+
+ /* StoreData file is not open */
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", r->dst->path, FILE_ASL_STORE_DATA);
+
+ memset(&sb, 0, sizeof(struct stat));
+ status = stat(dstpath, &sb);
+ if (status == 0)
+ {
+ /* StoreData file exists */
+ as_data->storedata = fopen(dstpath, "r+");
+ if (as_data->storedata == NULL)
+ {
+ asldebug("_asl_dir_storedata_open: fopen existing %s: %s\n", dstpath, strerror(errno));
+ return -1;
+ }
+ }
+ else if (errno == ENOENT)
+ {
+ /*
+ * StoreData file does not exist.
+ * Create a new StoreData with a given xid.
+ */
+ //TODO: This should return a failure if there are any ASL files.
+ /* that would require reading the directory, thus a performance hit */
+ as_data->storedata = fopen(dstpath, "w+");
+ if (as_data->storedata == NULL)
+ {
+ asldebug("_asl_dir_storedata_open: fopen new %s: %s\n", dstpath, strerror(errno));
+ return -1;
+ }
+
+ uint64_t xout = asl_core_htonq(xid);
+ status = fwrite(&xout, sizeof(uint64_t), 1, as_data->storedata);
+ if (status != 1)
+ {
+ asldebug("_asl_dir_storedata_open: storedata write failed %d %s\n", errno, strerror(errno));
+ return -1;
+ }
+
+#if !TARGET_IPHONE_SIMULATOR
+ if (chown(dstpath, r->dst->uid[0], r->dst->gid[0]) != 0)
+ {
+ asldebug("_asl_dir_storedata_open: chown %d %d new %s: %s\n", dstpath, r->dst->uid[0], r->dst->gid[0], strerror(errno));
+ return -1;
+ }
+#endif
+ }
+ else
+ {
+ /* Unexpected stat error */
+ asldebug("_asl_dir_storedata_open: stat error %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* create storedata_monitor */
+ int fd = fileno(as_data->storedata);
+ FILE *sdfp = as_data->storedata;
+
+ as_data->storedata_monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE, asl_action_queue);
+ if (as_data->storedata_monitor != NULL)
+ {
+ dispatch_source_set_event_handler(as_data->storedata_monitor, ^{
+ _act_dst_close(r, DST_CLOSE_DELETED);
+ });
+
+ dispatch_source_set_cancel_handler(as_data->storedata_monitor, ^{
+ asldebug("cancel/close ASL storedata fd %d\n", fd);
+ fclose(sdfp);
+ });
+
+ dispatch_resume(as_data->storedata_monitor);
+ }
+
+ asldebug("_asl_dir_storedata_open ASL storedata %s fd %d\n", dstpath, fd);
+ return 0;
+}
+
+/*
+ * Close an ASL Directory ASL file
+ * - cancel the dispatch source for the file
+ * - clears file name and timestamp in asl_action_asl_store_data_t structue
+ */
+static void
+_asl_dir_today_close(asl_out_rule_t *r)
+{
+ asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private;
+ if (as_data->aslfile == NULL) return;
+
+ if (as_data->pending != 0)
{
char *str = NULL;
- asprintf(&str, "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message Sentinel %s create/open failed (%s)]", global.pid, path, strerror(errno));
+ asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL Store %s was closed with %d pending messages]", global.pid, r->dst->fname, as_data->pending);
internal_log_message(str);
free(str);
- return;
}
- close(crashlog_sentinel_fd);
+ if (as_data->aslfile_monitor == NULL)
+ {
+ /*
+ * This should never happen, but _asl_dir_today_open allows
+ * dispatch_source_create to fail silently. If there is no dispatch
+ * source, we just close the file.
+ */
+ asldebug("close ASL fd %d\n", fileno(as_data->aslfile->store));
+ asl_file_close(as_data->aslfile);
+ }
+ else
+ {
+ /*
+ * The aslfile_monitor cancel handler will close the file.
+ */
+ dispatch_source_cancel(as_data->aslfile_monitor);
+ dispatch_release(as_data->aslfile_monitor);
+ as_data->aslfile_monitor = NULL;
+ }
+
+ as_data->p_year = 0;
+ as_data->p_month = 0;
+ as_data->p_day = 0;
+
+ free(r->dst->fname);
+ r->dst->fname = NULL;
+
+ as_data->aslfile = NULL;
+}
+
+/*
+ * Check file size.
+ */
+static int
+_act_checkpoint(asl_out_rule_t *r, uint32_t force)
+{
+ char tmpfname[MAXPATHLEN], *fn;
+
+ if (r == NULL) return 0;
+ if (r->dst == NULL) return 0;
+
+ fn = r->dst->fname;
+ if (fn == NULL)
+ {
+ if (r->dst->path == NULL) return 0;
+ asl_make_dst_filename(r->dst, tmpfname, sizeof(tmpfname));
+ fn = tmpfname;
+ }
+
+ if ((force == CHECKPOINT_TEST) && (r->dst->file_max == 0)) return 0;
+
+ if ((r->dst->size == 0) || (r->dst->stamp == 0))
+ {
+ struct stat sb;
+
+ memset(&sb, 0, sizeof(struct stat));
+
+ if (stat(fn, &sb) < 0)
+ {
+ if (errno == ENOENT) return 0;
+ return -1;
+ }
+
+ if (r->dst->stamp == 0) r->dst->stamp = sb.st_birthtimespec.tv_sec;
+ if (r->dst->stamp == 0) r->dst->stamp = sb.st_mtimespec.tv_sec;
+ r->dst->size = sb.st_size;
+ }
+
+ if ((force == CHECKPOINT_TEST) && (r->dst->size < r->dst->file_max)) return 0;
+
+ if (r->dst->flags & MODULE_FLAG_BASESTAMP)
+ {
+ _act_dst_close(r, DST_CLOSE_CHECKPOINT);
+ }
+ else
+ {
+ char srcpath[MAXPATHLEN];
+ char dstpath[MAXPATHLEN];
+ char tstamp[32];
+
+ if (r->dst->stamp == 0) r->dst->stamp = time(NULL);
+ asl_make_timestamp(r->dst->stamp, r->dst->flags, tstamp, sizeof(tstamp));
+
+ snprintf(srcpath, sizeof(srcpath), "%s", fn);
+ snprintf(dstpath, sizeof(dstpath), "%s.%s", fn, tstamp);
+
+ _act_dst_close(r, DST_CLOSE_CHECKPOINT);
+ rename(srcpath, dstpath);
+ }
+
+ r->dst->stamp = 0;
+ r->dst->size = 0;
+ return 1;
+}
+
+/*
+ * Open today's ASL file in an ASL directory
+ * - Checks date and closes a currently open file if it has the wrong date
+ * - Opens today's file
+ */
+static int
+_asl_dir_today_open(asl_out_rule_t *r, const time_t *tick)
+{
+ int status;
+ mode_t mask;
+ struct tm ctm;
+ time_t now;
+
+ if (r == NULL) return -1;
+ if (r->dst == NULL) return -1;
+
+ status = _asl_dir_create(r);
+ if (status != 0)
+ {
+ asldebug("_asl_dir_today_open: No directory at path %s\n", r->dst->path);
+ return -1;
+ }
+
+ asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private;
+
+ memset(&ctm, 0, sizeof(struct tm));
+ if (tick == NULL)
+ {
+ now = time(NULL);
+ tick = (const time_t *)&now;
+ }
+
+ if (localtime_r(tick, &ctm) == NULL)
+ {
+ asldebug("_asl_dir_today_open: localtime_r error %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* checks file_max and closes if required */
+ status = _act_checkpoint(r, CHECKPOINT_TEST);
+ if (status == 1) trigger_aslmanager();
+
+ if (as_data->aslfile != NULL)
+ {
+ /* Check the date */
+ if ((as_data->p_year == ctm.tm_year) && (as_data->p_month == ctm.tm_mon) && (as_data->p_day == ctm.tm_mday)) return 0;
+
+ /* Wrong date, close the current file */
+ _asl_dir_today_close(r);
+ }
+
+ /* Open data file */
+
+ if (r->dst->flags & MODULE_FLAG_BASESTAMP)
+ {
+ char tstamp[32];
+
+ if (tick == NULL)
+ {
+ now = time(NULL);
+ tick = (const time_t *)&now;
+ }
+
+ asl_make_timestamp(now, r->dst->flags, tstamp, sizeof(tstamp));
+ asprintf(&(r->dst->fname), "%s/%s.asl", r->dst->path, tstamp);
+ }
+ else
+ {
+ asprintf(&(r->dst->fname), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+ }
+
+
+ if (r->dst->fname == NULL)
+ {
+ asldebug("_asl_dir_today_open: asprintf error %s\n", strerror(errno));
+ return -1;
+ }
+
+#if TARGET_IPHONE_SIMULATOR
+ uid_t uid = -1;
+ gid_t gid = -1;
+#else
+ uid_t uid = r->dst->uid[0];
+ gid_t gid = r->dst->gid[0];
+#endif
+
+ mask = umask(0);
+ status = asl_file_open_write(r->dst->fname, (r->dst->mode & 00666), uid, gid, &(as_data->aslfile));
+ umask(mask);
+
+ if (status != ASL_STATUS_OK)
+ {
+ asldebug("_asl_dir_today_open: asl_file_open_write %s error %s\n", r->dst->fname, asl_core_error(status));
+ free(r->dst->fname);
+ r->dst->fname = NULL;
+ return -1;
+ }
+
+ if (fseek(as_data->aslfile->store, 0, SEEK_END) != 0)
+ {
+ asldebug("_asl_dir_today_open: fseek %s error %s\n", r->dst->fname, strerror(errno));
+ free(r->dst->fname);
+ r->dst->fname = NULL;
+ return -1;
+ }
+
+ as_data->p_year = ctm.tm_year;
+ as_data->p_month = ctm.tm_mon;
+ as_data->p_day = ctm.tm_mday;
- crashlog_sentinel_fd = open(path, O_EVTONLY, 0);
- if (crashlog_sentinel_fd < 0)
+ /* create aslfile_monitor */
+ int fd = fileno(as_data->aslfile->store);
+ asl_file_t *aslf = as_data->aslfile;
+
+ as_data->aslfile_monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE, asl_action_queue);
+ if (as_data->aslfile_monitor != NULL)
+ {
+ dispatch_source_set_event_handler(as_data->aslfile_monitor, ^{
+ _act_dst_close(r, DST_CLOSE_DELETED);
+ });
+
+ dispatch_source_set_cancel_handler(as_data->aslfile_monitor, ^{
+ asldebug("cancel/close ASL file fd %d\n", fd);
+ asl_file_close(aslf);
+ });
+
+ dispatch_resume(as_data->aslfile_monitor);
+ }
+
+ asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->fname, fd);
+
+ return 0;
+}
+
+static void
+_asl_file_close(asl_out_rule_t *r)
+{
+ if (r == NULL) return;
+ if (r->dst == NULL) return;
+
+ asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private;
+ if (af_data->aslfile == NULL) return;
+
+ if (af_data->pending != 0)
{
char *str = NULL;
- asprintf(&str, "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message Sentinel %s event/open failed (%s)]", global.pid, path, strerror(errno));
+ asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL File %s was closed with %d pending messages]", global.pid, r->dst->fname, af_data->pending);
internal_log_message(str);
free(str);
- return;
}
- crashlog_sentinel_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, (uintptr_t)crashlog_sentinel_fd, DISPATCH_VNODE_DELETE, asl_action_queue);
- if (crashlog_sentinel_src == NULL)
+ if (af_data->monitor == NULL)
+ {
+ /*
+ * This should never happen, but _asl_file_open allows
+ * dispatch_source_create to fail silently. If there is no dispatch
+ * source, we just close the file.
+ */
+ asldebug("close ASL fd %d\n", fileno(af_data->aslfile->store));
+ asl_file_close(af_data->aslfile);
+ }
+ else
+ {
+ /*
+ * The monitor cancel handler will close the file.
+ */
+ dispatch_source_cancel(af_data->monitor);
+ dispatch_release(af_data->monitor);
+ af_data->monitor = NULL;
+ }
+
+ af_data->aslfile = NULL;
+}
+
+static int
+_asl_file_open(asl_out_rule_t *r)
+{
+ int fd, status;
+
+ if (r == NULL) return -1;
+ if (r->dst == NULL) return -1;
+
+ asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private;
+ if (af_data->aslfile != NULL) return 0;
+
+ /* create path if necessary */
+ status = asl_out_mkpath(global.asl_out_module, r);
+ if (status != 0)
+ {
+ asldebug("_asl_file_open: asl_out_mkpath %s failed\n", r->dst->path);
+ return -1;
+ }
+
+ fd = _act_file_create_open(r->dst);
+ if (fd < 0)
+ {
+ asldebug("_asl_file_open: _act_file_create_open %s failed %d %s\n", r->dst->fname, errno, strerror(errno));
+ return -1;
+ }
+
+ close(fd);
+
+ if (r->dst->fname == NULL) return -1;
+
+ status = asl_file_open_write(r->dst->fname, 0, -1, -1, &(af_data->aslfile));
+ if (status != ASL_STATUS_OK)
+ {
+ asldebug("_asl_file_open: asl_file_open_write %s failed %d %s\n", r->dst->fname, errno, strerror(errno));
+ return -1;
+ }
+
+ /* create monitor */
+ fd = fileno(af_data->aslfile->store);
+ asl_file_t *aslf = af_data->aslfile;
+
+ af_data->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE, asl_action_queue);
+ if (af_data->monitor != NULL)
+ {
+ dispatch_source_set_event_handler(af_data->monitor, ^{
+ _act_dst_close(r, DST_CLOSE_DELETED);
+ });
+
+ dispatch_source_set_cancel_handler(af_data->monitor, ^{
+ asldebug("cancel/close ASL file fd %d\n", fd);
+ asl_file_close(aslf);
+ });
+
+ dispatch_resume(af_data->monitor);
+ }
+
+ asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->fname, fd);
+ return 0;
+}
+
+static void
+_text_file_close(asl_out_rule_t *r)
+{
+ asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private;
+ if (f_data->fd < 0) return;
+
+ if (f_data->pending != 0)
{
char *str = NULL;
- asprintf(&str, "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message Sentinel %s dispatch_source_create failed]", global.pid, path);
+ asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message File %s was closed with %d pending messages]", global.pid, r->dst->fname, f_data->pending);
internal_log_message(str);
free(str);
- close(crashlog_sentinel_fd);
- crashlog_sentinel_fd = -1;
- return;
}
- dispatch_source_set_event_handler(crashlog_sentinel_src, ^{
- if (crashmover_state != 0)
+ if (f_data->monitor == NULL)
+ {
+ /*
+ * This should never happen, but _text_file_open allows
+ * dispatch_source_create to fail silently. If there is no dispatch
+ * source, we just close the file.
+ */
+ asldebug("close fd %d\n", f_data->fd);
+ close(f_data->fd);
+ }
+ else
+ {
+ /*
+ * The monitor cancel handler will close the file.
+ */
+ dispatch_source_cancel(f_data->monitor);
+ dispatch_release(f_data->monitor);
+ f_data->monitor = NULL;
+ }
+
+ f_data->fd = -1;
+}
+
+static int
+_text_file_open(asl_out_rule_t *r)
+{
+ asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private;
+
+ if (f_data->fd < 0)
+ {
+ f_data->fd = _act_file_create_open(r->dst);
+ if (f_data->fd < 0)
+ {
+ /*
+ * lazy path creation: create path and retry
+ * _act_file_create_open does not create the path
+ * so we do it here.
+ */
+ int status = asl_out_mkpath(global.asl_out_module, r);
+ if (status != 0) return -1;
+
+ f_data->fd = _act_file_create_open(r->dst);
+ }
+
+ if (f_data->fd < 0) return -1;
+
+ f_data->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, f_data->fd, DISPATCH_VNODE_DELETE, asl_action_queue);
+ if (f_data->monitor != NULL)
+ {
+ int ffd = f_data->fd;
+
+ dispatch_source_set_event_handler(f_data->monitor, ^{
+ asldebug("dispatch_source DISPATCH_VNODE_DELETE fd %d\n", ffd);
+ _act_dst_close(r, DST_CLOSE_DELETED);
+ });
+
+ dispatch_source_set_cancel_handler(f_data->monitor, ^{
+ asldebug("cancel/close file fd %d\n", ffd);
+ close(ffd);
+ });
+
+ dispatch_resume(f_data->monitor);
+ }
+ }
+
+ return 0;
+}
+
+static int
+_act_dst_open(asl_out_rule_t *r, const time_t *tick, uint64_t xid)
+{
+ if (r == NULL) return -1;
+ if (r->dst == NULL) return -1;
+ if (r->dst->private == NULL) return -1;
+
+ if (r->action == ACTION_ASL_DIR)
+ {
+ if (_asl_dir_today_open(r, tick) != 0)
{
- asldebug("CrashMover inactive / sentinel deleted: resuming crashlog queue\n");
- dispatch_resume(crashlog_queue);
- crashmover_state = 0;
+ asldebug("_act_dst_open:_asl_dir_today_open %s FAILED!\n", r->dst->path);
+ return -1;
}
- if (crashlog_sentinel_src != NULL)
+ if (_asl_dir_storedata_open(r, xid) != 0)
{
- dispatch_source_cancel(crashlog_sentinel_src);
- dispatch_release(crashlog_sentinel_src);
+ asldebug("_act_dst_open:_asl_dir_storedata_open %s FAILED! Closing today file\n", r->dst->path);
+ _asl_dir_today_close(r);
+ return -1;
}
- crashlog_sentinel_src = NULL;
-
- close(crashlog_sentinel_fd);
- crashlog_sentinel_fd = -1;
- _crashlog_sentinel_init();
- });
-
- dispatch_resume(crashlog_sentinel_src);
- asldebug("Created CrashLog Sentinel: %s\n", path);
-}
-
-static void
-_crashlog_queue_check(void)
-{
- /*
- * Check whether the crashlog queue has been suspended for too long.
- * We allow the crashlog quque to be suspended for 60 seconds.
- * After that, we start logging again. This prevents syslogd from
- * filling memory due to a suspended queue. CrashMover really shoud
- * take no more than a second or two to finish.
- */
- if (crashmover_state == 0) return;
- if ((time(NULL) - crashmover_state) <= 60) return;
-
- asldebug("CrashMover timeout: resuming crashlog queue\n");
- dispatch_resume(crashlog_queue);
- crashmover_state = 0;
+ return 0;
+ }
- /*
- * crashlog_sentinel_src should never be NULL, but if
- * _crashlog_sentinel_init failed for some strange reason,
- * it will be NULL here.
- */
- if (crashlog_sentinel_src != NULL)
+ if (r->action == ACTION_ASL_FILE)
{
- dispatch_source_cancel(crashlog_sentinel_src);
- dispatch_release(crashlog_sentinel_src);
+ return _asl_file_open(r);
}
- crashlog_sentinel_src = NULL;
+ if (r->action == ACTION_FILE)
+ {
+ return _text_file_open(r);
+ }
- close(crashlog_sentinel_fd);
- crashlog_sentinel_fd = -1;
- _crashlog_sentinel_init();
+ return -1;
}
-#endif
static void
-_act_dst_close(asl_out_rule_t *r)
+_act_dst_close(asl_out_rule_t *r, int why)
{
if (r == NULL) return;
if (r->dst == NULL) return;
if (r->dst->private == NULL) return;
- if ((r->action == ACTION_ASL_DIR) || (r->action == ACTION_ASL_FILE))
+ if (r->action == ACTION_ASL_DIR)
{
- asl_action_store_data_t *sdata = (asl_action_store_data_t *)r->dst->private;
- if (sdata->store != NULL) asl_file_close(sdata->store);
- sdata->store = NULL;
-
- if (sdata->storedata != NULL) fclose(sdata->storedata);
- sdata->storedata = NULL;
-
- if (sdata->monitor != NULL)
- {
- dispatch_source_cancel(sdata->monitor);
- dispatch_release(sdata->monitor);
- sdata->monitor = NULL;
- }
+ asldebug("_act_dst_close: %s ASL DIR %s\n", why_str[why], r->dst->path);
+ if (why != DST_CLOSE_CHECKPOINT) _asl_dir_storedata_close(r);
+ _asl_dir_today_close(r);
+ }
+ else if (r->action == ACTION_ASL_FILE)
+ {
+ asldebug("_act_dst_close: %s ASL FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname);
+ _asl_file_close(r);
}
else if (r->action == ACTION_FILE)
{
- asl_action_file_data_t *fdata = (asl_action_file_data_t *)r->dst->private;
- if (fdata->fd >= 0) close(fdata->fd);
- fdata->fd = -1;
-
- if (fdata->monitor != NULL)
- {
- dispatch_source_cancel(fdata->monitor);
- dispatch_release(fdata->monitor);
- fdata->monitor = NULL;
- }
+ asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname);
+ _text_file_close(r);
}
}
_act_store_file_setup(asl_out_module_t *m, asl_out_rule_t *r)
{
uint32_t status;
- asl_action_store_data_t *sdata;
- char dstpath[MAXPATHLEN];
+ asl_action_asl_file_data_t *af_data;
if (r == NULL) return ASL_STATUS_INVALID_STORE;
if (r->dst == NULL) return ASL_STATUS_INVALID_STORE;
if (r->dst->private == NULL) return ASL_STATUS_INVALID_STORE;
- sdata = (asl_action_store_data_t *)r->dst->private;
- if (sdata->store == NULL)
+ af_data = (asl_action_asl_file_data_t *)r->dst->private;
+ if (af_data->aslfile != NULL)
{
- /* create path if necessary */
- asl_out_mkpath(r);
-
- int fd = asl_out_dst_file_create_open(r->dst);
- if (fd < 0)
- {
- asldebug("_act_store_file_setup: asl_out_dst_file_create_open failed %d %s\n", errno, strerror(errno));
- return ASL_STATUS_WRITE_FAILED;
- }
- close(fd);
-
- asl_make_dst_filename(r->dst, dstpath, sizeof(dstpath));
- status = asl_file_open_write(dstpath, 0, -1, -1, &(sdata->store));
- if (status != ASL_STATUS_OK) return status;
-
- sdata->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fileno(sdata->store->store), DISPATCH_VNODE_DELETE, asl_action_queue);
- if (sdata->monitor != NULL)
- {
- dispatch_source_set_event_handler(sdata->monitor, ^{ _act_dst_close(r); });
- dispatch_resume(sdata->monitor);
- }
+ af_data->next_id++;
+ return ASL_STATUS_OK;
+ }
- status = asl_file_read_set_position(sdata->store, ASL_FILE_POSITION_LAST);
- if (status != ASL_STATUS_OK)
- {
- asldebug("_act_store_file_setup: asl_file_read_set_position failed %d %s\n", status, asl_core_error(status));
- return status;
- }
+ if (_act_dst_open(r, NULL, 0) != 0) return ASL_STATUS_WRITE_FAILED;
- sdata->next_id = sdata->store->cursor_xid + 1;
- if (fseek(sdata->store->store, 0, SEEK_END) != 0)
- {
- asldebug("_act_store_file_setup: fseek failed %d %s\n", errno, strerror(errno));
- return ASL_STATUS_WRITE_FAILED;
- }
+ status = asl_file_read_set_position(af_data->aslfile, ASL_FILE_POSITION_LAST);
+ if (status != ASL_STATUS_OK)
+ {
+ asldebug("_act_store_file_setup: asl_file_read_set_position failed %d %s\n", status, asl_core_error(status));
+ _act_dst_close(r, DST_CLOSE_ERROR);
+ return status;
}
- else
+
+ af_data->next_id = af_data->aslfile->cursor_xid + 1;
+ if (fseek(af_data->aslfile->store, 0, SEEK_END) != 0)
{
- sdata->next_id++;
+ asldebug("_act_store_file_setup: fseek failed %d %s\n", errno, strerror(errno));
+ _act_dst_close(r, DST_CLOSE_ERROR);
+ return ASL_STATUS_WRITE_FAILED;
}
return ASL_STATUS_OK;
/*
* _act_store_dir_setup
*
- * Creates store directory if it does not exist
- * Creates StoreData file if it does not exist
+ * Opens StoreData file and today's file
* Reads ASL Message ID from StoreData file
* Writes ASL Message ID + 1 to StoreData file
- * Opens current day file (e.g. "/foo/bar/2012.04.06.asl")
*/
static uint32_t
_act_store_dir_setup(asl_out_module_t *m, asl_out_rule_t *r, time_t tick)
{
- struct tm ctm;
- char *path;
- struct stat sb;
uint64_t xid;
int status;
- mode_t mask;
- asl_action_store_data_t *sdata;
+ asl_action_asl_store_data_t *as_data;
if (r == NULL) return ASL_STATUS_INVALID_STORE;
if (r->dst == NULL) return ASL_STATUS_INVALID_STORE;
if (r->dst->private == NULL) return ASL_STATUS_INVALID_STORE;
if (r->dst->path == NULL) return ASL_STATUS_INVALID_STORE;
- sdata = (asl_action_store_data_t *)r->dst->private;
-
- /* get / set message id from StoreData file */
- xid = 0;
+ as_data = (asl_action_asl_store_data_t *)r->dst->private;
- if (sdata->storedata == NULL)
+ if (_act_dst_open(r, NULL, as_data->next_id) != 0)
{
- memset(&sb, 0, sizeof(struct stat));
- status = stat(r->dst->path, &sb);
- if (status == 0)
- {
- /* must be a directory */
- if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
- }
- else if (errno == ENOENT)
- {
- /* doesn't exist - create it */
- mask = umask(S_IWGRP | S_IWOTH);
- status = mkpath_np(r->dst->path, 0755);
- if (status == 0) status = chmod(r->dst->path, r->dst->mode);
- umask(mask);
-
- if (status != 0) return ASL_STATUS_WRITE_FAILED;
-#if !TARGET_IPHONE_SIMULATOR
- if (chown(r->dst->path, r->dst->uid[0], r->dst->gid[0]) != 0) return ASL_STATUS_WRITE_FAILED;
-#endif
- }
- else
- {
- /* Unexpected stat error */
- return ASL_STATUS_FAILED;
- }
-
- path = NULL;
- asprintf(&path, "%s/%s", r->dst->path, FILE_ASL_STORE_DATA);
- if (path == NULL) return ASL_STATUS_NO_MEMORY;
-
- memset(&sb, 0, sizeof(struct stat));
- status = stat(path, &sb);
- if (status == 0)
- {
- /* StoreData exists: open and read last xid */
- sdata->storedata = fopen(path, "r+");
- if (sdata->storedata == NULL)
- {
- free(path);
- return ASL_STATUS_FAILED;
- }
-
- if (fread(&xid, sizeof(uint64_t), 1, sdata->storedata) != 1)
- {
- free(path);
- fclose(sdata->storedata);
- sdata->storedata = NULL;
- return ASL_STATUS_READ_FAILED;
- }
- }
- else if (errno == ENOENT)
- {
- /* StoreData does not exist: create it */
- sdata->storedata = fopen(path, "w");
- if (sdata->storedata == NULL)
- {
- free(path);
- return ASL_STATUS_FAILED;
- }
-
-#if !TARGET_IPHONE_SIMULATOR
- if (chown(path, r->dst->uid[0], r->dst->gid[0]) != 0)
- {
- free(path);
- return ASL_STATUS_WRITE_FAILED;
- }
-#endif
- }
- else
- {
- /* Unexpected stat error */
- free(path);
- return ASL_STATUS_FAILED;
- }
-
- sdata->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fileno(sdata->storedata), DISPATCH_VNODE_DELETE, asl_action_queue);
- if (sdata->monitor != NULL)
- {
- dispatch_source_set_event_handler(sdata->monitor, ^{ _act_dst_close(r); });
- dispatch_resume(sdata->monitor);
- }
-
- free(path);
+ asldebug("_act_store_dir_setup: _act_dst_open %s failed\n", r->dst->path);
+ return ASL_STATUS_WRITE_FAILED;
}
- else
+
+ /* get / set message id from StoreData file */
+ xid = 0;
+ rewind(as_data->storedata);
+ if (fread(&xid, sizeof(uint64_t), 1, as_data->storedata) != 1)
{
- rewind(sdata->storedata);
- if (fread(&xid, sizeof(uint64_t), 1, sdata->storedata) != 1)
- {
- fclose(sdata->storedata);
- sdata->storedata = NULL;
- return ASL_STATUS_READ_FAILED;
- }
+ asldebug("_act_store_dir_setup: storedata read failed %d %s\n", errno, strerror(errno));
+ _act_dst_close(r, DST_CLOSE_ERROR);
+ return ASL_STATUS_READ_FAILED;
}
xid = asl_core_ntohq(xid);
xid++;
- sdata->next_id = xid;
+ as_data->next_id = xid;
xid = asl_core_htonq(xid);
- rewind(sdata->storedata);
- status = fwrite(&xid, sizeof(uint64_t), 1, sdata->storedata);
+ rewind(as_data->storedata);
+ status = fwrite(&xid, sizeof(uint64_t), 1, as_data->storedata);
if (status != 1)
{
- fclose(sdata->storedata);
- sdata->storedata = NULL;
+ asldebug("_act_store_dir_setup: storedata write failed %d %s\n", errno, strerror(errno));
+ _act_dst_close(r, DST_CLOSE_ERROR);
return ASL_STATUS_WRITE_FAILED;
}
- memset(&ctm, 0, sizeof(struct tm));
+ fflush(as_data->storedata);
- if (localtime_r((const time_t *)&tick, &ctm) == NULL) return ASL_STATUS_FAILED;
- if ((sdata->store != NULL) && (sdata->p_year == ctm.tm_year) && (sdata->p_month == ctm.tm_mon) && (sdata->p_day == ctm.tm_mday))
+ if (fseek(as_data->aslfile->store, 0, SEEK_END) != 0)
{
- return ASL_STATUS_OK;
- }
-
- if (sdata->store != NULL) asl_file_close(sdata->store);
- sdata->store = NULL;
- free(r->dst->fname);
- r->dst->fname = NULL;
-
- r->dst->stamp = tick;
-
- sdata->p_year = ctm.tm_year;
- sdata->p_month = ctm.tm_mon;
- sdata->p_day = ctm.tm_mday;
-
- asprintf(&(r->dst->fname), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
- if (r->dst->fname == NULL) return ASL_STATUS_NO_MEMORY;
- mask = umask(0);
-
- status = ASL_STATUS_OK;
- if (sdata->store == NULL) {
-#if TARGET_IPHONE_SIMULATOR
- uid_t uid = -1;
- gid_t gid = -1;
-#else
- uid_t uid = r->dst->uid[0];
- gid_t gid = r->dst->gid[0];
-#endif
- status = asl_file_open_write(r->dst->fname, (r->dst->mode & 0666), uid, gid, &(sdata->store));
+ asldebug("_act_store_dir_setup: aslfile fseek failed %d %s\n", errno, strerror(errno));
+ _act_dst_close(r, DST_CLOSE_ERROR);
+ return ASL_STATUS_FAILED;
}
- umask(mask);
-
- if (status != ASL_STATUS_OK) return status;
-
- if (fseek(sdata->store->store, 0, SEEK_END) != 0) return ASL_STATUS_FAILED;
return ASL_STATUS_OK;
}
static void
-_asl_action_store_data_free(asl_action_store_data_t *sdata)
+_asl_action_asl_store_data_free(asl_action_asl_store_data_t *as_data)
{
- if (sdata == NULL) return;
-
- if (sdata->store != NULL) asl_file_close(sdata->store);
- sdata->store = NULL;
-
- if (sdata->storedata != NULL) fclose(sdata->storedata);
- sdata->storedata = NULL;
+ if (as_data == NULL) return;
+ free(as_data);
+}
- free(sdata);
+static void
+_asl_action_asl_file_data_free(asl_action_asl_file_data_t *af_data)
+{
+ if (af_data == NULL) return;
+ free(af_data);
}
static void
-_asl_action_file_data_free(asl_action_file_data_t *fdata)
+_asl_action_file_data_free(asl_action_file_data_t *f_data)
{
- if (fdata == NULL) return;
+ if (f_data == NULL) return;
- if (fdata->dup_timer != NULL)
+ if (f_data->dup_timer != NULL)
{
- if (fdata->last_count == 0)
+ if (f_data->last_count == 0)
{
/*
* The timer exists, but last_count is zero, so the timer is suspended.
* Sources must not be released in when suspended.
* So we resume it so that we can release it.
*/
- dispatch_resume(fdata->dup_timer);
+ dispatch_resume(f_data->dup_timer);
}
- dispatch_release(fdata->dup_timer);
+ dispatch_release(f_data->dup_timer);
}
- free(fdata->last_msg);
- if (fdata->fd >= 0) close(fdata->fd);
- free(fdata);
+ free(f_data->last_msg);
+ free(f_data);
}
static void
internal_log_message(str);
free(str);
- if (r->action == ACTION_FILE) _asl_action_file_data_free((asl_action_file_data_t *)r->dst->private);
- else _asl_action_store_data_free((asl_action_store_data_t *)r->dst->private);
+ if (r->action == ACTION_ASL_DIR) _asl_action_asl_store_data_free((asl_action_asl_store_data_t *)r->dst->private);
+ else if (r->action == ACTION_ASL_FILE) _asl_action_asl_file_data_free((asl_action_asl_file_data_t *)r->dst->private);
+ else if (r->action == ACTION_FILE) _asl_action_file_data_free((asl_action_file_data_t *)r->dst->private);
r->dst->private = NULL;
r->action = ACTION_NONE;
}
}
+/*
+ * Save a message in an ASL file.
+ */
static int
-_act_store_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_store_file(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
- asl_action_store_data_t *sdata;
+ asl_action_asl_file_data_t *af_data;
uint32_t status;
uint64_t mid;
if (r->dst == NULL) return ACTION_STATUS_ERROR;
if (r->dst->private == NULL) return ACTION_STATUS_ERROR;
- sdata = (asl_action_store_data_t *)r->dst->private;
-
- /* check dst for file_max & etc */
- if (r->dst->flags & MODULE_FLAG_ROTATE)
- {
- if (asl_out_dst_checkpoint(r->dst, CHECKPOINT_TEST) != 0)
- {
- _act_dst_close(r);
- asl_trigger_aslmanager();
- }
- }
+ af_data = (asl_action_asl_file_data_t *)r->dst->private;
+ if (af_data->pending > 0) af_data->pending--;
status = _act_store_file_setup(m, r);
if (status == ASL_STATUS_OK)
{
- sdata->last_time = time(NULL);
+ af_data->last_time = time(NULL);
r->dst->fails = 0;
- mid = sdata->next_id;
+ mid = af_data->next_id;
/* save message to file and update dst size */
- status = asl_file_save(sdata->store, msg, &mid);
- if (status == ASL_STATUS_OK) r->dst->size = sdata->store->file_size;
+ status = asl_file_save(af_data->aslfile, msg, &mid);
+ if (status == ASL_STATUS_OK)
+ {
+ r->dst->size = af_data->aslfile->file_size;
+
+ if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager();
+ }
}
if (status != ASL_STATUS_OK)
return ACTION_STATUS_OK;
}
+/*
+ * Save a message in an ASL data store.
+ */
static int
-_act_store_dir(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_store_dir(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
- asl_action_store_data_t *sdata;
+ asl_action_asl_store_data_t *as_data;
uint32_t status;
uint64_t mid;
const char *val;
if (r->dst == NULL) return ACTION_STATUS_ERROR;
if (r->dst->private == NULL) return ACTION_STATUS_ERROR;
- sdata = (asl_action_store_data_t *)r->dst->private;
+ as_data = (asl_action_asl_store_data_t *)r->dst->private;
+ if (as_data->pending > 0) as_data->pending--;
- val = asl_get(msg, ASL_KEY_TIME);
+ val = asl_msg_get_val_for_key(msg, ASL_KEY_TIME);
if (val == NULL) return ACTION_STATUS_ERROR;
- /* check dst for file_max & etc */
- if (asl_out_dst_checkpoint(r->dst, CHECKPOINT_TEST) != 0)
- {
- _act_dst_close(r);
- asl_trigger_aslmanager();
- }
-
tick = atol(val);
status = _act_store_dir_setup(m, r, tick);
if (status == ASL_STATUS_OK)
{
- sdata->last_time = time(NULL);
+ as_data->last_time = time(NULL);
r->dst->fails = 0;
- mid = sdata->next_id;
- status = asl_file_save(sdata->store, msg, &mid);
- if (status == ASL_STATUS_OK) r->dst->size = sdata->store->file_size;
+ mid = as_data->next_id;
+ status = asl_file_save(as_data->aslfile, msg, &mid);
+ if (status == ASL_STATUS_OK) r->dst->size = as_data->aslfile->file_size;
+ else asldebug("_act_store_dir asl_file_save FAILED %s\n", asl_core_error(status));
+ //TODO: checkpoint here?
+ /*
+ * Currently, the checkpoint is in _asl_dir_today_open().
+ * Moving it here would be in keeping with the way that
+ * _act_store_file() and _act_file_final() do checkpoints.
+ */
}
if (status != ASL_STATUS_OK)
}
static void
-_act_store_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_store_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
if (r->action == ACTION_ASL_DIR) _act_store_dir(m, r, msg);
else _act_store_file(m, r, msg);
* or to an ASL directory (ACTION_ASL_DIR).
*/
static void
-_act_store(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_store(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
if (r == NULL) return;
+ if (r->dst == NULL) return;
if (msg == NULL) return;
if (m == NULL) return;
if ((m->flags & MODULE_FLAG_ENABLED) == 0) return;
- if (r->dst == NULL) return;
if (r->dst->flags & MODULE_FLAG_HAS_LOGGED) return;
+
r->dst->flags |= MODULE_FLAG_HAS_LOGGED;
+ if (r->action == ACTION_ASL_DIR)
+ {
+ asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private;
+ if (as_data != NULL) as_data->pending++;
+ }
+ else if (r->action == ACTION_ASL_FILE)
+ {
+ asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private;
+ if (af_data != NULL) af_data->pending++;
+ }
#if TARGET_OS_EMBEDDED
if (r->dst->flags & MODULE_FLAG_CRASHLOG)
{
_crashlog_queue_check();
- asl_msg_retain((asl_msg_t *)msg);
+ asl_msg_retain(msg);
dispatch_async(crashlog_queue, ^{
- _act_store_final(m, r, msg);
- asl_msg_release((asl_msg_t *)msg);
+ dispatch_async(asl_action_queue, ^{
+ _act_store_final(m, r, msg);
+ asl_msg_release(msg);
+ });
});
return;
}
static int
_send_repeat_msg(asl_out_rule_t *r)
{
- asl_action_file_data_t *fdata;
+ asl_action_file_data_t *f_data;
char vt[32], *msg;
int len, status;
time_t now = time(NULL);
if (r->dst == NULL) return -1;
if (r->dst->private == NULL) return -1;
- fdata = (asl_action_file_data_t *)r->dst->private;
+ f_data = (asl_action_file_data_t *)r->dst->private;
- free(fdata->last_msg);
- fdata->last_msg = NULL;
+ free(f_data->last_msg);
+ f_data->last_msg = NULL;
- if (fdata->last_count == 0) return 0;
+ if (f_data->last_count == 0) return 0;
/* stop the timer */
- dispatch_suspend(fdata->dup_timer);
+ dispatch_suspend(f_data->dup_timer);
memset(vt, 0, sizeof(vt));
ctime_r(&now, vt);
vt[19] = '\0';
msg = NULL;
- asprintf(&msg, "%s --- last message repeated %u time%s ---\n", vt + 4, fdata->last_count, (fdata->last_count == 1) ? "" : "s");
- fdata->last_count = 0;
- fdata->last_time = now;
+ asprintf(&msg, "%s --- last message repeated %u time%s ---\n", vt + 4, f_data->last_count, (f_data->last_count == 1) ? "" : "s");
+ f_data->last_count = 0;
+ f_data->last_time = now;
if (msg == NULL) return -1;
- if (fdata->fd < 0) fdata->fd = asl_out_dst_file_create_open(r->dst);
+ if (f_data->fd < 0) f_data->fd = _act_file_create_open(r->dst);
len = strlen(msg);
- status = write(fdata->fd, msg, len);
+ status = write(f_data->fd, msg, len);
free(msg);
if ((status < 0) || (status < len))
{
- asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->path, strerror(errno));
+ asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->fname, strerror(errno));
return -1;
}
return 0;
}
-static int
-_act_file_open(asl_out_module_t *m, asl_out_rule_t *r)
-{
- asl_action_file_data_t *fdata;
-
- if (r == NULL) return -1;
- if (r->dst == NULL) return -1;
- if (r->dst->private == NULL) return -1;
-
- fdata = (asl_action_file_data_t *)r->dst->private;
- if (fdata->fd < 0)
- {
- fdata->fd = asl_out_dst_file_create_open(r->dst);
- if (fdata->fd < 0)
- {
- /*
- * lazy path creation: create path and retry
- * asl_out_dst_file_create_open doesn not create the path
- * so we do it here.
- */
- asl_out_mkpath(r);
- fdata->fd = asl_out_dst_file_create_open(r->dst);
- }
-
- if (fdata->fd >= 0)
- {
- fdata->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fdata->fd, DISPATCH_VNODE_DELETE, asl_action_queue);
- if (fdata->monitor != NULL)
- {
- dispatch_source_set_event_handler(fdata->monitor, ^{ _act_dst_close(r); });
- dispatch_resume(fdata->monitor);
- }
- }
- }
-
- return fdata->fd;
-}
-
static void
_start_cycling()
{
{
if (r->dst->flags & MODULE_FLAG_CRASHLOG)
{
- if (asl_out_dst_checkpoint(r->dst, CHECKPOINT_FORCE) > 0)
+ if (_act_checkpoint(r, CHECKPOINT_FORCE) > 0)
{
did_checkpoint = 1;
- _act_dst_close(r);
+ _act_dst_close(r, DST_CLOSE_CHECKPOINT);
}
}
}
else
{
- if (asl_out_dst_checkpoint(r->dst, force) > 0)
+ if (_act_checkpoint(r, force) > 0)
{
did_checkpoint = 1;
- _act_dst_close(r);
+ _act_dst_close(r, DST_CLOSE_CHECKPOINT);
}
}
}
if (_act_file_checkpoint(m, NULL, force) > 0) did_checkpoint = 1;
}
- asl_trigger_aslmanager();
+ trigger_aslmanager();
return did_checkpoint;
}
+/*
+ * Save a message in a plain text file.
+ */
static void
-_act_file_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_file_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
- asl_action_file_data_t *fdata;
+ asl_action_file_data_t *f_data;
int is_dup;
uint32_t len, msg_hash = 0;
char *str;
time_t now;
+ if (r->dst->private == NULL) return;
+
+ f_data = (asl_action_file_data_t *)r->dst->private;
+ if (f_data->pending > 0) f_data->pending--;
+
/*
* If print format is std, bsd, or msg, then skip messages with
* no ASL_KEY_MSG, or without a value for it.
if (r->dst->flags & MODULE_FLAG_STD_BSD_MSG)
{
const char *msgval = NULL;
- if (asl_msg_lookup((asl_msg_t *)msg, ASL_KEY_MSG, &msgval, NULL) != 0) return;
+ if (asl_msg_lookup(msg, ASL_KEY_MSG, &msgval, NULL) != 0) return;
if (msgval == NULL) return;
}
- fdata = (asl_action_file_data_t *)r->dst->private;
-
now = time(NULL);
is_dup = 0;
- str = asl_format_message((asl_msg_t *)msg, r->dst->fmt, r->dst->tfmt, ASL_ENCODE_SAFE, &len);
+ str = asl_format_message(msg, r->dst->fmt, r->dst->tfmt, ASL_ENCODE_SAFE, &len);
if (r->dst->flags & MODULE_FLAG_COALESCE)
{
- if (fdata->dup_timer == NULL)
+ if (f_data->dup_timer == NULL)
{
/* create a timer to flush dups on this file */
- fdata->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, asl_action_queue);
- dispatch_source_set_event_handler(fdata->dup_timer, ^{ _send_repeat_msg(r); });
+ f_data->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, asl_action_queue);
+ dispatch_source_set_event_handler(f_data->dup_timer, ^{ _send_repeat_msg(r); });
}
- if ((global.bsd_max_dup_time > 0) && (str != NULL) && (fdata->last_msg != NULL))
+ if ((global.bsd_max_dup_time > 0) && (str != NULL) && (f_data->last_msg != NULL))
{
msg_hash = asl_core_string_hash(str + 16, len - 16);
- if ((fdata->last_hash == msg_hash) && (!strcmp(fdata->last_msg, str + 16)))
+ if ((f_data->last_hash == msg_hash) && (!strcmp(f_data->last_msg, str + 16)))
{
- if ((now - fdata->last_time) < global.bsd_max_dup_time) is_dup = 1;
+ if ((now - f_data->last_time) < global.bsd_max_dup_time) is_dup = 1;
}
}
}
if (is_dup == 1)
{
- if (fdata->last_count == 0)
+ if (f_data->last_count == 0)
{
/* start the timer */
- dispatch_source_set_timer(fdata->dup_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * global.bsd_max_dup_time), DISPATCH_TIME_FOREVER, 0);
- dispatch_resume(fdata->dup_timer);
+ dispatch_source_set_timer(f_data->dup_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * global.bsd_max_dup_time), DISPATCH_TIME_FOREVER, 0);
+ dispatch_resume(f_data->dup_timer);
}
- fdata->last_count++;
+ f_data->last_count++;
}
else
{
- if (_act_file_open(m, r) < 0)
+ if (_act_dst_open(r, NULL, 0) != 0)
{
_asl_action_save_failed("_act_file", m, r, ASL_STATUS_FAILED);
free(str);
}
/*
- * The current message is not a duplicate. If fdata->last_count > 0
+ * The current message is not a duplicate. If f_data->last_count > 0
* we need to write a "last message repeated N times" log entry.
* _send_repeat_msg will free last_msg and do nothing if
* last_count == 0, but we test and free here to avoid a function call.
*/
- if (fdata->last_count > 0)
+ if (f_data->last_count > 0)
{
_send_repeat_msg(r);
}
else
{
- free(fdata->last_msg);
- fdata->last_msg = NULL;
- }
-
- /* check dst for file_max & etc */
- if (r->dst->flags & MODULE_FLAG_ROTATE)
- {
- int ckpt = asl_out_dst_checkpoint(r->dst, CHECKPOINT_TEST);
- if (ckpt != 0)
- {
- _act_dst_close(r);
- asl_trigger_aslmanager();
-
- if (_act_file_open(m, r) < 0)
- {
- _asl_action_save_failed("_act_file", m, r, ASL_STATUS_FAILED);
- free(str);
- return;
- }
- else
- {
- r->dst->fails = 0;
- }
- }
+ free(f_data->last_msg);
+ f_data->last_msg = NULL;
}
- if (str != NULL) fdata->last_msg = strdup(str + 16);
+ if (str != NULL) f_data->last_msg = strdup(str + 16);
- fdata->last_hash = msg_hash;
- fdata->last_count = 0;
- fdata->last_time = now;
+ f_data->last_hash = msg_hash;
+ f_data->last_count = 0;
+ f_data->last_time = now;
if ((str != NULL) && (len > 1))
{
/* write line to file and update dst size */
- size_t bytes = write(fdata->fd, str, len - 1);
+ size_t bytes = write(f_data->fd, str, len - 1);
if (bytes > 0) r->dst->size += bytes;
+
+ if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager();
}
}
}
static void
-_act_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_file(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
+ asl_action_file_data_t *f_data;
+
if (r == NULL) return;
if (msg == NULL) return;
if (m == NULL) return;
if (r->dst->flags & MODULE_FLAG_HAS_LOGGED) return;
r->dst->flags |= MODULE_FLAG_HAS_LOGGED;
+ f_data = (asl_action_file_data_t *)r->dst->private;
+ if (f_data != NULL) f_data->pending++;
#if TARGET_OS_EMBEDDED
if (r->dst->flags & MODULE_FLAG_CRASHLOG)
{
_crashlog_queue_check();
- asl_msg_retain((asl_msg_t *)msg);
+ asl_msg_retain(msg);
dispatch_async(crashlog_queue, ^{
- _act_file_final(m, r, msg);
- asl_msg_release((asl_msg_t *)msg);
+ dispatch_async(asl_action_queue, ^{
+ _act_file_final(m, r, msg);
+ asl_msg_release(msg);
+ });
});
return;
}
}
static void
-_act_forward(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_forward(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
/* To do: <rdar://problem/6130747> Add a "forward" action to asl.conf */
}
static void
-_act_control(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg)
+_act_control(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg)
{
const char *p;
if (m == NULL) return;
if (r == NULL) return;
- p = asl_get(msg, ASL_KEY_MODULE);
+
+ p = asl_msg_get_val_for_key(msg, ASL_KEY_MODULE);
if (r->options == NULL) return;
}
static void
-_send_to_asl_store(aslmsg msg)
+_send_to_asl_store(asl_msg_t *msg)
{
if ((global.asl_out_module != NULL) && ((global.asl_out_module->flags & MODULE_FLAG_ENABLED) == 0)) return;
}
static int
-_asl_out_process_message(asl_out_module_t *m, aslmsg msg)
+_asl_out_process_message(asl_out_module_t *m, asl_msg_t *msg)
{
asl_out_rule_t *r;
*/
if (r->action == ACTION_CLAIM)
{
- if ((asl_msg_cmp(r->query, (asl_msg_t *)msg) != 1)) return 0;
+ if ((asl_msg_cmp(r->query, msg) != 1)) return 0;
}
- if ((asl_msg_cmp(r->query, (asl_msg_t *)msg) == 1))
+ if ((asl_msg_cmp(r->query, msg) == 1))
{
if (r->action == ACTION_NONE) continue;
else if (r->action == ACTION_IGNORE) return 1;
else if (r->action == ACTION_SKIP) return 0;
else if (r->action == ACTION_ASL_STORE) _send_to_asl_store(msg);
else if (r->action == ACTION_ACCESS) _act_access_control(m, r, msg);
+ else if (r->action == ACTION_SET_KEY) _act_set_key(m, r, msg);
+ else if (r->action == ACTION_UNSET_KEY) _act_unset_key(m, r, msg);
else if (r->action == ACTION_NOTIFY) _act_notify(m, r);
else if (r->action == ACTION_BROADCAST) _act_broadcast(m, r, msg);
else if (r->action == ACTION_FORWARD) _act_forward(m, r, msg);
}
void
-asl_out_message(aslmsg msg)
+asl_out_message(asl_msg_t *msg)
{
OSAtomicIncrement32(&global.asl_queue_count);
- asl_msg_retain((asl_msg_t *)msg);
+ asl_msg_retain(msg);
dispatch_async(asl_action_queue, ^{
int ignore = 0;
store_has_logged = false;
- p = asl_get(msg, ASL_KEY_MODULE);
+ p = asl_msg_get_val_for_key(msg, ASL_KEY_MODULE);
if (p == NULL)
{
if ((action_asl_store_count == 0) || (asl_check_option(msg, ASL_OPT_STORE) == 1)) _send_to_asl_store(msg);
}
}
- asl_msg_release((asl_msg_t *)msg);
+ p = asl_msg_get_val_for_key(msg, ASL_KEY_FINAL_NOTIFICATION);
+ if (p != NULL) asl_msg_set_key_val(msg, ASL_KEY_FREE_NOTE, p);
+
+ asl_msg_release(msg);
OSAtomicDecrement32(&global.asl_queue_count);
if ((now - sweep_time) >= IDLE_CLOSE)
bool eval;
/* ident is first message key */
- asl_msg_fetch((asl_msg_t *)r->query, 0, &ident, NULL, NULL);
+ asl_msg_fetch(r->query, 0, &ident, NULL, NULL);
if (ident == NULL)
{
r->action = ACTION_NONE;
bool eval;
/* path is first message key */
- asl_msg_fetch((asl_msg_t *)r->query, 0, &path, NULL, NULL);
+ asl_msg_fetch(r->query, 0, &path, NULL, NULL);
if (path == NULL)
{
r->action = ACTION_NONE;
}
else if (r->action == ACTION_ASL_DIR)
{
- if (r->dst->private == NULL) r->dst->private = (asl_action_store_data_t *)calloc(1, sizeof(asl_action_store_data_t));
+ if (r->dst->private == NULL) r->dst->private = (asl_action_asl_store_data_t *)calloc(1, sizeof(asl_action_asl_store_data_t));
}
else if (r->action == ACTION_ASL_FILE)
{
- if (r->dst->private == NULL)r->dst->private = (asl_action_store_data_t *)calloc(1, sizeof(asl_action_store_data_t));
+ if (r->dst->private == NULL)r->dst->private = (asl_action_asl_file_data_t *)calloc(1, sizeof(asl_action_asl_file_data_t));
}
else if (r->action == ACTION_FILE)
{
if (global.asl_out_module == NULL) global.asl_out_module = asl_out_module_init();
if (global.asl_out_module == NULL) return;
- if (global.debug != 0)
- {
- FILE *dfp;
- if (global.debug_file == NULL) dfp = fopen(_PATH_SYSLOGD_LOG, "a");
- else dfp = fopen(global.debug_file, "a");
- if (dfp != NULL)
- {
- for (m = global.asl_out_module; m != NULL; m = m->next)
- {
- fprintf(dfp, "module: %s%s\n", (m->name == NULL) ? "<unknown>" : m->name, (m->flags & MODULE_FLAG_LOCAL) ? " (local)" : "");
- asl_out_module_print(dfp, m);
- fprintf(dfp, "\n");
- }
- fclose(dfp);
- }
- }
-
asldebug("%s: init\n", MY_ID);
action_asl_store_count = 0;
_act_file_checkpoint_all(CHECKPOINT_TEST);
if (checkpoint_timer == NULL) _start_cycling();
}
-
-#if TARGET_OS_EMBEDDED
- if (flags & MODULE_FLAG_CRASHLOG) _crashlog_sentinel_init();
-#endif
}
int
asl_action_queue = dispatch_queue_create("ASL Action Queue", NULL);
#if TARGET_OS_EMBEDDED
crashlog_queue = dispatch_queue_create("iOS CrashLog Queue", NULL);
- notify_register_dispatch(CRASH_MOVER_WILL_START_NOTIFICATION, &crashmover_token, asl_action_queue, ^(int unused){
- if (crashmover_state == 0)
+ notify_register_dispatch(CRASH_MOVER_SERVICE, &crashmover_token, asl_action_queue, ^(int unused) {
+ uint64_t cmstate = 0;
+ uint64_t oldstate = (crashmover_state == 0) ? 0llu : 1llu;
+
+ uint32_t status = notify_get_state(crashmover_token, &cmstate);
+ if (status == 0)
{
- asldebug("CrashMover active: suspending crashlog queue and closing files\n");
- crashmover_state = time(NULL);
- dispatch_suspend(crashlog_queue);
- _asl_action_close_idle_files(0);
+ if (cmstate != oldstate)
+ {
+ crashmover_state = 0;
+ if (cmstate == 1) crashmover_state = time(NULL);
+
+ if (crashmover_state == 0)
+ {
+ asldebug("CrashMover finished\n");
+ dispatch_resume(crashlog_queue);
+ }
+ else
+ {
+ asldebug("CrashMover active: suspending crashlog queue and closing files\n");
+ dispatch_suspend(crashlog_queue);
+ _asl_action_close_idle_files(0);
+ }
+ }
}
});
#endif
}
/*
- * Free a module.
+ * Close outputs and free modules.
*/
static void
_asl_action_free_modules(asl_out_module_t *m)
{
for (r = x->ruleset; r != NULL; r = r->next)
{
- if ((r->action == ACTION_ASL_FILE) || (r->action == ACTION_ASL_DIR))
+ if (r->action == ACTION_ASL_DIR)
+ {
+ _act_dst_close(r, DST_CLOSE_SHUTDOWN);
+ if (r->dst != NULL)
+ {
+ _asl_action_asl_store_data_free((asl_action_asl_store_data_t *)r->dst->private);
+ r->dst->private = NULL;
+ }
+ }
+ else if (r->action == ACTION_ASL_FILE)
{
+ _act_dst_close(r, DST_CLOSE_SHUTDOWN);
if (r->dst != NULL)
{
- _asl_action_store_data_free((asl_action_store_data_t *)r->dst->private);
+ _asl_action_asl_file_data_free((asl_action_asl_file_data_t *)r->dst->private);
r->dst->private = NULL;
}
}
else if (r->action == ACTION_FILE)
{
+ _act_dst_close(r, DST_CLOSE_SHUTDOWN);
if (r->dst != NULL)
{
- asl_action_file_data_t *fdata = (asl_action_file_data_t *)r->dst->private;
- if (fdata != NULL)
+ asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private;
+ if (f_data != NULL)
{
/* flush repeat message if necessary */
- if (fdata->last_count > 0) _send_repeat_msg(r);
- _asl_action_file_data_free(fdata);
+ if (f_data->last_count > 0) _send_repeat_msg(r);
+ _asl_action_file_data_free(f_data);
r->dst->private = NULL;
}
}
{
_asl_action_set_param_data_free((asl_action_set_param_data_t *)r->private);
}
+ else if (r->action == ACTION_SET_FILE)
+ {
+ _asl_action_set_param_data_free((asl_action_set_param_data_t *)r->private);
+ }
}
}
_asl_action_close_internal(void)
{
#if TARGET_OS_EMBEDDED
- dispatch_source_cancel(crashlog_sentinel_src);
- dispatch_release(crashlog_sentinel_src);
- crashlog_sentinel_src = NULL;
- close(crashlog_sentinel_fd);
if (crashmover_state != 0)
{
dispatch_resume(crashlog_queue);
}
/* wait for the crashlog_queue to flush before _asl_action_free_modules() */
- dispatch_sync(crashlog_queue, ^{ crashlog_sentinel_fd = -1; });
+ dispatch_sync(crashlog_queue, ^{ int x = 0; if (x == 1) x = 2; });
#endif
_asl_action_free_modules(global.asl_out_module);
{
if ((r->dst != NULL) && (r->dst->flags & MODULE_FLAG_CRASHLOG))
{
- _act_dst_close(r);
- if (r->action != ACTION_ASL_DIR) asl_out_dst_checkpoint(r->dst, CHECKPOINT_FORCE);
+ _act_dst_close(r, DST_CLOSE_IDLE);
+ //TODO: can r->action even be ACTION_ASL_DIR?
+ /* if not, we can avoid the extra check here */
+ if (r->action != ACTION_ASL_DIR) _act_checkpoint(r, CHECKPOINT_FORCE);
+ }
+ }
+ else if (r->action == ACTION_ASL_DIR)
+ {
+ if (r->dst != NULL)
+ {
+ asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private;
+ if ((as_data != NULL) && (as_data->aslfile != NULL) && (as_data->pending == 0) && ((now - as_data->last_time) >= idle_time)) _act_dst_close(r, DST_CLOSE_IDLE);
}
}
- else if ((r->action == ACTION_ASL_DIR) || (r->action == ACTION_ASL_FILE))
+ else if (r->action == ACTION_ASL_FILE)
{
if (r->dst != NULL)
{
- asl_action_store_data_t *sdata = (asl_action_store_data_t *)r->dst->private;
- if ((sdata != NULL) && (sdata->store != NULL) && ((now - sdata->last_time) >= idle_time)) _act_dst_close(r);
+ asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private;
+ if ((af_data != NULL) && (af_data->aslfile != NULL) && (af_data->pending == 0) && ((now - af_data->last_time) >= idle_time)) _act_dst_close(r, DST_CLOSE_IDLE);
}
}
else if (r->action == ACTION_FILE)
{
if (r->dst != NULL)
{
- asl_action_file_data_t *fdata = (asl_action_file_data_t *)r->dst->private;
- if ((fdata != NULL) && (fdata->fd >= 0) && ((now - fdata->last_time) >= idle_time)) _act_dst_close(r);
+ asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private;
+ if ((f_data != NULL) && (f_data->fd >= 0) && (f_data->pending == 0) && ((now - f_data->last_time) >= idle_time)) _act_dst_close(r, DST_CLOSE_IDLE);
}
}
}
if (l != NULL) for (count = 0; l[count] != NULL; count++);
/* at least 2 parameters (l[0] = module, l[1] = param) required */
- if (count < 2) return -1;
+ if (count < 2)
+ {
+ free_string_list(l);
+ return -1;
+ }
if (global.asl_out_module == NULL)
{
asldebug("asl_action_control_set_param: no modules loaded\n");
+ free_string_list(l);
return -1;
}
if (p == NULL)
{
asldebug("asl_action_control_set_param: memory allocation failed\n");
+ free_string_list(l);
return -1;
}