1 /*
2 
3    nsjail - logging
4    -----------------------------------------
5 
6    Copyright 2014 Google Inc. All Rights Reserved.
7 
8    Licensed under the Apache License, Version 2.0 (the "License");
9    you may not use this file except in compliance with the License.
10    You may obtain a copy of the License at
11 
12      http://www.apache.org/licenses/LICENSE-2.0
13 
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19 
20 */
21 
22 #include "common.h"
23 #include "log.h"
24 
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <getopt.h>
28 #include <limits.h>
29 #include <pthread.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <time.h>
37 #include <unistd.h>
38 
39 #if defined(_HF_ARCH_LINUX)
40 #include <sys/syscall.h>
41 #define __hf_pid()      (pid_t) syscall(__NR_gettid)
42 #else                           /* defined(_HF_ARCH_LINUX) */
43 #define __hf_pid()      getpid()
44 #endif                          /* defined(_HF_ARCH_LINUX) */
45 
46 static int log_fd;
47 static bool log_fd_isatty;
48 enum llevel_t log_level;
49 pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
50 
51 __attribute__ ((constructor))
log_init(void)52 static void log_init(void)
53 {
54     log_level = INFO;
55     log_fd = dup(STDERR_FILENO);
56     fcntl(log_fd, F_SETFD, O_CLOEXEC);
57     log_fd_isatty = isatty(log_fd);
58 }
59 
60 /*
61  * Log to stderr by default. Use a dup()d fd, because in the future we'll associate the
62  * connection socket with fd (0, 1, 2).
63  */
logInitLogFile(const char * logfile,enum llevel_t ll)64 bool logInitLogFile(const char *logfile, enum llevel_t ll)
65 {
66     log_level = ll;
67 
68     if (logfile == NULL) {
69         return true;
70     }
71 
72     log_fd = open(logfile, O_CREAT | O_RDWR | O_APPEND, 0640);
73     if (log_fd == -1) {
74         log_fd = STDERR_FILENO;
75         PLOG_E("Couldn't open logfile open('%s')", logfile);
76         return false;
77     }
78     log_fd_isatty = (isatty(log_fd) == 1 ? true : false);
79     return true;
80 }
81 
logLog(enum llevel_t ll,const char * fn,int ln,bool perr,const char * fmt,...)82 void logLog(enum llevel_t ll, const char *fn, int ln, bool perr, const char *fmt, ...)
83 {
84     char strerr[512];
85     if (perr == true) {
86         snprintf(strerr, sizeof(strerr), "%s", strerror(errno));
87     }
88     struct ll_t {
89         char *descr;
90         char *prefix;
91         bool print_funcline;
92     };
93     struct ll_t logLevels[] = {
94         {"F", "\033[7;35m", true},
95         {"E", "\033[1;31m", true},
96         {"W", "\033[0;33m", true},
97         {"I", "\033[1m", true},
98         {"D", "\033[0;4m", true},
99         {"HR", "\033[0m", false},
100         {"HB", "\033[1m", false},
101     };
102 
103     time_t ltstamp = time(NULL);
104     struct tm utctime;
105     localtime_r(&ltstamp, &utctime);
106     char timestr[32];
107     if (strftime(timestr, sizeof(timestr) - 1, "%FT%T%z", &utctime) == 0) {
108         timestr[0] = '\0';
109     }
110 
111     /* Start printing logs */
112     {
113         pthread_mutex_lock(&log_mutex);
114         DEFER(pthread_mutex_unlock(&log_mutex));
115 
116         if (log_fd_isatty) {
117             dprintf(log_fd, "%s", logLevels[ll].prefix);
118         }
119         if (logLevels[ll].print_funcline) {
120             dprintf(log_fd, "[%s][%s][%d] %s():%d ", timestr, logLevels[ll].descr, __hf_pid(), fn,
121                     ln);
122         }
123 
124         va_list args;
125         va_start(args, fmt);
126         vdprintf(log_fd, fmt, args);
127         va_end(args);
128 
129         if (perr == true) {
130             dprintf(log_fd, ": %s", strerr);
131         }
132         if (log_fd_isatty) {
133             dprintf(log_fd, "\033[0m");
134         }
135         dprintf(log_fd, "\n");
136     }
137     /* End printing logs */
138 
139     if (ll == FATAL) {
140         exit(1);
141     }
142 }
143 
logStop(int sig)144 void logStop(int sig)
145 {
146     LOG_I("Server stops due to fatal signal (%d) caught. Exiting", sig);
147 }
148 
logRedirectLogFD(int fd)149 void logRedirectLogFD(int fd)
150 {
151     log_fd = fd;
152 }
153 
logDirectlyToFD(const char * msg)154 void logDirectlyToFD(const char *msg)
155 {
156     dprintf(log_fd, "%s", msg);
157 }
158