Change initialization order for logsys logging to files to work properly.
[openais.git] / exec / main.c
blob68a265683302dde0092571bdf8b7d1a842e4fa75
1 /*
2 * Copyright (c) 2002-2006 MontaVista Software, Inc.
3 * Copyright (c) 2006 Red Hat, Inc.
4 * Copyright (c) 2006 Sun Microsystems, Inc.
6 * All rights reserved.
8 * Author: Steven Dake (sdake@mvista.com)
10 * This software licensed under BSD license, the text of which follows:
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
15 * - Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * - Neither the name of the MontaVista Software, Inc. nor the names of its
21 * contributors may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGE.
36 #include <pthread.h>
37 #include <assert.h>
38 #include <pwd.h>
39 #include <grp.h>
40 #include <sys/types.h>
41 #include <sys/poll.h>
42 #include <sys/uio.h>
43 #include <sys/mman.h>
44 #include <sys/socket.h>
45 #include <sys/un.h>
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <errno.h>
55 #include <signal.h>
56 #include <sched.h>
57 #include <time.h>
59 #include "swab.h"
60 #include "../include/saAis.h"
61 #include "../include/list.h"
62 #include "../include/queue.h"
63 #include "../lcr/lcr_ifact.h"
64 #include "poll.h"
65 #include "totempg.h"
66 #include "totemsrp.h"
67 #include "mempool.h"
68 #include "mainconfig.h"
69 #include "totemconfig.h"
70 #include "main.h"
71 #include "service.h"
72 #include "sync.h"
73 #include "swab.h"
74 #include "objdb.h"
75 #include "config.h"
76 #include "tlist.h"
77 #include "flow.h"
78 #include "ipc.h"
79 #include "timer.h"
80 #include "logsys.h"
81 #include "util.h"
82 #include "flow.h"
83 #include "version.h"
85 LOGSYS_DECLARE_SYSTEM ("openais",
86 LOG_MODE_OUTPUT_STDERR | LOG_MODE_OUTPUT_SYSLOG_THREADED | LOG_MODE_DISPLAY_DEBUG | LOG_MODE_BUFFER_BEFORE_CONFIG,
87 NULL,
88 LOG_DAEMON);
90 LOGSYS_DECLARE_SUBSYS ("MAIN", LOG_INFO);
92 #define SERVER_BACKLOG 5
94 static int ais_uid = 0;
96 static int gid_valid = 0;
98 static unsigned int service_count = 32;
100 static pthread_mutex_t serialize_mutex = PTHREAD_MUTEX_INITIALIZER;
102 static struct totem_logging_configuration totem_logging_configuration;
104 static char delivery_data[MESSAGE_SIZE_MAX];
106 SaClmClusterNodeT *(*main_clm_get_by_nodeid) (unsigned int node_id);
108 static void sigusr2_handler (int num)
110 int i;
112 for (i = 0; ais_service[i]; i++) {
113 if (ais_service[i]->exec_dump_fn) {
114 ais_service[i]->exec_dump_fn ();
119 static void sigsegv_handler (int num)
121 signal (SIGSEGV, SIG_DFL);
122 logsys_flush ();
123 raise (SIGSEGV);
126 static void sigabrt_handler (int num)
128 signal (SIGABRT, SIG_DFL);
129 logsys_flush ();
130 raise (SIGABRT);
133 #define LOCALHOST_IP inet_addr("127.0.0.1")
135 totempg_groups_handle openais_group_handle;
137 struct totempg_group openais_group = {
138 .group = "a",
139 .group_len = 1
142 void sigintr_handler (int signum)
145 #ifdef DEBUG_MEMPOOL
146 int stats_inuse[MEMPOOL_GROUP_SIZE];
147 int stats_avail[MEMPOOL_GROUP_SIZE];
148 int stats_memoryused[MEMPOOL_GROUP_SIZE];
149 int i;
151 mempool_getstats (stats_inuse, stats_avail, stats_memoryused);
152 log_printf (LOG_LEVEL_DEBUG, "Memory pools:\n");
153 for (i = 0; i < MEMPOOL_GROUP_SIZE; i++) {
154 log_printf (LOG_LEVEL_DEBUG, "order %d size %d inuse %d avail %d memory used %d\n",
155 i, 1<<i, stats_inuse[i], stats_avail[i], stats_memoryused[i]);
157 #endif
159 totempg_finalize ();
160 openais_exit_error (AIS_DONE_EXIT);
164 static int pool_sizes[] = { 0, 0, 0, 0, 0, 4096, 0, 1, 0, /* 256 */
165 1024, 0, 1, 4096, 0, 0, 0, 0, /* 65536 */
166 1, 1, 1, 1, 1, 1, 1, 1, 1 };
168 void serialize_mutex_lock (void)
170 pthread_mutex_lock (&serialize_mutex);
173 void serialize_mutex_unlock (void)
175 pthread_mutex_unlock (&serialize_mutex);
179 static void openais_sync_completed (void)
183 static int openais_sync_callbacks_retrieve (int sync_id,
184 struct sync_callbacks *callbacks)
186 unsigned int ais_service_index;
187 unsigned int ais_services_found = 0;
189 for (ais_service_index = 0;
190 ais_service_index < SERVICE_HANDLER_MAXIMUM_COUNT;
191 ais_service_index++) {
193 if (ais_service[ais_service_index] != NULL) {
194 if (ais_services_found == sync_id) {
195 break;
197 ais_services_found += 1;
200 if (ais_service_index == SERVICE_HANDLER_MAXIMUM_COUNT) {
201 memset (callbacks, 0, sizeof (struct sync_callbacks));
202 return (-1);
204 callbacks->name = ais_service[ais_service_index]->name;
205 callbacks->sync_init = ais_service[ais_service_index]->sync_init;
206 callbacks->sync_process = ais_service[ais_service_index]->sync_process;
207 callbacks->sync_activate = ais_service[ais_service_index]->sync_activate;
208 callbacks->sync_abort = ais_service[ais_service_index]->sync_abort;
209 return (0);
212 static struct memb_ring_id aisexec_ring_id;
214 static void confchg_fn (
215 enum totem_configuration_type configuration_type,
216 unsigned int *member_list, int member_list_entries,
217 unsigned int *left_list, int left_list_entries,
218 unsigned int *joined_list, int joined_list_entries,
219 struct memb_ring_id *ring_id)
221 int i;
223 memcpy (&aisexec_ring_id, ring_id, sizeof (struct memb_ring_id));
226 * Call configuration change for all services
228 for (i = 0; i < service_count; i++) {
229 if (ais_service[i] && ais_service[i]->confchg_fn) {
230 ais_service[i]->confchg_fn (configuration_type,
231 member_list, member_list_entries,
232 left_list, left_list_entries,
233 joined_list, joined_list_entries, ring_id);
238 static void aisexec_uid_determine (struct main_config *main_config)
240 struct passwd *passwd;
242 passwd = getpwnam(main_config->user);
243 if (passwd == 0) {
244 log_printf (LOG_LEVEL_ERROR, "ERROR: The '%s' user is not found in /etc/passwd, please read the documentation.\n", main_config->user);
245 openais_exit_error (AIS_DONE_UID_DETERMINE);
247 ais_uid = passwd->pw_uid;
248 endpwent ();
251 static void aisexec_gid_determine (struct main_config *main_config)
253 struct group *group;
254 group = getgrnam (main_config->group);
255 if (group == 0) {
256 log_printf (LOG_LEVEL_ERROR, "ERROR: The '%s' group is not found in /etc/group, please read the documentation.\n", group->gr_name);
257 openais_exit_error (AIS_DONE_GID_DETERMINE);
259 gid_valid = group->gr_gid;
260 endgrent ();
263 static void aisexec_priv_drop (void)
265 return;
266 setuid (ais_uid);
267 setegid (ais_uid);
270 static void aisexec_mempool_init (void)
272 int res;
274 res = mempool_init (pool_sizes);
275 if (res == ENOMEM) {
276 log_printf (LOG_LEVEL_ERROR, "Couldn't allocate memory pools, not enough memory");
277 openais_exit_error (AIS_DONE_MEMPOOL_INIT);
281 static void aisexec_tty_detach (void)
283 int lpc, fd;
284 struct rlimit oflimits;
287 * Disconnect from TTY if this is not a debug run
289 switch (fork ()) {
290 case -1:
291 openais_exit_error (AIS_DONE_FORK);
292 break;
293 case 0:
295 * child which is disconnected, run this process
297 break;
298 default:
299 exit (0);
300 break;
303 /* Create new session */
304 setsid();
307 * Map stdin/out/err to /dev/null.
309 fd = open("/dev/null", O_RDWR);
310 if (fd >= 0) {
311 /* dup2 to 0 / 1 / 2 (stdin / stdout / stderr) */
312 dup2(fd, STDIN_FILENO); /* 0 */
313 dup2(fd, STDOUT_FILENO); /* 1 */
314 dup2(fd, STDERR_FILENO); /* 2 */
316 /* Should be 0, but just in case it isn't... */
317 if (fd > 2)
318 close(fd);
322 static void aisexec_setscheduler (void)
324 #if ! defined(TS_CLASS) && (defined(OPENAIS_BSD) || defined(OPENAIS_LINUX) || defined(OPENAIS_SOLARIS))
325 struct sched_param sched_param;
326 int res;
328 res = sched_get_priority_max (SCHED_RR);
329 if (res != -1) {
330 sched_param.sched_priority = 1;//res;
331 res = sched_setscheduler (0, SCHED_RR, &sched_param);
332 if (res == -1) {
333 log_printf (LOG_LEVEL_WARNING, "Could not set SCHED_RR at priority %d: %s\n",
334 sched_param.sched_priority, strerror (errno));
336 } else
337 log_printf (LOG_LEVEL_WARNING, "Could not get maximum scheduler priority: %s\n", strerror (errno));
338 #else
339 log_printf(LOG_LEVEL_WARNING, "Scheduler priority left to default value (no OS support)\n");
340 #endif
343 static void aisexec_mlockall (void)
345 #if !defined(OPENAIS_BSD)
346 int res;
347 #endif
348 struct rlimit rlimit;
350 rlimit.rlim_cur = RLIM_INFINITY;
351 rlimit.rlim_max = RLIM_INFINITY;
352 #ifndef OPENAIS_SOLARIS
353 setrlimit (RLIMIT_MEMLOCK, &rlimit);
354 #else
355 setrlimit (RLIMIT_VMEM, &rlimit);
356 #endif
358 #if defined(OPENAIS_BSD)
359 /* under FreeBSD a process with locked page cannot call dlopen
360 * code disabled until FreeBSD bug i386/93396 was solved
362 log_printf (LOG_LEVEL_WARNING, "Could not lock memory of service to avoid page faults\n");
363 #else
364 res = mlockall (MCL_CURRENT | MCL_FUTURE);
365 if (res == -1) {
366 log_printf (LOG_LEVEL_WARNING, "Could not lock memory of service to avoid page faults: %s\n", strerror (errno));
368 #endif
372 static void deliver_fn (
373 unsigned int nodeid,
374 struct iovec *iovec,
375 int iov_len,
376 int endian_conversion_required)
378 mar_req_header_t *header;
379 int pos = 0;
380 int i;
381 int service;
382 int fn_id;
385 * Build buffer without iovecs to make processing easier
386 * This is only used for messages which are multicast with iovecs
387 * and self-delivered. All other mechanisms avoid the copy.
389 if (iov_len > 1) {
390 for (i = 0; i < iov_len; i++) {
391 memcpy (&delivery_data[pos], iovec[i].iov_base, iovec[i].iov_len);
392 pos += iovec[i].iov_len;
393 assert (pos < MESSAGE_SIZE_MAX);
395 header = (mar_req_header_t *)delivery_data;
396 } else {
397 header = (mar_req_header_t *)iovec[0].iov_base;
399 if (endian_conversion_required) {
400 header->id = swab32 (header->id);
401 header->size = swab32 (header->size);
404 // assert(iovec->iov_len == header->size);
407 * Call the proper executive handler
409 service = header->id >> 16;
410 fn_id = header->id & 0xffff;
411 if (endian_conversion_required) {
412 assert(ais_service[service]->exec_service[fn_id].exec_endian_convert_fn != NULL);
413 ais_service[service]->exec_service[fn_id].exec_endian_convert_fn
414 (header);
417 ais_service[service]->exec_service[fn_id].exec_handler_fn
418 (header, nodeid);
421 int main (int argc, char **argv)
423 char *error_string;
424 struct main_config main_config;
425 struct totem_config totem_config;
426 unsigned int objdb_handle;
427 unsigned int config_handle;
428 unsigned int config_version = 0;
429 struct objdb_iface_ver0 *objdb;
430 void *objdb_p;
431 struct config_iface_ver0 *config;
432 void *config_p;
433 char *config_iface;
434 char *iface;
435 int res, ch;
436 int background, setprio;
437 int totem_log_service;
439 /* default configuration
441 background = 1;
442 setprio = 1;
444 while ((ch = getopt (argc, argv, "fp")) != EOF) {
446 switch (ch) {
447 case 'f':
448 background = 0;
449 logsys_config_mode_set (LOG_MODE_OUTPUT_STDERR|LOG_MODE_FLUSH_AFTER_CONFIG);
450 break;
451 case 'p':
452 setprio = 0;
453 break;
454 default:
455 fprintf(stderr, \
456 "usage:\n"\
457 " -f : Start application in foreground.\n"\
458 " -p : Do not set process priority. \n");
459 return EXIT_FAILURE;
463 if (background)
464 aisexec_tty_detach ();
466 log_printf (LOG_LEVEL_NOTICE, "AIS Executive Service RELEASE '%s'\n", RELEASE_VERSION);
467 log_printf (LOG_LEVEL_NOTICE, "Copyright (C) 2002-2006 MontaVista Software, Inc and contributors.\n");
468 log_printf (LOG_LEVEL_NOTICE, "Copyright (C) 2006-2007 Red Hat, Inc.\n");
470 signal (SIGINT, sigintr_handler);
471 signal (SIGUSR2, sigusr2_handler);
472 signal (SIGSEGV, sigsegv_handler);
473 signal (SIGABRT, sigabrt_handler);
475 openais_timer_init (
476 serialize_mutex_lock,
477 serialize_mutex_unlock);
479 log_printf (LOG_LEVEL_NOTICE, "AIS Executive Service: started and ready to provide service.\n");
481 aisexec_poll_handle = poll_create (
482 serialize_mutex_lock,
483 serialize_mutex_unlock);
486 * Load the object database interface
488 res = lcr_ifact_reference (
489 &objdb_handle,
490 "objdb",
492 &objdb_p,
494 if (res == -1) {
495 log_printf (LOG_LEVEL_ERROR, "AIS Executive couldn't open configuration object database component.\n");
496 openais_exit_error (AIS_DONE_OBJDB);
499 objdb = (struct objdb_iface_ver0 *)objdb_p;
501 objdb->objdb_init ();
503 /* User's bootstrap config service */
504 config_iface = getenv("OPENAIS_DEFAULT_CONFIG_IFACE");
505 if (!config_iface) {
506 config_iface = "aisparser";
509 /* Make a copy so we can deface it with strtok */
510 config_iface = strdup(config_iface);
512 iface = strtok(config_iface, ":");
513 while (iface)
515 res = lcr_ifact_reference (
516 &config_handle,
517 iface,
518 config_version,
519 &config_p,
522 config = (struct config_iface_ver0 *)config_p;
523 if (res == -1) {
524 log_printf (LOG_LEVEL_ERROR, "AIS Executive couldn't open configuration component '%s'\n", iface);
525 openais_exit_error (AIS_DONE_MAINCONFIGREAD);
528 res = config->config_readconfig(objdb, &error_string);
529 if (res == -1) {
530 log_printf (LOG_LEVEL_ERROR, error_string);
531 openais_exit_error (AIS_DONE_MAINCONFIGREAD);
533 log_printf (LOG_LEVEL_NOTICE, error_string);
535 iface = strtok(NULL, ":");
537 if (config_iface)
538 free(config_iface);
540 openais_service_default_objdb_set (objdb);
542 res = openais_service_link_all (objdb);
543 if (res == -1) {
544 log_printf (LOG_LEVEL_ERROR, "Could not load services\n");
545 openais_exit_error (AIS_DONE_DYNAMICLOAD);
548 res = openais_main_config_read (objdb, &error_string, &main_config);
549 if (res == -1) {
550 log_printf (LOG_LEVEL_ERROR, error_string);
551 openais_exit_error (AIS_DONE_MAINCONFIGREAD);
554 res = totem_config_read (objdb, &totem_config, &error_string);
555 if (res == -1) {
556 log_printf (LOG_LEVEL_ERROR, error_string);
557 openais_exit_error (AIS_DONE_MAINCONFIGREAD);
560 res = totem_config_keyread (objdb, &totem_config, &error_string);
561 if (res == -1) {
562 log_printf (LOG_LEVEL_ERROR, error_string);
563 openais_exit_error (AIS_DONE_MAINCONFIGREAD);
566 res = totem_config_validate (&totem_config, &error_string);
567 if (res == -1) {
568 log_printf (LOG_LEVEL_ERROR, error_string);
569 openais_exit_error (AIS_DONE_MAINCONFIGREAD);
572 logsys_config_facility_set ("openais", main_config.syslog_facility);
573 logsys_config_mode_set (main_config.logmode);
575 res = logsys_config_file_set (&error_string, main_config.logfile);
576 if (res == -1) {
577 log_printf (LOG_LEVEL_ERROR, error_string);
578 openais_exit_error (AIS_DONE_LOGSETUP);
581 aisexec_uid_determine (&main_config);
583 aisexec_gid_determine (&main_config);
586 * Set round robin realtime scheduling with priority 99
587 * Lock all memory to avoid page faults which may interrupt
588 * application healthchecking
590 if (setprio)
591 aisexec_setscheduler ();
593 aisexec_mlockall ();
595 totem_config.totem_logging_configuration = totem_logging_configuration;
596 totem_log_service = _logsys_subsys_create ("TOTEM", LOG_INFO);
597 totem_config.totem_logging_configuration.log_level_security = logsys_mkpri (LOG_LEVEL_SECURITY, totem_log_service);
598 totem_config.totem_logging_configuration.log_level_error = logsys_mkpri (LOG_LEVEL_ERROR, totem_log_service);
599 totem_config.totem_logging_configuration.log_level_warning = logsys_mkpri (LOG_LEVEL_WARNING, totem_log_service);
600 totem_config.totem_logging_configuration.log_level_notice = logsys_mkpri (LOG_LEVEL_NOTICE, totem_log_service);
601 totem_config.totem_logging_configuration.log_level_debug = logsys_mkpri (LOG_LEVEL_DEBUG, totem_log_service);
602 totem_config.totem_logging_configuration.log_printf = logsys_log_printf;
605 * Sleep for a while to let other nodes in the cluster
606 * understand that this node has been away (if it was
607 * an aisexec restart).
610 // TODO what is this hack for? usleep(totem_config.token_timeout * 2000);
613 * if totempg_initialize doesn't have root priveleges, it cannot
614 * bind to a specific interface. This only matters if
615 * there is more then one interface in a system, so
616 * in this case, only a warning is printed
619 * Join multicast group and setup delivery
620 * and configuration change functions
622 totempg_initialize (
623 aisexec_poll_handle,
624 &totem_config);
626 totempg_groups_initialize (
627 &openais_group_handle,
628 deliver_fn,
629 confchg_fn);
631 totempg_groups_join (
632 openais_group_handle,
633 &openais_group,
637 * This must occur after totempg is initialized because "this_ip" must be set
639 res = openais_service_init_all (service_count, objdb);
640 if (res == -1) {
641 log_printf (LOG_LEVEL_ERROR, "Could not init services\n");
642 openais_exit_error (AIS_DONE_INIT_SERVICES);
645 sync_register (openais_sync_callbacks_retrieve, openais_sync_completed,
646 totem_config.vsf_type);
649 res = openais_flow_control_initialize ();
652 * Drop root privleges to user 'ais'
653 * TODO: Don't really need full root capabilities;
654 * needed capabilities are:
655 * CAP_NET_RAW (bindtodevice)
656 * CAP_SYS_NICE (setscheduler)
657 * CAP_IPC_LOCK (mlockall)
659 aisexec_priv_drop ();
661 aisexec_mempool_init ();
663 openais_ipc_init (
664 serialize_mutex_lock,
665 serialize_mutex_unlock,
666 gid_valid);
669 * Start main processing loop
671 poll_run (aisexec_poll_handle);
673 return EXIT_SUCCESS;