VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gvstartup.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gvstartup.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gvstartup.h"
23 #include "gvexit.h"
24 #include "genvironment.h"
25 #include "gdaemon.h"
26 #include "gsharedmemory.h"
27 #include "groot.h"
28 #include "gprocess.h"
29 #include "geventloop.h"
30 #include "locale.h"
31 #include <iostream>
32 #include <signal.h>
33 
34 #ifndef PACKAGE_VERSION
35 #define PACKAGE_VERSION "0.1"
36 #endif
37 
38 static const char * legal_text =
39  "Copyright (C) 2017 Graeme Walker\n"
40  "\n"
41  "This program is free software: you can redistribute it and/or modify\n"
42  "it under the terms of the GNU General Public License as published by\n"
43  "the Free Software Foundation, either version 3 of the License, or\n"
44  "(at your option) any later version.\n"
45  "\n"
46  "This program is distributed in the hope that it will be useful,\n"
47  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
48  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
49  "GNU General Public License for more details.\n"
50  "\n"
51  "You should have received a copy of the GNU General Public License\n"
52  "along with this program. If not, see <http://www.gnu.org/licenses/>.\n"
53 ;
54 
55 namespace
56 {
57  struct gconfig
58  {
59  static bool have_libjpeg ;
60  static bool have_libpng ;
61  static bool have_libav ;
62  static bool have_libv4l ;
63  static bool have_v4l ;
64  static bool have_curses ;
65  static bool have_x11 ;
66  } ;
67  bool with_debug( bool b )
68  {
69  return b || G::Environment::get("VT_DEBUG","")=="1" ;
70  }
71  bool with_verbose( bool b )
72  {
73  return b || G::Environment::get("VT_VERBOSE","")=="1" ;
74  }
75 }
76 
77 Gv::Startup::Startup( const G::GetOpt & opt , const std::string & args_help ,
78  bool argc_ok , const std::string & extra_help ) :
79  m_debug(with_debug(opt.contains("debug"))) ,
80  m_log_output(opt.args().prefix() ,
81  true , // output from G_*()
82  true , // output from G_LOG_S()
83  with_verbose(opt.contains("verbose")||m_debug) , // output from G_LOG()
84  m_debug , // output from G_DEBUG()
85  true , // with level
86  opt.contains("log-time") , // with timestamp
87  !m_debug , // strip context
88  opt.contains("syslog")) ,
89  m_daemon(opt.contains("daemon")) ,
90  m_syslog(opt.contains("syslog")) ,
91  m_verbose(opt.contains("verbose")) ,
92  m_pid_file(opt.value("pid-file")) ,
93  m_user(opt.value("user","")) ,
94  m_started(false)
95 {
96  if( opt.hasErrors() )
97  {
98  opt.showErrors( std::cerr ) ;
99  throw Gv::Exit( EXIT_FAILURE ) ;
100  }
101  if( opt.contains("help") )
102  {
103  opt.options().showUsage( std::cout , opt.args().prefix() , args_help ) ;
104  if( !extra_help.empty() )
105  std::cout << "\n" << extra_help << std::endl ;
106  std::cout << "\nCopyright (C) 2017 Graeme Walker" << std::endl ;
107  throw Gv::Exit( EXIT_SUCCESS ) ;
108  }
109  if( opt.contains("version") )
110  {
111  std::cout << PACKAGE_VERSION << std::endl ; // version from automake header
112  if( opt.contains("verbose") )
113  {
114  std::cout << "libjpeg: " << gconfig::have_libjpeg << std::endl ;
115  std::cout << "libpng: " << gconfig::have_libpng << std::endl ;
116  std::cout << "libav: " << gconfig::have_libav << std::endl ;
117  std::cout << "libv4l: " << gconfig::have_libv4l << std::endl ;
118  std::cout << "v4l: " << gconfig::have_v4l << std::endl ;
119  std::cout << "curses: " << gconfig::have_curses << std::endl ;
120  std::cout << "xlib: " << gconfig::have_x11 << std::endl ;
121  }
122  std::cout << "\n" << legal_text << std::endl ;
123  throw Gv::Exit( EXIT_SUCCESS ) ;
124  }
125  if( !argc_ok )
126  {
127  opt.options().showUsage( std::cerr , opt.args().prefix() , args_help ) ;
128  std::cerr << "\nCopyright (C) 2017 Graeme Walker" << std::endl ;
129  throw Gv::Exit( EXIT_FAILURE ) ;
130  }
131 
132  setlocale( LC_ALL , "" ) ;
133  G::SharedMemory::help( ": consider doing \"vt-channel %s delete\" to clean up if the channel publisher is not running" ) ;
134  G::SharedMemory::prefix( "vt-" ) ;
135  G::SharedMemory::filetext( "# shmem placeholder -- see man videotools\n" ) ;
136 
137  if( m_daemon )
138  {
139  // during startup we keep stderr open so that startup errors are visible
140  const bool keep_stderr = true ; // see closeStderr() below
141  G::Process::closeFiles( keep_stderr ) ;
142 
143  // but verbose logging is probably not wanted until after we have gone
144  // syslog-only, with stderr closed
145  if( m_syslog )
146  m_log_output.verbose( false ) ;
147  }
148 
149  // switch to the non-privileged account early so that any file-system
150  // and ipc resources have the correct group ownership
151  if( !m_user.empty() )
152  {
153  // do not change group-id by default -- resources will be created
154  // with the parent process's real group-id or the exe's group id
155  // if group-suid
156  G::Root::init( m_user , false/*chgrp(root)*/ ) ;
157  }
158 }
159 
161 {
162  if( m_daemon )
163  G::Daemon::detach( m_pid_file ) ;
164 
165  {
166  G::Root claim_root ;
167  G::Process::Umask umask( G::Process::Umask::Readable ) ;
168  m_pid_file.commit() ;
169  }
170 
171  if( m_daemon && m_syslog )
172  {
173  G::Process::closeStderr() ;
174  m_log_output.verbose( m_verbose ) ;
175  }
176 
177  // set a SIGHUP signal handler to quit the event loop, esp. for profiling
179  ::signal( SIGHUP , Gv::Startup::onSignal ) ;
180 
181  m_started = true ;
182 }
183 
184 void Gv::Startup::onSignal( int )
185 {
187 }
188 
189 void Gv::Startup::report( const std::string & prefix , std::exception & e )
190 {
191  report( prefix , e.what() ) ;
192 }
193 
194 void Gv::Startup::report( const std::string & prefix , const std::string & what )
195 {
196  try
197  {
198  if( m_started && ( m_daemon || m_syslog ) )
199  G_ERROR( "" << prefix << ": " << what ) ;
200  }
201  catch(...)
202  {
203  }
204 }
205 
206 void Gv::Startup::sanitise( int , char * [] )
207 {
208  // TODO remove passwords from urls in argv
209 }
210 
211 
212 
213 
214 #if GCONFIG_HAVE_LIBJPEG
215 bool gconfig::have_libjpeg = true ;
216 #else
217 bool gconfig::have_libjpeg = false ;
218 #endif
219 
220 #if GCONFIG_HAVE_LIBPNG
221 bool gconfig::have_libpng = true ;
222 #else
223 bool gconfig::have_libpng = false ;
224 #endif
225 
226 #if GCONFIG_HAVE_LIBAV
227 bool gconfig::have_libav = true ;
228 #else
229 bool gconfig::have_libav = false ;
230 #endif
231 
232 #if GCONFIG_HAVE_LIBV4L
233 bool gconfig::have_libv4l = true ;
234 #else
235 bool gconfig::have_libv4l = false ;
236 #endif
237 
238 #if GCONFIG_HAVE_V4L
239 bool gconfig::have_v4l = true ;
240 #else
241 bool gconfig::have_v4l = false ;
242 #endif
243 
244 #if GCONFIG_HAVE_CURSES
245 bool gconfig::have_curses = true ;
246 #else
247 bool gconfig::have_curses = false ;
248 #endif
249 
250 #if GCONFIG_HAVE_X11
251 bool gconfig::have_x11 = true ;
252 #else
253 bool gconfig::have_x11 = false ;
254 #endif
255 
256 /// \file gvstartup.cpp
static void help(const std::string &)
Sets some error-message help text for the case when named shared memory cannot be created because it ...
static void stop(const G::SignalSafe &)
Calls quit() on instance().
Definition: geventloop.cpp:56
static std::string get(const std::string &name, const std::string &default_)
Returns the environment variable value or the given default.
void showErrors(std::ostream &stream, std::string prefix_1, std::string prefix_2=std::string(": ")) const
A convenience function which streams out each errorList() item to the given stream, prefixed with the given prefix(es).
Definition: ggetopt.cpp:154
std::string prefix() const
Returns the basename of v(0) without any extension.
Definition: garg.cpp:172
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:36
static std::string prefix()
Returns the prefix, as set by by a call to the other overload.
bool hasErrors() const
Returns true if there are errors.
Definition: ggetopt.cpp:144
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
static void init(const std::string &non_root, bool default_change_group=true)
Initialises this class on process start-up by releasing root (or suid) privileges.
Definition: groot.cpp:92
void report(const std::string &prefix, std::exception &e)
Reports an error if start()ed and "daemon" or "syslog" are in effect.
Definition: gvstartup.cpp:189
A simple exception structure holding a program exit value.
Definition: gvexit.h:35
A command line option parser.
Definition: ggetopt.h:55
Arg args() const
Returns all the non-option command-line arguments.
Definition: ggetopt.cpp:139
Startup(const G::GetOpt &, const std::string &args_help, bool argc_ok, const std::string &extra_help=std::string())
Constructor, typically used very early in main().
Definition: gvstartup.cpp:77
const Options & options() const
Returns a reference to the internal option specification object.
Definition: ggetopt.cpp:103
static void sanitise(int argc, char *argv[])
Removes sensitive information from the command-line, if possible.
Definition: gvstartup.cpp:206
static void detach()
Detaches from the parent environment.
static bool exists()
Returns true if an instance exists.
Definition: geventloop.cpp:51
bool contains(char option_letter) const
Returns true if the command line contains the option identified by its short-form letter...
Definition: ggetopt.cpp:113
void start()
Called just before the event loop.
Definition: gvstartup.cpp:160
static void filetext(const std::string &)
Sets some help text that gets written into the placeholder files.
void showUsage(std::ostream &stream, const std::string &exe, const std::string &args=std::string(), const std::string &introducer=introducerDefault(), Level level=levelDefault(), Layout layout=layoutDefault(), bool extra=true) const
Streams out multi-line usage text using usageSummary() and usageHelp().
Definition: goptions.cpp:292
void verbose(bool verbose_log=true)
Enables or disables verbose logging.
Definition: glogoutput.cpp:121