commit 88295ba42a7a6297b548e1b928353867afd6a553 Author: Thierry FOURNIER Date: Thu Sep 19 16:54:24 2013 +0200 BUILTIN: Add function sendlog. sendlog [-i] [-p pri] [-t tag] [message ...] Logger makes entries in the system log. It provides a shell command interface to the syslog system log module. Options: -i Log the process id of the logger process with each line. -p pri Enter the message with the specified priority. The priority may be specified numerically or as a "facility.level" pair. For example, "-p local3.info" logs the message(s) as informational level in the local3 facility. The default is "user.notice." -t tag Mark every line in the log with the specified tag. message Write the message to log; if not specified, and the -f flag is not provided, standard input is logged. The logger utility exits 0 on success, and >0 if an error occurs. Valid facility names are: auth, authpriv (for security information of a sensitive nature), cron, daemon, ftp, kern, lpr, mail, news, security (deprecated synonym for auth), syslog, user, uucp, and local0 to local7, inclusive. Valid level names are): alert, crit, debug, emerg, err, error (deprecated synonym for err), info, notice, panic (deprecated synonym for), warning, warn (deprecated synonym for warning). For the priority order and intended purposes of these levels, see syslog(3). diff --git ./builtins/Makefile.in ./builtins/Makefile.in index 06c11b5..4943bd8 100644 --- ./builtins/Makefile.in +++ ./builtins/Makefile.in @@ -122,6 +122,7 @@ RL_LIBSRC = $(topdir)/lib/readline DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \ $(srcdir)/sleep.def \ $(srcdir)/usleep.def \ + $(srcdir)/sendlog.def \ $(srcdir)/builtin.def $(srcdir)/caller.def \ $(srcdir)/cd.def $(srcdir)/colon.def \ $(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \ @@ -143,6 +144,7 @@ STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \ OFILES = builtins.o \ sleep.o \ usleep.o \ + sendlog.o \ alias.o bind.o break.o builtin.o caller.o cd.o colon.o command.o \ common.o declare.o echo.o enable.o eval.o evalfile.o \ evalstring.o exec.o \ @@ -286,6 +288,7 @@ reserved.o: reserved.def complete.o: complete.def sleep.o: sleep.def usleep.o: usleep.def +sendlog.o: sendlog.def # C files bashgetopt.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h diff --git ./builtins/sendlog.def ./builtins/sendlog.def new file mode 100644 index 0000000..de619b2 --- /dev/null +++ ./builtins/sendlog.def @@ -0,0 +1,258 @@ +$BUILTIN sendlog +$FUNCTION sendlog_builtin +$PRODUCES sendlog.c +$SHORT_DOC sendlog [-i] [-p pri] [-t tag] [message ...] + +Logger makes entries in the system log. It provides a shell command interface +to the syslog system log module. + +Options: + +-i Log the process id of the logger process with each line. + +-p pri Enter the message with the specified priority. The priority may be + specified numerically or as a "facility.level" pair. For example, + "-p local3.info" logs the message(s) as informational level in the + local3 facility. The default is "user.notice." + +-t tag Mark every line in the log with the specified tag. + +message Write the message to log; if not specified, and the -f flag is not +provided, standard input is logged. The logger utility exits 0 on success, and +>0 if an error occurs. Valid facility names are: auth, authpriv (for security +information of a sensitive nature), cron, daemon, ftp, kern, lpr, mail, news, +security (deprecated synonym for auth), syslog, user, uucp, and local0 to +local7, inclusive. Valid level names are): alert, crit, debug, emerg, err, +error (deprecated synonym for err), info, notice, panic (deprecated synonym +for), warning, warn (deprecated synonym for warning). For the priority order and +intended purposes of these levels, see syslog(3). + +$END + +#include +#include + +#include +#include +#include +#include + +#include + +#include "../shell.h" +#include "common.h" +#include "bashgetopt.h" + +#define LOGSIZE 1024 +static char *month[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +int sendlog_builtin(WORD_LIST *list) +{ + int opt; + char *pri = NULL; + char *tag = NULL; + int log_procid = 0; + int facility; + int severity; + int len; + int l; + int priority = LOG_MAKEPRI(LOG_USER, LOG_NOTICE); + char *p; + static char *user = NULL; + static char buffer[LOGSIZE]; + char *log = buffer; + static int syslog_fd = -1; + struct sockaddr_un sa; + int loglen = 0; + struct timeval now; + struct tm tm; + + reset_internal_getopt(); + while ((opt = internal_getopt (list, "hip:t:")) != -1) { + switch (opt) { + case 'i': + log_procid = 1; + break; + case 'p': + pri = list_optarg; + break; + case 't': + tag = list_optarg; + break; + case 'h': + default: + builtin_usage(); + return (EX_USAGE); + } + } + list = loptend; + + /* check tag syntax. Check if char ios printable and if is not a space */ + if (tag) { + for (p = tag; + *p != '\0'; + p++) { + if (!isprint(*p)) { + builtin_error("bad character in -p option: '%s'", tag); + return 1; + } + if (isspace(*p)) { + builtin_error("-p option must no contain space: '%s'", tag); + return 1; + } + } + } + + /* set default tag to username */ + else { + if (user == NULL) { + if (current_user.user_name == NULL) + get_current_user_info(); + if (current_user.user_name == NULL) { + builtin_error("internal error: cannot retrieve username"); + return 1; + } + user = strdup(current_user.user_name); + } + tag = user; + } + + /* parse pri */ + if (pri != NULL) { + + /* match facility */ + /**/ if (strncmp(pri, "auth.", strlen("auth.")) == 0) { facility = LOG_AUTH; len = strlen("auth."); } + else if (strncmp(pri, "authpriv.", strlen("authpriv.")) == 0) { facility = LOG_AUTHPRIV; len = strlen("authpriv."); } + else if (strncmp(pri, "cron.", strlen("cron.")) == 0) { facility = LOG_CRON; len = strlen("cron."); } + else if (strncmp(pri, "daemon.", strlen("daemon.")) == 0) { facility = LOG_DAEMON; len = strlen("daemon."); } + else if (strncmp(pri, "ftp.", strlen("ftp.")) == 0) { facility = LOG_FTP; len = strlen("ftp."); } + else if (strncmp(pri, "kern.", strlen("kern.")) == 0) { facility = LOG_KERN; len = strlen("kern."); } + else if (strncmp(pri, "lpr.", strlen("lpr.")) == 0) { facility = LOG_LPR; len = strlen("lpr."); } + else if (strncmp(pri, "mail.", strlen("mail.")) == 0) { facility = LOG_MAIL; len = strlen("mail."); } + else if (strncmp(pri, "news.", strlen("news.")) == 0) { facility = LOG_NEWS; len = strlen("news."); } + else if (strncmp(pri, "security.", strlen("security.")) == 0) { facility = LOG_AUTH; len = strlen("security."); } + else if (strncmp(pri, "syslog.", strlen("syslog.")) == 0) { facility = LOG_SYSLOG; len = strlen("syslog."); } + else if (strncmp(pri, "user.", strlen("user.")) == 0) { facility = LOG_USER; len = strlen("user."); } + else if (strncmp(pri, "uucp.", strlen("uucp.")) == 0) { facility = LOG_UUCP; len = strlen("uucp."); } + else if (strncmp(pri, "local0.", strlen("local0.")) == 0) { facility = LOG_LOCAL0; len = strlen("local0."); } + else if (strncmp(pri, "local1.", strlen("local1.")) == 0) { facility = LOG_LOCAL1; len = strlen("local1."); } + else if (strncmp(pri, "local2.", strlen("local2.")) == 0) { facility = LOG_LOCAL2; len = strlen("local2."); } + else if (strncmp(pri, "local3.", strlen("local3.")) == 0) { facility = LOG_LOCAL3; len = strlen("local3."); } + else if (strncmp(pri, "local4.", strlen("local4.")) == 0) { facility = LOG_LOCAL4; len = strlen("local4."); } + else if (strncmp(pri, "local5.", strlen("local5.")) == 0) { facility = LOG_LOCAL5; len = strlen("local5."); } + else if (strncmp(pri, "local6.", strlen("local6.")) == 0) { facility = LOG_LOCAL6; len = strlen("local6."); } + else if (strncmp(pri, "local7.", strlen("local7.")) == 0) { facility = LOG_LOCAL7; len = strlen("local7."); } + else { + builtin_error("unknown priority name: %s", pri); + return 1; + } + + /* match severity */ + p = pri + len; + /**/ if (strcmp(p, "alert") == 0) { severity = LOG_ALERT; } + else if (strcmp(p, "crit") == 0) { severity = LOG_CRIT; } + else if (strcmp(p, "debug") == 0) { severity = LOG_DEBUG; } + else if (strcmp(p, "emerg") == 0) { severity = LOG_EMERG; } + else if (strcmp(p, "err") == 0) { severity = LOG_ERR; } + else if (strcmp(p, "error") == 0) { severity = LOG_ERR; } + else if (strcmp(p, "info") == 0) { severity = LOG_INFO; } + else if (strcmp(p, "notice") == 0) { severity = LOG_NOTICE; } + else if (strcmp(p, "panic") == 0) { severity = LOG_EMERG; } + else if (strcmp(p, "warning") == 0) { severity = LOG_WARNING; } + else if (strcmp(p, "warn") == 0) { severity = LOG_WARNING; } + else { + builtin_error("unknown priority name: %s", pri); + return 1; + } + + priority = LOG_MAKEPRI(facility, severity); + } + + /* get current time */ + gettimeofday(&now, NULL); + localtime_r(&now.tv_sec, &tm); + + /* prepare syslog header */ + l = snprintf(log, LOGSIZE, + "<%d>%s %2d %02d:%02d:%02d %s", + priority, + month[tm.tm_mon-1], tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tag); + if (l >= LOGSIZE - 1) { + builtin_error("log line too long"); + return 1; + } + loglen += l; + log += l; + + /* add processus id '[%d]: ' or ': ' */ + if (log_procid) { + l = snprintf(log, LOGSIZE - loglen, "[%d]: ", + getpid()); + if (l >= LOGSIZE - loglen - 1) { + builtin_error("log line too long"); + return 1; + } + loglen += l; + log += l; + } else { + log[0] = ':'; + log[1] = ' '; + loglen += 2; + log += 2; + } + + /* read each argument */ + for (; list; list = list->next) { + + /* error */ + if (list->word == NULL || list->word->word == NULL) { + builtin_error("read argument error"); + return 1; + } + + /* prevent overflow */ + l = strlen(list->word->word); + if (l >= LOGSIZE - loglen - 1) { + builtin_error("log line too long"); + return 1; + } + + /* catenate log */ + memcpy(log, list->word->word, l); + loglen += l; + log += l; + + /* add space */ + *log = ' '; + log++; + loglen++; + } + loglen --; + + /* send log */ + if (send(syslog_fd, buffer, loglen, MSG_DONTWAIT | MSG_NOSIGNAL) == -1) { + close(syslog_fd); + sa.sun_family = AF_FILE; + strcpy(sa.sun_path, "/dev/log"); + syslog_fd = socket(PF_FILE, SOCK_DGRAM, 0); + if (syslog_fd == -1) { + builtin_error("send log error: %s", strerror(errno)); + return 1; + } + if (connect(syslog_fd, (struct sockaddr *)&sa, + sizeof(struct sockaddr_un)) == -1) { + builtin_error("send log error: %s", strerror(errno)); + close(syslog_fd); + return 1; + } + if (send(syslog_fd, buffer, loglen, MSG_DONTWAIT | MSG_NOSIGNAL) == -1) { + builtin_error("send log error: %s", strerror(errno)); + return 1; + } + } + return 0; +}