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