1 #include "first.h" 2 3 #include "fdlog.h" 4 5 #include <sys/types.h> 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 12 #include "fdevent.h" 13 #include "ck.h" 14 #include "log.h" 15 16 /* 17 * Notes: 18 * - Use of "/dev/stdin" and "/dev/stdout" is not recommended 19 * since those are manipulated at startup in server_main_setup() 20 * "/dev/stderr" might similarly be manipulated at startup. 21 * - Use of "/proc/self/fd/..." is permitted, and admin may use a shell script 22 * to dup standard fds to higher numbers before starting lighttpd if admin 23 * wants to direct logs to the standard fds on which lighttpd was started. 24 * Future: might detect and use the open fd rather than open() a new fd to the 25 * already-open path. If so, should stat() to check that fd actually exists, 26 * and must check for and not close() those paths when closing fdlog_st fds. 27 */ 28 29 struct fdlog_files_t { 30 fdlog_st **ptr; 31 uint32_t used; 32 uint32_t size; 33 }; 34 35 static struct fdlog_files_t fdlog_files; 36 37 typedef struct fdlog_pipe { 38 /* ((fdlog_st *) is ptr rather than inlined struct since multiple callers 39 * might have reference to (fdlog_st *), and if fdlog_pipes.ptr is 40 * reallocated those ptrs could be invalided if inlined struct) */ 41 fdlog_st *fdlog; /*(contains write-side of pipe)*/ 42 pid_t pid; 43 int fd; /*(contains read-side of pipe)*/ 44 unix_time64_t start; 45 } fdlog_pipe; 46 47 48 struct fdlog_pipes_t { 49 fdlog_pipe *ptr; 50 uint32_t used; 51 uint32_t size; 52 }; 53 54 static struct fdlog_pipes_t fdlog_pipes; 55 56 57 static pid_t 58 fdlog_pipe_spawn (const char * const fn, const int rfd) 59 { 60 char *args[4]; 61 int devnull = fdevent_open_devnull(); 62 pid_t pid; 63 64 if (-1 == devnull) { 65 return -1; 66 } 67 68 *(const char **)&args[0] = "/bin/sh"; 69 *(const char **)&args[1] = "-c"; 70 *(const char **)&args[2] = fn; 71 args[3] = NULL; 72 73 pid = fdevent_fork_execve(args[0], args, NULL, rfd, devnull, devnull, -1); 74 75 if (pid > 0) { 76 close(devnull); 77 } 78 else { 79 int errnum = errno; 80 close(devnull); 81 errno = errnum; 82 } 83 return pid; 84 } 85 86 87 __attribute_noinline__ 88 static int 89 fdlog_pipe_restart (fdlog_pipe * const fdp, const unix_time64_t ts) 90 { 91 if (fdp->start + 5 < ts) { /* limit restart to once every 5 sec */ 92 /* restart child process using existing pipe fds */ 93 fdp->start = ts; 94 fdp->pid = fdlog_pipe_spawn(fdp->fdlog->fn, fdp->fd); 95 } 96 return (fdp->pid > 0) ? 1 : -1; 97 } 98 99 100 void 101 fdlog_pipes_restart (const unix_time64_t ts) 102 { 103 for (uint32_t i = 0; i < fdlog_pipes.used; ++i) { 104 fdlog_pipe * const fdp = fdlog_pipes.ptr+i; 105 if (fdp->pid > 0) continue; 106 fdlog_pipe_restart(fdp, ts); 107 } 108 } 109 110 111 int 112 fdlog_pipes_waitpid_cb (const pid_t pid) 113 { 114 for (uint32_t i = 0; i < fdlog_pipes.used; ++i) { 115 fdlog_pipe * const fdp = fdlog_pipes.ptr+i; 116 if (fdp->pid != pid) continue; 117 118 fdp->pid = -1; 119 return fdlog_pipe_restart(fdp, log_monotonic_secs); 120 } 121 return 0; 122 } 123 124 125 static void 126 fdlog_pipes_close (fdlog_st * const retain) 127 { 128 for (uint32_t i = 0; i < fdlog_pipes.used; ++i) { 129 fdlog_pipe * const fdp = fdlog_pipes.ptr+i; 130 fdlog_st * const fdlog = fdp->fdlog; 131 close(fdp->fd); 132 fdp->fd = -1; 133 if (fdlog == retain) continue; /*(free'd later)*/ 134 fdlog_free(fdlog); 135 } 136 free(fdlog_pipes.ptr); 137 fdlog_pipes.ptr = NULL; 138 fdlog_pipes.used = 0; 139 fdlog_pipes.size = 0; 140 } 141 142 143 void 144 fdlog_pipes_abandon_pids (void) 145 { 146 for (uint32_t i = 0; i < fdlog_pipes.used; ++i) { 147 fdlog_pipe * const fdp = fdlog_pipes.ptr+i; 148 fdp->pid = -1; 149 } 150 } 151 152 153 void 154 fdlog_pipe_serrh (const int fd) 155 { 156 for (uint32_t i = 0; i < fdlog_pipes.used; ++i) { 157 fdlog_st * const fdlog = fdlog_pipes.ptr[i].fdlog; 158 if (fdlog->fd != fd) continue; 159 160 fdlog->fd = STDERR_FILENO; 161 break; 162 } 163 } 164 165 166 static fdlog_st * 167 fdlog_pipe_init (const char * const fn, const int fds[2], const pid_t pid) 168 { 169 if (fdlog_pipes.used == fdlog_pipes.size) { 170 fdlog_pipes.size += 4; 171 fdlog_pipes.ptr = 172 realloc(fdlog_pipes.ptr, fdlog_pipes.size * sizeof(fdlog_pipe)); 173 force_assert(fdlog_pipes.ptr); 174 } 175 fdlog_pipe * const fdp = fdlog_pipes.ptr + fdlog_pipes.used++; 176 fdp->fd = fds[0]; 177 fdp->pid = pid; 178 fdp->start = log_monotonic_secs; 179 return (fdp->fdlog = fdlog_init(fn, fds[1], FDLOG_PIPE)); 180 } 181 182 183 static fdlog_st * 184 fdlog_pipe_open (const char * const fn) 185 { 186 for (uint32_t i = 0; i < fdlog_pipes.used; ++i) { 187 fdlog_st * const fdlog = fdlog_pipes.ptr[i].fdlog; 188 if (0 != strcmp(fdlog->fn, fn)) continue; 189 return fdlog; 190 } 191 192 int fds[2]; 193 if (fdevent_pipe_cloexec(fds, 65536)) 194 return NULL; 195 196 pid_t pid = fdlog_pipe_spawn(fn, fds[0]); 197 if (pid > 0) { 198 /*(nonblocking write() from lighttpd)*/ 199 if (0 != fdevent_fcntl_set_nb(fds[1])) { /*(ignore)*/ } 200 return fdlog_pipe_init(fn, fds, pid); 201 } 202 else { 203 int errnum = errno; 204 close(fds[0]); 205 close(fds[1]); 206 errno = errnum; 207 return NULL; 208 } 209 } 210 211 212 static fdlog_st * 213 fdlog_file_init (const char * const fn, const int fd) 214 { 215 if (fdlog_files.used == fdlog_files.size) { 216 fdlog_files.size += 4; 217 fdlog_files.ptr = 218 realloc(fdlog_files.ptr, fdlog_files.size * sizeof(fdlog_st *)); 219 force_assert(fdlog_files.ptr); 220 } 221 return (fdlog_files.ptr[fdlog_files.used++] = fdlog_init(fn,fd,FDLOG_FILE)); 222 } 223 224 225 static int 226 fdlog_file_open_fd (const char * const fn) 227 { 228 int flags = O_APPEND | O_WRONLY | O_CREAT; 229 return fdevent_open_cloexec(fn, 1, flags, 0644); /*(permit symlinks)*/ 230 } 231 232 233 static fdlog_st * 234 fdlog_file_open (const char * const fn) 235 { 236 for (uint32_t i = 0; i < fdlog_files.used; ++i) { 237 fdlog_st * const fdlog = fdlog_files.ptr[i]; 238 if (0 != strcmp(fdlog->fn, fn)) continue; 239 return fdlog; 240 } 241 242 int fd = fdlog_file_open_fd(fn); 243 return (-1 != fd) ? fdlog_file_init(fn, fd) : NULL; 244 } 245 246 247 fdlog_st * 248 fdlog_open (const char * const fn) 249 { 250 return (fn[0] != '|') 251 ? fdlog_file_open(fn) 252 : fdlog_pipe_open(fn+1); /*(skip the '|')*/ 253 } 254 255 256 void 257 fdlog_files_flush (fdlog_st * const errh, const int memrel) 258 { 259 for (uint32_t i = 0; i < fdlog_files.used; ++i) { 260 fdlog_st * const fdlog = fdlog_files.ptr[i]; 261 buffer * const b = &fdlog->b; 262 if (!buffer_is_blank(b)) { 263 const ssize_t wr = write_all(fdlog->fd, BUF_PTR_LEN(b)); 264 buffer_clear(b); /*(clear buffer, even on error)*/ 265 if (-1 == wr) 266 log_perror(errh, __FILE__, __LINE__, 267 "error flushing log %s", fdlog->fn); 268 } 269 if (memrel && b->ptr) buffer_free_ptr(b); 270 } 271 } 272 273 274 void 275 fdlog_files_cycle (fdlog_st * const errh) 276 { 277 fdlog_files_flush(errh, 0); 278 for (uint32_t i = 0; i < fdlog_files.used; ++i) { 279 fdlog_st * const fdlog = fdlog_files.ptr[i]; 280 int fd = fdlog_file_open_fd(fdlog->fn); 281 if (-1 != fd) { 282 if (fdlog->fd > STDERR_FILENO) { 283 close(fdlog->fd); 284 fdlog->fd = fd; 285 } 286 else { 287 if (fdlog->fd != dup2(fd, fdlog->fd)) 288 log_perror(errh, __FILE__, __LINE__, 289 "dup2() %s to %d", fdlog->fn, fdlog->fd); 290 close(fd); 291 } 292 } 293 else { 294 log_perror(errh, __FILE__, __LINE__, 295 "error cycling log %s", fdlog->fn); 296 /*(leave prior log file open)*/ 297 } 298 } 299 } 300 301 302 static void 303 fdlog_files_close (fdlog_st * const retain) 304 { 305 fdlog_files_flush(retain, 0); 306 for (uint32_t i = 0; i < fdlog_files.used; ++i) { 307 fdlog_st * const fdlog = fdlog_files.ptr[i]; 308 if (fdlog == retain) continue; /*(free'd later)*/ 309 fdlog_free(fdlog); 310 } 311 free(fdlog_files.ptr); 312 fdlog_files.ptr = NULL; 313 fdlog_files.used = 0; 314 fdlog_files.size = 0; 315 } 316 317 318 void 319 fdlog_closeall (fdlog_st * const errh) 320 { 321 fdlog_files_close(errh); 322 fdlog_pipes_close(errh); 323 } 324 325 326 void 327 fdlog_flushall (fdlog_st * const errh) 328 { 329 fdlog_files_flush(errh, 1); /*(flush, then release buffer memory)*/ 330 /*(at the moment, pipe loggers clear buffer after each write attempt, 331 * so there is nothing to flush, though there are buffers to be freed)*/ 332 for (uint32_t i = 0; i < fdlog_pipes.used; ++i) { 333 buffer * const b = &fdlog_pipes.ptr[i].fdlog->b; 334 if (b->ptr) buffer_free_ptr(b); 335 } 336 if (errh->b.ptr) buffer_free_ptr(&errh->b); 337 } 338