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