On Thu, Feb 12, 2009 at 03:32:10PM +0100, Jan Safranek wrote:
> Rework whole cgrulesengd logging to be able to send log messages to syslog.
> Also introduce more log levels:
> 
> LOG_NOTICE is the default log level, it logs startup/shutdown/configuration
> reload and errors.
> 
> LOG_INFO shows in addition content of configuration file (only
> if logging to file is enabled) and changing cgroup of a PID.
> 
> LOG_DEBUG show all details as it was before the patch.
> 
> TODO: if something gets wrong with mounted hierarchies (e.g. root unmounts
> them), the log gets full of "Cgroup change for PID: ... FAILED". Some
> suppression should be implemented.
> 
> Signed-off-by: Jan Safranek <[email protected]>
> Acked-by: Dhaval Giani <[email protected]>
> ---
> 
>  cgrulesengd.c |  234 
> +++++++++++++++++++++++++++++++++++++--------------------
>  cgrulesengd.h |   18 ++--
>  2 files changed, 160 insertions(+), 92 deletions(-)
> 
> diff --git a/cgrulesengd.c b/cgrulesengd.c
> index 527184b..da2b6f0 100644
> --- a/cgrulesengd.c
> +++ b/cgrulesengd.c
> @@ -44,15 +44,22 @@
>  #include <linux/netlink.h>
>  #include <signal.h>
>  #include <time.h>
> +#include <syslog.h>
> 
>  #include <sys/stat.h>
>  #include <unistd.h>
>  #include <linux/connector.h>
>  #include <linux/cn_proc.h>
> 
> -/* Log file */
> +/* Log file, NULL if logging to file is disabled */
>  FILE* logfile;
> 
> +/* Log facility, 0 if logging to syslog is disabled */
> +int logfacility;
> +
> +/* Current log level */
> +int loglevel;
> +
>  /**
>   * Prints the usage information for this program and, optionally, an error
>   * message.  This function uses vfprintf.
> @@ -78,24 +85,41 @@ void usage(FILE* fd, const char* msg, ...)
>  }
> 
>  /**
> - * Prints a formatted message (like printf()) to a file stream, and flushes
> - * the file stream's buffer so that the message is immediately readable.
> - *   @param fd The file stream to write to
> + * Prints a formatted message (like printf()) to all log destinations.
> + * Flushes the file stream's buffer so that the message is immediately
> + * readable.
> + *   @param level The log level (LOG_EMERG ... LOG_DEBUG)
>   *   @param format The format for the message (printf style)
>   *   @param ... Any args to format (printf style)
>   */
> -void flog(FILE* fd, const char* format, ...)
> +void flog(int level, const char *format, ...)
>  {
>       /* List of args to format */
>       va_list ap;
> 
> -     /* Print the message to the given stream. */
> -     va_start(ap, format);
> -     vfprintf(fd, format, ap);
> -     va_end(ap);
> +     /* Check the log level */
> +     if (level > loglevel)
> +             return;
> +
> +     if (logfile) {
> +             /* Print the message to the given stream. */
> +             va_start(ap, format);
> +             vfprintf(logfile, format, ap);
> +             va_end(ap);
> +             fprintf(logfile, "\n");
> +
> +             /*
> +              * Flush the stream's buffer, so the data is readable
> +              * immediately.
> +              */
> +             fflush(logfile);
> +     }
> 
> -     /* Flush the stream's buffer, so the data is readable immediately. */
> -     fflush(fd);
> +     if (logfacility) {
> +             va_start(ap, format);
> +             vsyslog(LOG_MAKEPRI(logfacility, level), format, ap);
> +             va_end(ap);
> +     }
>  }
> 
>  /**
> @@ -135,15 +159,15 @@ int cgre_process_event(const struct proc_event *ev, 
> const int type)
>       sprintf(path, "/proc/%d/status", ev->event_data.id.process_pid);
>       f = fopen(path, "r");
>       if (!f) {
> -             flog(logfile, "Failed to open %s", path);
> +             flog(LOG_WARNING, "Failed to open %s", path);
>               goto finished;
>       }
> 
>       /* Now, we need to find either the eUID or the eGID of the process. */
>       buf = calloc(4096, sizeof(char));
>       if (!buf) {
> -             flog(logfile, "Failed to process event, out of"
> -                             "memory?  Error: %s\n",
> +             flog(LOG_WARNING, "Failed to process event, out of"
> +                             "memory?  Error: %s",
>                               strerror(errno));
>               ret = errno;
>               fclose(f);
> @@ -173,8 +197,8 @@ int cgre_process_event(const struct proc_event *ev, const 
> int type)
>               }
>               break;
>       default:
> -             flog(logfile, "For some reason, we're processing a non-UID/GID"
> -                             " event.  Something is wrong!\n");
> +             flog(LOG_WARNING, "For some reason, we're processing a"
> +                             " non-UID/GID event. Something is wrong!");
>               break;
>       }
>       free(buf);
> @@ -186,7 +210,7 @@ int cgre_process_event(const struct proc_event *ev, const 
> int type)
>        */
>       switch (type) {
>       case PROC_EVENT_UID:
> -             flog(logfile, "Attempting to change cgroup for PID: %d, "
> +             flog(LOG_DEBUG, "Attempting to change cgroup for PID: %d, "
>                               "UID: %d, GID: %d... ",
>                               ev->event_data.id.process_pid,
>                               ev->event_data.id.e.euid, egid);
> @@ -196,7 +220,7 @@ int cgre_process_event(const struct proc_event *ev, const 
> int type)
>                                       CGFLAG_USECACHE);
>               break;
>       case PROC_EVENT_GID:
> -             flog(logfile, "Attempting to change cgroup for PID: %d, "
> +             flog(LOG_DEBUG, "Attempting to change cgroup for PID: %d, "
>                               "UID: %d, GID: %d... ",
>                               ev->event_data.id.process_pid, euid,
>                               ev->event_data.id.e.egid);
> @@ -210,9 +234,9 @@ int cgre_process_event(const struct proc_event *ev, const 
> int type)
>       }
> 
>       if (ret) {
> -             flog(logfile, "FAILED!\n  (Error Code: %d)\n", ret);
> +             flog(LOG_WARNING, "FAILED!\n  (Error Code: %d)\n", ret);
>       } else {
> -             flog(logfile, "OK!\n");
> +             flog(LOG_INFO, "OK!\n");
>       }
> 
>  finished:
> @@ -238,18 +262,16 @@ int cgre_handle_msg(struct cn_msg *cn_hdr)
>       ev = (struct proc_event*)cn_hdr->data;
>       switch (ev->what) {
>       case PROC_EVENT_UID:
> -             flog(logfile, "UID Event:\n");
> -             flog(logfile, "  PID = %d, tGID = %d, rUID = %d, eUID = %d\n",
> -                             ev->event_data.id.process_pid,
> +             flog(LOG_DEBUG, "UID Event: PID = %d, tGID = %d, rUID = %d,"
> +                             " eUID = %d", ev->event_data.id.process_pid,
>                               ev->event_data.id.process_tgid,
>                               ev->event_data.id.r.ruid,
>                               ev->event_data.id.e.euid);
>               ret = cgre_process_event(ev, PROC_EVENT_UID);
>               break;
>       case PROC_EVENT_GID:
> -             flog(logfile, "GID Event:\n");
> -             flog(logfile, "  PID = %d, tGID = %d, rGID = %d, eGID = %d\n",
> -                             ev->event_data.id.process_pid,
> +             flog(LOG_DEBUG, "GID Event: PID = %d, tGID = %d, rGID = %d,"
> +                             " eGID = %d", ev->event_data.id.process_pid,
>                               ev->event_data.id.process_tgid,
>                               ev->event_data.id.r.rgid,
>                               ev->event_data.id.e.egid);
> @@ -338,12 +360,8 @@ int cgre_create_netlink_socket_process_msg()
>               recv_len = recvfrom(sk_nl, buff, BUFF_SIZE, 0,
>               (struct sockaddr*)&from_nla, &from_nla_len);
>               if (recv_len == ENOBUFS) {
> -                     flog(logfile, "************************************"
> -                                     "***********\n"
> -                                     "!***ERROR: NETLINK BUFFER FULL, MSG "
> -                                     "DROPPED***!\n"
> -                                     "************************************"
> -                                     "***********\n");
> +                     flog(LOG_ERR, "ERROR: NETLINK BUFFER FULL, MESSAGE "
> +                                     "DROPPED!");
>                       continue;
>               }
>               if (recv_len < 1)
> @@ -370,23 +388,84 @@ close_and_exit:
>  }
> 
>  /**
> + * Start logging. Opens syslog and/or log file and sets log level.
> + *   @param logp Path of the log file, NULL if no log file was specified
> + *   @param logf Syslog facility, NULL if no facility was specified
> + *   @param logv Log verbosity, 2 is the default, 0 = no logging, 4 = 
> everything
> + */
> +static void cgre_start_log(const char *logp, int logf, int logv)
> +{
> +     /* Current system time */
> +     time_t tm;
> +
> +     /* Log levels */
> +     int loglevels[] = {
> +             LOG_EMERG,              /* -qq */
> +             LOG_ERR,                /* -q */
> +             LOG_NOTICE,             /* default */
> +             LOG_INFO,               /* -v */
> +             LOG_DEBUG               /* -vv */
> +     };
> +
> +     /* Set default logging destination if nothing was specified */
> +     if (!logp && !logf)
> +             logf = LOG_DAEMON;
> +
> +     /* Open log file */
> +     if (logp) {
> +             if (strcmp("-", logp) == 0) {
> +                     logfile = stdout;
> +             } else {
> +                     logfile = fopen(logp, "a");
> +                     if (!logfile) {
> +                             fprintf(stderr, "Failed to open log file %s,"
> +                                     " error: %s. Continuing anyway.\n",
> +                                     logp, strerror(errno));
> +                             logfile = stdout;
> +                     }
> +             }
> +     } else
> +             logfile = NULL;
> +
> +     /* Open syslog */
> +     if (logf) {
> +             openlog("CGRE", LOG_CONS | LOG_PID, logf);
> +             logfacility = logf;
> +     } else
> +             logfacility = 0;
> +
> +     /* Set the log level */
> +     if (logv < 0)
> +             logv = 0;
> +     if (logv >= sizeof(loglevels)/sizeof(int))
> +             logv = sizeof(loglevels)/sizeof(int)-1;
> +
> +     loglevel = loglevels[logv];
> +
> +     flog(LOG_DEBUG, "CGroup Rules Engine Daemon log started");
> +     tm = time(0);
> +     flog(LOG_DEBUG, "Current time: %s", ctime(&tm));
> +     flog(LOG_DEBUG, "Opened log file: %s, log facility: %d, log level: %d",
> +                     logp, logfacility, loglevel);
> +}
> +
> +
> +/**
>   * Turns this program into a daemon.  In doing so, we fork() and kill the
>   * parent process.  Note too that stdout, stdin, and stderr are closed in
>   * daemon mode, and a file descriptor for a log file is opened.
> - *   @param logp Path of the log file
> + *   @param logp Path of the log file, NULL if no log file was specified
> + *   @param logf Syslog facility, 0 if no facility was specified
>   *   @param daemon False to turn off daemon mode (no fork, leave FDs open)
> - *   @param logs False to disable logging (no log FD, leave stdout open)
> + *   @param logv Log verbosity, 2 is the default, 0 = no logging, 5 = 
> everything
>   *   @return 0 on success, > 0 on error
>   */
> -int cgre_start_daemon(const char* logp, const unsigned char daemon,
> -                     const unsigned char logs)
> +int cgre_start_daemon(const char *logp, const int logf,
> +                     const unsigned char daemon, const int logv)
>  {
>       /* PID returned from the fork() */
>       pid_t pid;
> 
> -     /* Current system time */
> -     time_t tm;
> -
>       /* Fork and die. */
>       if (daemon) {
>               pid = fork();
> @@ -395,10 +474,10 @@ int cgre_start_daemon(const char* logp, const unsigned 
> char daemon,
>                       syslog(LOG_DAEMON|LOG_WARNING, "Failed to fork,"
>                                       " error: %s", strerror(errno));
>                       closelog();
> -                     flog(stderr, "Failed to fork(), %s\n", strerror(errno));
> +                     fprintf(stderr, "Failed to fork(), %s\n",
> +                                     strerror(errno));
>                       return 1;
>               } else if (pid > 0) {
> -                     flog(stdout, "Starting in daemon mode.\n");
>                       exit(EXIT_SUCCESS);
>               }
> 
> @@ -409,41 +488,23 @@ int cgre_start_daemon(const char* logp, const unsigned 
> char daemon,
>               pid = getpid();
>       }
> 
> -     if (logs) {
> -             logfile = fopen(logp, "a");
> -             if (!logfile) {
> -                     flog(stderr, "Failed to open log file %s, error: %s."
> -                                     "  Continuing anyway.\n", logp,
> -                                     strerror(errno));
> -                     logfile = stdout;
> -             } else {
> -                     flog(logfile, "CGroup Rules Engine Daemon\n");
> -                     tm = time(0);
> -                     flog(logfile, "Current time: %s", ctime(&tm));
> -                     flog(stdout, "Opened log file: %s\n", logp);
> -             }
> -     } else {
> -             logfile = stdout;
> -             flog(stdout, "Proceeding with stdout as log output.\n");
> -     }
> +     cgre_start_log(logp, logf, logv);
> 
>       if (!daemon) {
>               /* We can skip the rest, since we're not becoming a daemon. */
> -             flog(logfile, "Proceeding with PID %d\n\n", getpid());
> -             if (logfile != stdout)
> -                     flog(stdout, "Proceeding with PID %d\n", getpid());
> +             flog(LOG_INFO, "Proceeding with PID %d", getpid());
>               return 0;
>       } else {
>               /* Get a new SID for the child. */
>               if (setsid() < 0) {
> -                     flog(logfile, "Failed to get a new SID, error: %s\n",
> +                     flog(LOG_ERR, "Failed to get a new SID, error: %s",
>                                       strerror(errno));
>                       return 2;
>               }
> 
>               /* Change to the root directory. */
>               if (chdir("/") < 0) {
> -                     flog(logfile, "Failed to chdir to /, error: %s\n",
> +                     flog(LOG_ERR, "Failed to chdir to /, error: %s",
>                                       strerror(errno));
>                       return 3;
>               }
> @@ -456,7 +517,7 @@ int cgre_start_daemon(const char* logp, const unsigned 
> char daemon,
>       }
> 
>       /* If we make it this far, we're a real daemon! Or we chose not to.  */
> -     flog(logfile, "Proceeding with PID %d\n\n", getpid());
> +     flog(LOG_INFO, "Proceeding with PID %d", getpid());
>       return 0;
>  }
> 
> @@ -470,15 +531,17 @@ void cgre_flash_rules(int signum)
>       /* Current time */
>       time_t tm = time(0);
> 
> -     flog(logfile, "\nReloading rules configuration.\n");
> -     flog(logfile, "Current time: %s\n", ctime(&tm));
> +     flog(LOG_NOTICE, "Reloading rules configuration.");
> +     flog(LOG_DEBUG, "Current time: %s", ctime(&tm));
> 
>       /* Ask libcgroup to reload the rules table. */
>       cgroup_reload_cached_rules();
> 
>       /* Print the results of the new table to our log file. */
> -     cgroup_print_rules_config(logfile);
> -     flog(logfile, "\n");
> +     if (logfile && loglevel >= LOG_INFO) {
> +             cgroup_print_rules_config(logfile);
> +             fprintf(logfile, "\n");
> +     }
>  }
> 
>  /**
> @@ -491,15 +554,17 @@ void cgre_catch_term(int signum)
>       /* Current time */
>       time_t tm = time(0);
> 
> -     flog(logfile, "\nStopped CGroup Rules Engine Daemon at %s",
> +     flog(LOG_NOTICE, "Stopped CGroup Rules Engine Daemon at %s",
>                       ctime(&tm));
> -     flog(logfile, "========================================");
> -     flog(logfile, "========================================\n\n");
> 
> -     /* Close the log file, if we opened one. */
> +     /* Close the log file, if we opened one */
>       if (logfile && logfile != stdout)
>               fclose(logfile);
> 
> +     /* Close syslog */
> +     if (logfacility)
> +             closelog();
> +
>       exit(EXIT_SUCCESS);
>  }
> 
> @@ -514,8 +579,8 @@ int main(int argc, char *argv[])
>       /* Should we daemonize? */
>       unsigned char daemon = 1;
> 
> -     /* Should we log? */
> -     unsigned char logs = 1;
> +     /* Log level */
> +     int loglevel = 4;
> 

Another patch, (since I am merging this set in) to change these magic
numbers please.

>       /* Return codes */
>       int ret = 0;
> @@ -550,7 +615,7 @@ int main(int argc, char *argv[])
>                       continue;
>               }
>               if (strncmp(argv[i], "--nolog", strlen("--nolog")) == 0) {
> -                     logs = 0;
> +                     loglevel = 0;
>                       continue;
>               }
> 
> @@ -560,8 +625,6 @@ int main(int argc, char *argv[])
>               goto finished;
>       }
> 
> -     flog(stdout, "Log file is: %s\n", logp);
> -
>       /* Initialize libcgroup. */
>       if ((ret = cgroup_init()) != 0) {
>               fprintf(stderr, "Error: libcgroup initialization failed, %d\n",
> @@ -577,7 +640,8 @@ int main(int argc, char *argv[])
>       }
> 
>       /* Now, start the daemon. */
> -     if ((ret = cgre_start_daemon(logp, daemon, logs)) < 0) {
> +     ret = cgre_start_daemon(logp, 0, daemon, loglevel);
> +     if (ret < 0) {
>               fprintf(stderr, "Error: Failed to launch the daemon, %d\n",
>                       ret);
>               goto finished;
> @@ -592,8 +656,8 @@ int main(int argc, char *argv[])
>       sa.sa_restorer = NULL;
>       sigemptyset(&sa.sa_mask);
>       if ((ret = sigaction(SIGUSR2, &sa, NULL))) {

This can probably be another patch as well. (while you are at it)

> -             flog(logfile, "Failed to set up signal handler for SIGUSR2."
> -                             " Error: %s\n", strerror(errno));
> +             flog(LOG_ERR, "Failed to set up signal handler for SIGUSR2."
> +                             " Error: %s", strerror(errno));
>               goto finished;
>       }
> 
> @@ -605,14 +669,16 @@ int main(int argc, char *argv[])
>       ret = sigaction(SIGINT, &sa, NULL);
>       ret |= sigaction(SIGTERM, &sa, NULL);
>       if (ret) {
> -             flog(logfile, "Failed to set up the signal handler.  Error:"
> -                             " %s\n", strerror(errno));
> +             flog(LOG_ERR, "Failed to set up the signal handler.  Error:"
> +                             " %s", strerror(errno));
>               goto finished;
>       }
> 
>       /* Print the configuration to the log file, or stdout. */
> -     cgroup_print_rules_config(logfile);
> -     flog(logfile, "Started the CGroup Rules Engine Daemon.\n");
> +     if (logfile && loglevel >= LOG_INFO)
> +             cgroup_print_rules_config(logfile);
> +
> +     flog(LOG_NOTICE, "Started the CGroup Rules Engine Daemon.");
> 
>       /* We loop endlesly in this function, unless we encounter an error. */
>       ret =  cgre_create_netlink_socket_process_msg();
> diff --git a/cgrulesengd.h b/cgrulesengd.h
> index bdffd31..5c5d2a5 100644
> --- a/cgrulesengd.h
> +++ b/cgrulesengd.h
> @@ -65,13 +65,14 @@ __BEGIN_DECLS
>  void cgre_usage(FILE *fd, const char *msg, ...);
> 
>  /**
> - * Prints a formatted message (like printf()) to a file stream, and flushes
> - * the file stream's buffer so that the message is immediately readable.
> - *   @param fd The file stream to write to
> + * Prints a formatted message (like printf()) to all log destinations.
> + * Flushes the file stream's buffer so that the message is immediately
> + * readable.
> + *   @param level The log level (LOG_EMERG ... LOG_DEBUG)
>   *   @param format The format for the message (printf style)
>   *   @param ... Any args to format (printf style)
>   */
> -void flog(FILE* fd, const char* msg, ...);
> +void flog(int level, const char *msg, ...);
> 
>  /**
>   * Process an event from the kernel, and determine the correct UID/GID/PID to
> @@ -96,13 +97,14 @@ int cgre_handle_message(struct cn_msg *cn_hdr);
>   * Turns this program into a daemon.  In doing so, we fork() and kill the
>   * parent process.  Note too that stdout, stdin, and stderr are closed in
>   * daemon mode, and a file descriptor for a log file is opened.
> - *   @param logp Path of the log file
> + *   @param logp Path of the log file, NULL if no log file was specified
> + *   @param logf Syslog facility, NULL if no facility was specified
>   *   @param daemon False to turn off daemon mode (no fork, leave FDs open)
> - *   @param logs False to disable logging (no log FD, leave stdout open)
> + *   @param logv Log verbosity, 2 is the default, 0 = no logging, 5 = 
> everything
>   *   @return 0 on success, > 0 on error
>   */
> -int cgre_start_daemon(const char *logp, const unsigned char daemon,
> -                     const unsigned char logs);
> +int cgre_start_daemon(const char *logp, const int logf,
> +                     const unsigned char daemon, const int logv);
> 
>  /**
>   * Catch the SIGUSR2 signal and reload the rules configuration.  This 
> function
> 
> 

-- 
regards,
Dhaval

------------------------------------------------------------------------------
_______________________________________________
Libcg-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to