]> git.proxmox.com Git - pve-cluster.git/blame - data/src/pmxcfs.c
With _FORTIFY_SOURCE and optimization, glibc defines a fortify_function for open...
[pve-cluster.git] / data / src / pmxcfs.c
CommitLineData
fe000966
DM
1/*
2 Copyright (C) 2010 Proxmox Server Solutions GmbH
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 Author: Dietmar Maurer <dietmar@proxmox.com>
18
19*/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif /* HAVE_CONFIG_H */
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <unistd.h>
29#include <glib.h>
fe000966
DM
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/mount.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <sys/file.h>
36#include <sys/types.h>
37#include <dirent.h>
38#include <sys/utsname.h>
39#include <grp.h>
40#include <netdb.h>
41#include <sys/socket.h>
42#include <netinet/in.h>
43#include <arpa/inet.h>
44
45#include <qb/qbdefs.h>
46#include <qb/qbutil.h>
64405e32 47#include <qb/qblog.h>
fe000966
DM
48
49#include "cfs-utils.h"
50#include "cfs-plug.h"
51#include "cfs-plug-memdb.h"
52#include "status.h"
53#include "dcdb.h"
54#include "dfsm.h"
55#include "quorum.h"
56#include "confdb.h"
57#include "server.h"
58
59#define DBFILENAME VARLIBDIR "/config.db"
60#define LOCKFILE VARLIBDIR "/.pmxcfs.lockfile"
61
62#define CFSDIR "/etc/pve"
63
64cfs_t cfs = {
65 .debug = 0,
fe000966
DM
66};
67
68static struct fuse *fuse = NULL;
69
70static cfs_plug_t *root_plug;
71
72static void glib_print_handler(const gchar *string)
73{
64405e32 74 printf("%s", string);
fe000966
DM
75}
76
77static void glib_log_handler(const gchar *log_domain,
78 GLogLevelFlags log_level,
79 const gchar *message,
80 gpointer user_data)
81{
82
83 cfs_log(log_domain, log_level, NULL, 0, NULL, message);
84}
85
86static gboolean write_pidfile(pid_t pid)
87{
88 char *strpid = g_strdup_printf("%d\n", pid);
89 gboolean res = atomic_write_file(CFS_PID_FN, strpid, strlen(strpid), 0644, getgid());
90 g_free(strpid);
91
92 return res;
93}
94
95static cfs_plug_t *find_plug(const char *path, char **sub)
96{
97 g_return_val_if_fail(root_plug != NULL, NULL);
98 g_return_val_if_fail(path != NULL, NULL);
99
100 while(*path == '/') path++;
101
102 cfs_debug("find_plug start %s", path);
103
104 char *tmppath = g_strdup(path);
105 char *subpath = tmppath;
106
107 cfs_plug_t *plug = root_plug->lookup_plug(root_plug, &subpath);
108
109 cfs_debug("find_plug end %s = %p (%s)", path, plug, subpath);
110
111 if (subpath && subpath[0])
112 *sub = g_strdup(subpath);
113
114 g_free(tmppath);
115
116 return plug;
117}
118
119void *cfs_fuse_init(struct fuse_conn_info *conn)
120{
121 return NULL;
122}
123
124static int cfs_fuse_getattr(const char *path, struct stat *stbuf)
125{
126 cfs_debug("enter cfs_fuse_getattr %s", path);
127
128 int ret = -EACCES;
129
130 char *subpath = NULL;
131 cfs_plug_t *plug = find_plug(path, &subpath);
132
133 if (plug && plug->ops && plug->ops->getattr) {
134 ret = plug->ops->getattr(plug, subpath ? subpath : "", stbuf);
135
136 stbuf->st_gid = cfs.gid;
137
42789cda 138 if (path_is_private(path)) {
fe000966 139 stbuf->st_mode &= 0777700;
42789cda
DM
140 } else {
141 if (S_ISDIR(stbuf->st_mode) || S_ISLNK(stbuf->st_mode)) {
142 stbuf->st_mode &= 0777755; // access for other users
143 } else {
144 if (path_is_lxc_conf(path)) {
145 stbuf->st_mode &= 0777755; // access for other users
146 } else {
147 stbuf->st_mode &= 0777750; // no access for other users
148 }
149 }
150 }
fe000966
DM
151 }
152
153 cfs_debug("leave cfs_fuse_getattr %s (%d)", path, ret);
154
155 if (subpath)
156 g_free(subpath);
157
158 return ret;
159
160}
161
162static int cfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
163 off_t offset, struct fuse_file_info *fi)
164{
165 (void) offset;
166 (void) fi;
167
168 cfs_debug("enter cfs_fuse_readdir %s", path);
169
170 int ret = -EACCES;
171
172 char *subpath = NULL;
173 cfs_plug_t *plug = find_plug(path, &subpath);
174
175 if (!plug)
176 goto ret;
177
178 if (plug->ops && plug->ops->readdir)
179 ret = plug->ops->readdir(plug, subpath ? subpath : "", buf, filler, 0, fi);
180ret:
181 cfs_debug("leave cfs_fuse_readdir %s (%d)", path, ret);
182
183 if (subpath)
184 g_free(subpath);
185
186 return ret;
187}
188
189static int cfs_fuse_mkdir(const char *path, mode_t mode)
190{
191 cfs_debug("enter cfs_fuse_mkdir %s", path);
192
193 int ret = -EACCES;
194
195 char *subpath = NULL;
196 cfs_plug_t *plug = find_plug(path, &subpath);
197
198 if (!plug)
199 goto ret;
200
201 if (subpath && plug->ops && plug->ops->mkdir)
202 ret = plug->ops->mkdir(plug, subpath, mode);
203
204 ret:
205 cfs_debug("leave cfs_fuse_mkdir %s (%d)", path, ret);
206
207 if (subpath)
208 g_free(subpath);
209
210 return ret;
211}
212
213static int cfs_fuse_rmdir(const char *path)
214{
215 cfs_debug("enter cfs_fuse_rmdir %s", path);
216
217 int ret = -EACCES;
218
219 char *subpath = NULL;
220 cfs_plug_t *plug = find_plug(path, &subpath);
221
222 if (!plug)
223 goto ret;
224
225 if (subpath && plug->ops && plug->ops->rmdir)
226 ret = plug->ops->rmdir(plug, subpath);
227
228 ret:
229 cfs_debug("leave cfs_fuse_rmdir %s (%d)", path, ret);
230
231 if (subpath)
232 g_free(subpath);
233
234 return ret;
235}
236
237static int cfs_fuse_rename(const char *from, const char *to)
238{
239 cfs_debug("enter cfs_fuse_rename from %s to %s", from, to);
240
241 int ret = -EACCES;
242
243 char *sub_from = NULL;
244 cfs_plug_t *plug_from = find_plug(from, &sub_from);
245
246 char *sub_to = NULL;
247 cfs_plug_t *plug_to = find_plug(to, &sub_to);
248
249 if (!plug_from || !plug_to || plug_from != plug_to)
250 goto ret;
251
252 if (plug_from->ops && plug_from->ops->rename && sub_from && sub_to)
253 ret = plug_from->ops->rename(plug_from, sub_from, sub_to);
254
255 ret:
256 cfs_debug("leave cfs_fuse_rename from %s to %s (%d)", from, to, ret);
257
258 if (sub_from)
259 g_free(sub_from);
260
261 if (sub_to)
262 g_free(sub_to);
263
264 return ret;
265}
266
267static int cfs_fuse_open(const char *path, struct fuse_file_info *fi)
268{
269 cfs_debug("enter cfs_fuse_open %s", path);
270
271 fi->direct_io = 1;
272 fi->keep_cache = 0;
273
274 int ret = -EACCES;
275
276 char *subpath = NULL;
277 cfs_plug_t *plug = find_plug(path, &subpath);
278
279 if (plug && plug->ops) {
280 if ((subpath || !plug->ops->readdir) && plug->ops->open) {
281 ret = plug->ops->open(plug, subpath ? subpath : "", fi);
282 }
283 }
284
285 cfs_debug("leave cfs_fuse_open %s (%d)", path, ret);
286
287 if (subpath)
288 g_free(subpath);
289
290 return ret;
291}
292
293static int cfs_fuse_read(const char *path, char *buf, size_t size, off_t offset,
294 struct fuse_file_info *fi)
295{
296 (void) fi;
297
298 cfs_debug("enter cfs_fuse_read %s %lu %ld", path, size, offset);
299
300 int ret = -EACCES;
301
302 char *subpath = NULL;
303 cfs_plug_t *plug = find_plug(path, &subpath);
304
305 if (plug && plug->ops) {
306 if ((subpath || !plug->ops->readdir) && plug->ops->read)
307 ret = plug->ops->read(plug, subpath ? subpath : "", buf, size, offset, fi);
308 }
309
310 cfs_debug("leave cfs_fuse_read %s (%d)", path, ret);
311
312 if (subpath)
313 g_free(subpath);
314
315 return ret;
316}
317
318static int cfs_fuse_write(const char *path, const char *buf, size_t size,
319 off_t offset, struct fuse_file_info *fi)
320{
321 (void) fi;
322
323 cfs_debug("enter cfs_fuse_write %s %lu %ld", path, size, offset);
324
325 int ret = -EACCES;
326
327 char *subpath = NULL;
328 cfs_plug_t *plug = find_plug(path, &subpath);
329
330 if (plug && plug->ops) {
331 if ((subpath || !plug->ops->readdir) && plug->ops->write)
332 ret = plug->ops->write(plug, subpath ? subpath : "",
333 buf, size, offset, fi);
334 }
335
336 cfs_debug("leave cfs_fuse_write %s (%d)", path, ret);
337
338 if (subpath)
339 g_free(subpath);
340
341 return ret;
342}
343
344static int cfs_fuse_truncate(const char *path, off_t size)
345{
346 cfs_debug("enter cfs_fuse_truncate %s %ld", path, size);
347
348 int ret = -EACCES;
349
350 char *subpath = NULL;
351 cfs_plug_t *plug = find_plug(path, &subpath);
352
353 if (plug && plug->ops) {
354 if ((subpath || !plug->ops->readdir) && plug->ops->truncate)
355 ret = plug->ops->truncate(plug, subpath ? subpath : "", size);
356 }
357
358 cfs_debug("leave cfs_fuse_truncate %s (%d)", path, ret);
359
360 if (subpath)
361 g_free(subpath);
362
363 return ret;
364}
365
366static int cfs_fuse_create(const char *path, mode_t mode, struct fuse_file_info *fi)
367{
368 cfs_debug("enter cfs_fuse_create %s", path);
369
370 int ret = -EACCES;
371
372 char *subpath = NULL;
373 cfs_plug_t *plug = find_plug(path, &subpath);
374
375 if (!plug)
376 goto ret;
377
378 if (subpath && plug->ops && plug->ops->create)
379 ret = plug->ops->create(plug, subpath, mode, fi);
380
381ret:
382 cfs_debug("leave cfs_fuse_create %s (%d)", path, ret);
383
384 if (subpath)
385 g_free(subpath);
386
387 return ret;
388}
389
390static int cfs_fuse_unlink(const char *path)
391{
392 cfs_debug("enter cfs_fuse_unlink %s", path);
393
394 int ret = -EACCES;
395
396 char *subpath = NULL;
397 cfs_plug_t *plug = find_plug(path, &subpath);
398
399 if (!plug)
400 goto ret;
401
402 if (subpath && plug->ops && plug->ops->unlink)
403 ret = plug->ops->unlink(plug, subpath);
404
405ret:
406 cfs_debug("leave cfs_fuse_unlink %s (%d)", path, ret);
407
408 if (subpath)
409 g_free(subpath);
410
411 return ret;
412}
413
414static int cfs_fuse_readlink(const char *path, char *buf, size_t max)
415{
416 cfs_debug("enter cfs_fuse_readlink %s", path);
417
418 int ret = -EACCES;
419
420 char *subpath = NULL;
421 cfs_plug_t *plug = find_plug(path, &subpath);
422
423 if (!plug)
424 goto ret;
425
426 if (plug->ops && plug->ops->readlink)
427 ret = plug->ops->readlink(plug, subpath ? subpath : "", buf, max);
428
429ret:
430 cfs_debug("leave cfs_fuse_readlink %s (%d)", path, ret);
431
432 if (subpath)
433 g_free(subpath);
434
435 return ret;
436}
437
438static int cfs_fuse_utimens(const char *path, const struct timespec tv[2])
439{
440 cfs_debug("enter cfs_fuse_utimens %s", path);
441
442 int ret = -EACCES;
443
444 char *subpath = NULL;
445 cfs_plug_t *plug = find_plug(path, &subpath);
446
447 if (!plug)
448 goto ret;
449
450 if (plug->ops && plug->ops->utimens)
451 ret = plug->ops->utimens(plug, subpath ? subpath : "", tv);
452
453ret:
454 cfs_debug("leave cfs_fuse_utimens %s (%d)", path, ret);
455
456 if (subpath)
457 g_free(subpath);
458
459 return ret;
460}
461
462static int cfs_fuse_statfs(const char *path, struct statvfs *stbuf)
463{
464 g_return_val_if_fail(root_plug != NULL, PARAM_CHECK_ERRNO);
465
466 cfs_debug("enter cfs_fuse_statfs %s", path);
467
468 int ret = -EACCES;
469
470 if (root_plug && root_plug->ops && root_plug->ops->statfs)
471 ret = root_plug->ops->statfs(root_plug, "", stbuf);
472
473 return ret;
474}
475
476static struct fuse_operations fuse_ops = {
477 .getattr = cfs_fuse_getattr,
478 .readdir = cfs_fuse_readdir,
479 .mkdir = cfs_fuse_mkdir,
480 .rmdir = cfs_fuse_rmdir,
481 .rename = cfs_fuse_rename,
482 .open = cfs_fuse_open,
483 .read = cfs_fuse_read,
484 .write = cfs_fuse_write,
485 .truncate = cfs_fuse_truncate,
486 .create = cfs_fuse_create,
487 .unlink = cfs_fuse_unlink,
488 .readlink = cfs_fuse_readlink,
489 .utimens = cfs_fuse_utimens,
490 .statfs = cfs_fuse_statfs,
491 .init = cfs_fuse_init
492};
493
494static char *
495create_dot_version_cb(cfs_plug_t *plug)
496{
497 GString *outbuf = g_string_new(NULL);
498 char *data = NULL;
499
500 if (cfs_create_version_msg(outbuf) == 0) {
501 data = outbuf->str;
502 g_string_free(outbuf, FALSE);
503 } else {
504 g_string_free(outbuf, TRUE);
505 }
506
507 return data;
508}
509
510static char *
511create_dot_members_cb(cfs_plug_t *plug)
512{
513 GString *outbuf = g_string_new(NULL);
514 char *data = NULL;
515
516 if (cfs_create_memberlist_msg(outbuf) == 0) {
517 data = outbuf->str;
518 g_string_free(outbuf, FALSE);
519 } else {
520 g_string_free(outbuf, TRUE);
521 }
522
523 return data;
524}
525
526static char *
527create_dot_vmlist_cb(cfs_plug_t *plug)
528{
529 GString *outbuf = g_string_new(NULL);
530 char *data = NULL;
531
532 if (cfs_create_vmlist_msg(outbuf) == 0) {
533 data = outbuf->str;
534 g_string_free(outbuf, FALSE);
535 } else {
536 g_string_free(outbuf, TRUE);
537 }
538
539 return data;
540}
541
542static char *
543create_dot_rrd_cb(cfs_plug_t *plug)
544{
545 GString *outbuf = g_string_new(NULL);
546
547 cfs_rrd_dump(outbuf);
548 char *data = outbuf->str;
549 g_string_free(outbuf, FALSE);
550
551 return data;
552}
553
554static char *
555create_dot_clusterlog_cb(cfs_plug_t *plug)
556{
557 GString *outbuf = g_string_new(NULL);
558
559 cfs_cluster_log_dump(outbuf, NULL, 50);
560 char *data = outbuf->str;
561 g_string_free(outbuf, FALSE);
562
563 return data;
564}
565
566static char *
567read_debug_setting_cb(cfs_plug_t *plug)
568{
569 return g_strdup_printf("%d\n", !!cfs.debug);
570}
571
65420fb3
DM
572static void
573my_qb_log_filter(struct qb_log_callsite *cs)
574{
575 int32_t priority = cfs.debug ? LOG_DEBUG : LOG_INFO;
576
577 if (qb_bit_is_set(cs->tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
578 if (cs->priority <= (cfs.debug ? priority : LOG_WARNING)) {
579 qb_bit_set(cs->targets, QB_LOG_SYSLOG);
580 } else {
581 qb_bit_clear(cs->targets, QB_LOG_SYSLOG);
582 }
583 if (cs->priority <= priority) {
584 qb_bit_set(cs->targets, QB_LOG_STDERR);
585 } else {
586 qb_bit_clear(cs->targets, QB_LOG_STDERR);
587 }
588 } else {
589 if (cs->priority <= priority) {
590 qb_bit_set(cs->targets, QB_LOG_SYSLOG);
591 qb_bit_set(cs->targets, QB_LOG_STDERR);
592 } else {
593 qb_bit_clear(cs->targets, QB_LOG_SYSLOG);
594 qb_bit_clear(cs->targets, QB_LOG_STDERR);
595 }
596 }
597}
598
64405e32
DM
599static void
600update_qb_log_settings(void)
601{
65420fb3 602 qb_log_filter_fn_set(my_qb_log_filter);
92bc48dd 603
64405e32
DM
604 if (cfs.debug) {
605 qb_log_format_set(QB_LOG_SYSLOG, "[%g] %p: %b (%f:%l:%n)");
606 qb_log_format_set(QB_LOG_STDERR, "[%g] %p: %b (%f:%l:%n)");
64405e32
DM
607 } else {
608 qb_log_format_set(QB_LOG_SYSLOG, "[%g] %p: %b");
609 qb_log_format_set(QB_LOG_STDERR, "[%g] %p: %b");
64405e32
DM
610 }
611}
612
65420fb3
DM
613static int
614write_debug_setting_cb(
fe000966
DM
615 cfs_plug_t *plug,
616 const char *buf,
617 size_t size)
618{
619 int res = -EIO;
620
621 if (size < 2)
622 return res;
623
624 if (strncmp(buf, "0\n", 2) == 0) {
625 if (cfs.debug) {
626 cfs_message("disable debug mode");
627 cfs.debug = 0;
64405e32 628 update_qb_log_settings();
fe000966
DM
629 }
630 return 2;
631 } else if (strncmp(buf, "1\n", 2) == 0) {
632 if (!cfs.debug) {
fe000966 633 cfs.debug = 1;
64405e32
DM
634 update_qb_log_settings();
635 cfs_message("enable debug mode");
fe000966
DM
636 }
637 return 2;
638 }
639
640 return res;
641}
642
fe000966
DM
643static void
644create_symlinks(cfs_plug_base_t *bplug, const char *nodename)
645{
646 g_return_if_fail(bplug != NULL);
647 g_return_if_fail(nodename != NULL);
648
649 char *lnktarget = g_strdup_printf("nodes/%s", nodename);
650 cfs_plug_link_t *lnk = cfs_plug_link_new("local", lnktarget);
651 g_free(lnktarget);
652 cfs_plug_base_insert(bplug, (cfs_plug_t*)lnk);
653
654 lnktarget = g_strdup_printf("nodes/%s/qemu-server", nodename);
655 lnk = cfs_plug_link_new("qemu-server", lnktarget);
656 g_free(lnktarget);
657 cfs_plug_base_insert(bplug, (cfs_plug_t*)lnk);
658
659 lnktarget = g_strdup_printf("nodes/%s/openvz", nodename);
660 lnk = cfs_plug_link_new("openvz", lnktarget);
661 g_free(lnktarget);
662 cfs_plug_base_insert(bplug, (cfs_plug_t*)lnk);
663
7f66b436
DM
664 lnktarget = g_strdup_printf("nodes/%s/lxc", nodename);
665 lnk = cfs_plug_link_new("lxc", lnktarget);
666 g_free(lnktarget);
667 cfs_plug_base_insert(bplug, (cfs_plug_t*)lnk);
668
fe000966
DM
669 cfs_plug_func_t *fplug = cfs_plug_func_new(".version", 0440, create_dot_version_cb, NULL);
670 cfs_plug_base_insert(bplug, (cfs_plug_t*)fplug);
671
672 fplug = cfs_plug_func_new(".members", 0440, create_dot_members_cb, NULL);
673 cfs_plug_base_insert(bplug, (cfs_plug_t*)fplug);
674
675 fplug = cfs_plug_func_new(".vmlist", 0440, create_dot_vmlist_cb, NULL);
676 cfs_plug_base_insert(bplug, (cfs_plug_t*)fplug);
677
678 fplug = cfs_plug_func_new(".rrd", 0440, create_dot_rrd_cb, NULL);
679 cfs_plug_base_insert(bplug, (cfs_plug_t*)fplug);
680
681 fplug = cfs_plug_func_new(".clusterlog", 0440, create_dot_clusterlog_cb, NULL);
682 cfs_plug_base_insert(bplug, (cfs_plug_t*)fplug);
683
684 fplug = cfs_plug_func_new(".debug", 0640, read_debug_setting_cb, write_debug_setting_cb);
685 cfs_plug_base_insert(bplug, (cfs_plug_t*)fplug);
686
687
688}
689
690static char *
691lookup_node_ip(const char *nodename)
692{
693 struct addrinfo *ainfo;
694 struct addrinfo ahints;
695 memset(&ahints, 0, sizeof(ahints));
696
697 if (getaddrinfo(nodename, NULL, &ahints, &ainfo))
698 return NULL;
699
700 if (ainfo->ai_family == AF_INET) {
701 char buf[INET6_ADDRSTRLEN];
702 struct sockaddr_in *sa = (struct sockaddr_in *)ainfo->ai_addr;
703 inet_ntop(ainfo->ai_family, &sa->sin_addr, buf, sizeof(buf));
704 if (strncmp(buf, "127.", 4) != 0) {
705 return g_strdup(buf);
706 }
707 }
708
709 // ipv6 support ?
710
711 return NULL;
712}
64405e32
DM
713
714static const char*
715log_tags_stringify(uint32_t tags) {
716 if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
717 return "libqb";
718 } else {
719 GQuark quark = tags;
720 const char *domain = g_quark_to_string(quark);
721 if (domain != NULL) {
722 return domain;
723 } else {
724 return "main";
725 }
726 }
727}
728
fe000966
DM
729int main(int argc, char *argv[])
730{
731 int ret = -1;
732 int lockfd = -1;
733
734 gboolean foreground = FALSE;
735 gboolean force_local_mode = FALSE;
736 gboolean wrote_pidfile = FALSE;
737 memdb_t *memdb = NULL;
738 dfsm_t *dcdb = NULL;
739 dfsm_t *status_fsm = NULL;
740
64405e32 741 qb_log_init("pmxcfs", LOG_DAEMON, LOG_DEBUG);
65420fb3
DM
742 /* remove default filter */
743 qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_REMOVE,
744 QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
745
64405e32
DM
746 qb_log_tags_stringify_fn_set(log_tags_stringify);
747
748 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
64405e32
DM
749
750 update_qb_log_settings();
fe000966
DM
751
752 g_set_print_handler(glib_print_handler);
753 g_set_printerr_handler(glib_print_handler);
754 g_log_set_default_handler(glib_log_handler, NULL);
755
756 GOptionContext *context;
fe000966
DM
757
758 GOptionEntry entries[] = {
759 { "debug", 'd', 0, G_OPTION_ARG_NONE, &cfs.debug, "Turn on debug messages", NULL },
760 { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Do not daemonize server", NULL },
761 { "local", 'l', 0, G_OPTION_ARG_NONE, &force_local_mode,
2113d031 762 "Force local mode (ignore corosync.conf, force quorum)", NULL },
fe000966
DM
763 { NULL },
764 };
765
766 context = g_option_context_new ("");
767 g_option_context_add_main_entries (context, entries, NULL);
768
769 GError *err = NULL;
770 if (!g_option_context_parse (context, &argc, &argv, &err))
771 {
772 cfs_critical("option parsing failed: %s", err->message);
773 g_error_free (err);
64405e32 774 qb_log_fini();
fe000966
DM
775 exit (1);
776 }
777 g_option_context_free(context);
778
779 if (optind < argc) {
780 cfs_critical("too many arguments");
64405e32 781 qb_log_fini();
fe000966
DM
782 exit(-1);
783 }
64405e32
DM
784
785 if (cfs.debug) {
786 update_qb_log_settings();
787 }
788
fe000966
DM
789 struct utsname utsname;
790 if (uname(&utsname) != 0) {
791 cfs_critical("Unable to read local node name");
64405e32 792 qb_log_fini();
fe000966
DM
793 exit (-1);
794 }
795
796 for (int i=0; i < sizeof(utsname.nodename); i++) {
797 if (utsname.nodename[i] =='.') utsname.nodename[i] = 0;
798 }
799
800 cfs.nodename = g_strdup(utsname.nodename);
801
802 if (!(cfs.ip = lookup_node_ip(cfs.nodename))) {
803 cfs_critical("Unable to get local IP address");
64405e32 804 qb_log_fini();
fe000966
DM
805 exit(-1);
806 }
807
808 struct group *www_data = getgrnam("www-data");
809 if (!www_data) {
810 cfs_critical("Unable to get www-data group ID");
64405e32 811 qb_log_fini();
fe000966
DM
812 exit (-1);
813 }
814 cfs.gid = www_data->gr_gid;
815
fe000966
DM
816 umask(027);
817
818 mkdir(VARLIBDIR, 0755);
819
fbe6b41e 820 if ((lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_APPEND, 0600)) == -1) {
fe000966
DM
821 cfs_critical("unable to create lock '%s': %s", LOCKFILE, strerror (errno));
822 goto err;
823 }
824
825 for (int i = 10; i >= 0; i--) {
826 if (flock(lockfd, LOCK_EX|LOCK_NB) != 0) {
827 if (!i) {
828 cfs_critical("unable to aquire pmxcfs lock: %s", strerror (errno));
829 goto err;
830 }
831 if (i == 10)
832 cfs_message("unable to aquire pmxcfs lock - trying again");
833
834 sleep(1);
835 }
836 }
837
838 cfs_status_init();
839
840 gboolean create = !g_file_test(DBFILENAME, G_FILE_TEST_EXISTS);
841
842 if (!(memdb = memdb_open (DBFILENAME))) {
843 cfs_critical("memdb_open failed - unable to open database '%s'", DBFILENAME);
844 goto err;
845 }
846
2113d031 847 // automatically import corosync.conf from host
fe000966
DM
848 if (create && !force_local_mode) {
849 char *cdata = NULL;
850 gsize clen = 0;
851 if (g_file_get_contents(HOST_CLUSTER_CONF_FN, &cdata, &clen, NULL)) {
852
853 guint32 mtime = time(NULL);
854
2113d031
DM
855 memdb_create(memdb, "/corosync.conf", 0, mtime);
856 if (memdb_write(memdb, "/corosync.conf", 0, mtime, cdata, clen, 0, 1) < 0) {
857 cfs_critical("memdb_write failed - unable to import corosync.conf");
fe000966
DM
858 goto err;
859 }
860 }
861 }
862
2113d031 863 // does corosync.conf exist?
fe000966 864 gpointer conf_data = NULL;
2113d031 865 int len = memdb_read(memdb, "corosync.conf", &conf_data);
fe000966
DM
866 if (len >= 0) {
867 if (force_local_mode) {
2113d031 868 cfs_message("forcing local mode (althought corosync.conf exists)");
fe000966
DM
869 cfs_set_quorate(1, TRUE);
870 } else {
871 if (!(dcdb = dcdb_new(memdb)))
872 goto err;
2113d031 873 dcdb_sync_corosync_conf(memdb, 1);
fe000966
DM
874 }
875 } else {
2113d031 876 cfs_debug("using local mode (corosync.conf does not exist)");
fe000966
DM
877 cfs_set_quorate(1, TRUE);
878 }
879 if (conf_data) g_free(conf_data);
880
881 cfs_plug_memdb_t *config = cfs_plug_memdb_new("memdb", memdb, dcdb);
882
883 cfs_plug_base_t *bplug = cfs_plug_base_new("", (cfs_plug_t *)config);
884
885 create_symlinks(bplug, cfs.nodename);
886
887 root_plug = (cfs_plug_t *)bplug;
888
889 system("umount -f " CFSDIR " >/dev/null 2>&1");
890
27b69f59
DM
891 mkdir(CFSDIR, 0755);
892
fe000966
DM
893 char *fa[] = { "-f", "-odefault_permissions", "-oallow_other", NULL};
894
895 struct fuse_args fuse_args = FUSE_ARGS_INIT(sizeof (fa)/sizeof(gpointer) - 1, fa);
896
897 struct fuse_chan *fuse_chan = fuse_mount(CFSDIR, &fuse_args);
898 if (!fuse_chan) {
899 cfs_critical("fuse_mount error: %s", strerror(errno));
900 goto err;
901 }
902
903 if (!(fuse = fuse_new(fuse_chan, &fuse_args, &fuse_ops, sizeof(fuse_ops), NULL))) {
904 cfs_critical("fuse_new error: %s", strerror(errno));
905 goto err;
906 }
907
908 fuse_set_signal_handlers(fuse_get_session(fuse));
909
fe000966
DM
910 if (!foreground) {
911 pid_t cpid = fork();
912
913 if (cpid == -1) {
914 cfs_critical("failed to daemonize program - %s", strerror (errno));
915 goto err;
916 } else if (cpid) {
917 write_pidfile(cpid);
64405e32 918 qb_log_fini();
fe000966
DM
919 _exit (0);
920 } else {
921 int nullfd;
922
923 chroot("/");
924
925 if ((nullfd = open("/dev/null", O_RDWR, 0)) != -1) {
926 dup2(nullfd, 0);
927 dup2(nullfd, 1);
928 dup2(nullfd, 2);
929 if (nullfd > 2)
930 close (nullfd);
931 }
932
933 // do not print to the console after this point
64405e32
DM
934 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_FALSE);
935
fe000966
DM
936 setsid();
937 }
938 } else {
939 write_pidfile(getpid());
940 }
941
942 wrote_pidfile = TRUE;
943
944 cfs_loop_t *corosync_loop = cfs_loop_new(fuse);
945
946 cfs_service_t *service_quorum = NULL;
947 cfs_service_t *service_confdb = NULL;
948 cfs_service_t *service_dcdb = NULL;
949 cfs_service_t *service_status = NULL;
950
951 if (dcdb) {
952
953 service_quorum = service_quorum_new();
954
955 cfs_loop_add_service(corosync_loop, service_quorum, QB_LOOP_HIGH);
956
957 service_confdb = service_confdb_new();
958
959 cfs_loop_add_service(corosync_loop, service_confdb, QB_LOOP_MED);
960
961 service_dcdb = service_dfsm_new(dcdb);
962 cfs_service_set_timer(service_dcdb, DCDB_VERIFY_TIME);
963
964 cfs_loop_add_service(corosync_loop, service_dcdb, QB_LOOP_MED);
965
966 status_fsm = cfs_status_dfsm_new();
967 service_status = service_dfsm_new(status_fsm);
968
969 cfs_loop_add_service(corosync_loop, service_status, QB_LOOP_LOW);
970
971 }
972
973 cfs_loop_start_worker(corosync_loop);
974
975 server_start(memdb);
976
977 ret = fuse_loop_mt(fuse);
978
979 cfs_message("teardown filesystem");
980
981 server_stop();
982
983 fuse_unmount(CFSDIR, fuse_chan);
984
985 fuse_destroy(fuse);
986
987 cfs_debug("set stop event loop flag");
988
989 cfs_loop_stop_worker(corosync_loop);
990
991 cfs_loop_destroy(corosync_loop);
992
993 cfs_debug("worker finished");
994
995 if (service_dcdb)
996 service_dfsm_destroy(service_dcdb);
997
998 if (service_confdb)
999 service_confdb_destroy(service_confdb);
1000
1001 if (service_quorum)
1002 service_quorum_destroy(service_quorum);
1003
1004 if (service_status)
1005 service_dfsm_destroy(service_status);
1006
1007 sleep(1); /* do not restart too fast */
1008 ret:
1009
1010 if (status_fsm)
1011 dfsm_destroy(status_fsm);
1012
1013 if (dcdb)
1014 dfsm_destroy(dcdb);
1015
1016 if (memdb)
1017 memdb_close(memdb);
1018
1019 if (wrote_pidfile)
1020 unlink(CFS_PID_FN);
1021
1022 cfs_message("exit proxmox configuration filesystem (%d)", ret);
1023
1024 cfs_status_cleanup();
1025
64405e32
DM
1026 qb_log_fini();
1027
fe000966
DM
1028 exit(ret);
1029
1030 err:
1031 goto ret;
1032}