1 /*
2  * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #ifndef MFSMAXFILES
26 #define MFSMAXFILES 4096
27 #endif
28 
29 #if defined(HAVE_MLOCKALL)
30 #  if defined(HAVE_SYS_MMAN_H)
31 #    include <sys/mman.h>
32 #  endif
33 #  if defined(HAVE_SYS_RESOURCE_H)
34 #    include <sys/resource.h>
35 #  endif
36 #  if defined(RLIMIT_MEMLOCK) && defined(MCL_CURRENT) && defined(MCL_FUTURE)
37 #    define MFS_USE_MEMLOCK 1
38 #  endif
39 #endif
40 
41 #if defined(HAVE_MALLOC_H)
42 #  include <malloc.h>
43 #endif
44 
45 #if defined(HAVE_SYS_PRCTL_H)
46 #  include <sys/prctl.h>
47 #endif
48 
49 #include <sys/stat.h>
50 #include <sys/wait.h>
51 #include <sys/types.h>
52 #include <sys/time.h>
53 
54 #include <signal.h>
55 #include <fcntl.h>
56 #include <unistd.h>
57 #include <errno.h>
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <syslog.h>
61 #include <string.h>
62 #include <strings.h>
63 #include <time.h>
64 #include <sys/resource.h>
65 #include <grp.h>
66 #include <pwd.h>
67 
68 #define STR_AUX(x) #x
69 #define STR(x) STR_AUX(x)
70 
71 #include "main.h"
72 #include "clocks.h"
73 #include "sockets.h"
74 #include "cfg.h"
75 #include "strerr.h"
76 #include "crc.h"
77 #include "init.h"
78 #include "massert.h"
79 #include "slogger.h"
80 #include "portable.h"
81 
82 #define RM_RESTART 0
83 #define RM_START 1
84 #define RM_STOP 2
85 #define RM_RELOAD 3
86 #define RM_INFO 4
87 #define RM_TEST 5
88 #define RM_KILL 6
89 #define RM_TRY_RESTART 7
90 
91 typedef struct deentry {
92 	void (*fun)(void);
93 	struct deentry *next;
94 } deentry;
95 
96 static deentry *dehead=NULL;
97 
98 
99 typedef struct weentry {
100 	void (*fun)(void);
101 	struct weentry *next;
102 } weentry;
103 
104 static weentry *wehead=NULL;
105 
106 
107 typedef struct ceentry {
108 	int (*fun)(void);
109 	struct ceentry *next;
110 } ceentry;
111 
112 static ceentry *cehead=NULL;
113 
114 
115 typedef struct rlentry {
116 	void (*fun)(void);
117 	struct rlentry *next;
118 } rlentry;
119 
120 static rlentry *rlhead=NULL;
121 
122 
123 typedef struct inentry {
124 	void (*fun)(void);
125 	struct inentry *next;
126 } inentry;
127 
128 static inentry *inhead=NULL;
129 
130 
131 typedef struct kaentry {
132 	void (*fun)(void);
133 	struct kaentry *next;
134 } kaentry;
135 
136 static kaentry *kahead=NULL;
137 
138 
139 typedef struct pollentry {
140 	void (*desc)(struct pollfd *,uint32_t *);
141 	void (*serve)(struct pollfd *);
142 	struct pollentry *next;
143 } pollentry;
144 
145 static pollentry *pollhead=NULL;
146 
147 
148 typedef struct eloopentry {
149 	void (*fun)(void);
150 	struct eloopentry *next;
151 } eloopentry;
152 
153 static eloopentry *eloophead=NULL;
154 
155 
156 typedef struct chldentry {
157 	pid_t pid;
158 	void (*fun)(int);
159 	struct chldentry *next;
160 } chldentry;
161 
162 static chldentry *chldhead=NULL;
163 
164 
165 typedef struct timeentry {
166 	uint64_t nextevent;
167 	uint64_t useconds;
168 	uint64_t usecoffset;
169 	void (*fun)(void);
170 	struct timeentry *next;
171 } timeentry;
172 
173 static timeentry *timehead=NULL;
174 
175 static uint32_t now;
176 static uint64_t usecnow;
177 //static int alcnt=0;
178 
179 static int signalpipe[2];
180 
181 /* interface */
182 
main_destruct_register(void (* fun)(void))183 void main_destruct_register (void (*fun)(void)) {
184 	deentry *aux=(deentry*)malloc(sizeof(deentry));
185 	passert(aux);
186 	aux->fun = fun;
187 	aux->next = dehead;
188 	dehead = aux;
189 }
190 
main_canexit_register(int (* fun)(void))191 void main_canexit_register (int (*fun)(void)) {
192 	ceentry *aux=(ceentry*)malloc(sizeof(ceentry));
193 	passert(aux);
194 	aux->fun = fun;
195 	aux->next = cehead;
196 	cehead = aux;
197 }
198 
main_wantexit_register(void (* fun)(void))199 void main_wantexit_register (void (*fun)(void)) {
200 	weentry *aux=(weentry*)malloc(sizeof(weentry));
201 	passert(aux);
202 	aux->fun = fun;
203 	aux->next = wehead;
204 	wehead = aux;
205 }
206 
main_reload_register(void (* fun)(void))207 void main_reload_register (void (*fun)(void)) {
208 	rlentry *aux=(rlentry*)malloc(sizeof(rlentry));
209 	passert(aux);
210 	aux->fun = fun;
211 	aux->next = rlhead;
212 	rlhead = aux;
213 }
214 
main_info_register(void (* fun)(void))215 void main_info_register (void (*fun)(void)) {
216 	inentry *aux=(inentry*)malloc(sizeof(inentry));
217 	passert(aux);
218 	aux->fun = fun;
219 	aux->next = inhead;
220 	inhead = aux;
221 }
222 
main_keepalive_register(void (* fun)(void))223 void main_keepalive_register (void (*fun)(void)) {
224 	kaentry *aux=(kaentry*)malloc(sizeof(kaentry));
225 	passert(aux);
226 	aux->fun = fun;
227 	aux->next = kahead;
228 	kahead = aux;
229 }
230 
main_poll_register(void (* desc)(struct pollfd *,uint32_t *),void (* serve)(struct pollfd *))231 void main_poll_register (void (*desc)(struct pollfd *,uint32_t *),void (*serve)(struct pollfd *)) {
232 	pollentry *aux=(pollentry*)malloc(sizeof(pollentry));
233 	passert(aux);
234 	aux->desc = desc;
235 	aux->serve = serve;
236 	aux->next = pollhead;
237 	pollhead = aux;
238 }
239 
main_eachloop_register(void (* fun)(void))240 void main_eachloop_register (void (*fun)(void)) {
241 	eloopentry *aux=(eloopentry*)malloc(sizeof(eloopentry));
242 	passert(aux);
243 	aux->fun = fun;
244 	aux->next = eloophead;
245 	eloophead = aux;
246 }
247 
main_chld_register(pid_t pid,void (* fun)(int))248 void main_chld_register (pid_t pid,void (*fun)(int)) {
249 	chldentry *aux=(chldentry*)malloc(sizeof(chldentry));
250 	passert(aux);
251 	aux->fun = fun;
252 	aux->pid = pid;
253 	aux->next = chldhead;
254 	chldhead = aux;
255 }
256 
main_msectime_register(uint32_t mseconds,uint32_t offset,void (* fun)(void))257 void* main_msectime_register (uint32_t mseconds,uint32_t offset,void (*fun)(void)) {
258 	timeentry *aux;
259 	uint64_t useconds = UINT64_C(1000) * (uint64_t)mseconds;
260 	uint64_t usecoffset = UINT64_C(1000) * (uint64_t)offset;
261 	if (useconds==0 || usecoffset>=useconds) {
262 		return NULL;
263 	}
264 	aux = (timeentry*)malloc(sizeof(timeentry));
265 	passert(aux);
266 	aux->nextevent = (((usecnow / useconds) * useconds) + usecoffset);
267 	while (aux->nextevent<usecnow) {
268 		aux->nextevent+=useconds;
269 	}
270 	aux->useconds = useconds;
271 	aux->usecoffset = usecoffset;
272 	aux->fun = fun;
273 	aux->next = timehead;
274 	timehead = aux;
275 	return aux;
276 }
277 
main_msectime_change(void * x,uint32_t mseconds,uint32_t offset)278 int main_msectime_change(void* x,uint32_t mseconds,uint32_t offset) {
279 	timeentry *aux = (timeentry*)x;
280 	uint64_t useconds = UINT64_C(1000) * (uint64_t)mseconds;
281 	uint64_t usecoffset = UINT64_C(1000) * (uint64_t)offset;
282 	if (useconds==0 || usecoffset>=useconds) {
283 		return -1;
284 	}
285 	aux->nextevent = (((usecnow / useconds) * useconds) + usecoffset);
286 	while (aux->nextevent<usecnow) {
287 		aux->nextevent+=useconds;
288 	}
289 	aux->useconds = useconds;
290 	aux->usecoffset = usecoffset;
291 	return 0;
292 }
293 
main_time_register(uint32_t seconds,uint32_t offset,void (* fun)(void))294 void* main_time_register (uint32_t seconds,uint32_t offset,void (*fun)(void)) {
295 	return main_msectime_register(1000*seconds,1000*offset,fun);
296 /*	timeentry *aux;
297 	if (seconds==0 || offset>=seconds) {
298 		return NULL;
299 	}
300 	aux = (timeentry*)malloc(sizeof(timeentry));
301 	passert(aux);
302 	aux->nextevent = (((now / seconds) * seconds) + offset);
303 	while (aux->nextevent<now) {
304 		aux->nextevent+=seconds;
305 	}
306 	aux->seconds = seconds;
307 	aux->offset = offset;
308 	aux->mode = mode;
309 	aux->fun = fun;
310 	aux->next = timehead;
311 	timehead = aux;
312 	return aux;
313 */
314 }
315 
main_time_change(void * x,uint32_t seconds,uint32_t offset)316 int main_time_change(void* x,uint32_t seconds,uint32_t offset) {
317 	return main_msectime_change(x,1000*seconds,1000*offset);
318 /*	timeentry *aux = (timeentry*)x;
319 	if (seconds==0 || offset>=seconds) {
320 		return -1;
321 	}
322 	aux->nextevent = ((now / seconds) * seconds) + offset;
323 	while (aux->nextevent<now) {
324 		aux->nextevent+=seconds;
325 	}
326 	aux->seconds = seconds;
327 	aux->offset = offset;
328 	aux->mode = mode;
329 	return 0;
330 */
331 }
332 
333 /* internal */
334 
free_all_registered_entries(void)335 void free_all_registered_entries(void) {
336 	deentry *de,*den;
337 	ceentry *ce,*cen;
338 	weentry *we,*wen;
339 	rlentry *re,*ren;
340 	inentry *ie,*ien;
341 	pollentry *pe,*pen;
342 	eloopentry *ee,*een;
343 	timeentry *te,*ten;
344 
345 	for (de = dehead ; de ; de = den) {
346 		den = de->next;
347 		free(de);
348 	}
349 
350 	for (ce = cehead ; ce ; ce = cen) {
351 		cen = ce->next;
352 		free(ce);
353 	}
354 
355 	for (we = wehead ; we ; we = wen) {
356 		wen = we->next;
357 		free(we);
358 	}
359 
360 	for (re = rlhead ; re ; re = ren) {
361 		ren = re->next;
362 		free(re);
363 	}
364 
365 	for (ie = inhead ; ie ; ie = ien) {
366 		ien = ie->next;
367 		free(ie);
368 	}
369 
370 	for (pe = pollhead ; pe ; pe = pen) {
371 		pen = pe->next;
372 		free(pe);
373 	}
374 
375 	for (ee = eloophead ; ee ; ee = een) {
376 		een = ee->next;
377 		free(ee);
378 	}
379 
380 	for (te = timehead ; te ; te = ten) {
381 		ten = te->next;
382 		free(te);
383 	}
384 }
385 
canexit()386 int canexit() {
387 	ceentry *aux;
388 	for (aux = cehead ; aux!=NULL ; aux=aux->next ) {
389 		if (aux->fun()==0) {
390 			return 0;
391 		}
392 	}
393 	return 1;
394 }
395 
main_time()396 uint32_t main_time() {
397 	return now;
398 }
399 
400 /*
401 uint64_t main_utime() {
402 	return usecnow;
403 }
404 */
destruct(void)405 static inline void destruct(void) {
406 	deentry *deit;
407 	for (deit = dehead ; deit!=NULL ; deit=deit->next ) {
408 		deit->fun();
409 	}
410 }
411 
main_keep_alive(void)412 void main_keep_alive(void) {
413 	struct timeval tv;
414 	gettimeofday(&tv,NULL);
415 	usecnow = tv.tv_sec;
416 	usecnow *= 1000000;
417 	usecnow += tv.tv_usec;
418 	now = tv.tv_sec;
419 	kaentry *kait;
420 	for (kait = kahead ; kait!=NULL ; kait=kait->next ) {
421 		kait->fun();
422 	}
423 }
424 
mainloop()425 void mainloop() {
426 	uint64_t prevtime = 0;
427 	struct timeval tv;
428 	pollentry *pollit;
429 	eloopentry *eloopit;
430 	timeentry *timeit;
431 	ceentry *ceit;
432 	weentry *weit;
433 	rlentry *rlit;
434 	inentry *init;
435 	struct pollfd pdesc[MFSMAXFILES];
436 	uint32_t ndesc;
437 	int i;
438 	int t,r;
439 
440 	t = 0;
441 	r = 0;
442 	while (t!=3) {
443 		ndesc=1;
444 		pdesc[0].fd = signalpipe[0];
445 		pdesc[0].events = POLLIN;
446 		pdesc[0].revents = 0;
447 		for (pollit = pollhead ; pollit != NULL ; pollit = pollit->next) {
448 			pollit->desc(pdesc,&ndesc);
449 		}
450 		i = poll(pdesc,ndesc,10);
451 		gettimeofday(&tv,NULL);
452 		usecnow = tv.tv_sec;
453 		usecnow *= 1000000;
454 		usecnow += tv.tv_usec;
455 		now = tv.tv_sec;
456 		if (i<0) {
457 			if (!ERRNO_ERROR) {
458 				syslog(LOG_WARNING,"poll returned EAGAIN");
459 				portable_usleep(10000);
460 				continue;
461 			}
462 			if (errno!=EINTR) {
463 				syslog(LOG_WARNING,"poll error: %s",strerr(errno));
464 				break;
465 			}
466 		} else {
467 			if ((pdesc[0].revents)&POLLIN) {
468 				uint8_t sigid;
469 				if (read(signalpipe[0],&sigid,1)==1) {
470 					if (sigid=='\001' && t==0) {
471 						syslog(LOG_NOTICE,"terminate signal received");
472 						t = 1;
473 					} else if (sigid=='\002') {
474 						syslog(LOG_NOTICE,"reloading config files");
475 						r = 1;
476 					} else if (sigid=='\003') {
477 						syslog(LOG_NOTICE,"child finished");
478 						r = 2;
479 					} else if (sigid=='\004') {
480 						syslog(LOG_NOTICE,"log extra info");
481 						r = 3;
482 					} else if (sigid=='\005') {
483 						syslog(LOG_NOTICE,"unexpected alarm/prof signal received - ignoring");
484 					} else if (sigid=='\006') {
485 						syslog(LOG_NOTICE,"internal terminate request");
486 						t = 1;
487 					}
488 				}
489 			}
490 			for (pollit = pollhead ; pollit != NULL ; pollit = pollit->next) {
491 				pollit->serve(pdesc);
492 			}
493 		}
494 		for (eloopit = eloophead ; eloopit != NULL ; eloopit = eloopit->next) {
495 			eloopit->fun();
496 		}
497 		if (usecnow<prevtime) {
498 			// time went backward !!! - recalculate "nextevent" time
499 			// adding previous_time_to_run prevents from running next event too soon.
500 			for (timeit = timehead ; timeit != NULL ; timeit = timeit->next) {
501 				uint64_t previous_time_to_run = timeit->nextevent - prevtime;
502 				if (previous_time_to_run > timeit->useconds) {
503 					previous_time_to_run = timeit->useconds;
504 				}
505 				timeit->nextevent = ((usecnow / timeit->useconds) * timeit->useconds) + timeit->usecoffset;
506 				while (timeit->nextevent <= usecnow+previous_time_to_run) {
507 					timeit->nextevent += timeit->useconds;
508 				}
509 			}
510 		} else if (usecnow>prevtime+UINT64_C(3600000000)) {
511 			// time went forward !!! - just recalculate "nextevent" time
512 			for (timeit = timehead ; timeit != NULL ; timeit = timeit->next) {
513 				timeit->nextevent = ((usecnow / timeit->useconds) * timeit->useconds) + timeit->usecoffset;
514 				while (usecnow >= timeit->nextevent) {
515 					timeit->nextevent += timeit->useconds;
516 				}
517 			}
518 		}
519 		for (timeit = timehead ; timeit != NULL ; timeit = timeit->next) {
520 			if (usecnow >= timeit->nextevent) {
521 				uint32_t eventcounter = 0;
522 				while (usecnow >= timeit->nextevent && eventcounter<10) { // do not run more than 10 late entries
523 					timeit->fun();
524 					timeit->nextevent += timeit->useconds;
525 					eventcounter++;
526 				}
527 				if (usecnow >= timeit->nextevent) {
528 					timeit->nextevent = ((usecnow / timeit->useconds) * timeit->useconds) + timeit->usecoffset;
529 					while (usecnow >= timeit->nextevent) {
530 						timeit->nextevent += timeit->useconds;
531 					}
532 				}
533 			}
534 		}
535 		prevtime = usecnow;
536 		if (r==2) {
537 			chldentry *chldit,**chldptr;
538 			pid_t pid;
539 			int status;
540 
541 			while ( (pid = waitpid(-1,&status,WNOHANG)) >= 0) {
542 				chldptr = &chldhead;
543 				while ((chldit = *chldptr)) {
544 					if (chldit->pid == pid) {
545 						chldit->fun(status);
546 						*chldptr = chldit->next;
547 						free(chldit);
548 					} else {
549 						chldptr = &(chldit->next);
550 					}
551 				}
552 			}
553 			r = 0;
554 		}
555 		if (t==0) {
556 			if (r==1) {
557 				cfg_reload();
558 				for (rlit = rlhead ; rlit!=NULL ; rlit=rlit->next ) {
559 					rlit->fun();
560 				}
561 				r = 0;
562 			} else if (r==3) {
563 				for (init = inhead ; init!=NULL ; init=init->next ) {
564 					init->fun();
565 				}
566 				r = 0;
567 			}
568 		}
569 		if (t==1) {
570 			for (weit = wehead ; weit!=NULL ; weit=weit->next ) {
571 				weit->fun();
572 			}
573 			t = 2;
574 		}
575 		if (t==2) {
576 			i = 1;
577 			for (ceit = cehead ; ceit!=NULL && i ; ceit=ceit->next ) {
578 				if (ceit->fun()==0) {
579 					i=0;
580 				}
581 			}
582 			if (i) {
583 				t = 3;
584 			}
585 		}
586 	}
587 }
588 
initialize(void)589 int initialize(void) {
590 	uint32_t i;
591 	int ok;
592 	ok = 1;
593 	for (i=0 ; (long int)(RunTab[i].fn)!=0 && ok ; i++) {
594 		now = time(NULL);
595 		if (RunTab[i].fn()<0) {
596 			mfs_arg_syslog(LOG_ERR,"init: %s failed !!!",RunTab[i].name);
597 			ok=0;
598 		}
599 	}
600 	return ok;
601 }
602 
initialize_late(void)603 int initialize_late(void) {
604 	uint32_t i;
605 	int ok;
606 	ok = 1;
607 	for (i=0 ; (long int)(LateRunTab[i].fn)!=0 && ok ; i++) {
608 		now = time(NULL);
609 		if (LateRunTab[i].fn()<0) {
610 			mfs_arg_syslog(LOG_ERR,"init: %s failed !!!",RunTab[i].name);
611 			ok=0;
612 		}
613 	}
614 	now = time(NULL);
615 	return ok;
616 }
617 
618 
619 
620 /* signals */
621 
622 static int termsignal[]={
623 	SIGTERM,
624 	-1
625 };
626 
627 static int reloadsignal[]={
628 	SIGHUP,
629 	-1
630 };
631 
632 static int infosignal[]={
633 #ifdef SIGINFO
634 	SIGINFO,
635 #endif
636 #ifdef SIGUSR1
637 	SIGUSR1,
638 #endif
639 	-1
640 };
641 
642 static int chldsignal[]={
643 #ifdef SIGCHLD
644 	SIGCHLD,
645 #endif
646 #ifdef SIGCLD
647 	SIGCLD,
648 #endif
649 	-1
650 };
651 
652 static int ignoresignal[]={
653 	SIGQUIT,
654 #ifdef SIGPIPE
655 	SIGPIPE,
656 #endif
657 #ifdef SIGTSTP
658 	SIGTSTP,
659 #endif
660 #ifdef SIGTTIN
661 	SIGTTIN,
662 #endif
663 #ifdef SIGTTOU
664 	SIGTTOU,
665 #endif
666 #ifdef SIGUSR2
667 	SIGUSR2,
668 #endif
669 	-1
670 };
671 
672 static int alarmsignal[]={
673 #ifdef SIGALRM
674 	SIGALRM,
675 #endif
676 #ifdef SIGVTALRM
677 	SIGVTALRM,
678 #endif
679 #ifdef SIGPROF
680 	SIGPROF,
681 #endif
682 	-1
683 };
684 
685 static int daemonignoresignal[]={
686 	SIGINT,
687 	-1
688 };
689 
termhandle(int signo)690 void termhandle(int signo) {
691 	signo = write(signalpipe[1],"\001",1); // killing two birds with one stone - use signo and do something with value returned by write :)
692 	(void)signo; // and then use this value to calm down compiler ;)
693 }
694 
reloadhandle(int signo)695 void reloadhandle(int signo) {
696 	signo = write(signalpipe[1],"\002",1); // see above
697 	(void)signo;
698 }
699 
chldhandle(int signo)700 void chldhandle(int signo) {
701 	signo = write(signalpipe[1],"\003",1); // see above
702 	(void)signo;
703 }
704 
infohandle(int signo)705 void infohandle(int signo) {
706 	signo = write(signalpipe[1],"\004",1); // see above
707 	(void)signo;
708 }
709 
alarmhandle(int signo)710 void alarmhandle(int signo) {
711 	signo = write(signalpipe[1],"\005",1); // see above
712 	(void)signo;
713 }
714 
set_signal_handlers(int daemonflag)715 void set_signal_handlers(int daemonflag) {
716 	struct sigaction sa;
717 	uint32_t i;
718 
719 	zassert(pipe(signalpipe));
720 
721 #ifdef SA_RESTART
722 	sa.sa_flags = SA_RESTART;
723 #else
724 	sa.sa_flags = 0;
725 #endif
726 	sigemptyset(&sa.sa_mask);
727 
728 	sa.sa_handler = termhandle;
729 	for (i=0 ; termsignal[i]>0 ; i++) {
730 		sigaction(termsignal[i],&sa,(struct sigaction *)0);
731 	}
732 	sa.sa_handler = reloadhandle;
733 	for (i=0 ; reloadsignal[i]>0 ; i++) {
734 		sigaction(reloadsignal[i],&sa,(struct sigaction *)0);
735 	}
736 	sa.sa_handler = infohandle;
737 	for (i=0 ; infosignal[i]>0 ; i++) {
738 		sigaction(infosignal[i],&sa,(struct sigaction *)0);
739 	}
740 	sa.sa_handler = alarmhandle;
741 	for (i=0 ; alarmsignal[i]>0 ; i++) {
742 		sigaction(alarmsignal[i],&sa,(struct sigaction *)0);
743 	}
744 	sa.sa_handler = chldhandle;
745 	for (i=0 ; chldsignal[i]>0 ; i++) {
746 		sigaction(chldsignal[i],&sa,(struct sigaction *)0);
747 	}
748 	sa.sa_handler = SIG_IGN;
749 	for (i=0 ; ignoresignal[i]>0 ; i++) {
750 		sigaction(ignoresignal[i],&sa,(struct sigaction *)0);
751 	}
752 	sa.sa_handler = daemonflag?SIG_IGN:termhandle;
753 	for (i=0 ; daemonignoresignal[i]>0 ; i++) {
754 		sigaction(daemonignoresignal[i],&sa,(struct sigaction *)0);
755 	}
756 }
757 
758 #ifdef USE_PTHREADS
main_thread_create(pthread_t * th,const pthread_attr_t * attr,void * (* fn)(void *),void * arg)759 int main_thread_create(pthread_t *th,const pthread_attr_t *attr,void *(*fn)(void *),void *arg) {
760 	sigset_t oldset;
761 	sigset_t newset;
762 	uint32_t i;
763 	int res;
764 
765 	sigemptyset(&newset);
766 	for (i=0 ; termsignal[i]>0 ; i++) {
767 		sigaddset(&newset, termsignal[i]);
768 	}
769 	for (i=0 ; reloadsignal[i]>0 ; i++) {
770 		sigaddset(&newset, reloadsignal[i]);
771 	}
772 	for (i=0 ; infosignal[i]>0 ; i++) {
773 		sigaddset(&newset, infosignal[i]);
774 	}
775 	for (i=0 ; alarmsignal[i]>0 ; i++) {
776 		sigaddset(&newset, alarmsignal[i]);
777 	}
778 	for (i=0 ; chldsignal[i]>0 ; i++) {
779 		sigaddset(&newset, chldsignal[i]);
780 	}
781 	for (i=0 ; ignoresignal[i]>0 ; i++) {
782 		sigaddset(&newset, ignoresignal[i]);
783 	}
784 	for (i=0 ; daemonignoresignal[i]>0 ; i++) {
785 		sigaddset(&newset, daemonignoresignal[i]);
786 	}
787 	pthread_sigmask(SIG_BLOCK, &newset, &oldset);
788 	res = pthread_create(th,attr,fn,arg);
789 	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
790 	return res;
791 }
792 
main_minthread_create(pthread_t * th,uint8_t detached,void * (* fn)(void *),void * arg)793 int main_minthread_create(pthread_t *th,uint8_t detached,void *(*fn)(void *),void *arg) {
794 	static pthread_attr_t *thattr = NULL;
795 	static uint8_t thattr_detached;
796 	if (thattr == NULL) {
797 		size_t mystacksize;
798 		thattr = malloc(sizeof(pthread_attr_t));
799 		passert(thattr);
800 		zassert(pthread_attr_init(thattr));
801 #ifdef PTHREAD_STACK_MIN
802 		mystacksize = PTHREAD_STACK_MIN;
803 		if (mystacksize < 0x100000) {
804 			mystacksize = 0x100000;
805 		}
806 #else
807 		mystacksize = 0x100000;
808 #endif
809 		zassert(pthread_attr_setstacksize(thattr,mystacksize));
810 		thattr_detached = detached + 1; // make it different
811 	}
812 	if (detached != thattr_detached) {
813 		if (detached) {
814 			zassert(pthread_attr_setdetachstate(thattr,PTHREAD_CREATE_DETACHED));
815 		} else {
816 			zassert(pthread_attr_setdetachstate(thattr,PTHREAD_CREATE_JOINABLE));
817 		}
818 		thattr_detached = detached;
819 	}
820 	return main_thread_create(th,thattr,fn,arg);
821 }
822 #endif
823 
main_exit(void)824 void main_exit(void) {
825 	int i;
826 	i = write(signalpipe[1],"\006",1);
827 	(void)i;
828 }
829 
signal_cleanup(void)830 void signal_cleanup(void) {
831 	close(signalpipe[0]);
832 	close(signalpipe[1]);
833 }
834 
changeugid(void)835 void changeugid(void) {
836 	char pwdgrpbuff[16384];
837 	struct passwd pwd,*pw;
838 	struct group grp,*gr;
839 	char *wuser;
840 	char *wgroup;
841 	uid_t wrk_uid;
842 	gid_t wrk_gid;
843 	int gidok;
844 
845 	if (geteuid()==0) {
846 		wuser = cfg_getstr("WORKING_USER",DEFAULT_USER);
847 		wgroup = cfg_getstr("WORKING_GROUP",DEFAULT_GROUP);
848 
849 		gidok = 0;
850 		wrk_gid = -1;
851 		if (wgroup[0]=='#') {
852 			wrk_gid = strtol(wgroup+1,NULL,10);
853 			gidok = 1;
854 		} else if (wgroup[0]) {
855 			getgrnam_r(wgroup,&grp,pwdgrpbuff,16384,&gr);
856 			if (gr==NULL) {
857 				mfs_arg_syslog(LOG_WARNING,"%s: no such group !!!",wgroup);
858 				exit(1);
859 			} else {
860 				wrk_gid = gr->gr_gid;
861 				gidok = 1;
862 			}
863 		}
864 
865 		if (wuser[0]=='#') {
866 			wrk_uid = strtol(wuser+1,NULL,10);
867 			if (gidok==0) {
868 				getpwuid_r(wrk_uid,&pwd,pwdgrpbuff,16384,&pw);
869 				if (pw==NULL) {
870 					mfs_arg_syslog(LOG_ERR,"%s: no such user id - can't obtain group id",wuser+1);
871 					exit(1);
872 				}
873 				wrk_gid = pw->pw_gid;
874 			}
875 		} else {
876 			getpwnam_r(wuser,&pwd,pwdgrpbuff,16384,&pw);
877 			if (pw==NULL) {
878 				mfs_arg_syslog(LOG_ERR,"%s: no such user !!!",wuser);
879 				exit(1);
880 			}
881 			wrk_uid = pw->pw_uid;
882 			if (gidok==0) {
883 				wrk_gid = pw->pw_gid;
884 			}
885 		}
886 		free(wuser);
887 		free(wgroup);
888 
889 		if (setgid(wrk_gid)<0) {
890 			mfs_arg_errlog(LOG_ERR,"can't set gid to %d",(int)wrk_gid);
891 			exit(1);
892 		} else {
893 			syslog(LOG_NOTICE,"set gid to %d",(int)wrk_gid);
894 		}
895 		if (setuid(wrk_uid)<0) {
896 			mfs_arg_errlog(LOG_ERR,"can't set uid to %d",(int)wrk_uid);
897 			exit(1);
898 		} else {
899 			syslog(LOG_NOTICE,"set uid to %d",(int)wrk_uid);
900 		}
901 	}
902 }
903 
904 static int lfd = -1;	// main lock
905 
mylock(int fd)906 pid_t mylock(int fd) {
907 	struct flock fl;
908 	fl.l_start = 0;
909 	fl.l_len = 0;
910 	fl.l_pid = getpid();
911 	fl.l_type = F_WRLCK;
912 	fl.l_whence = SEEK_SET;
913 	for (;;) {
914 		if (fcntl(fd,F_SETLK,&fl)>=0) {	// lock set
915 			return 0;	// ok
916 		}
917 		if (ERRNO_ERROR) {	// error other than "already locked"
918 			return -1;	// error
919 		}
920 		if (fcntl(fd,F_GETLK,&fl)<0) {	// get lock owner
921 			return -1;	// error getting lock
922 		}
923 		if (fl.l_type!=F_UNLCK) {	// found lock
924 			return fl.l_pid;	// return lock owner
925 		}
926 	}
927 	return -1;	// pro forma
928 }
929 
wdunlock(void)930 void wdunlock(void) {
931 	if (lfd>=0) {
932 		close(lfd);
933 	}
934 }
935 
wdlock(uint8_t runmode,uint32_t timeout)936 uint8_t wdlock(uint8_t runmode,uint32_t timeout) {
937 	pid_t ownerpid;
938 	pid_t newownerpid;
939 	uint32_t l;
940 
941 	lfd = open("." STR(APPNAME) ".lock",O_WRONLY|O_CREAT,0666);
942 	if (lfd<0) {
943 		mfs_errlog(LOG_ERR,"can't create lockfile in working directory");
944 		return 1;
945 	}
946 	ownerpid = mylock(lfd);
947 	if (ownerpid<0) {
948 		mfs_errlog(LOG_ERR,"fcntl error");
949 		return 1;
950 	}
951 	if (ownerpid>0) {
952 		if (runmode==RM_TEST) {
953 			fprintf(stderr,STR(APPNAME) " pid: %ld\n",(long)ownerpid);
954 			return 0;
955 		}
956 		if (runmode==RM_START) {
957 			fprintf(stderr,"can't start: lockfile is already locked by another process\n");
958 			return 1;
959 		}
960 		if (runmode==RM_RELOAD) {
961 			if (kill(ownerpid,SIGHUP)<0) {
962 				mfs_errlog(LOG_WARNING,"can't send reload signal to lock owner");
963 				return 1;
964 			}
965 			fprintf(stderr,"reload signal has been sent\n");
966 			return 0;
967 		}
968 		if (runmode==RM_INFO) {
969 #ifdef SIGINFO
970 			if (kill(ownerpid,SIGINFO)<0) {
971 #else
972 			if (kill(ownerpid,SIGUSR1)<0) {
973 #endif
974 				mfs_errlog(LOG_WARNING,"can't send info signal to lock owner");
975 				return 1;
976 			}
977 			fprintf(stderr,"info signal has been sent\n");
978 			return 0;
979 		}
980 		if (runmode==RM_KILL) {
981 			fprintf(stderr,"sending SIGKILL to lock owner (pid:%ld)\n",(long int)ownerpid);
982 			if (kill(ownerpid,SIGKILL)<0) {
983 				mfs_errlog(LOG_WARNING,"can't kill lock owner");
984 				return 1;
985 			}
986 		} else {
987 			fprintf(stderr,"sending SIGTERM to lock owner (pid:%ld)\n",(long int)ownerpid);
988 			if (kill(ownerpid,SIGTERM)<0) {
989 				mfs_errlog(LOG_WARNING,"can't kill lock owner");
990 				return 1;
991 			}
992 		}
993 		l=0;
994 		fprintf(stderr,"waiting for termination ");
995 		fflush(stderr);
996 		do {
997 			newownerpid = mylock(lfd);
998 			if (newownerpid<0) {
999 				mfs_errlog(LOG_ERR,"fcntl error");
1000 				return 1;
1001 			}
1002 			if (newownerpid>0) {
1003 				l++;
1004 				if (l>=timeout) {
1005 					syslog(LOG_ERR,"about %"PRIu32" seconds passed and lockfile is still locked - giving up",l);
1006 					fprintf(stderr,":giving up\n");
1007 					return 1;
1008 				}
1009 				if (l%10==0) {
1010 					syslog(LOG_WARNING,"about %"PRIu32" seconds passed and lock still exists",l);
1011 					fprintf(stderr,".");
1012 					fflush(stderr);
1013 				}
1014 				if (newownerpid!=ownerpid) {
1015 					fprintf(stderr,"\nnew lock owner detected\n");
1016 					if (runmode==RM_KILL) {
1017 						fprintf(stderr,":sending SIGKILL to lock owner (pid:%ld):",(long int)newownerpid);
1018 						fflush(stderr);
1019 						if (kill(newownerpid,SIGKILL)<0) {
1020 							mfs_errlog(LOG_WARNING,"can't kill lock owner");
1021 							return 1;
1022 						}
1023 					} else {
1024 						fprintf(stderr,":sending SIGTERM to lock owner (pid:%ld):",(long int)newownerpid);
1025 						fflush(stderr);
1026 						if (kill(newownerpid,SIGTERM)<0) {
1027 							mfs_errlog(LOG_WARNING,"can't kill lock owner");
1028 							return 1;
1029 						}
1030 					}
1031 					ownerpid = newownerpid;
1032 				}
1033 			}
1034 			sleep(1);
1035 		} while (newownerpid!=0);
1036 		fprintf(stderr,"terminated\n");
1037 		return 0;
1038 	}
1039 	if (runmode==RM_START || runmode==RM_RESTART) {
1040 		char pidstr[20];
1041 		l = snprintf(pidstr,20,"%ld\n",(long)(getpid()));
1042 		if (ftruncate(lfd,0)<0) {
1043 			fprintf(stderr,"can't truncate pidfile\n");
1044 		}
1045 		if (write(lfd,pidstr,l)!=(ssize_t)l) {
1046 			fprintf(stderr,"can't write pid to pidfile\n");
1047 		}
1048 		fprintf(stderr,"lockfile created and locked\n");
1049 	} else if (runmode==RM_TRY_RESTART) {
1050 		fprintf(stderr,"can't find process to restart\n");
1051 		return 1;
1052 	} else if (runmode==RM_STOP || runmode==RM_KILL) {
1053 		fprintf(stderr,"can't find process to terminate\n");
1054 		return 0;
1055 	} else if (runmode==RM_RELOAD) {
1056 		fprintf(stderr,"can't find process to send reload signal\n");
1057 		return 1;
1058 	} else if (runmode==RM_INFO) {
1059 		fprintf(stderr,"can't find process to send info signal\n");
1060 		return 1;
1061 	} else if (runmode==RM_TEST) {
1062 		fprintf(stderr,STR(APPNAME) " is not running\n");
1063 		return 1;
1064 	}
1065 	return 0;
1066 }
1067 
1068 void makedaemon() {
1069 	int f;
1070 	uint8_t pipebuff[1000];
1071 	ssize_t r;
1072 	size_t happy;
1073 	int piped[2];
1074 
1075 	fflush(stdout);
1076 	fflush(stderr);
1077 	if (pipe(piped)<0) {
1078 		fprintf(stderr,"pipe error\n");
1079 		exit(1);
1080 	}
1081 	f = fork();
1082 	if (f<0) {
1083 		syslog(LOG_ERR,"first fork error: %s",strerr(errno));
1084 		exit(1);
1085 	}
1086 	if (f>0) {
1087 		wait(&f);	// just get child status - prevents child from being zombie during initialization stage
1088 		if (f) {
1089 			fprintf(stderr,"Child status: %d\n",f);
1090 			exit(1);
1091 		}
1092 		close(piped[1]);
1093 //		printf("Starting daemon ...\n");
1094 		while ((r=read(piped[0],pipebuff,1000))) {
1095 			if (r>0) {
1096 				if (pipebuff[r-1]==0) {	// zero as a last char in the pipe means error
1097 					if (r>1) {
1098 						happy = fwrite(pipebuff,1,r-1,stderr);
1099 						(void)happy;
1100 					}
1101 					exit(1);
1102 				}
1103 				happy = fwrite(pipebuff,1,r,stderr);
1104 				(void)happy;
1105 			} else {
1106 				fprintf(stderr,"Error reading pipe: %s\n",strerr(errno));
1107 				exit(1);
1108 			}
1109 		}
1110 		exit(0);
1111 	}
1112 	setsid();
1113 	setpgid(0,getpid());
1114 	f = fork();
1115 	if (f<0) {
1116 		syslog(LOG_ERR,"second fork error: %s",strerr(errno));
1117 		if (write(piped[1],"fork error\n",11)!=11) {
1118 			syslog(LOG_ERR,"pipe write error: %s",strerr(errno));
1119 		}
1120 		close(piped[1]);
1121 		exit(1);
1122 	}
1123 	if (f>0) {
1124 		exit(0);
1125 	}
1126 	set_signal_handlers(1);
1127 
1128 	close(STDIN_FILENO);
1129 	sassert(open("/dev/null", O_RDWR, 0)==STDIN_FILENO);
1130 	close(STDOUT_FILENO);
1131 	sassert(dup(STDIN_FILENO)==STDOUT_FILENO);
1132 	close(STDERR_FILENO);
1133 	sassert(dup(piped[1])==STDERR_FILENO);
1134 	close(piped[1]);
1135 //	setvbuf(stderr,(char *)NULL,_IOLBF,0);
1136 }
1137 
1138 void close_msg_channel() {
1139 	fflush(stderr);
1140 	close(STDERR_FILENO);
1141 	sassert(open("/dev/null", O_RDWR, 0)==STDERR_FILENO);
1142 }
1143 
1144 void createpath(const char *filename) {
1145 	char pathbuff[1024];
1146 	const char *src = filename;
1147 	char *dst = pathbuff;
1148 	if (*src=='/') *dst++=*src++;
1149 
1150 	while (*src) {
1151 		while (*src!='/' && *src) {
1152 			*dst++=*src++;
1153 		}
1154 		if (*src=='/') {
1155 			*dst='\0';
1156 			if (mkdir(pathbuff,(mode_t)0777)<0) {
1157 				if (errno!=EEXIST) {
1158 					mfs_arg_errlog(LOG_NOTICE,"creating directory %s",pathbuff);
1159 				}
1160 			} else {
1161 				mfs_arg_syslog(LOG_NOTICE,"directory %s has been created",pathbuff);
1162 			}
1163 			*dst++=*src++;
1164 		}
1165 	}
1166 }
1167 
1168 void usage(const char *appname) {
1169 	printf(
1170 "usage: %s [-vfun] [-t locktimeout] [-c cfgfile] " MODULE_OPTIONS_SYNOPIS "[start|stop|restart|reload|info|test|kill]\n"
1171 "\n"
1172 "-v : print version number and exit\n"
1173 "-f : run in foreground\n"
1174 "-u : log undefined config variables\n"
1175 "-n : do not attempt to increase limit of core dump size\n"
1176 "-t locktimeout : how long wait for lockfile\n"
1177 "-c cfgfile : use given config file\n"
1178 MODULE_OPTIONS_DESC
1179 	,appname);
1180 	exit(1);
1181 }
1182 
1183 int main(int argc,char **argv) {
1184 	char *logappname;
1185 //	char *lockfname;
1186 	char *wrkdir;
1187 	char *cfgfile;
1188 	char *ocfgfile;
1189 	char *appname;
1190 	int ch;
1191 	uint8_t runmode;
1192 	int rundaemon,logundefined;
1193 	int lockmemory;
1194 	int forcecoredump;
1195 	int32_t nicelevel;
1196 	uint32_t locktimeout;
1197 	int fd;
1198 	uint8_t movewarning;
1199 	struct rlimit rls;
1200 
1201 	strerr_init();
1202 	mycrc32_init();
1203 
1204 	movewarning = 0;
1205 	cfgfile=strdup(ETC_PATH "/mfs/" STR(APPNAME) ".cfg");
1206 	passert(cfgfile);
1207 	if ((fd = open(cfgfile,O_RDONLY))<0 && errno==ENOENT) {
1208 		ocfgfile=strdup(ETC_PATH "/" STR(APPNAME) ".cfg");
1209 		passert(ocfgfile);
1210 		if ((fd = open(ocfgfile,O_RDONLY))>=0) {
1211 			free(cfgfile);
1212 			cfgfile = ocfgfile;
1213 			movewarning = 1;
1214 		}
1215 	}
1216 	if (fd>=0) {
1217 		close(fd);
1218 	}
1219 	locktimeout = 1800;
1220 	rundaemon = 1;
1221 	runmode = RM_RESTART;
1222 	logundefined = 0;
1223 	lockmemory = 0;
1224 	forcecoredump = 1;
1225 	appname = argv[0];
1226 
1227 	while ((ch = getopt(argc, argv, "nuvfdc:t:h?" MODULE_OPTIONS_GETOPT)) != -1) {
1228 		switch(ch) {
1229 			case 'v':
1230 				printf("version: %s\n",VERSSTR);
1231 				return 0;
1232 			case 'd':
1233 				printf("option '-d' is deprecated - use '-f' instead\n");
1234 				// no break on purpose
1235 			case 'f':
1236 				rundaemon=0;
1237 				break;
1238 			case 't':
1239 				locktimeout=strtoul(optarg,NULL,10);
1240 				break;
1241 			case 'c':
1242 				free(cfgfile);
1243 				cfgfile = strdup(optarg);
1244 				passert(cfgfile);
1245 				movewarning = 0;
1246 				break;
1247 			case 'u':
1248 				logundefined=1;
1249 				break;
1250 			case 'n':
1251 				forcecoredump = 0;
1252 				break;
1253 			MODULE_OPTIONS_SWITCH
1254 			default:
1255 				usage(appname);
1256 				return 1;
1257 		}
1258 	}
1259 	argc -= optind;
1260 	argv += optind;
1261 	if (argc==1) {
1262 		if (strcasecmp(argv[0],"start")==0) {
1263 			runmode = RM_START;
1264 		} else if (strcasecmp(argv[0],"stop")==0) {
1265 			runmode = RM_STOP;
1266 		} else if (strcasecmp(argv[0],"restart")==0) {
1267 			runmode = RM_RESTART;
1268 		} else if (strcasecmp(argv[0],"try-restart")==0) {
1269 			runmode = RM_TRY_RESTART;
1270 		} else if (strcasecmp(argv[0],"reload")==0) {
1271 			runmode = RM_RELOAD;
1272 		} else if (strcasecmp(argv[0],"info")==0) {
1273 			runmode = RM_INFO;
1274 		} else if (strcasecmp(argv[0],"test")==0 || strcasecmp(argv[0],"status")==0) {
1275 			runmode = RM_TEST;
1276 		} else if (strcasecmp(argv[0],"kill")==0) {
1277 			runmode = RM_KILL;
1278 		} else {
1279 			usage(appname);
1280 			return 1;
1281 		}
1282 	} else if (argc!=0) {
1283 		usage(appname);
1284 		return 1;
1285 	}
1286 
1287 	if (movewarning) {
1288 		mfs_syslog(LOG_WARNING,"default sysconf path has changed - please move " STR(APPNAME) ".cfg from "ETC_PATH"/ to "ETC_PATH"/mfs/");
1289 	}
1290 
1291 	if (runmode==RM_START || runmode==RM_RESTART || runmode==RM_TRY_RESTART) {
1292 		if (rundaemon) {
1293 			makedaemon();
1294 		} else {
1295 			set_signal_handlers(0);
1296 		}
1297 	}
1298 
1299 	if (cfg_load(cfgfile,logundefined)==0) {
1300 		fprintf(stderr,"can't load config file: %s - using defaults\n",cfgfile);
1301 	}
1302 	free(cfgfile);
1303 
1304 	logappname = cfg_getstr("SYSLOG_IDENT",STR(APPNAME));
1305 
1306 	if (rundaemon) {
1307 		if (logappname[0]) {
1308 			openlog(logappname, LOG_PID | LOG_NDELAY , LOG_DAEMON);
1309 		} else {
1310 			openlog(STR(APPNAME), LOG_PID | LOG_NDELAY , LOG_DAEMON);
1311 		}
1312 	} else {
1313 #if defined(LOG_PERROR)
1314 		if (logappname[0]) {
1315 			openlog(logappname, LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_USER);
1316 		} else {
1317 			openlog(STR(APPNAME), LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_USER);
1318 		}
1319 #else
1320 		if (logappname[0]) {
1321 			openlog(logappname, LOG_PID | LOG_NDELAY, LOG_USER);
1322 		} else {
1323 			openlog(STR(APPNAME), LOG_PID | LOG_NDELAY, LOG_USER);
1324 		}
1325 #endif
1326 	}
1327 
1328 	if (runmode==RM_START || runmode==RM_RESTART || runmode==RM_TRY_RESTART) {
1329 		rls.rlim_cur = MFSMAXFILES;
1330 		rls.rlim_max = MFSMAXFILES;
1331 		if (setrlimit(RLIMIT_NOFILE,&rls)<0) {
1332 			syslog(LOG_NOTICE,"can't change open files limit to: %u (trying to set smaller value)",MFSMAXFILES);
1333 			if (getrlimit(RLIMIT_NOFILE,&rls)>=0) {
1334 				uint32_t limit;
1335 				if (rls.rlim_max > MFSMAXFILES) {
1336 					limit = MFSMAXFILES;
1337 				} else {
1338 					limit = rls.rlim_max;
1339 				}
1340 				while (limit>1024) {
1341 					rls.rlim_cur = limit;
1342 					if (setrlimit(RLIMIT_NOFILE,&rls)>=0) {
1343 						mfs_arg_syslog(LOG_NOTICE,"open files limit has been set to: %"PRIu32,limit);
1344 						break;
1345 					}
1346 					limit *= 3;
1347 					limit /= 4;
1348 				}
1349 			}
1350 		} else {
1351 			mfs_arg_syslog(LOG_NOTICE,"open files limit has been set to: %u",MFSMAXFILES);
1352 		}
1353 
1354 		lockmemory = cfg_getnum("LOCK_MEMORY",0);
1355 #ifdef MFS_USE_MEMLOCK
1356 		if (lockmemory) {
1357 			rls.rlim_cur = RLIM_INFINITY;
1358 			rls.rlim_max = RLIM_INFINITY;
1359 			setrlimit(RLIMIT_MEMLOCK,&rls);
1360 		}
1361 #endif
1362 		nicelevel = cfg_getint32("NICE_LEVEL",-19);
1363 		setpriority(PRIO_PROCESS,getpid(),nicelevel);
1364 	}
1365 
1366 	changeugid();
1367 
1368 	wrkdir = cfg_getstr("DATA_PATH",DATA_PATH);
1369 	if (runmode==RM_START || runmode==RM_RESTART || runmode==RM_TRY_RESTART) {
1370 		fprintf(stderr,"working directory: %s\n",wrkdir);
1371 	}
1372 
1373 	if (chdir(wrkdir)<0) {
1374 		mfs_arg_syslog(LOG_ERR,"can't set working directory to %s",wrkdir);
1375 		if (rundaemon) {
1376 			fputc(0,stderr);
1377 			close_msg_channel();
1378 		}
1379 		closelog();
1380 		free(logappname);
1381 		return 1;
1382 	}
1383 	free(wrkdir);
1384 
1385 	umask(cfg_getuint32("FILE_UMASK",027)&077);
1386 
1387 	ch = wdlock(runmode,locktimeout);
1388 	if (ch) {
1389 		if (rundaemon) {
1390 			fputc(0,stderr);
1391 			close_msg_channel();
1392 		}
1393 		closelog();
1394 		free(logappname);
1395 		wdunlock();
1396 		return ch;
1397 	}
1398 
1399 	if (runmode==RM_STOP || runmode==RM_KILL || runmode==RM_RELOAD || runmode==RM_INFO || runmode==RM_TEST) {
1400 		if (rundaemon) {
1401 			close_msg_channel();
1402 		}
1403 		closelog();
1404 		free(logappname);
1405 		wdunlock();
1406 		return 0;
1407 	}
1408 
1409 #ifdef MFS_USE_MEMLOCK
1410 	if (lockmemory) {
1411 		if (getrlimit(RLIMIT_MEMLOCK,&rls)<0) {
1412 			mfs_errlog(LOG_WARNING,"error getting memory lock limits");
1413 		} else {
1414 			if (rls.rlim_cur!=RLIM_INFINITY && rls.rlim_max==RLIM_INFINITY) {
1415 				rls.rlim_cur = RLIM_INFINITY;
1416 				rls.rlim_max = RLIM_INFINITY;
1417 				if (setrlimit(RLIMIT_MEMLOCK,&rls)<0) {
1418 					mfs_errlog(LOG_WARNING,"error setting memory lock limit to unlimited");
1419 				}
1420 			}
1421 			if (getrlimit(RLIMIT_MEMLOCK,&rls)<0) {
1422 				mfs_errlog(LOG_WARNING,"error getting memory lock limits");
1423 			} else {
1424 				if (rls.rlim_cur!=RLIM_INFINITY) {
1425 					mfs_errlog(LOG_WARNING,"can't set memory lock limit to unlimited");
1426 				} else {
1427 					if (mlockall(MCL_CURRENT|MCL_FUTURE)<0) {
1428 						mfs_errlog(LOG_WARNING,"memory lock error");
1429 					} else {
1430 						mfs_syslog(LOG_NOTICE,"process memory was successfully locked in RAM");
1431 					}
1432 			}	}
1433 		}
1434 	}
1435 #else
1436 	if (lockmemory) {
1437 		mfs_syslog(LOG_WARNING,"memory lock not supported !!!");
1438 	}
1439 #endif
1440 
1441 	if (forcecoredump) {
1442 		rls.rlim_cur = RLIM_INFINITY;
1443 		rls.rlim_max = RLIM_INFINITY;
1444 		setrlimit(RLIMIT_CORE,&rls);
1445 #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
1446 		prctl(PR_SET_DUMPABLE,1);
1447 #endif
1448 	}
1449 
1450 /* glibc malloc tuning */
1451 #if defined(USE_PTHREADS) && defined(M_ARENA_MAX) && defined(M_ARENA_TEST) && defined(HAVE_MALLOPT)
1452 	if (cfg_getuint8("CHANGE_GLIBC_MALLOC_ARENAS",1)==1) {
1453 		if (!getenv("MALLOC_ARENA_MAX")) {
1454 			mfs_syslog(LOG_NOTICE,"setting glibc malloc arena max to 8");
1455 			mallopt(M_ARENA_MAX, 8);
1456 		}
1457 		if (!getenv("MALLOC_ARENA_TEST")) {
1458 			mfs_syslog(LOG_NOTICE,"setting glibc malloc arena test to 1");
1459 			mallopt(M_ARENA_TEST, 1);
1460 		}
1461 	} else {
1462 		mfs_syslog(LOG_NOTICE,"setting glibc malloc arenas turned off");
1463 	}
1464 #endif /* glibc malloc tuning */
1465 
1466 	syslog(LOG_NOTICE,"monotonic clock function: %s",monotonic_method());
1467 	syslog(LOG_NOTICE,"monotonic clock speed: %"PRIu32" ops / 10 mili seconds",monotonic_speed());
1468 
1469 	fprintf(stderr,"initializing %s modules ...\n",logappname);
1470 
1471 	if (initialize()) {
1472 //		if (getrlimit(RLIMIT_NOFILE,&rls)==0) {
1473 //			syslog(LOG_NOTICE,"open files limit: %lu",(unsigned long)(rls.rlim_cur));
1474 //		}
1475 		fprintf(stderr,"%s daemon initialized properly\n",logappname);
1476 		if (rundaemon) {
1477 			close_msg_channel();
1478 		}
1479 		if (initialize_late()) {
1480 			mainloop();
1481 			mfs_syslog(LOG_NOTICE,"exited from main loop");
1482 			ch=0;
1483 		} else {
1484 			ch=1;
1485 		}
1486 	} else {
1487 		fprintf(stderr,"error occurred during initialization - exiting\n");
1488 		if (rundaemon) {
1489 			fputc(0,stderr);
1490 			close_msg_channel();
1491 		}
1492 		ch=1;
1493 	}
1494 	mfs_syslog(LOG_NOTICE,"exititng ...");
1495 	destruct();
1496 	free_all_registered_entries();
1497 	signal_cleanup();
1498 	cfg_term();
1499 	strerr_term();
1500 	closelog();
1501 	free(logappname);
1502 	wdunlock();
1503 	mfs_arg_syslog(LOG_NOTICE,"process exited successfully (status:%d)",ch);
1504 	return ch;
1505 }
1506