The code excluded from mini-project of mail log parser.
/* $Id: main.c,v 1.1 2016/08/14 23:47:57 root Exp root $ */ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <err.h> #include <syslog.h> #include <signal.h> #include <syslog.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sys/stat.h> #include <libgen.h> #include <libpq-fe.h> #include <confuse.h> #include "config.h" #include "parser.h" #include "lexer.h" #include "maillogd.h" extern record_t _record; #define DEFAULT_PID_FILE "/var/run/maillogd.pid" char pid_file[FILENAME_MAX]; int pid_file_h; void shutdown(); //void signal_handler(int sig); ///void daemonize(); #ifndef MAILLOG_DB_SERVER #define MAILLOG_DB_SERVER "localhost" #endif #ifndef MAILLOG_DB_USERNAME #define MAILLOG_DB_USERNAME "maillog" #endif #ifndef MAILLOG_DB_PASSWORD #define MAILLOG_DB_PASSWORD "maillog" #endif #ifndef MAILLOG_DBNAME #define MAILLOG_DBNAME "maillog" #endif #ifndef MAILLOG_LOGFILE #define MAILLOG_LOGFILE "/var/log/exim/main.log" #endif #ifndef MAILLOG_SYSCON #define MAILLOG_SYSCONF "/usr/local/etc/maillog.conf" #endif static char *dbserver = MAILLOG_DB_SERVER; static char *username = MAILLOG_DB_USERNAME; static char *password = MAILLOG_DB_PASSWORD; static char *dbname = MAILLOG_DBNAME; static char *logfile = MAILLOG_LOGFILE; static long int debug = 0; cfg_opt_t opts[] = { CFG_SIMPLE_STR("dbserver", &dbserver), CFG_SIMPLE_STR("username", &username), CFG_SIMPLE_STR("password", &password), CFG_SIMPLE_STR("dbname", &dbname), CFG_SIMPLE_STR("logfile", &logfile), CFG_SIMPLE_INT("debug", &debug), CFG_END() }; cfg_t *config; PGconn *pgconn; char* pgconnstr = NULL; void handle_config_error(cfg_t *cfg, char *fmt, va_list ap) { // if (cfg && cfg->filename && cfg->line) // fprintf(stderr, "%s:%d: ", cfg->filename, cfg->line); // else if (cfg && cfg->filename) // fprintf(stderr, "%s: ", cfg->filename); // vfprintf(stderr, fmt, ap); // fprintf(stderr, "\n"); } void handle_signal(int sig){ switch (sig) { case SIGHUP: syslog(LOG_WARNING, "Received %s signal.", strsignal(sig)); break; case SIGINT: case SIGTERM: syslog(LOG_INFO, "Received %s, exiting.", strsignal(sig)); shutdown(); exit(EXIT_SUCCESS); break; default: syslog(LOG_WARNING, "Unhandled signal %s.", strsignal(sig)); break; } } void shutdown() { if (pgconn != NULL) { syslog(LOG_INFO, "Finish PGconn"); PQfinish(pgconn); } if (pid_file_h > 0) close(pid_file_h); if (pid_file != NULL) unlink(pid_file); closelog(); } void underground_self() { int pid, sid, i; struct sigaction new_sig_action; sigset_t new_sig_set; if (getppid() == 1) { return; } sigemptyset(&new_sig_set); sigaddset(&new_sig_set, SIGCHLD); sigaddset(&new_sig_set, SIGTSTP); sigaddset(&new_sig_set, SIGTTOU); sigaddset(&new_sig_set, SIGTTIN); sigprocmask(SIG_BLOCK, &new_sig_set, NULL); new_sig_action.sa_handler = handle_signal; sigemptyset(&new_sig_action.sa_mask); new_sig_action.sa_flags = 0; sigaction(SIGHUP, &new_sig_action, NULL); sigaction(SIGTERM, &new_sig_action, NULL); sigaction(SIGINT, &new_sig_action, NULL); pid = fork(); if (pid < 0) { syslog(LOG_ERR, "Could not fork"); exit(EXIT_FAILURE); } if (pid > 0) { syslog(LOG_INFO, "Child process created: %d\n", pid); exit(EXIT_SUCCESS); } umask(027); sid = setsid(); if (sid < 0) { syslog(LOG_INFO, "Could not process session"); exit(EXIT_FAILURE); } for (i = getdtablesize(); i >= 0; --i) { close(i); } i = open("/dev/null", O_RDWR); dup(i); dup(i); chdir("/"); } int write_pidfile (char* pid_file) { char str[FILENAME_MAX]; int file_h = open(pid_file, O_RDWR | O_CREAT, 0600); if (file_h == -1) { syslog(LOG_INFO, "Could not open PID lock file %s, exiting", pid_file); exit(EXIT_FAILURE); } if (lockf(file_h, F_TLOCK, 0) == -1) { syslog(LOG_INFO, "Could not lock PID lock file %s, exiting", pid_file); exit(EXIT_FAILURE); } sprintf(str, "%d\n", getpid()); write(file_h, str, strlen(str)); return file_h; } #define MICRO_SLEEP_TIME 250000 #define START_SLEEP_TIME 1000000 void read_logfile(char *logfile, char *pgconnstr, PGconn *pgconn) { FILE* logfile_p; struct stat logfile_st; struct stat st2; char bufstr[BUFSIZ]; fpos_t pos; /* open file, read stat and write it to struct file */ for (;;) { if ((logfile_p = fopen(logfile, "r")) == NULL || fstat(fileno(logfile_p), &logfile_st)) { if (logfile_p != NULL) { fclose(logfile_p); logfile_p = NULL; syslog(LOG_ERR, "Cannot open file: %s\n", logfile); (void)usleep(START_SLEEP_TIME); continue; } } syslog(LOG_INFO, "Try open file: %s\n", logfile); if ((logfile_p = fopen(logfile, "r")) == NULL) { syslog(LOG_ERR, "Cannot open file: %s\n", logfile); fclose(logfile_p); logfile_p = NULL; (void)usleep(START_SLEEP_TIME); continue; } if (fseek(logfile_p, 0, SEEK_END) != 0) { syslog(LOG_ERR, "Cannot read file: %s\n", logfile); fclose(logfile_p); logfile_p = NULL; (void)usleep(START_SLEEP_TIME); continue; } if (fgetpos(logfile_p, &pos) == -1) { syslog(LOG_ERR, "Cannot position file: %s\n", logfile); fclose(logfile_p); logfile_p = NULL; (void)usleep(START_SLEEP_TIME); continue; } break; } // pgconn = PQconnectdb(pgconnstr); // if (PQstatus(pgconn) == CONNECTION_BAD) { // syslog(LOG_ERR, "Connection to database failed: %s", PQerrorMessage(pgconn)); // PQfinish(pgconn); // } else { // syslog(LOG_INFO, "Connection to database success"); // } for (;;) { if (stat(logfile, &st2) == -1) { syslog(LOG_INFO, "Ups, maybe file %s is closed", logfile); if (logfile_p != NULL) { fclose(logfile_p); logfile_p = NULL; } (void)usleep(MICRO_SLEEP_TIME); continue; } if (st2.st_ino != logfile_st.st_ino || st2.st_dev != logfile_st.st_dev || st2.st_nlink == 0) { syslog(LOG_INFO, "Ups, logfile %s changed", logfile); if (logfile_p != NULL) { syslog(LOG_INFO, "Close logfile"); fclose(logfile_p); logfile_p = NULL; } logfile_p = fopen(logfile, "r"); syslog(LOG_INFO, "Again open logfile"); if (logfile_p != NULL) { memcpy(&logfile_st, &st2, sizeof(struct stat)); } else { syslog(LOG_INFO, "Cannot reopen file %s", logfile); (void) usleep(MICRO_SLEEP_TIME); continue; } if (fseek(logfile_p, 0, SEEK_END) != 0) { syslog(LOG_ERR, "Cannot read file: %s\n", logfile); (void) usleep(MICRO_SLEEP_TIME); continue; } if (fgetpos(logfile_p, &pos) == -1) { syslog(LOG_ERR, "Cannot position file: %s\n", logfile); (void) usleep(MICRO_SLEEP_TIME); continue; } } fgets(bufstr, BUFSIZ, logfile_p); if (ferror(logfile_p)) { syslog(LOG_INFO, "Error reading file %s", logfile); (void) usleep(MICRO_SLEEP_TIME); continue; } if (feof(logfile_p)) { fsetpos(logfile_p, &pos); clearerr(logfile_p); (void) usleep(MICRO_SLEEP_TIME); continue; } fgetpos(logfile_p, &pos); syslog(LOG_INFO, "I read from log: %s", bufstr); } if (logfile_p != NULL) { syslog(LOG_INFO, "Close logfile"); fclose(logfile_p); logfile_p = NULL; } } int main(int argc, char **argv) { /* change process name */ char cur_wdir[FILENAME_MAX]; char base_pname[FILENAME_MAX]; char new_pname[FILENAME_MAX]; basename_r(argv[0], base_pname); getwd(cur_wdir); sprintf(new_pname, "%s/%s", cur_wdir, base_pname); argv[0] = new_pname; /* init syslog parameters */ setlogmask(LOG_UPTO(LOG_INFO)); openlog(base_pname, LOG_CONS | LOG_PERROR, LOG_DAEMON); /* daemonize */ syslog(LOG_INFO, "Try start daemon\n"); underground_self(); /* write pid file with process id */ strncpy(pid_file, DEFAULT_PID_FILE, sizeof(DEFAULT_PID_FILE)); pid_file_h = write_pidfile(pid_file); /* read configuration */ config = cfg_init(opts, 0); (void)cfg_set_error_function(config, (cfg_errfunc_t)handle_config_error); cfg_parse(config, MAILLOG_SYSCONF); #define MAX_PGCONN_LEN 1024 /* prepare db connection config */ pgconnstr = malloc(MAX_PGCONN_LEN); if (pgconnstr == NULL) { syslog(LOG_ERR, "Cannot allocate memory for pgconnstr\n"); exit(1); } (void)sprintf(pgconnstr, "user=%s password=%s dbname=%s hostname=%s", username, password, dbname, dbserver); /* main work cicle */ // while (1) { // syslog(LOG_INFO, "daemon says hello and %s", pgconnstr); // usleep(1000000); // } read_logfile(logfile, pgconnstr, pgconn); free(dbserver); free(username); free(password); free(dbname); free(logfile); cfg_free(config); shutdown(); return 0; } /* EOF */