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