Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 1 | /** |
| 2 | * @brief Host logger service entry point. |
| 3 | * |
| 4 | * This file is part of HostLogger project. |
| 5 | * |
| 6 | * Copyright (c) 2018 YADRO |
| 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 | #include "config.hpp" |
| 22 | #include "dbus_server.hpp" |
| 23 | #include "dbus_watch.hpp" |
| 24 | #include "log_manager.hpp" |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 25 | |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 26 | #include <getopt.h> |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 27 | |
| 28 | #include <climits> |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 29 | #include <cstdio> |
| 30 | #include <cstdlib> |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 31 | |
| 32 | // Global logger configuration instance |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 33 | Config loggerConfig = {.path = LOG_OUTPUT_PATH, |
| 34 | .storageSizeLimit = LOG_STORAGE_SIZE_LIMIT, |
| 35 | .storageTimeLimit = LOG_STORAGE_TIME_LIMIT, |
| 36 | .flushPeriod = LOG_FLUSH_PERIOD, |
| 37 | .rotationLimit = LOG_ROTATION_LIMIT}; |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 38 | |
| 39 | /** @brief Print title with version info. */ |
| 40 | static void printTitle() |
| 41 | { |
| 42 | printf("Host logger service " PACKAGE_VERSION ".\n"); |
| 43 | } |
| 44 | |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 45 | /** @brief Print help usage info. |
| 46 | * |
| 47 | * @param[in] app - application's file name |
| 48 | */ |
| 49 | static void printHelp(const char* app) |
| 50 | { |
| 51 | printTitle(); |
| 52 | printf("Copyright (c) 2018 YADRO.\n"); |
| 53 | printf("Usage: %s [options]\n", app); |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 54 | printf( |
| 55 | "Options (defaults are specified in brackets):\n" |
| 56 | " -p, --path=PATH Path used to store logs [%s]\n" |
| 57 | "Intermediate storage buffer capacity setup:\n" |
| 58 | " -s, --szlimit=N Store up to N last messages [%i], 0=unlimited\n" |
| 59 | " -t, --tmlimit=N Store messages for last N hours [%i], " |
| 60 | "0=unlimited\n" |
| 61 | "Flush storage buffer policy:\n" |
| 62 | " -f, --flush=N Flush logs every N hours [%i]\n" |
| 63 | " If this option is set to 0 flush will be called " |
| 64 | "at\n" |
| 65 | " every host state change event from D-Bus.\n" |
| 66 | "Log files rotation policy:\n" |
| 67 | " -r, --rotate=N Store up to N files in the log directory [%i],\n" |
| 68 | " 0=unlimited\n" |
| 69 | "Common options:\n" |
| 70 | " -v, --version Print version and exit\n" |
| 71 | " -h, --help Print this help and exit\n", |
| 72 | loggerConfig.path, loggerConfig.storageSizeLimit, |
| 73 | loggerConfig.storageTimeLimit, loggerConfig.flushPeriod, |
| 74 | loggerConfig.rotationLimit); |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 75 | } |
| 76 | |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 77 | /** @brief Get numeric positive value from string argument. |
| 78 | * |
| 79 | * @param[in] param - parameter name |
| 80 | * @param[in] arg - parameter text value |
| 81 | * |
| 82 | * @return positive numeric value from string argument or -1 on errors |
| 83 | */ |
| 84 | static int getNumericArg(const char* param, const char* arg) |
| 85 | { |
| 86 | char* ep = nullptr; |
| 87 | const unsigned long val = strtoul(arg, &ep, 0); |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 88 | if (val > INT_MAX || !ep || ep == arg || *ep != 0) |
| 89 | { |
| 90 | fprintf(stderr, "Invalid %s param: %s, expected 0<=N<=%i\n", param, arg, |
| 91 | INT_MAX); |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 92 | return -1; |
| 93 | } |
| 94 | return static_cast<int>(val); |
| 95 | } |
| 96 | |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 97 | /** @brief Application entry point. */ |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 98 | int main(int argc, char* argv[]) |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 99 | { |
| 100 | int opt_val; |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 101 | // clang-format off |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 102 | const struct option opts[] = { |
| 103 | { "path", required_argument, 0, 'p' }, |
| 104 | { "szlimit", required_argument, 0, 's' }, |
| 105 | { "tmlimit", required_argument, 0, 't' }, |
| 106 | { "flush", required_argument, 0, 'f' }, |
| 107 | { "rotate", required_argument, 0, 'r' }, |
| 108 | { "version", no_argument, 0, 'v' }, |
| 109 | { "help", no_argument, 0, 'h' }, |
| 110 | { 0, 0, 0, 0 } |
| 111 | }; |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 112 | // clang-format on |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 113 | |
| 114 | opterr = 0; |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 115 | while ((opt_val = getopt_long(argc, argv, "p:s:t:f:r:vh", opts, NULL)) != |
| 116 | -1) |
| 117 | { |
| 118 | switch (opt_val) |
| 119 | { |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 120 | case 'p': |
| 121 | loggerConfig.path = optarg; |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 122 | if (*loggerConfig.path != '/') |
| 123 | { |
| 124 | fprintf(stderr, |
| 125 | "Invalid directory: %s, expected absolute path\n", |
| 126 | loggerConfig.path); |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 127 | return EXIT_FAILURE; |
| 128 | } |
| 129 | break; |
| 130 | case 's': |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 131 | loggerConfig.storageSizeLimit = |
| 132 | getNumericArg(opts[optind - 1].name, optarg); |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 133 | if (loggerConfig.storageSizeLimit < 0) |
| 134 | return EXIT_FAILURE; |
| 135 | break; |
| 136 | case 't': |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 137 | loggerConfig.storageTimeLimit = |
| 138 | getNumericArg(opts[optind - 1].name, optarg); |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 139 | if (loggerConfig.storageTimeLimit < 0) |
| 140 | return EXIT_FAILURE; |
| 141 | break; |
| 142 | case 'f': |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 143 | loggerConfig.flushPeriod = |
| 144 | getNumericArg(opts[optind - 1].name, optarg); |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 145 | if (loggerConfig.flushPeriod < 0) |
| 146 | return EXIT_FAILURE; |
| 147 | break; |
| 148 | case 'r': |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 149 | loggerConfig.rotationLimit = |
| 150 | getNumericArg(opts[optind - 1].name, optarg); |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 151 | if (loggerConfig.rotationLimit < 0) |
| 152 | return EXIT_FAILURE; |
| 153 | break; |
| 154 | case 'v': |
| 155 | printTitle(); |
| 156 | return EXIT_SUCCESS; |
| 157 | case 'h': |
| 158 | printHelp(argv[0]); |
| 159 | return EXIT_SUCCESS; |
| 160 | default: |
| 161 | fprintf(stderr, "Invalid option: %s\n", argv[optind - 1]); |
| 162 | return EXIT_FAILURE; |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | int rc; |
| 167 | |
| 168 | // Initialize log manager |
| 169 | LogManager logManager; |
| 170 | rc = logManager.openHostLog(); |
| 171 | if (rc != 0) |
| 172 | return rc; |
| 173 | |
| 174 | // Initialize D-Bus server |
| 175 | sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| 176 | sd_event* event = nullptr; |
| 177 | rc = sd_event_default(&event); |
Patrick Venture | 4d5a5dc | 2018-11-14 08:51:13 -0800 | [diff] [blame] | 178 | if (rc < 0) |
| 179 | { |
Artem Senichev | efd5d74 | 2018-10-24 16:14:04 +0300 | [diff] [blame] | 180 | fprintf(stderr, "Error occurred during the sd_event_default: %i\n", rc); |
| 181 | return EXIT_FAILURE; |
| 182 | } |
| 183 | EventPtr eventPtr(event); |
| 184 | bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL); |
| 185 | |
| 186 | DbusServer dbusMgr(logManager, bus); |
| 187 | bus.request_name(HOSTLOGGER_DBUS_IFACE); |
| 188 | |
| 189 | // Initialize D-Bus watcher |
| 190 | DbusWatcher dbusWatch(logManager, bus); |
| 191 | rc = dbusWatch.initialize(); |
| 192 | if (rc < 0) |
| 193 | return EXIT_FAILURE; |
| 194 | |
| 195 | // D-Bus event processing |
| 196 | rc = sd_event_loop(eventPtr.get()); |
| 197 | if (rc != 0) |
| 198 | fprintf(stderr, "Error occurred during the sd_event_loop: %i\n", rc); |
| 199 | |
| 200 | return rc ? rc : -1; // Allways retrun an error code |
| 201 | } |