1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2025 OmniOS Community Edition (OmniOSce) Association.
29 */
30
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <pthread.h>
38 #include <errno.h>
39 #include <libscf.h>
40 #ifdef DEBUG
41 #include <time.h>
42 #endif
43 #include <signal.h>
44 #include <semaphore.h>
45 #include <sys/wait.h>
46
47 #include "isns_server.h"
48 #include "isns_dseng.h"
49 #include "isns_msgq.h"
50 #include "isns_log.h"
51 #include "isns_cfg.h"
52 #include "isns_utils.h"
53 #include "isns_cache.h"
54 #include "isns_obj.h"
55 #include "isns_dd.h"
56 #include "isns_scn.h"
57 #include "isns_sched.h"
58 #include "isns_esi.h"
59 #include "isns_mgmt.h"
60
61 /*
62 * iSNS Server administrative settings.
63 */
64 uint8_t daemonlize = 0;
65 int dbg_level = 7;
66 uint64_t esi_threshold;
67 uint8_t mgmt_scn;
68 ctrl_node_t *control_nodes = NULL;
69 pthread_mutex_t ctrl_node_mtx = PTHREAD_MUTEX_INITIALIZER;
70 char data_store[MAXPATHLEN];
71
72
73 /* semaphore for handling exit */
74 static sem_t isns_child_sem;
75 static int isns_child_smf_exit_code;
76 static pid_t isns_child_pid;
77
78 #if !defined(SMF_EXIT_ERR_OTHER)
79 #define SMF_EXIT_ERR_OTHER -1
80 #endif
81
82 /*
83 * Globals for singal handling. time_to_exit is set by sig_handle()
84 * when set the main thread(daemon) and othere threads should exit.
85 *
86 * semaphone is used to make sure all threads that are created
87 * by isns_port_watcher and esi.
88 */
89 boolean_t time_to_exit = B_FALSE;
90 static uint32_t thr_ref_count;
91 static pthread_mutex_t thr_count_mtx = PTHREAD_MUTEX_INITIALIZER;
92 #define MAX_RETRY_COUNT 10 /* for checking remaining threads before exit. */
93
94 /*
95 * Door creation flag.
96 */
97 boolean_t door_created = B_FALSE;
98
99 /*
100 * global system message queue
101 */
102 msg_queue_t *sys_q = NULL;
103 msg_queue_t *scn_q = NULL;
104
105 #ifdef DEBUG
106 extern void *cli_test(void *argv);
107 extern int dump_db(void);
108 #endif
109
110 extern void sigalrm(int);
111
112 /*
113 * sigusr2_handler -- SIGUSR2 Handler
114 * sigusr2 is exepected only when child is running okay.
115 */
116 /* ARGSUSED */
117 static void
sigusr2_handler(int sig)118 sigusr2_handler(
119 int sig
120 )
121 {
122 /* post okay status. */
123 isnslog(LOG_DEBUG, "sigusr2_handler",
124 "SIGUSR@ is received. Parent is existing...");
125 isns_child_smf_exit_code = SMF_EXIT_OK;
126
127 (void) sem_post(&isns_child_sem);
128 }
129
130 /*
131 * sigchld_handler -- SIGCHLD Handler
132 * sigchld is exepected only when there is an error.
133 */
134 /* ARGSUSED */
135 static void
sigchld_handler(int sig)136 sigchld_handler(
137 int sig
138 )
139 {
140 int status;
141 pid_t ret_pid;
142
143 /* This is the default code. */
144 isns_child_smf_exit_code = SMF_EXIT_ERR_OTHER;
145
146 ret_pid = waitpid(isns_child_pid, &status, WNOHANG);
147
148 if (ret_pid == isns_child_pid) {
149 if (WIFEXITED(status)) {
150 isns_child_smf_exit_code = WEXITSTATUS(status);
151 }
152 }
153 (void) sem_post(&isns_child_sem);
154 }
155
156 /* ARGSUSED */
157 static void
sighup_handler(int sig)158 sighup_handler(
159 int sig
160 )
161 {
162
163 isnslog(LOG_DEBUG, "sighup_handle",
164 "SIGHUP is received. Reloading config...");
165 (void) queue_msg_set(sys_q, CONFIG_RELOAD, NULL);
166 }
167
168 /* ARGSUSED */
169 static void
sigexit_handler(int sig)170 sigexit_handler(
171 int sig
172 )
173 {
174 isnslog(LOG_DEBUG, "sigexit_handler",
175 "Signal: %d received and sending server exit.", sig);
176 shutdown_server();
177 }
178
179 void
inc_thr_count()180 inc_thr_count(
181 )
182 {
183 (void) pthread_mutex_lock(&thr_count_mtx);
184
185 isnslog(LOG_DEBUG, "inc_thr_count",
186 "increase thread reference count(%d).", thr_ref_count);
187
188 thr_ref_count++;
189
190 (void) pthread_mutex_unlock(&thr_count_mtx);
191 }
192
193 void
dec_thr_count()194 dec_thr_count(
195 )
196 {
197 (void) pthread_mutex_lock(&thr_count_mtx);
198
199 isnslog(LOG_DEBUG, "dec_thr_count",
200 "decrease thread reference count(%d).", thr_ref_count);
201
202 thr_ref_count--;
203
204 (void) pthread_mutex_unlock(&thr_count_mtx);
205 }
206
207 uint32_t
get_thr_count()208 get_thr_count(
209 )
210 {
211 uint32_t ref;
212
213 (void) pthread_mutex_lock(&thr_count_mtx);
214
215 ref = thr_ref_count;
216
217 (void) pthread_mutex_unlock(&thr_count_mtx);
218
219 isnslog(LOG_DEBUG, "get_thr_count",
220 "checking thread reference count %d.", ref);
221
222 return (ref);
223 }
224
225 void
shutdown_server()226 shutdown_server(
227 )
228 {
229 isnslog(LOG_DEBUG, "shutdown", "raise exit flag.");
230 time_to_exit = B_TRUE;
231 (void) queue_msg_set(sys_q, SERVER_EXIT, NULL);
232 }
233
234 int
main(int argc,char * argv[])235 main(
236 /* LINTED E_FUNC_ARG_UNUSED */
237 int argc,
238 /* LINTED E_FUNC_ARG_UNUSED */
239 char *argv[]
240 )
241 {
242 int opt_i = 0;
243 pthread_t port_tid, esi_tid, scn_tid;
244 uint32_t thr_cnt;
245 int i;
246
247 #ifdef DEBUG
248 time_t t;
249 clock_t c;
250 #endif
251
252 #ifdef DEBUG
253 if (getopt(argc, argv, "i") == 'i') {
254 opt_i = 1; /* interactive mode */
255 }
256 #endif
257
258 /* set locale */
259 openlog(ISNS_DAEMON_SYSLOG_PP, LOG_PID | LOG_CONS, LOG_DAEMON);
260
261 /* load administative settings. pick up data location. */
262 if (load_config(B_TRUE) != 0) {
263 isnslog(LOG_ERR, "main", "administrative settings load error.");
264 exit(SMF_EXIT_ERR_OTHER);
265 }
266
267 /* A signal handler is set for SIGCHLD. */
268 (void) signal(SIGCHLD, sigchld_handler);
269 (void) signal(SIGUSR2, sigusr2_handler);
270 (void) sigset(SIGALRM, sigalrm);
271
272 #ifdef DEBUG
273 printf("start daemon\n");
274 #endif
275 if (opt_i == 0 || daemonlize) {
276 isnslog(LOG_DEBUG, "main", "now forking... pid %d", getpid());
277 daemonlize = 1;
278 /* daemonlize */
279 isns_child_pid = fork();
280 if (isns_child_pid < 0) {
281 /*
282 * cannot fork(), terminate the server.
283 */
284 exit(SMF_EXIT_ERR_CONFIG);
285 }
286 if (isns_child_pid > 0) {
287 /*
288 * terminate parent.
289 */
290 (void) sem_wait(&isns_child_sem);
291 (void) sem_destroy(&isns_child_sem);
292 isnslog(LOG_DEBUG, "main", "exiting with %d",
293 isns_child_smf_exit_code);
294 exit(isns_child_smf_exit_code);
295 }
296
297 /*
298 * redirect stdout, and stderr to /dev/null.
299 */
300 i = open("/dev/null", O_RDWR);
301 (void) dup2(i, 1);
302 (void) dup2(i, 2);
303 } /* end of daemonlize */
304
305 #ifdef DEBUG
306 printf("calling cache init\n");
307 #endif
308 /* initialize object hash table */
309 if (cache_init() != 0) {
310 isnslog(LOG_ERR, "main",
311 "object hash table initialization error.");
312 exit(SMF_EXIT_ERR_OTHER);
313 }
314
315 /* initialize event list */
316 if (el_init(10, 60, 6) != 0) {
317 isnslog(LOG_ERR, "main",
318 "ESI event list initialization error.");
319 exit(SMF_EXIT_ERR_OTHER);
320 }
321
322 /* initialize iSNS database */
323 if (init_data() != 0) {
324 isnslog(LOG_ERR, "main",
325 "internal database initialization error");
326 exit(SMF_EXIT_ERR_OTHER);
327 }
328
329 #ifdef DEBUG
330 printf("calling load_data\n");
331 t = time(NULL);
332 c = clock();
333 #endif
334
335 if (load_data() != 0) {
336 isnslog(LOG_ERR, "main", "loading data store failed");
337 exit(SMF_EXIT_ERR_OTHER);
338 }
339
340 #ifdef DEBUG
341 t = time(NULL) - t;
342 c = clock() - c;
343 printf("time %d clock %.4lf -loading data\n",
344 t, c / (double)CLOCKS_PER_SEC);
345 #endif
346
347 #ifdef DEBUG
348 printf("sys queue creating...\n");
349 #endif
350 /* create a message queue for system control */
351 sys_q = queue_calloc();
352 if (!sys_q) {
353 exit(SMF_EXIT_ERR_OTHER);
354 }
355
356 /* create a message queue for scn thread */
357 scn_q = queue_calloc();
358 if (!scn_q) {
359 exit(SMF_EXIT_ERR_OTHER);
360 }
361
362 /* create scn thread */
363 /* Check for Default DD/DD-set existence and */
364 /* create them if they are not there. */
365 if (verify_ddd() != 0) {
366 exit(SMF_EXIT_ERR_OTHER);
367 }
368
369 /* setup and verify the portal(s) for scn(s) */
370 /* after scn registry is loaded from data store. */
371 if (verify_scn_portal() != 0) {
372 exit(SMF_EXIT_ERR_OTHER);
373 }
374
375 /* setup and verify the portal(s) for esi(s) */
376 /* after esi list is loaded from data store. */
377 if (verify_esi_portal() != 0) {
378 exit(SMF_EXIT_ERR_OTHER);
379 }
380
381 #ifdef DEBUG
382 printf("scn queue creating...\n");
383 #endif
384
385 (void) sigset(SIGHUP, sighup_handler);
386 (void) sigset(SIGINT, sigexit_handler);
387 (void) sigset(SIGTERM, sigexit_handler);
388 (void) sigset(SIGQUIT, sigexit_handler);
389
390 /* create scn thread */
391 if (pthread_create(&scn_tid, NULL, scn_proc, NULL) != 0) {
392 isnslog(LOG_ERR, "main", "SCN thread creating error.");
393 exit(SMF_EXIT_ERR_OTHER);
394 }
395
396 /* setup a door for management interface */
397 if (setup_mgmt_door(sys_q) != 0) {
398 exit(SMF_EXIT_ERR_OTHER);
399 }
400
401 /* create server port watcher */
402 if (pthread_create(&port_tid, NULL,
403 isns_port_watcher, (void *)sys_q) != 0) {
404 isnslog(LOG_ERR, "main", "iSNS port thread creating error.");
405 exit(SMF_EXIT_ERR_OTHER);
406 }
407
408 /* create entity status inquiry thread */
409 if (pthread_create(&esi_tid, NULL,
410 esi_proc, NULL) != 0) {
411 isnslog(LOG_ERR, "main", "ESI thread creating error.");
412 exit(SMF_EXIT_ERR_OTHER);
413 }
414
415 #ifdef DEBUG
416 if (!daemonlize) {
417 pthread_t tid;
418 (void) pthread_create(&tid,
419 NULL,
420 cli_test,
421 (void *)sys_q);
422 }
423 #endif
424 if (opt_i == 0 || daemonlize) {
425 isnslog(LOG_DEBUG, "main", "issuing SIGUSR2.. parent pid %d",
426 getppid());
427 (void) kill(getppid(), SIGUSR2);
428 }
429
430 /* pause */
431 for (;;) {
432 msg_text_t *msg = queue_msg_get(sys_q);
433 switch (msg->id) {
434 case DATA_ADD:
435 case DATA_UPDATE:
436 case DATA_DELETE:
437 case DATA_DELETE_ASSOC:
438 case DATA_COMMIT:
439 case DATA_RETREAT:
440 break;
441 case REG_EXP:
442 /* registration expiring */
443 reg_expiring(msg->data);
444 break;
445 case DEAD_PORTAL:
446 portal_dies((uint32_t)msg->data);
447 break;
448 case SERVER_EXIT:
449 /* graceful exit. */
450 (void) queue_msg_free(msg);
451 isnslog(LOG_DEBUG, "main",
452 "wake up ESI and stop it.");
453 (void) get_stopwatch(1);
454 isnslog(LOG_DEBUG, "main",
455 "sending SCN stop msg.");
456 (void) queue_msg_set(scn_q, SCN_STOP, NULL);
457 if (door_created) {
458 isnslog(LOG_DEBUG, "main",
459 "closing the door.");
460 (void) fdetach(ISNS_DOOR_NAME);
461 }
462 (void) pthread_join(esi_tid, NULL);
463 isnslog(LOG_DEBUG, "main",
464 "esi thread %d exited.", esi_tid);
465 (void) pthread_join(port_tid, NULL);
466 isnslog(LOG_DEBUG, "main",
467 "port watcher thread %d exited.", port_tid);
468 (void) pthread_join(scn_tid, NULL);
469 isnslog(LOG_DEBUG, "main",
470 "scn thread %d exited.", scn_tid);
471
472 /* now check any remaining threads. */
473 i = 0;
474 do {
475 thr_cnt = get_thr_count();
476 if (thr_cnt == 0) {
477 isnslog(LOG_DEBUG, "main",
478 "main thread %d is done.",
479 pthread_self());
480 exit(1);
481 } else {
482 (void) sleep(1);
483 i++;
484 }
485 } while (MAX_RETRY_COUNT > i);
486 isnslog(LOG_DEBUG, "main",
487 "main thread %d existing ...",
488 pthread_self());
489 exit(1);
490 break;
491 case CONFIG_RELOAD:
492 /* load config again. don't pick data store. */
493 (void) load_config(B_FALSE);
494 break;
495 case SYS_QUIT_OK:
496 (void) queue_msg_free(msg);
497 exit(0);
498 default:
499 break;
500 }
501 (void) queue_msg_free(msg);
502 }
503
504 /* LINTED E_STMT_NOT_REACHED */
505 return (0);
506 }
507