/* * parse_append_logger.c * * Copyright (c) 2018-2023 Eric Vidal <eric@obarun.org> * * All rights reserved. * * This file is part of Obarun. It is subject to the license terms in * the LICENSE file found in the top-level directory of this * distribution. * This file may not be copied, modified, propagated, or distributed * except according to the terms contained in the LICENSE file./ */ #include <string.h> #include <oblibs/string.h> #include <oblibs/log.h> #include <66/resolve.h> #include <66/service.h> #include <66/enum.h> #include <66/constants.h> #include <66/config.h> #include <66/utils.h> #include <66/config.h> #include <66/parse.h> #include <s6/config.h> #ifndef FAKELEN #define FAKELEN strlen(run) #endif static uint32_t compute_log_dir(resolve_wrapper_t_ref wres, resolve_service_t *res) { log_flow() ; size_t namelen = strlen(res->sa.s + res->name) ; size_t syslen = res->owner ? strlen(res->sa.s + res->path.home) + strlen(SS_LOGGER_USERDIR) : strlen(SS_LOGGER_SYSDIR) ; size_t dstlen = res->logger.destination ? strlen(res->sa.s + res->logger.destination) : strlen(SS_LOGGER_SYSDIR) ; char dstlog[syslen + dstlen + namelen + 1] ; if (!res->logger.destination) { if (res->owner) { char home[syslen + 1 + strlen(SS_LOGGER_USERDIR) + 1] ; if (!set_ownerhome_stack(home)) log_dieusys(LOG_EXIT_SYS,"set home directory") ; auto_strings(dstlog, home, SS_LOGGER_USERDIR, res->sa.s + res->name) ; } else auto_strings(dstlog, SS_LOGGER_SYSDIR, res->sa.s + res->name) ; } else { auto_strings(dstlog, res->sa.s + res->logger.destination) ; } return resolve_add_string(wres, dstlog) ; } static void compute_log_script(resolve_service_t *res, resolve_service_t *log) { log_flow() ; resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, log) ; int build = !strcmp(res->sa.s + res->logger.execute.run.build, "custom") ? BUILD_CUSTOM : BUILD_AUTO ; char *pmax = 0 ; char *pback = 0 ; char max[UINT32_FMT] ; char back[UINT32_FMT] ; char *timestamp = 0 ; int itimestamp = SS_LOGGER_TIMESTAMP ; char *logrunner = res->logger.execute.run.runas ? res->sa.s + res->logger.execute.run.runas : SS_LOGGER_RUNNER ; log->execute.run.runas = resolve_add_string(wres, logrunner) ; /** timestamp */ if (res->logger.timestamp != 3) timestamp = res->logger.timestamp == TIME_NONE ? "" : res->logger.timestamp == TIME_ISO ? "T" : "t" ; else timestamp = itimestamp == TIME_NONE ? "" : itimestamp == TIME_ISO ? "T" : "t" ; /** backup */ if (res->logger.backup) { back[uint32_fmt(back,res->logger.backup)] = 0 ; pback = back ; } /** file size */ if (res->logger.maxsize) { max[uint32_fmt(max,res->logger.maxsize)] = 0 ; pmax = max ; } char *shebang = "#!" SS_EXECLINE_SHEBANGPREFIX "execlineb -P\n" ; { /** run scripts */ char run[SS_MAX_PATH_LEN + 1] ; auto_strings(run, \ shebang, \ "s6-fdholder-retrieve ", \ res->sa.s + res->live.fdholderdir, "/s ", \ "\"" SS_FDHOLDER_PIPENAME "r-", \ res->sa.s + res->logger.name, "\"\n", \ "./run.user\n") ; log->execute.run.run = resolve_add_string(wres, run) ; } { if (!build) { /** run.user script */ char run[SS_MAX_PATH_LEN + 1] ; auto_strings(run, shebang) ; auto_strings(run + FAKELEN, "fdmove -c 2 1\n") ; /** runas */ if (!res->owner) auto_strings(run + FAKELEN, S6_BINPREFIX "s6-setuidgid ", logrunner, "\n") ; auto_strings(run + FAKELEN, "s6-log ") ; if (SS_LOGGER_NOTIFY) auto_strings(run + FAKELEN, "-d3 ") ; auto_strings(run + FAKELEN, "n", pback, " ") ; if (res->logger.timestamp < TIME_NONE) auto_strings(run + FAKELEN, timestamp, " ") ; auto_strings(run + FAKELEN, "s", pmax, " ", res->sa.s + res->logger.destination, "\n") ; log->execute.run.run_user = resolve_add_string(wres, run) ; } else { if (res->logger.execute.run.shebang) log_warn("@shebang field is deprecated -- please define it at start of your @execute field instead") ; char *shebang = res->logger.execute.run.shebang ? res->sa.s + res->logger.execute.run.shebang : "#!" SS_EXECLINE_SHEBANGPREFIX "execlineb -P\n" ; size_t shebanglen = strlen(shebang) ; char run[shebanglen + strlen(res->sa.s + res->logger.execute.run.run_user) + 2] ; auto_strings(run, shebang, res->sa.s + res->logger.execute.run.run_user, "\n") ; log->execute.run.run_user = resolve_add_string(wres, run) ; } } free(wres) ; } static void compute_logger(resolve_service_t *res, resolve_service_t *log, ssexec_t *info) { log_flow() ; if (!res->logger.name) return ; resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, log) ; resolve_init(wres) ; char *str = res->sa.s ; size_t namelen = strlen(str + res->logger.name) ; char name[namelen + 1] ; char description[namelen + 7 + 1] ; auto_strings(name, str + res->logger.name) ; auto_strings(description, str + res->name, " logger") ; log->name = resolve_add_string(wres, name) ; log->description = resolve_add_string(wres, description) ; log->version = resolve_add_string(wres, str + res->version) ; log->type = res->type ; log->notify = 3 ; log->maxdeath = res->maxdeath ; log->earlier = res->earlier ; if (res->intree) log->intree = resolve_add_string(wres, str + res->intree) ; log->ownerstr = resolve_add_string(wres, str + res->ownerstr) ; log->owner = res->owner ; log->treename = resolve_add_string(wres, str + res->treename) ; log->user = resolve_add_string(wres, str + res->user) ; if (res->inns) log->inns = resolve_add_string(wres, str + res->inns) ; log->path.home = resolve_add_string(wres, str + res->path.home) ; log->path.frontend = resolve_add_string(wres, str + res->path.frontend) ; log->path.servicedir = compute_src_servicedir(wres, info) ; log->dependencies.requiredby = resolve_add_string(wres, str + res->name) ; log->dependencies.nrequiredby = 1 ; log->execute.run.build = resolve_add_string(wres, str + res->logger.execute.run.build) ; log->execute.run.shebang = res->logger.execute.run.shebang ? resolve_add_string(wres, str + res->logger.execute.run.shebang) : 0 ; log->execute.run.runas = resolve_add_string(wres, str + res->logger.execute.run.runas) ; log->execute.timeout.kill = res->logger.execute.timeout.kill ; log->execute.timeout.finish = res->logger.execute.timeout.finish ; log->execute.down = res->logger.execute.down ; log->execute.downsignal = res->logger.execute.downsignal ; log->live.livedir = resolve_add_string(wres, info->live.s) ; log->live.status = compute_status(wres, info) ; log->live.servicedir = compute_live_servicedir(wres, info) ; log->live.scandir = compute_scan_dir(wres, info) ; log->live.statedir = compute_state_dir(wres, info, SS_STATE + 1) ; log->live.eventdir = compute_state_dir(wres, info, SS_EVENTDIR + 1) ; log->live.notifdir = compute_state_dir(wres, info, "notif") ; log->live.supervisedir = compute_state_dir(wres, info, SS_SUPERVISEDIR + 1) ; log->live.fdholderdir = compute_pipe_service(wres, info, SS_FDHOLDER) ; log->live.oneshotddir = compute_pipe_service(wres, info, SS_ONESHOTD) ; log->logger.destination = resolve_add_string(wres, str + res->logger.destination) ; log->logger.backup = res->logger.backup ; log->logger.maxsize = res->logger.maxsize ; log->logger.timestamp = res->logger.timestamp ; log->logger.want = 0 ; // oneshot do not use fdholder daemon if (res->type == TYPE_CLASSIC) compute_log_script(res, log) ; free(wres) ; } void parse_append_logger(struct resolve_hash_s **hres, resolve_service_t *res, ssexec_t *info) { log_flow() ; char *name = res->sa.s + res->name ; struct resolve_hash_s *hash ; resolve_service_t lres = RESOLVE_SERVICE_ZERO ; resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; size_t namelen = strlen(name) ; char logname[namelen + SS_LOG_SUFFIX_LEN + 1] ; auto_strings(logname, name, SS_LOG_SUFFIX) ; res->logger.name = resolve_add_string(wres, logname) ; res->logger.destination = compute_log_dir(wres, res) ; res->logger.execute.run.runas = res->logger.execute.run.runas ? resolve_add_string(wres, res->sa.s + res->logger.execute.run.runas) : resolve_add_string(wres, SS_LOGGER_RUNNER) ; hash = hash_search(hres, logname) ; if (hash == NULL && res->type == TYPE_CLASSIC) { /** the logger is not a service with oneshot type */ if (res->dependencies.ndepends) { char buf[strlen(res->sa.s + res->dependencies.depends) + 1 + strlen(res->sa.s + res->logger.name) + 1] ; auto_strings(buf, res->sa.s + res->dependencies.depends, " ", res->sa.s + res->logger.name) ; res->dependencies.depends = resolve_add_string(wres, buf) ; } else { res->dependencies.depends = resolve_add_string(wres, res->sa.s + res->logger.name) ; } res->dependencies.ndepends++ ; compute_logger(res, &lres, info) ; /** sanitize_init use this field */ res->logger.execute.run.run = resolve_add_string(wres, lres.sa.s + lres.execute.run.run) ; res->logger.execute.run.run_user = resolve_add_string(wres, lres.sa.s + lres.execute.run.run_user) ; if (hash_count(hres) > SS_MAX_SERVICE) log_die(LOG_EXIT_SYS, "too many services to parse -- compile again 66 changing the --max-service options") ; log_trace("add service: ", logname, " to the service selection") ; if (!hash_add(hres, logname, lres)) log_dieu(LOG_EXIT_SYS, "append service selection with: ", logname) ; } free(wres) ; }