unix/aix/APIService.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.ibm.com/developerworks/oss/CPLv1.0.htm */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 
39 #ifdef HAVE_CONFIG_H
40 # include "config.h"
41 #endif
42 
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <fcntl.h>
48 #include <signal.h>
49 #include <pwd.h>
50 #include "APIServer.hpp"
51 #include "stdio.h"
52 
53 // Temp fix for AXI 6.1 problem - will be removed later
54 // - switching the daemon to nobody does not work on AIX 6.1
55 // - it does work on AIX 5.2 / 5.3
56 #ifndef AIX_REMOVED
57 # define ENABLE_NOBODY
58 #endif
59 
60 // For testing purposes comment out the following line to force RXAPI to
61 // run as a foreground process.
62 #define RUN_AS_DAEMON
63 
64 #ifdef RUN_AS_DAEMON
65 #define OOREXX_PIDFILE "/var/run/ooRexx.pid"
66 bool run_as_daemon = true;
67 #else
68 #define OOREXX_PIDFILE "/tmp/ooRexx.pid"
69 bool run_as_daemon = false;
70 #endif
71 
72 APIServer apiServer; // the real server instance
73 
74 
75 /*==========================================================================*
76  * Function: Run
77  *
78  * Purpose:
79  *
80  * handles the original RXAPI functions.
81  * Perform the message loop
82  *
83  *
84  *==========================================================================*/
85 void Run (bool asService)
86 {
87  try
88  {
89  apiServer.initServer(); // start up the server
90  apiServer.listenForConnections(); // go into the message loop
91  }
92  catch (ServiceException *)
93  {
94  }
95  apiServer.terminateServer(); // shut everything down
96 }
97 
98 /*==========================================================================*
99  * Function: Stop
100  *
101  * Purpose:
102  *
103  * handles the stop request.
104  *
105  *
106  *==========================================================================*/
107 void Stop(int signo)
108 {
109  apiServer.terminateServer(); // shut everything down
110 
111  exit(1);
112 }
113 
114 /////////////////////////////////////////////////////////////////
115 /////////////////////////////////////////////////////////////////
116 // Routines to run RXAPI as an daemon BEGIN
117 
118 
119 /*==========================================================================*
120  * Function: morph2daemon
121  *
122  * Purpose:
123  *
124  * Turn this process into a daemon.
125  *
126  * Returns TRUE if a daemon, FALSE if not or an error
127  *
128  *==========================================================================*/
129 static bool morph2daemon(void)
130 {
131  char pid_buf[256];
132 
133  if (run_as_daemon == false) {
134  return true; // go ahead and run in the foreground
135  }
136 
137  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
138  return false;
139  }
140 
141  pid_t pid = fork();
142  if (pid < 0) {
143  return false;
144  }
145  // if we are the parent process then we are done
146  if (pid != 0) {
147  exit( 0 );
148  }
149 
150  // become the session leader
151  setsid();
152  // second fork to become a real daemon
153  pid = fork();
154  if (pid < 0) {
155  return false;
156  }
157  // if we are the parent process then we are done
158  if (pid != 0) {
159  exit(0);
160  }
161 
162  // create the pid file (overwrite of old pid file is ok)
163  unlink(OOREXX_PIDFILE);
164  int pfile = open(OOREXX_PIDFILE, O_WRONLY | O_CREAT, 0640);
165  snprintf(pid_buf, sizeof(pid_buf), "%d\n", (int)getpid());
166  write(pfile, pid_buf, strlen(pid_buf));
167  close(pfile);
168 
169  // housekeeping
170  chdir("/");
171  umask(0);
172  for(int i = 0; i < 1024; i++) {
173  close(i);
174  }
175 
176 #ifdef ENABLE_NOBODY
177  // We start out with root privileges. This is bad from a security perspective. So
178  // switch to the nobody user so we do not have previleges we do not need.
179  struct passwd *pw;
180  pw = getpwnam("nobody");
181  if (pw != NULL) {
182  setuid(pw->pw_uid);
183  }
184 #endif
185  return true;
186 }
187 
188 
189 /*==========================================================================*
190  * Function: main
191  *
192  * Purpose:
193  *
194  * Main entry point.
195  *
196  *==========================================================================*/
197 int main(int argc, char *argv[])
198 {
199  char pid_buf[256];
200  int pfile, len;
201  pid_t pid = 0;
202  struct stat st;
203  struct sigaction sa;
204  // Get the command line args
205  if (argc > 1) {
206  printf("Error: Invalid command line option(s).\n");
207  printf(" Aborting execution.\n\n");
208  return -1;
209  }
210 
211  // see if we are already running
212  if ((pfile = open(OOREXX_PIDFILE, O_RDONLY)) > 0) {
213  len = read(pfile, pid_buf, sizeof(pid_buf) - 1);
214  close(pfile);
215  pid_buf[len] = '\0';
216  pid = (pid_t)atoi(pid_buf);
217  if (pid && (pid == getpid() || kill(pid, 0) < 0)) {
218  unlink(OOREXX_PIDFILE);
219  } else {
220  // there is already a server running
221  printf("Error: There is already a server running.\n");
222  printf(" Aborting execution.\n");
223  return -1;
224  }
225  }
226 
227  // write the pid file
228  pfile = open(OOREXX_PIDFILE, O_WRONLY | O_CREAT,
229  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
230  if (pfile == -1) {
231  // cannot open pid file
232  printf("Error: Cannot open PID file %s.\n", OOREXX_PIDFILE);
233  printf(" Aborting execution.\n\n");
234  return -1;
235  }
236  snprintf(pid_buf, sizeof(pid_buf), "%d\n", (int)getpid());
237  write(pfile, pid_buf, strlen(pid_buf));
238  close(pfile);
239 
240  // make ourselves a daemon
241  // - if this is AIX we check if the rxapi daemon was sarted via SRC
242  // - if the daemon was started via SRC we do not morph - the SRC handles this
243  //
244  // - add to AIX SRC without auto restart:
245  // mkssys -s rxapi -p /opt/ooRexx/bin/rxapi -i /dev/null -e /dev/console \
246  // -o /dev/console -u 0 -S -n 15 -f 9 -O -Q
247  //
248  // - add to AIX SRC with auto restart:
249  // mkssys -s rxapi -p /opt/ooRexx/bin/rxapi -i /dev/null -e /dev/console \
250  // -o /dev/console -u 0 -S -n 15 -f 9 -R -Q
251  if (fstat(0, &st) <0) {
252  if (morph2daemon() == false) {
253  return -1;
254  }
255  } else {
256  if ((st.st_mode & S_IFMT) == S_IFCHR) {
257  if (isatty(0)) {
258  if (morph2daemon() == false) {
259  return -1;
260  }
261  }
262  } else {
263  if (morph2daemon() == false) {
264  return -1;
265  }
266  }
267  }
268 
269  // run the server
270  if (run_as_daemon == false) {
271  printf("Starting request processing loop.\n");
272  } else {
273  (void) setsid();
274  printf("Starting request processing loop.\n");
275 #ifdef ENABLE_NOBODY
276  // We start out with root privileges. This is bad from a security perspective. So
277  // switch to the nobody user so we do not have previleges we do not need.
278  struct passwd *pw;
279  pw = getpwnam("nobody");
280  if (pw != NULL) {
281  setuid(pw->pw_uid);
282  }
283 #endif
284  }
285 
286  // handle kill -15
287  (void) sigemptyset(&sa.sa_mask);
288  (void) sigaddset(&sa.sa_mask, SIGTERM);
289  sa.sa_flags = SA_RESTART;
290  sa.sa_handler = Stop;
291  if (sigaction(SIGTERM, &sa, NULL) == -1) {
292  exit(1);
293  }
294 
295  Run(false);
296 
297  return 0;
298 }
299 
void initServer()
Definition: APIServer.cpp:53
void terminateServer()
Definition: APIServer.cpp:69
void listenForConnections()
Definition: APIServer.cpp:82
static bool morph2daemon(void)
int main(int argc, char *argv[])
void Stop(int signo)
void Run(bool asService)
#define OOREXX_PIDFILE
bool run_as_daemon
APIServer apiServer