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