2 Copyright (C) 2010 Proxmox Server Solutions GmbH
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.
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.
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/>.
17 Author: Dietmar Maurer <dietmar@proxmox.com>
23 #endif /* HAVE_CONFIG_H */
31 #include <sys/types.h>
33 #include <sys/mount.h>
37 #include <sys/types.h>
39 #include <sys/utsname.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
46 #include <qb/qbdefs.h>
47 #include <qb/qbutil.h>
49 #include "cfs-utils.h"
51 #include "cfs-plug-memdb.h"
59 #define DBFILENAME VARLIBDIR "/config.db"
60 #define LOCKFILE VARLIBDIR "/.pmxcfs.lockfile"
62 #define CFSDIR "/etc/pve"
66 .print_to_console
= 1,
69 static struct fuse
*fuse
= NULL
;
71 static cfs_plug_t
*root_plug
;
73 static void glib_print_handler(const gchar
*string
)
75 if (cfs
.debug
|| cfs
.print_to_console
)
79 static void glib_log_handler(const gchar
*log_domain
,
80 GLogLevelFlags log_level
,
85 cfs_log(log_domain
, log_level
, NULL
, 0, NULL
, message
);
88 static gboolean
write_pidfile(pid_t pid
)
90 char *strpid
= g_strdup_printf("%d\n", pid
);
91 gboolean res
= atomic_write_file(CFS_PID_FN
, strpid
, strlen(strpid
), 0644, getgid());
97 static cfs_plug_t
*find_plug(const char *path
, char **sub
)
99 g_return_val_if_fail(root_plug
!= NULL
, NULL
);
100 g_return_val_if_fail(path
!= NULL
, NULL
);
102 while(*path
== '/') path
++;
104 cfs_debug("find_plug start %s", path
);
106 char *tmppath
= g_strdup(path
);
107 char *subpath
= tmppath
;
109 cfs_plug_t
*plug
= root_plug
->lookup_plug(root_plug
, &subpath
);
111 cfs_debug("find_plug end %s = %p (%s)", path
, plug
, subpath
);
113 if (subpath
&& subpath
[0])
114 *sub
= g_strdup(subpath
);
121 void *cfs_fuse_init(struct fuse_conn_info
*conn
)
126 static int cfs_fuse_getattr(const char *path
, struct stat
*stbuf
)
128 cfs_debug("enter cfs_fuse_getattr %s", path
);
132 char *subpath
= NULL
;
133 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
135 if (plug
&& plug
->ops
&& plug
->ops
->getattr
) {
136 ret
= plug
->ops
->getattr(plug
, subpath
? subpath
: "", stbuf
);
138 stbuf
->st_gid
= cfs
.gid
;
140 stbuf
->st_mode
&= 0777750; // no access for other users
142 if (path_is_private(path
))
143 stbuf
->st_mode
&= 0777700;
146 cfs_debug("leave cfs_fuse_getattr %s (%d)", path
, ret
);
155 static int cfs_fuse_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
156 off_t offset
, struct fuse_file_info
*fi
)
161 cfs_debug("enter cfs_fuse_readdir %s", path
);
165 char *subpath
= NULL
;
166 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
171 if (plug
->ops
&& plug
->ops
->readdir
)
172 ret
= plug
->ops
->readdir(plug
, subpath
? subpath
: "", buf
, filler
, 0, fi
);
174 cfs_debug("leave cfs_fuse_readdir %s (%d)", path
, ret
);
182 static int cfs_fuse_mkdir(const char *path
, mode_t mode
)
184 cfs_debug("enter cfs_fuse_mkdir %s", path
);
188 char *subpath
= NULL
;
189 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
194 if (subpath
&& plug
->ops
&& plug
->ops
->mkdir
)
195 ret
= plug
->ops
->mkdir(plug
, subpath
, mode
);
198 cfs_debug("leave cfs_fuse_mkdir %s (%d)", path
, ret
);
206 static int cfs_fuse_rmdir(const char *path
)
208 cfs_debug("enter cfs_fuse_rmdir %s", path
);
212 char *subpath
= NULL
;
213 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
218 if (subpath
&& plug
->ops
&& plug
->ops
->rmdir
)
219 ret
= plug
->ops
->rmdir(plug
, subpath
);
222 cfs_debug("leave cfs_fuse_rmdir %s (%d)", path
, ret
);
230 static int cfs_fuse_rename(const char *from
, const char *to
)
232 cfs_debug("enter cfs_fuse_rename from %s to %s", from
, to
);
236 char *sub_from
= NULL
;
237 cfs_plug_t
*plug_from
= find_plug(from
, &sub_from
);
240 cfs_plug_t
*plug_to
= find_plug(to
, &sub_to
);
242 if (!plug_from
|| !plug_to
|| plug_from
!= plug_to
)
245 if (plug_from
->ops
&& plug_from
->ops
->rename
&& sub_from
&& sub_to
)
246 ret
= plug_from
->ops
->rename(plug_from
, sub_from
, sub_to
);
249 cfs_debug("leave cfs_fuse_rename from %s to %s (%d)", from
, to
, ret
);
260 static int cfs_fuse_open(const char *path
, struct fuse_file_info
*fi
)
262 cfs_debug("enter cfs_fuse_open %s", path
);
269 char *subpath
= NULL
;
270 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
272 if (plug
&& plug
->ops
) {
273 if ((subpath
|| !plug
->ops
->readdir
) && plug
->ops
->open
) {
274 ret
= plug
->ops
->open(plug
, subpath
? subpath
: "", fi
);
278 cfs_debug("leave cfs_fuse_open %s (%d)", path
, ret
);
286 static int cfs_fuse_read(const char *path
, char *buf
, size_t size
, off_t offset
,
287 struct fuse_file_info
*fi
)
291 cfs_debug("enter cfs_fuse_read %s %lu %ld", path
, size
, offset
);
295 char *subpath
= NULL
;
296 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
298 if (plug
&& plug
->ops
) {
299 if ((subpath
|| !plug
->ops
->readdir
) && plug
->ops
->read
)
300 ret
= plug
->ops
->read(plug
, subpath
? subpath
: "", buf
, size
, offset
, fi
);
303 cfs_debug("leave cfs_fuse_read %s (%d)", path
, ret
);
311 static int cfs_fuse_write(const char *path
, const char *buf
, size_t size
,
312 off_t offset
, struct fuse_file_info
*fi
)
316 cfs_debug("enter cfs_fuse_write %s %lu %ld", path
, size
, offset
);
320 char *subpath
= NULL
;
321 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
323 if (plug
&& plug
->ops
) {
324 if ((subpath
|| !plug
->ops
->readdir
) && plug
->ops
->write
)
325 ret
= plug
->ops
->write(plug
, subpath
? subpath
: "",
326 buf
, size
, offset
, fi
);
329 cfs_debug("leave cfs_fuse_write %s (%d)", path
, ret
);
337 static int cfs_fuse_truncate(const char *path
, off_t size
)
339 cfs_debug("enter cfs_fuse_truncate %s %ld", path
, size
);
343 char *subpath
= NULL
;
344 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
346 if (plug
&& plug
->ops
) {
347 if ((subpath
|| !plug
->ops
->readdir
) && plug
->ops
->truncate
)
348 ret
= plug
->ops
->truncate(plug
, subpath
? subpath
: "", size
);
351 cfs_debug("leave cfs_fuse_truncate %s (%d)", path
, ret
);
359 static int cfs_fuse_create(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
361 cfs_debug("enter cfs_fuse_create %s", path
);
365 char *subpath
= NULL
;
366 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
371 if (subpath
&& plug
->ops
&& plug
->ops
->create
)
372 ret
= plug
->ops
->create(plug
, subpath
, mode
, fi
);
375 cfs_debug("leave cfs_fuse_create %s (%d)", path
, ret
);
383 static int cfs_fuse_unlink(const char *path
)
385 cfs_debug("enter cfs_fuse_unlink %s", path
);
389 char *subpath
= NULL
;
390 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
395 if (subpath
&& plug
->ops
&& plug
->ops
->unlink
)
396 ret
= plug
->ops
->unlink(plug
, subpath
);
399 cfs_debug("leave cfs_fuse_unlink %s (%d)", path
, ret
);
407 static int cfs_fuse_readlink(const char *path
, char *buf
, size_t max
)
409 cfs_debug("enter cfs_fuse_readlink %s", path
);
413 char *subpath
= NULL
;
414 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
419 if (plug
->ops
&& plug
->ops
->readlink
)
420 ret
= plug
->ops
->readlink(plug
, subpath
? subpath
: "", buf
, max
);
423 cfs_debug("leave cfs_fuse_readlink %s (%d)", path
, ret
);
431 static int cfs_fuse_utimens(const char *path
, const struct timespec tv
[2])
433 cfs_debug("enter cfs_fuse_utimens %s", path
);
437 char *subpath
= NULL
;
438 cfs_plug_t
*plug
= find_plug(path
, &subpath
);
443 if (plug
->ops
&& plug
->ops
->utimens
)
444 ret
= plug
->ops
->utimens(plug
, subpath
? subpath
: "", tv
);
447 cfs_debug("leave cfs_fuse_utimens %s (%d)", path
, ret
);
455 static int cfs_fuse_statfs(const char *path
, struct statvfs
*stbuf
)
457 g_return_val_if_fail(root_plug
!= NULL
, PARAM_CHECK_ERRNO
);
459 cfs_debug("enter cfs_fuse_statfs %s", path
);
463 if (root_plug
&& root_plug
->ops
&& root_plug
->ops
->statfs
)
464 ret
= root_plug
->ops
->statfs(root_plug
, "", stbuf
);
469 static struct fuse_operations fuse_ops
= {
470 .getattr
= cfs_fuse_getattr
,
471 .readdir
= cfs_fuse_readdir
,
472 .mkdir
= cfs_fuse_mkdir
,
473 .rmdir
= cfs_fuse_rmdir
,
474 .rename
= cfs_fuse_rename
,
475 .open
= cfs_fuse_open
,
476 .read
= cfs_fuse_read
,
477 .write
= cfs_fuse_write
,
478 .truncate
= cfs_fuse_truncate
,
479 .create
= cfs_fuse_create
,
480 .unlink
= cfs_fuse_unlink
,
481 .readlink
= cfs_fuse_readlink
,
482 .utimens
= cfs_fuse_utimens
,
483 .statfs
= cfs_fuse_statfs
,
484 .init
= cfs_fuse_init
488 create_dot_version_cb(cfs_plug_t
*plug
)
490 GString
*outbuf
= g_string_new(NULL
);
493 if (cfs_create_version_msg(outbuf
) == 0) {
495 g_string_free(outbuf
, FALSE
);
497 g_string_free(outbuf
, TRUE
);
504 create_dot_members_cb(cfs_plug_t
*plug
)
506 GString
*outbuf
= g_string_new(NULL
);
509 if (cfs_create_memberlist_msg(outbuf
) == 0) {
511 g_string_free(outbuf
, FALSE
);
513 g_string_free(outbuf
, TRUE
);
520 create_dot_vmlist_cb(cfs_plug_t
*plug
)
522 GString
*outbuf
= g_string_new(NULL
);
525 if (cfs_create_vmlist_msg(outbuf
) == 0) {
527 g_string_free(outbuf
, FALSE
);
529 g_string_free(outbuf
, TRUE
);
536 create_dot_rrd_cb(cfs_plug_t
*plug
)
538 GString
*outbuf
= g_string_new(NULL
);
540 cfs_rrd_dump(outbuf
);
541 char *data
= outbuf
->str
;
542 g_string_free(outbuf
, FALSE
);
548 create_dot_clusterlog_cb(cfs_plug_t
*plug
)
550 GString
*outbuf
= g_string_new(NULL
);
552 cfs_cluster_log_dump(outbuf
, NULL
, 50);
553 char *data
= outbuf
->str
;
554 g_string_free(outbuf
, FALSE
);
560 read_debug_setting_cb(cfs_plug_t
*plug
)
562 return g_strdup_printf("%d\n", !!cfs
.debug
);
565 static int write_debug_setting_cb(
575 if (strncmp(buf
, "0\n", 2) == 0) {
577 cfs_message("disable debug mode");
581 } else if (strncmp(buf
, "1\n", 2) == 0) {
583 cfs_message("enable debug mode");
594 create_symlinks(cfs_plug_base_t
*bplug
, const char *nodename
)
596 g_return_if_fail(bplug
!= NULL
);
597 g_return_if_fail(nodename
!= NULL
);
599 char *lnktarget
= g_strdup_printf("nodes/%s", nodename
);
600 cfs_plug_link_t
*lnk
= cfs_plug_link_new("local", lnktarget
);
602 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)lnk
);
604 lnktarget
= g_strdup_printf("nodes/%s/qemu-server", nodename
);
605 lnk
= cfs_plug_link_new("qemu-server", lnktarget
);
607 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)lnk
);
609 lnktarget
= g_strdup_printf("nodes/%s/openvz", nodename
);
610 lnk
= cfs_plug_link_new("openvz", lnktarget
);
612 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)lnk
);
614 cfs_plug_func_t
*fplug
= cfs_plug_func_new(".version", 0440, create_dot_version_cb
, NULL
);
615 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)fplug
);
617 fplug
= cfs_plug_func_new(".members", 0440, create_dot_members_cb
, NULL
);
618 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)fplug
);
620 fplug
= cfs_plug_func_new(".vmlist", 0440, create_dot_vmlist_cb
, NULL
);
621 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)fplug
);
623 fplug
= cfs_plug_func_new(".rrd", 0440, create_dot_rrd_cb
, NULL
);
624 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)fplug
);
626 fplug
= cfs_plug_func_new(".clusterlog", 0440, create_dot_clusterlog_cb
, NULL
);
627 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)fplug
);
629 fplug
= cfs_plug_func_new(".debug", 0640, read_debug_setting_cb
, write_debug_setting_cb
);
630 cfs_plug_base_insert(bplug
, (cfs_plug_t
*)fplug
);
636 lookup_node_ip(const char *nodename
)
638 struct addrinfo
*ainfo
;
639 struct addrinfo ahints
;
640 memset(&ahints
, 0, sizeof(ahints
));
642 if (getaddrinfo(nodename
, NULL
, &ahints
, &ainfo
))
645 if (ainfo
->ai_family
== AF_INET
) {
646 char buf
[INET6_ADDRSTRLEN
];
647 struct sockaddr_in
*sa
= (struct sockaddr_in
*)ainfo
->ai_addr
;
648 inet_ntop(ainfo
->ai_family
, &sa
->sin_addr
, buf
, sizeof(buf
));
649 if (strncmp(buf
, "127.", 4) != 0) {
650 return g_strdup(buf
);
658 int main(int argc
, char *argv
[])
663 gboolean foreground
= FALSE
;
664 gboolean force_local_mode
= FALSE
;
665 gboolean wrote_pidfile
= FALSE
;
666 memdb_t
*memdb
= NULL
;
668 dfsm_t
*status_fsm
= NULL
;
670 openlog("pmxcfs", LOG_PID
, LOG_DAEMON
);
672 g_set_print_handler(glib_print_handler
);
673 g_set_printerr_handler(glib_print_handler
);
674 g_log_set_default_handler(glib_log_handler
, NULL
);
676 GOptionContext
*context
;
677 gboolean opt_quiet
= FALSE
;
679 GOptionEntry entries
[] = {
680 { "debug", 'd', 0, G_OPTION_ARG_NONE
, &cfs
.debug
, "Turn on debug messages", NULL
},
681 { "foreground", 'f', 0, G_OPTION_ARG_NONE
, &foreground
, "Do not daemonize server", NULL
},
682 { "local", 'l', 0, G_OPTION_ARG_NONE
, &force_local_mode
,
683 "Force local mode (ignore cluster.conf, force quorum)", NULL
},
684 { "quiet", 'q', 0, G_OPTION_ARG_NONE
, &opt_quiet
, "Supress console output", NULL
},
688 context
= g_option_context_new ("");
689 g_option_context_add_main_entries (context
, entries
, NULL
);
692 if (!g_option_context_parse (context
, &argc
, &argv
, &err
))
694 cfs_critical("option parsing failed: %s", err
->message
);
698 g_option_context_free(context
);
701 cfs_critical("too many arguments");
706 cfs
.print_to_console
= 0;
708 struct utsname utsname
;
709 if (uname(&utsname
) != 0) {
710 cfs_critical("Unable to read local node name");
714 for (int i
=0; i
< sizeof(utsname
.nodename
); i
++) {
715 if (utsname
.nodename
[i
] =='.') utsname
.nodename
[i
] = 0;
718 cfs
.nodename
= g_strdup(utsname
.nodename
);
720 if (!(cfs
.ip
= lookup_node_ip(cfs
.nodename
))) {
721 cfs_critical("Unable to get local IP address");
725 struct group
*www_data
= getgrnam("www-data");
727 cfs_critical("Unable to get www-data group ID");
730 cfs
.gid
= www_data
->gr_gid
;
734 qb_util_set_log_function(ipc_log_fn
);
738 mkdir(VARLIBDIR
, 0755);
740 if ((lockfd
= open(LOCKFILE
, O_RDWR
|O_CREAT
|O_APPEND
)) == -1) {
741 cfs_critical("unable to create lock '%s': %s", LOCKFILE
, strerror (errno
));
745 for (int i
= 10; i
>= 0; i
--) {
746 if (flock(lockfd
, LOCK_EX
|LOCK_NB
) != 0) {
748 cfs_critical("unable to aquire pmxcfs lock: %s", strerror (errno
));
752 cfs_message("unable to aquire pmxcfs lock - trying again");
760 gboolean create
= !g_file_test(DBFILENAME
, G_FILE_TEST_EXISTS
);
762 if (!(memdb
= memdb_open (DBFILENAME
))) {
763 cfs_critical("memdb_open failed - unable to open database '%s'", DBFILENAME
);
767 // automatically import cluster.conf from host
768 if (create
&& !force_local_mode
) {
771 if (g_file_get_contents(HOST_CLUSTER_CONF_FN
, &cdata
, &clen
, NULL
)) {
773 guint32 mtime
= time(NULL
);
775 memdb_create(memdb
, "/cluster.conf", 0, mtime
);
776 if (memdb_write(memdb
, "/cluster.conf", 0, mtime
, cdata
, clen
, 0, 1) < 0) {
777 cfs_critical("memdb_write failed - unable to import cluster.conf");
783 // does cluster.conf exist?
784 gpointer conf_data
= NULL
;
785 int len
= memdb_read(memdb
, "cluster.conf", &conf_data
);
787 if (force_local_mode
) {
788 cfs_message("forcing local mode (althought cluster.conf exists)");
789 cfs_set_quorate(1, TRUE
);
791 if (!(dcdb
= dcdb_new(memdb
)))
793 dcdb_sync_cluster_conf(memdb
, 1);
796 cfs_debug("using local mode (cluster.conf does not exist)");
797 cfs_set_quorate(1, TRUE
);
799 if (conf_data
) g_free(conf_data
);
801 cfs_plug_memdb_t
*config
= cfs_plug_memdb_new("memdb", memdb
, dcdb
);
803 cfs_plug_base_t
*bplug
= cfs_plug_base_new("", (cfs_plug_t
*)config
);
805 create_symlinks(bplug
, cfs
.nodename
);
807 root_plug
= (cfs_plug_t
*)bplug
;
809 system("umount -f " CFSDIR
" >/dev/null 2>&1");
811 char *fa
[] = { "-f", "-odefault_permissions", "-oallow_other", NULL
};
813 struct fuse_args fuse_args
= FUSE_ARGS_INIT(sizeof (fa
)/sizeof(gpointer
) - 1, fa
);
815 struct fuse_chan
*fuse_chan
= fuse_mount(CFSDIR
, &fuse_args
);
817 cfs_critical("fuse_mount error: %s", strerror(errno
));
821 if (!(fuse
= fuse_new(fuse_chan
, &fuse_args
, &fuse_ops
, sizeof(fuse_ops
), NULL
))) {
822 cfs_critical("fuse_new error: %s", strerror(errno
));
826 fuse_set_signal_handlers(fuse_get_session(fuse
));
828 cfs_message("starting proxmox configuration filesystem (node = %s)",
835 cfs_critical("failed to daemonize program - %s", strerror (errno
));
845 if ((nullfd
= open("/dev/null", O_RDWR
, 0)) != -1) {
853 // do not print to the console after this point
854 cfs
.print_to_console
= 0;
858 write_pidfile(getpid());
861 wrote_pidfile
= TRUE
;
863 cfs_loop_t
*corosync_loop
= cfs_loop_new(fuse
);
865 cfs_service_t
*service_quorum
= NULL
;
866 cfs_service_t
*service_confdb
= NULL
;
867 cfs_service_t
*service_dcdb
= NULL
;
868 cfs_service_t
*service_status
= NULL
;
872 service_quorum
= service_quorum_new();
874 cfs_loop_add_service(corosync_loop
, service_quorum
, QB_LOOP_HIGH
);
876 service_confdb
= service_confdb_new();
878 cfs_loop_add_service(corosync_loop
, service_confdb
, QB_LOOP_MED
);
880 service_dcdb
= service_dfsm_new(dcdb
);
881 cfs_service_set_timer(service_dcdb
, DCDB_VERIFY_TIME
);
883 cfs_loop_add_service(corosync_loop
, service_dcdb
, QB_LOOP_MED
);
885 status_fsm
= cfs_status_dfsm_new();
886 service_status
= service_dfsm_new(status_fsm
);
888 cfs_loop_add_service(corosync_loop
, service_status
, QB_LOOP_LOW
);
892 cfs_loop_start_worker(corosync_loop
);
896 ret
= fuse_loop_mt(fuse
);
898 cfs_message("teardown filesystem");
902 fuse_unmount(CFSDIR
, fuse_chan
);
906 cfs_debug("set stop event loop flag");
908 cfs_loop_stop_worker(corosync_loop
);
910 cfs_loop_destroy(corosync_loop
);
912 cfs_debug("worker finished");
915 service_dfsm_destroy(service_dcdb
);
918 service_confdb_destroy(service_confdb
);
921 service_quorum_destroy(service_quorum
);
924 service_dfsm_destroy(service_status
);
926 sleep(1); /* do not restart too fast */
930 dfsm_destroy(status_fsm
);
941 cfs_message("exit proxmox configuration filesystem (%d)", ret
);
943 cfs_status_cleanup();