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