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