Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE
mcelog.6975
email.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File email.patch of Package mcelog.6975
--- Makefile | 10 ++- email.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ email.h | 34 ++++++++++ mcelog.c | 93 +++++++++++++++++++++++++++++ mcelog.h | 1 msg.c | 8 ++ 6 files changed, 343 insertions(+), 2 deletions(-) Index: mcelog-1.20/Makefile =================================================================== --- mcelog-1.20.orig/Makefile 2015-06-15 14:25:23.000000000 +0200 +++ mcelog-1.20/Makefile 2015-06-15 15:15:14.281052761 +0200 @@ -1,3 +1,4 @@ +CONFIG_EMAIL := 1 CFLAGS := -g -Os prefix := /usr etcprefix := @@ -38,7 +39,8 @@ client.o cache.o sysfs.o yellow.o page.o rbtree.o \ xeon75xx.o sandy-bridge.o ivy-bridge.o haswell.o msr.o bus.o unknown.o DISKDB_OBJ := diskdb.o dimm.o db.o -CLEAN := mcelog dmi tsc dbquery .depend .depend.X dbquery.o ${DISKDB_OBJ} +EMAIL_OBJ := email.o +CLEAN := mcelog dmi tsc dbquery .depend .depend.X dbquery.o ${DISKDB_OBJ} ${EMAIL_OBJ} DOC := mce.pdf ADD_DEFINES := @@ -50,6 +52,12 @@ all: dbquery endif +ifdef CONFIG_EMAIL +ADD_DEFINES := -DCONFIG_EMAIL=1 +LDFLAGS := -lesmtp +OBJ += ${EMAIL_OBJ} +endif + SRC := $(OBJ:.o=.c) mcelog: ${OBJ} Index: mcelog-1.20/email.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ mcelog-1.20/email.c 2015-06-15 15:15:14.285053019 +0200 @@ -0,0 +1,199 @@ +#include <unistd.h> +#include <signal.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#define __USE_GNU +/* To fetch the dnsname */ +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include <libesmtp.h> +#include "mcelog.h" +#include "email.h" + +#define MAX_STRING_LEN 512 +char c_recipient[MAX_STRING_LEN] = ""; +static int debug; +static char dnsname[MAX_STRING_LEN]; + +static char buf[128]; +#define ERROR() { fprintf (stderr, "SMTP problem [%d] %s\n", __LINE__, \ + smtp_strerror (smtp_errno (), buf, sizeof buf)); \ + return -1; } + + +void email_usage(void) { + fprintf(stderr, + "--email address Requires daemon mode\n"); +} + +int email_cmd(int opt, int ac, char **av) +{ + char *arg = optarg; + + switch (opt) { + case O_EMAIL_ADDRESS: + if (arg) { + if (strlen(arg) >= MAX_STRING_LEN) { + Eprintf("email address too long" + " [max:%d]\n", MAX_STRING_LEN); + return 0; + } + strcpy(c_recipient, arg); + return 1; + } + case O_EMAIL_DEBUG: + debug = 1; + return 0; + } + return 0; +} + +int email_env(void) +{ + char *email_env = getenv("MCELOG_EMAIL_DEBUG"); + + if (email_env) + debug=0; + + email_env = getenv("MCELOG_ADMIN_EMAIL"); + if (email_env) { + strncpy(c_recipient, email_env, MAX_STRING_LEN - 1); + return 1; + } + return 0; +} + +/* Callback to prnt the recipient status */ +static void +print_recipient_status (smtp_recipient_t recipient, + const char *mailbox, void *arg) +{ + const smtp_status_t *status; + + status = smtp_recipient_status (recipient); + if (debug) + printf ("%s: %d %s", mailbox, status->code, status->text); +} + +void setup_mail_header(FILE *fp, struct mce *m) +{ + char host[MAX_STRING_LEN]; + struct addrinfo hints; + struct addrinfo *res=NULL; + int ret, retry=3; + + /* Taken from net-tools hostname.c showhname() */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME | AI_CANONIDN; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (gethostname(host, MAX_STRING_LEN)) { + fprintf(stderr, "Cannot get host name\n"); + return; + } + + do { + ret = getaddrinfo(host, NULL, &hints, &res); + } while(ret == EAI_AGAIN && retry-- > 0 + && usleep(50000) == 0); + + if (ret != 0 || res == NULL) { + fprintf(stderr, "Could not retrieve hostname\n"); + return; + } + + memset(dnsname, '\0', MAX_STRING_LEN); + strncpy(dnsname, res->ai_canonname, MAX_STRING_LEN - 1); + + fprintf(fp, "Return-Path: <dummy@will_get_overridden.net>\r\n" + "Subject: Machine Check Exception on %s detected\r\n" + "MIME-Version: 1.0\r\n" + "Content-Type: text/plain;\r\n" + " charset=iso-8859-1\r\n" + "Content-Transfer-Encoding: 7bit\r\n\r\n", dnsname); + freeaddrinfo(res); +} + + +int send_mail(FILE *fp) +{ + char smtp_host[MAX_STRING_LEN] = "localhost:25"; + char from[MAX_STRING_LEN]; + + const smtp_status_t *status; + smtp_session_t session; + smtp_message_t message; + smtp_recipient_t recipient; + struct sigaction sa; + + session = smtp_create_session (); + message = smtp_add_message (session); + + snprintf(from, MAX_STRING_LEN, "root@%s", dnsname); + + /* NB. libESMTP sets timeouts as it progresses through the protocol. + In addition the remote server might close its socket on a timeout. + Consequently libESMTP may sometimes try to write to a socket with + no reader. Ignore SIGPIPE, then the program doesn't get killed + if/when this happens. */ + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGPIPE, &sa, NULL); + + /* Set the host running the SMTP server. LibESMTP has a default port + number of 587, however this is not widely deployed so the port + is specified as 25 along with the default MTA host. */ + if (!smtp_set_server (session, smtp_host)) + ERROR(); + + smtp_set_reverse_path (message, from); + + /* RFC 2822 doesn't require recipient headers but a To: header would + be nice to have if not present. */ + smtp_set_header (message, "To", NULL, NULL); + + /* RFC 2822 doesn't require recipient headers but a To: header would + be nice to have if not present. */ + if (!smtp_set_header (message, "From", "mcelog", from)) + ERROR(); + + smtp_set_message_fp (message, fp); + + recipient = smtp_add_recipient (message, c_recipient); + if (!recipient) + ERROR(); + if (!smtp_dsn_set_notify (recipient, Notify_NEVER)) + ERROR(); + + /* Initiate a connection to the SMTP server and transfer the + message. */ + if (!smtp_start_session (session)) + Eprintf("SMTP server problem %s\n", + smtp_strerror (smtp_errno (), buf, sizeof buf)); + else { + /* Report on the success or otherwise of the mail transfer. + */ + if (debug) { + status = smtp_message_transfer_status (message); + printf ("%d %s", status->code, + (status->text != NULL) ? status->text : "\n"); + } + smtp_enumerate_recipients (message, print_recipient_status, NULL); + } + + if (debug) + fprintf(stderr, "Email sent successfully!\n"); + + /* Free resources consumed by the program. + */ + smtp_destroy_session (session); + return 0; +} Index: mcelog-1.20/email.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ mcelog-1.20/email.h 2015-06-15 15:15:14.289053315 +0200 @@ -0,0 +1,34 @@ +#ifndef _MCELOG_EMAIL_H_ +#define _MCELOG_EMAIL_H_ + +extern FILE *email_fd; +extern int email_mode; + +#ifdef CONFIG_EMAIL +extern int send_mail(FILE *email_fd); +extern void setup_mail_header(FILE *email_fd, struct mce *m); +extern void email_usage(void); +extern int email_cmd(int opt, int ac, char **av); +extern int email_env(void); + +#define EMAIL_OPTIONS \ + { "email", 1, NULL, O_EMAIL_ADDRESS }, \ + { "email-debug", 0, NULL, O_EMAIL_DEBUG }, + +enum email_options { + O_EMAIL_ADDRESS = O_EMAIL, + O_EMAIL_DEBUG, +}; + +#else +/* +static int send_mail(FILE *email_fd) { return 0; } +static void setup_mail_header(FILE *email_fd) { return; }; +*/ +static void email_usage(void) { return; } +static int email_cmd(int opt, int ac, char **av) { return 0; } +static int email_env(void) { return 0; } +#define EMAIL_OPTIONS +#endif + +#endif Index: mcelog-1.20/mcelog.c =================================================================== --- mcelog-1.20.orig/mcelog.c 2015-06-15 14:25:23.000000000 +0200 +++ mcelog-1.20/mcelog.c 2015-06-15 15:15:14.293053554 +0200 @@ -37,6 +37,7 @@ #include <assert.h> #include <signal.h> #include <pwd.h> +#include <sys/wait.h> #include <fnmatch.h> #include "mcelog.h" #include "paths.h" @@ -61,6 +62,9 @@ #include "bus.h" #include "unknown.h" +#include "email.h" +int email_mode; + enum cputype cputype = CPU_GENERIC; char *logfn = LOG_DEV_FILENAME; @@ -72,7 +76,7 @@ static int cpumhz_forced; int ascii_mode; int dump_raw_ascii; -int daemon_mode; +int daemon_mode = 0; static char *inputfile; char *processor_flags; static int foreground; @@ -949,6 +953,7 @@ "--pidfile file Write pid of daemon into file\n" "--no-imc-log Disable extended iMC logging\n" ); + email_usage(); diskdb_usage(); print_cputypes(); exit(1); @@ -1016,6 +1021,7 @@ { "debug-numerrors", 0, NULL, O_DEBUG_NUMERRORS }, /* undocumented: for testing */ { "no-imc-log", 0, NULL, O_NO_IMC_LOG }, DISKDB_OPTIONS + EMAIL_OPTIONS {} }; @@ -1193,11 +1199,86 @@ } } +#ifdef CONFIG_EMAIL +pid_t c_pid; + +/* Not more than 12 mails in 5 mins... */ +#define LAST_LIMIT_COUNT (60 * 5) +#define LIMIT_COUNT 12 +static time_t last_limit_count; +static int limit_count; +static const char *mail_thread = "mcelog_mail_thread"; + + +static int setup_email(struct mce *m) { + int pdes[2]; + static int suppressed; + int ret; + + if (time(NULL) - last_limit_count < LAST_LIMIT_COUNT) { + if (limit_count >= LIMIT_COUNT && !suppressed) { + Eprintf("email rate limit [%d mails per %d mins]" + " reached, mails supressed\n", + LIMIT_COUNT, LAST_LIMIT_COUNT / 60); + suppressed = 1; + } + if (suppressed) + return -1; + } else { + suppressed = 0; + limit_count = 0; + last_limit_count = time(NULL); + } + + limit_count++; + + ret = pipe(pdes); + if (ret) + return ret; + + c_pid = mcelog_fork(mail_thread); + if ( c_pid == 0 ) { /* child */ + FILE *x = fdopen(pdes[0], "r"); + close(pdes[1]); + send_mail(x); + exit(0); + } else { + close(pdes[0]); + /* something went wrong, better close... */ + if (email_fd) + fclose(email_fd); + /* Wprintf will now also write into this pipe */ + email_fd = fdopen(pdes[1], "w"); + setup_mail_header(email_fd, m); + } + return 0; +} + +static int finish_email(void) { + int status; + + fclose(email_fd); + fprintf(stderr, "Email set up for sending\n"); + /* Anything else we can make sure we do not get orphaned threads? */ + waitpid (c_pid, &status, WUNTRACED); + if (WIFSTOPPED(status)){ + kill(c_pid, 9); + SYSERRprintf("Killed stopped email thread %d\n", + c_pid); + return -1; + } + email_fd = NULL; + return 0; +} + +#endif + static void process(int fd, unsigned recordlen, unsigned loglen, char *buf) { int i; int len, count; int finish = 0, flags; + int mail_setup = 0; if (recordlen == 0) { Wprintf("no data in mce record\n"); @@ -1224,12 +1305,16 @@ finish = 1; if (!mce_filter(mce, recordlen)) continue; + if (email_mode) + mail_setup = setup_email(mce); if (!dump_raw_ascii) { disclaimer(); Wprintf("MCE %d\n", i); dump_mce(mce, recordlen); } else dump_mce_raw_ascii(mce, recordlen); + if (email_mode && !mail_setup) + finish_email(); flushlog(); } @@ -1340,6 +1425,8 @@ exit(0); } else if (diskdb_cmd(opt, ac, av)) { exit(0); + } else if (email_cmd(opt, ac, av)) { + email_mode = 1; } else if (opt == 0) break; } @@ -1368,6 +1455,10 @@ logfn = av[optind++]; if (av[optind]) usage(); + if (email_mode == 0) + email_mode = email_env(); + /* email sending only in daemon mode */ + email_mode &= daemon_mode; checkdmi(); general_setup(); Index: mcelog-1.20/mcelog.h =================================================================== --- mcelog-1.20.orig/mcelog.h 2015-06-15 14:25:23.000000000 +0200 +++ mcelog-1.20/mcelog.h 2015-06-15 15:15:14.297053784 +0200 @@ -131,6 +131,7 @@ enum option_ranges { O_COMMON = 500, O_DISKDB = 1000, + O_EMAIL = 1500, }; enum syslog_opt { Index: mcelog-1.20/msg.c =================================================================== --- mcelog-1.20.orig/msg.c 2015-06-15 14:25:23.000000000 +0200 +++ mcelog-1.20/msg.c 2015-06-15 15:15:14.301053996 +0200 @@ -8,10 +8,13 @@ #include "mcelog.h" #include "msg.h" #include "memutil.h" +#include "email.h" + enum syslog_opt syslog_opt = SYSLOG_REMARK; int syslog_level = LOG_WARNING; static FILE *output_fh; + FILE *email_fd; static char *output_fn; int need_stdout(void) @@ -135,6 +138,11 @@ n = vfprintf(output_fh ? output_fh : stdout, fmt, ap); va_end(ap); } + if (email_fd) { + va_start(ap,fmt); + n = vfprintf(email_fd, fmt, ap); + va_end(ap); + } return n; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor