1 /*
2    Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 #include <my_sys.h>
27 #include <my_getopt.h>
28 #include <mysql_version.h>
29 #include <ndb_version.h>
30 
31 #include "CPCD.hpp"
32 #include "APIService.hpp"
33 #include <NdbMain.h>
34 #include <NdbSleep.h>
35 #include <portlib/NdbDir.hpp>
36 #include <BaseString.hpp>
37 #include <logger/Logger.hpp>
38 #include <logger/FileLogHandler.hpp>
39 #include <logger/SysLogHandler.hpp>
40 
41 #include "common.hpp"
42 
43 static const char *work_dir = CPCD_DEFAULT_WORK_DIR;
44 static int unsigned port;
45 static int use_syslog;
46 static const char *logfile = NULL;
47 static const char *user = 0;
48 
49 static struct my_option my_long_options[] =
50 {
51   { "work-dir", 'w', "Work directory",
52     (uchar**) &work_dir, (uchar**) &work_dir,  0,
53     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
54   { "port", 'p', "TCP port to listen on",
55     (uchar**) &port, (uchar**) &port, 0,
56     GET_INT, REQUIRED_ARG, CPCD_DEFAULT_TCP_PORT, 0, 0, 0, 0, 0 },
57   { "syslog", 'S', "Log events to syslog",
58     (uchar**) &use_syslog, (uchar**) &use_syslog, 0,
59     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
60   { "logfile", 'L', "File to log events to",
61     (uchar**) &logfile, (uchar**) &logfile, 0,
62     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
63   { "debug", 'D', "Enable debug mode",
64     (uchar**) &debug, (uchar**) &debug, 0,
65     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
66   { "user", 'u', "Run as user",
67     (uchar**) &user, (uchar**) &user, 0,
68     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
69   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
70 };
71 
72 static my_bool
get_one_option(int optid,const struct my_option * opt MY_ATTRIBUTE ((unused)),char * argument)73 get_one_option(int optid, const struct my_option *opt MY_ATTRIBUTE((unused)),
74 	       char *argument)
75 {
76   return 0;
77 }
78 
79 static CPCD * g_cpcd = 0;
80 
81 
main(int argc,char ** argv)82 int main(int argc, char** argv){
83   const char *load_default_groups[]= { "ndb_cpcd",0 };
84   NDB_INIT(argv[0]);
85 
86   load_defaults("ndb_cpcd",load_default_groups,&argc,&argv);
87   if (handle_options(&argc, &argv, my_long_options, get_one_option)) {
88     print_defaults(MYSQL_CONFIG_NAME,load_default_groups);
89     puts("");
90     my_print_help(my_long_options);
91     my_print_variables(my_long_options);
92     exit(1);
93   }
94 
95   logger.setCategory("ndb_cpcd");
96   logger.enable(Logger::LL_ALL);
97 
98   if(debug)
99     logger.createConsoleHandler();
100 
101 #ifndef _WIN32
102   if(user && runas(user) != 0){
103     logger.critical("Unable to change user: %s", user);
104     _exit(1);
105   }
106 #endif
107 
108   if(logfile != NULL){
109     BaseString tmp;
110     if(logfile[0] != '/')
111       tmp.append(work_dir);
112     tmp.append(logfile);
113     logger.addHandler(new FileLogHandler(tmp.c_str()));
114   }
115 
116 #ifndef _WIN32
117   if(use_syslog)
118     logger.addHandler(new SysLogHandler());
119 #endif
120 
121   logger.info("Starting");
122 
123 #if defined SIGPIPE && !defined _WIN32
124   (void)signal(SIGPIPE, SIG_IGN);
125 #endif
126 #ifdef SIGCHLD
127   /* Only "poll" for child to be alive, never use 'wait' */
128   (void)signal(SIGCHLD, SIG_IGN);
129 #endif
130 
131   CPCD cpcd;
132   g_cpcd = &cpcd;
133 
134   /* Create working directory unless it already exists */
135   if (access(work_dir, F_OK))
136   {
137     logger.info("Working directory '%s' does not exist, trying "
138                 "to create it", work_dir);
139     if (!NdbDir::create(work_dir,
140                         NdbDir::u_rwx() | NdbDir::g_r() | NdbDir::o_r()))
141     {
142       logger.error("Failed to create working directory, terminating!");
143       exit(1);
144     }
145   }
146 
147   if(strlen(work_dir) > 0){
148     logger.debug("Changing dir to '%s'", work_dir);
149     if(NdbDir::chdir(work_dir) != 0){
150       logger.error("Cannot change directory to '%s', error: %d, terminating!",
151                    work_dir, errno);
152       exit(1);
153     }
154   }
155 
156   cpcd.loadProcessList();
157 
158   SocketServer * ss = new SocketServer();
159   CPCDAPIService * serv = new CPCDAPIService(cpcd);
160   unsigned short real_port= port; // correct type
161   if(!ss->setup(serv, &real_port)){
162     logger.critical("Cannot setup server: %s", strerror(errno));
163     sleep(1);
164     delete ss;
165     delete serv;
166     return 1;
167   }
168 
169   ss->startServer();
170 
171   logger.debug("Start completed");
172   while(true)
173     NdbSleep_MilliSleep(1000);
174 
175   delete ss;
176   return 0;
177 }
178