1
/*
2
    Copyright (c) 2009, 2010 digitalSTROM.org, Zurich, Switzerland
3
4
    Author: Patrick Staehlin, futureLAB AG <pstaehlin@futurelab.ch>
5
6
    This file is part of digitalSTROM Server.
7
8
    digitalSTROM Server is free software: you can redistribute it and/or modify
9
    it under the terms of the GNU General Public License as published by
10
    the Free Software Foundation, either version 3 of the License, or
11
    (at your option) any later version.
12
13
    digitalSTROM Server is distributed in the hope that it will be useful,
14
    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
    GNU General Public License for more details.
17
18
    You should have received a copy of the GNU General Public License
19
    along with digitalSTROM Server. If not, see <http://www.gnu.org/licenses/>.
20
21
*/
22
23
24
#ifdef HAVE_CONFIG_H
25
  #include "config.h"
26
#endif
27
28
#include "core/base.h"
29
#include "core/dss.h"
30
#include "core/logger.h"
31
#include "core/datetools.h"
32
#ifdef WITH_TESTS
33
#include "tests/tests.h"
34
#endif
35
36
#include <ctime>
37
#include <csignal>
38
#include <getopt.h>
39
40
#include <boost/program_options.hpp>
41
42
#ifdef USE_LIBXML
43
  #include <libxml/tree.h>
44
  #include <libxml/encoding.h>
45
#endif
46
47
#include <iostream>
48
49
using namespace std;
50
namespace po = boost::program_options;
51
52
pair<string, string> parse_prop(const string& s) {
53
    if ((s.find("--prop") == 0) && (s.length() >=7)) {
54
      return make_pair("prop", s.substr(7));
55
    } else {
56
      return make_pair(string(), string());
57
    }
58
} // parse_prop
59
60
void platformSpecificStartup() {
61
#ifndef WIN32
62
  srand((getpid() << 16) ^ getuid() ^ time(0));
63
  // disable broken pipe signal
64
  signal(SIGPIPE, SIG_IGN);
65
  signal(SIGUSR1, dss::DSS::handleSignal);
66
  signal(SIGTERM, dss::DSS::handleSignal);
67
  signal(SIGINT, dss::DSS::handleSignal);
68
  signal(SIGSEGV, dss::DSS::handleSignal);
69
  signal(SIGABRT, dss::DSS::handleSignal);
70
#else
71
  srand( (int)time( (time_t)NULL ) );
72
  WSAData dat;
73
  WSAStartup( 0x1010, &dat );
74
#endif
75
} // platformSpecificStartup
76
77
char* tzNameCopy;
78
79
bool setupLocale() {
80
  if (!setlocale(LC_CTYPE, "")) {
81
    dss::Logger::getInstance()->log("Can't set the specified locale! Check LANG, LC_CTYPE, LC_ALL.", lsError);
82
    return false;
83
  }
84
85
  // make sure timezone gets set
86
  tzset();
87
88
  long int time_offset = timezone;
89
90
#if defined(__linux__)
91
  time_t now;
92
  struct tm t;
93
  time(&now);
94
  localtime_r(&now, &t);
95
  mktime(&t);
96
  // gmtoff is east of UTC, however timezone is west of UTC
97
  time_offset = t.tm_gmtoff * (-1);
98
#endif
99
100
  dss::DateTime::configureUTCOffset(time_offset);
101
102
  tzNameCopy = strdup("GMT");
103
  tzname[0] = tzname[1] = tzNameCopy;
104
  timezone = 0;
105
  daylight = 0;
106
107
  setenv("TZ", "UTC", 1);
108
  return true;
109
}
110
111
int main (int argc, char* argv[]) {
112
113
  if(!setupLocale()) {
114
    return -1;
115
  }
116
  platformSpecificStartup();
117
118
  vector<string> properties;
119
120
  po::options_description desc("Allowed options");
121
  desc.add_options()
122
      ("help", "produce help message")
123
      ("prop", po::value<vector<string> >(), "sets a property")
124
      ("version,v", "print version information and exit")
125
      ("datadir,D", po::value<string>(), "set data directory")
126
      ("webrootdir,w", po::value<string>(), "set webroot directory")
127
      ("configdir,c", po::value<string>(), "set config directory")
128
      ("config,C", po::value<string>(), "set configuration file to use")
129
      ("savedpropsdir,p", po::value<string>(), "set saved properties directory")
130
#ifndef __APPLE__ // daemon() is marked as deprecated on OS X
131
      ("daemonize,d", "start as a daemon")
132
#endif
133
  ;
134
135
  po::variables_map vm;
136
  try {
137
    po::store(po::command_line_parser(argc, argv).options(desc).extra_parser(parse_prop)
138
          .run(), vm);
139
  } catch (const po::error& e) {
140
    cout << "Error parsing command line: " << e.what() << endl;
141
    return 1;
142
  }
143
  po::notify(vm);
144
145
  if (vm.count("help")) {
146
      cout << desc << "\n";
147
      return 1;
148
  }
149
150
  if (vm.count("version")) {
151
    std::cout << dss::DSS::versionString() << std::endl;
152
    return 1;
153
  }
154
155
  if(vm.count("prop")) {
156
      properties = vm["prop"].as< vector<string> >();
157
  }
158
159
  if(vm.count("datadir")) {
160
    properties.push_back("/config/datadirectory=" +
161
                         vm["datadir"].as<string>());
162
  }
163
164
  if(vm.count("webrootdir")) {
165
    properties.push_back("/config/webrootdirectory=" +
166
                          vm["webrootdir"].as<string>());
167
  }
168
169
  if(vm.count("configdir")) {
170
    properties.push_back("/config/configdirectory=" +
171
                         vm["configdir"].as<string>());
172
  }
173
174
  string config_file;
175
  if(vm.count("config")) {
176
    config_file = vm["config"].as<string>();
177
  }
178
179
  if(vm.count("savedpropsdir")) {
180
    properties.push_back("/config/savedpropsdirectory=" +
181
                         vm["savedpropsdir"].as<string>());
182
  }
183
184
  string snifferDev;
185
  bool startSniffer = false;
186
187
  if(vm.count("sniff")) {
188
    startSniffer = true;
189
    snifferDev = vm["sniff"].as<string>();
190
  }
191
192
#ifndef __APPLE__
193
  bool daemonize = vm.count("daemonize") != 0;
194
#endif
195
196
  // start DSS
197
  if (dss::DSS::getInstance()->initialize(properties, config_file)) {
198
#ifndef __APPLE__
199
    if(daemonize) {
200
      int result = daemon(1,0);
201
      if(result != 0) {
202
        perror("daemon()");
203
        return 0;
204
      }
205
    }
206
#endif
207
    dss::DSS::getInstance()->run();
208
  } else {
209
    dss::Logger::getInstance()->log("Failed to initialize dss. Exiting", lsFatal);
210
  }
211
  if(dss::DSS::hasInstance()) {
212
    dss::DSS::shutdown();
213
  }
214
  dss::Logger::shutdown();
215
216
  free(tzNameCopy);
217
218
  return 0;
219
}