1111#include " visor_config.h"
1212#include < docopt/docopt.h>
1313#include < resolv.h>
14+ #include < spdlog/sinks/basic_file_sink.h>
1415#include < spdlog/sinks/stdout_color_sinks.h>
16+ #include < spdlog/sinks/syslog_sink.h>
1517#include < spdlog/spdlog.h>
1618
1719#include " GeoDB.h"
@@ -38,12 +40,16 @@ static const char USAGE[] =
3840 --admin-api Enable admin REST API giving complete control plane functionality [default: false]
3941 When not specified, the exposed API is read-only access to summarized metrics.
4042 When specified, write access is enabled for all modules.
43+ -d Daemonize; fork and continue running in the background [default: false]
4144 -h --help Show this screen
4245 -v Verbose log output
4346 --no-track Don't send lightweight, anonymous usage metrics.
4447 --version Show version
45- --geo-city FILE GeoLite2 City database to use for IP to Geo mapping (if enabled)
46- --geo-asn FILE GeoLite2 ASN database to use for IP to ASN mapping (if enabled)
48+ --geo-city FILE GeoLite2 City database to use for IP to Geo mapping
49+ --geo-asn FILE GeoLite2 ASN database to use for IP to ASN mapping
50+ Logging Options:
51+ --log-file FILE Log to the given output file name
52+ --syslog Log to syslog
4753 Prometheus Options:
4854 --prometheus Enable native Prometheus metrics at path /metrics
4955 --prom-instance ID Optionally set the 'instance' tag to ID
@@ -77,6 +83,70 @@ void initialize_geo(const docopt::value &city, const docopt::value &asn)
7783 }
7884}
7985
86+ // adapted from LPI becomeDaemon()
87+ int daemonize ()
88+ {
89+ switch (fork ()) {
90+ case -1 :
91+ return -1 ;
92+ case 0 :
93+ // Child falls through...
94+ break ;
95+ default :
96+ // while parent terminates
97+ _exit (EXIT_SUCCESS);
98+ }
99+
100+ // Become leader of new session
101+ if (setsid () == -1 ) {
102+ return -1 ;
103+ }
104+
105+ // Ensure we are not session leader
106+ switch (auto pid = fork ()) {
107+ case -1 :
108+ return -1 ;
109+ case 0 :
110+ break ;
111+ default :
112+ std::cerr << " pktvisord running at PID " << pid << std::endl;
113+ _exit (EXIT_SUCCESS);
114+ }
115+
116+ // Clear file mode creation mask
117+ umask (0 );
118+
119+ // Change to root directory
120+ chdir (" /" );
121+ int maxfd, fd;
122+ maxfd = sysconf (_SC_OPEN_MAX);
123+ // Limit is indeterminate...
124+ if (maxfd == -1 ) {
125+ maxfd = 8192 ; // so take a guess
126+ }
127+
128+ for (fd = 0 ; fd < maxfd; fd++) {
129+ close (fd);
130+ }
131+
132+ // Reopen standard fd's to /dev/null
133+ close (STDIN_FILENO);
134+
135+ fd = open (" /dev/null" , O_RDWR);
136+
137+ if (fd != STDIN_FILENO) {
138+ return -1 ;
139+ }
140+ if (dup2 (STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) {
141+ return -1 ;
142+ }
143+ if (dup2 (STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
144+ return -1 ;
145+ }
146+
147+ return 0 ;
148+ }
149+
80150int main (int argc, char *argv[])
81151{
82152
@@ -85,7 +155,26 @@ int main(int argc, char *argv[])
85155 true , // show help if requested
86156 VISOR_VERSION); // version string
87157
88- auto logger = spdlog::stdout_color_mt (" pktvisor" );
158+ if (args[" -d" ].asBool ()) {
159+ if (daemonize ()) {
160+ std::cerr << " failed to daemonize" << std::endl;
161+ exit (EXIT_FAILURE);
162+ }
163+ }
164+
165+ std::shared_ptr<spdlog::logger> logger;
166+ if (args[" --log-file" ]) {
167+ try {
168+ logger = spdlog::basic_logger_mt (" pktvisor" , args[" --log-file" ].asString ());
169+ } catch (const spdlog::spdlog_ex &ex) {
170+ std::cerr << " Log init failed: " << ex.what () << std::endl;
171+ exit (EXIT_FAILURE);
172+ }
173+ } else if (args[" --syslog" ].asBool ()) {
174+ logger = spdlog::syslog_logger_mt (" pktvisor" , " pktvisord" , LOG_PID);
175+ } else {
176+ logger = spdlog::stdout_color_mt (" pktvisor" );
177+ }
89178 if (args[" -v" ].asBool ()) {
90179 logger->set_level (spdlog::level::debug);
91180 }
@@ -151,7 +240,7 @@ int main(int argc, char *argv[])
151240 initialize_geo (args[" --geo-city" ], args[" --geo-asn" ]);
152241 } catch (const std::exception &e) {
153242 logger->error (" Fatal error: {}" , e.what ());
154- exit (- 1 );
243+ exit (EXIT_FAILURE );
155244 }
156245
157246 if (args[" IFACE" ]) {
@@ -195,21 +284,21 @@ int main(int argc, char *argv[])
195284
196285 } catch (const std::exception &e) {
197286 logger->error (e.what ());
198- exit (- 1 );
287+ exit (EXIT_FAILURE );
199288 }
200289 } else if (!args[" --admin-api" ].asBool ()) {
201290 // if they didn't specify pcap target, or config file, or admin api then there is nothing to do
202291 logger->error (" Nothing to do: specify --admin-api or IFACE." );
203292 std::cerr << USAGE << std::endl;
204- exit (- 1 );
293+ exit (EXIT_FAILURE );
205294 }
206295
207296 try {
208297 svr.start (host.c_str (), port);
209298 } catch (const std::exception &e) {
210299 logger->error (e.what ());
211- exit (- 1 );
300+ exit (EXIT_FAILURE );
212301 }
213302
214- return 0 ;
303+ exit (EXIT_SUCCESS) ;
215304}
0 commit comments