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