/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * */ #include "config.h" #include #include #include #include #include #ifdef __FreeBSD__ #include #endif #include #include #include #include #include #include #include #include #include #include "ck-log-event.h" #define DEFAULT_LOG_FILENAME LOCALSTATEDIR "/log/ConsoleKit/history" #ifdef __linux__ #define LINUX_KERNEL_CMDLINE "/proc/cmdline" #endif /* Adapted from auditd auditd-event.c */ static gboolean open_log_file (const char *filename, int *fdp, FILE **filep) { int flags; int fd; int res; char *dirname; FILE *file; gboolean ret; ret = FALSE; /* * Likely errors on rotate: ENFILE, ENOMEM, ENOSPC */ flags = O_WRONLY | O_APPEND; #ifdef O_NOFOLLOW flags |= O_NOFOLLOW; #endif dirname = g_path_get_dirname (filename); /* always make sure we have a directory */ errno = 0; res = g_mkdir_with_parents (dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (res < 0) { g_warning ("Unable to create directory %s (%s)", dirname, g_strerror (errno)); g_free (dirname); return FALSE; } g_free (dirname); retry: fd = g_open (filename, flags, 0600); if (fd < 0) { if (errno == ENOENT) { /* FIXME: should we just skip if file doesn't exist? */ fd = g_open (filename, O_CREAT | O_EXCL | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { g_warning ("Couldn't create log file %s (%s)", filename, g_strerror (errno)); goto out; } close (fd); fd = g_open (filename, flags, 0600); } else if (errno == ENFILE) { /* All system descriptors used, try again... */ goto retry; } if (fd < 0) { g_warning ("Couldn't open log file %s (%s)", filename, g_strerror (errno)); goto out; } } if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) { close (fd); g_warning ("Error setting log file CLOEXEC flag (%s)", g_strerror (errno)); goto out; } if (fchown (fd, 0, 0) == -1) { g_warning ("Error changing owner of log file (%s)", g_strerror (errno)); } file = fdopen (fd, "a"); if (file == NULL) { g_warning ("Error setting up log descriptor (%s)", g_strerror (errno)); close (fd); goto out; } /* Set it to line buffering */ setlinebuf (file); ret = TRUE; if (fdp != NULL) { *fdp = fd; } if (filep != NULL) { *filep = file; } out: return ret; } static gboolean write_log_for_event (CkLogEvent *event) { GString *str; FILE *file; int fd; str = g_string_new (NULL); ck_log_event_to_string (event, str); if (! open_log_file (DEFAULT_LOG_FILENAME, &fd, &file)) { exit (1); } if (file != NULL) { int rc; rc = fprintf (file, "%s\n", str->str); if (rc <= 0) { g_warning ("Record was not written to disk (%s)", g_strerror (errno)); } } else { g_warning ("Log file not open for writing"); } g_string_free (str, TRUE); return TRUE; } static char * get_boot_arguments (void) { #if defined(__linux__) char *contents; gboolean res; contents = NULL; res = g_file_get_contents (LINUX_KERNEL_CMDLINE, &contents, NULL, NULL); if (!res) { g_free (contents); contents = NULL; } else { g_strchomp (contents); } return contents; #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) char kern_name[1024], root[1024], mopts[1024]; char *options; options = NULL; if (kenv(KENV_GET, "kernelname", kern_name, sizeof (kern_name)) == -1) { return options; } if (kenv(KENV_GET, "vfs.root.mountfrom.options", mopts, sizeof (mopts)) == -1) { g_strlcpy (mopts, "ro", sizeof (mopts)); } if (kenv(KENV_GET, "vfs.root.mountfrom", root, sizeof (root)) == -1) { g_strlcpy (root, "/", sizeof (root)); } options = g_strdup_printf ("%s %s root=%s", mopts, kern_name, root); return options; #else return NULL; #endif } int main (int argc, char **argv) { CkLogEvent event; CkLogSystemStartEvent *e; struct utsname uts; /* Setup for i18n */ setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif memset (&event, 0, sizeof (CkLogEvent)); event.type = CK_LOG_EVENT_SYSTEM_START; g_get_current_time (&event.timestamp); e = (CkLogSystemStartEvent *) &event.event; if (uname (&uts) == 0) { e->kernel_release = uts.release; } e->boot_arguments = get_boot_arguments (); write_log_for_event (&event); return 0; }