Line data Source code
1 : #include "../../../shared/commands/configure/configure.h"
2 : #include "../../../platform/fd_file_util.h"
3 :
4 : #include <errno.h>
5 : #include <fcntl.h> /* open */
6 : #include <unistd.h> /* fchown, close */
7 : #include <sys/stat.h> /* fchmod */
8 : #include <sys/statvfs.h> /* fstatvfs */
9 :
10 : static int
11 0 : enabled( config_t const * config ) {
12 0 : return !config->firedancer.accounts.in_memory_only;
13 0 : }
14 :
15 : static void
16 0 : init( config_t const * config ) {
17 0 : FD_LOG_NOTICE(( "RUN: `mkdir -p %s`", config->paths.accounts ));
18 0 : if( FD_UNLIKELY( -1==fd_file_util_mkdir_all( config->paths.accounts, config->uid, config->gid, 0 ) ) ) {
19 0 : FD_LOG_ERR(( "fd_file_util_mkdir_all(`%s`) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) ));
20 0 : }
21 :
22 0 : FD_LOG_NOTICE(( "RUN: `touch %s", config->paths.accounts ));
23 0 : int vinyl_fd = open( config->paths.accounts, O_RDWR|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR );
24 0 : if( FD_UNLIKELY( vinyl_fd<0 ) ) {
25 0 : FD_LOG_ERR(( "open(`%s`,O_RDWR|O_CREAT|O_CLOEXEC,S_IRUSR|S_IWUSR) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) ));
26 0 : }
27 :
28 : // FD_LOG_NOTICE(( "RUN: `chown %u:%u %s`", config->uid, config->gid, config->paths.accounts ));
29 0 : if( FD_UNLIKELY( fchown( vinyl_fd, config->uid, config->gid )<0 ) ) {
30 0 : FD_LOG_ERR(( "chown(`%s`,%u:%u) failed (%i-%s)", config->paths.accounts, config->uid, config->gid, errno, fd_io_strerror( errno ) ));
31 0 : }
32 :
33 : // FD_LOG_NOTICE(( "RUN: `chmod 0600 %s`", config->paths.accounts ));
34 0 : if( FD_UNLIKELY( fchmod( vinyl_fd, S_IRUSR|S_IWUSR )<0 ) ) {
35 0 : FD_LOG_ERR(( "chmod(`%s`,S_IRUSR|S_IWUSR) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) ));
36 0 : }
37 0 : struct stat st;
38 0 : if( FD_UNLIKELY( 0!=fstat( vinyl_fd, &st ) ) ) {
39 0 : FD_LOG_ERR(( "fstat(`%s`) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) ));
40 0 : }
41 :
42 0 : ulong bstream_sz = config->firedancer.accounts.file_size_gib<<30;
43 0 : if( (ulong)st.st_size < bstream_sz ) {
44 0 : struct statvfs fs;
45 0 : if( FD_UNLIKELY( 0!=fstatvfs( vinyl_fd, &fs ) ) ) {
46 0 : FD_LOG_ERR(( "fstatvfs(`%s`) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) ));
47 0 : }
48 0 : ulong avail = (ulong)fs.f_bavail * (ulong)fs.f_frsize;
49 0 : ulong need = bstream_sz - (ulong)st.st_size;
50 0 : if( FD_UNLIKELY( avail<need ) ) {
51 0 : FD_LOG_ERR(( "insufficient disk space for accounts database `%s` "
52 0 : "(need %lu GiB, available %lu GiB)",
53 0 : config->paths.accounts, (need>>30)+1, avail>>30 ));
54 0 : }
55 0 : FD_LOG_NOTICE(( "RUN: `fallocate -l %lu %s`", bstream_sz, config->paths.accounts ));
56 0 : int err = posix_fallocate( vinyl_fd, 0L, (long)bstream_sz );
57 0 : if( FD_UNLIKELY( err ) ) {
58 0 : FD_LOG_ERR(( "posix_fallocate(`%s`,%lu MiB) failed (%i-%s)", config->paths.accounts, bstream_sz>>20, err, fd_io_strerror( err ) ));
59 0 : }
60 0 : }
61 :
62 0 : if( FD_UNLIKELY( close( vinyl_fd )<0 ) ) {
63 0 : FD_LOG_ERR(( "close(`%s`) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) ));
64 0 : }
65 0 : }
66 :
67 : static int
68 : fini( config_t const * config,
69 0 : int pre_init ) {
70 0 : (void)pre_init;
71 :
72 0 : FD_LOG_NOTICE(( "RUN: `rm %s`", config->paths.accounts ));
73 0 : if( FD_UNLIKELY( unlink( config->paths.accounts )<0 ) ) {
74 0 : FD_LOG_ERR(( "unlink(`%s`) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) ));
75 0 : }
76 0 : return 1;
77 0 : }
78 :
79 : static configure_result_t
80 : check( config_t const * config,
81 0 : int check_type FD_PARAM_UNUSED ) {
82 0 : struct stat st;
83 0 : if( FD_UNLIKELY( 0!=stat( config->paths.accounts, &st ) ) ) {
84 0 : if( errno==ENOENT ) NOT_CONFIGURED( "`%s` does not exist", config->paths.accounts );
85 0 : else PARTIALLY_CONFIGURED( "stat(`%s`) failed (%i-%s)", config->paths.accounts, errno, fd_io_strerror( errno ) );
86 0 : }
87 :
88 0 : ulong bstream_sz = config->firedancer.accounts.file_size_gib<<30;
89 0 : if( FD_UNLIKELY( (ulong)st.st_size < bstream_sz ) )
90 0 : PARTIALLY_CONFIGURED( "accounts database `%s` needs to be resized (have %lu GiB, want %lu GiB)", config->paths.accounts, (ulong)(st.st_size>>30), config->firedancer.accounts.file_size_gib );
91 :
92 0 : CHECK( check_file( config->paths.accounts, config->uid, config->gid, S_IFREG | S_IRUSR | S_IWUSR ) );
93 0 : CONFIGURE_OK();
94 0 : }
95 :
96 : configure_stage_t fd_cfg_stage_accdb = {
97 : .name = "accdb",
98 : .enabled = enabled,
99 : .init = init,
100 : .fini = fini,
101 : .check = check,
102 : };
|