Line data Source code
1 : #include "configure.h"
2 :
3 : #include <sys/stat.h>
4 :
5 : void
6 : configure_cmd_args( int * pargc,
7 : char *** pargv,
8 0 : args_t * args) {
9 0 : char * usage = "usage: configure <init|check|fini> <stage>...";
10 0 : if( FD_UNLIKELY( *pargc < 2 ) ) FD_LOG_ERR(( "%s", usage ));
11 :
12 0 : if( FD_LIKELY( !strcmp( *pargv[ 0 ], "check" ) ) ) args->configure.command = CONFIGURE_CMD_CHECK;
13 0 : else if( FD_LIKELY( !strcmp( *pargv[ 0 ], "init" ) ) ) args->configure.command = CONFIGURE_CMD_INIT;
14 0 : else if( FD_LIKELY( !strcmp( *pargv[ 0 ], "fini" ) ) ) args->configure.command = CONFIGURE_CMD_FINI;
15 0 : else FD_LOG_ERR(( "unrecognized command `%s`, %s", *pargv[0], usage ));
16 :
17 0 : (*pargc)--;
18 0 : (*pargv)++;
19 :
20 0 : for( int i=0; i<*pargc; i++ ) {
21 0 : if( FD_UNLIKELY( !strcmp( (*pargv)[ i ], "all" ) ) ) {
22 0 : (*pargc) -= i + 1;
23 0 : (*pargv) += i + 1;
24 0 : for( int j=0; j<CONFIGURE_STAGE_COUNT; j++) args->configure.stages[ j ] = STAGES[ j ];
25 0 : return;
26 0 : }
27 0 : }
28 :
29 0 : if( FD_UNLIKELY( *pargc >= CONFIGURE_STAGE_COUNT ) ) FD_LOG_ERR(( "too many stages specified" ));
30 :
31 0 : ulong nstage = 0;
32 0 : while( *pargc ) {
33 0 : int found = 0;
34 0 : for( configure_stage_t ** stage = STAGES; *stage; stage++ ) {
35 0 : if( FD_UNLIKELY( !strcmp( (*pargv)[0], (*stage)->name ) ) ) {
36 0 : args->configure.stages[ nstage++ ] = *stage;
37 0 : found = 1;
38 0 : break;
39 0 : }
40 0 : }
41 :
42 0 : if( FD_UNLIKELY( !found ) ) FD_LOG_ERR(( "unknown configure stage: %s", (*pargv)[0] ));
43 :
44 0 : (*pargc)--;
45 0 : (*pargv)++;
46 0 : }
47 0 : return;
48 0 : }
49 :
50 : void
51 : configure_cmd_perm( args_t * args,
52 : fd_caps_ctx_t * caps,
53 0 : config_t * const config ) {
54 0 : for( configure_stage_t ** stage = args->configure.stages; *stage; stage++ ) {
55 0 : switch( args->configure.command ) {
56 0 : case CONFIGURE_CMD_INIT: {
57 0 : int enabled = !(*stage)->enabled || (*stage)->enabled( config );
58 0 : if( FD_LIKELY( enabled && (*stage)->check( config ).result != CONFIGURE_OK ) )
59 0 : if( FD_LIKELY( (*stage)->init_perm ) ) (*stage)->init_perm( caps, config );
60 0 : break;
61 0 : }
62 0 : case CONFIGURE_CMD_CHECK:
63 0 : break;
64 0 : case CONFIGURE_CMD_FINI: {
65 0 : int enabled = !(*stage)->enabled || (*stage)->enabled( config );
66 0 : if( FD_LIKELY( enabled && (*stage)->check( config ).result != CONFIGURE_NOT_CONFIGURED ) )
67 0 : if( FD_LIKELY( (*stage)->fini_perm ) ) (*stage)->fini_perm( caps, config );
68 0 : break;
69 0 : }
70 0 : }
71 0 : }
72 0 : }
73 :
74 : static int
75 : configure_stage( configure_stage_t * stage,
76 : configure_cmd_t command,
77 0 : config_t * const config ) {
78 0 : if( FD_UNLIKELY( stage->enabled && !stage->enabled( config ) ) ) {
79 0 : FD_LOG_NOTICE(( "%s ... skipping .. not enabled", stage->name ));
80 0 : return 0;
81 0 : }
82 :
83 0 : switch( command ) {
84 0 : case CONFIGURE_CMD_INIT: {
85 0 : configure_result_t result = stage->check( config );
86 0 : if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) )
87 0 : FD_LOG_NOTICE(( "%s ... unconfigured ... %s", stage->name, result.message ));
88 0 : else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED ) ) {
89 0 : if( FD_LIKELY( stage->fini ) ) {
90 0 : FD_LOG_NOTICE(( "%s ... undoing ... %s", stage->name, result.message ));
91 0 : stage->fini( config, 1 );
92 0 : } else if( FD_UNLIKELY( !stage->always_recreate ) ) {
93 0 : FD_LOG_ERR(( "%s ... does not support undo but was not valid ... %s", stage->name, result.message ));
94 0 : }
95 :
96 0 : result = stage->check( config );
97 0 : if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate ) )
98 0 : FD_LOG_ERR(( "%s ... clean was unable to get back to an unconfigured state ... %s", stage->name, result.message ));
99 0 : } else {
100 0 : FD_LOG_NOTICE(( "%s ... already valid", stage->name ));
101 0 : return 0;
102 0 : }
103 :
104 0 : FD_LOG_NOTICE(( "%s ... configuring", stage->name ));
105 0 : if( FD_LIKELY( stage->init ) ) stage->init( config );
106 :
107 0 : result = stage->check( config );
108 0 : if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) )
109 0 : FD_LOG_ERR(( "%s ... tried to initialize but didn't do anything ... %s", stage->name, result.message ));
110 0 : else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate ) )
111 0 : FD_LOG_ERR(( "%s ... tried to initialize but was still unconfigured ... %s", stage->name, result.message ));
112 0 : break;
113 0 : }
114 0 : case CONFIGURE_CMD_CHECK: {
115 0 : configure_result_t result = stage->check( config );
116 0 : if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) ) {
117 0 : FD_LOG_WARNING(( "%s ... not configured ... %s", stage->name, result.message ));
118 0 : return 1;
119 0 : } else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED ) ) {
120 0 : if( FD_UNLIKELY( !stage->always_recreate ) ) {
121 0 : FD_LOG_WARNING(( "%s ... invalid ... %s", stage->name, result.message ));
122 0 : return 1;
123 0 : } else {
124 0 : FD_LOG_NOTICE(( "%s ... not configured ... must always be recreated", stage->name ));
125 0 : }
126 0 : }
127 0 : break;
128 0 : }
129 0 : case CONFIGURE_CMD_FINI: {
130 0 : configure_result_t result = stage->check( config );
131 :
132 0 : if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) ) {
133 0 : FD_LOG_NOTICE(( "%s ... not configured ... %s", stage->name, result.message ));
134 0 : return 0;
135 0 : } else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate && !stage->fini ) ) {
136 0 : FD_LOG_ERR(( "%s ... not valid ... %s", stage->name, result.message ));
137 0 : }
138 :
139 0 : FD_LOG_NOTICE(( "%s ... finishing", stage->name ));
140 0 : if( FD_LIKELY( stage->fini ) ) stage->fini( config, 0 );
141 :
142 0 : result = stage->check( config );
143 0 : if( FD_UNLIKELY( result.result == CONFIGURE_OK && stage->init && stage->fini ) ) {
144 : /* if the step does nothing, it's fine if it's fully configured
145 : after being undone */
146 0 : FD_LOG_ERR(( "%s ... not undone", stage->name ));
147 0 : } else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate ) ) {
148 0 : FD_LOG_ERR(( "%s ... invalid ... %s", stage->name, result.message ));
149 0 : }
150 0 : break;
151 0 : }
152 0 : }
153 :
154 0 : return 0;
155 0 : }
156 :
157 : void
158 : configure_cmd_fn( args_t * args,
159 0 : config_t * const config ) {
160 0 : int error = 0;
161 :
162 0 : if( FD_LIKELY( (configure_cmd_t)args->configure.command != CONFIGURE_CMD_FINI ) ) {
163 0 : for( configure_stage_t ** stage = args->configure.stages; *stage; stage++ ) {
164 0 : if( FD_UNLIKELY( configure_stage( *stage, (configure_cmd_t)args->configure.command, config ) ) ) error = 1;
165 0 : }
166 0 : } else {
167 0 : ulong i;
168 0 : for( i=0; args->configure.stages[ i ]; i++ ) ;
169 0 : if( FD_LIKELY( i > 0 ) ) {
170 0 : for( ulong j=0; j<i; j++ ) {
171 0 : if( FD_UNLIKELY( configure_stage( args->configure.stages[ i-1-j ], (configure_cmd_t)args->configure.command, config ) ) ) error = 1;
172 0 : }
173 0 : }
174 0 : }
175 :
176 :
177 0 : if( FD_UNLIKELY( error ) ) FD_LOG_ERR(( "failed to configure some stages" ));
178 0 : }
179 :
180 : static configure_result_t
181 : check_path( const char * path,
182 : uint expected_uid,
183 : uint expected_gid,
184 : uint expected_mode,
185 0 : int expected_dir ) {
186 0 : struct stat st;
187 0 : if( FD_UNLIKELY( stat( path, &st ) ) ) {
188 0 : if( FD_LIKELY( errno == ENOENT ) ) PARTIALLY_CONFIGURED( "path `%s` does not exist", path );
189 0 : PARTIALLY_CONFIGURED( "failed to stat `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) );
190 0 : }
191 0 : if( FD_UNLIKELY( expected_dir && !S_ISDIR( st.st_mode ) ) )
192 0 : PARTIALLY_CONFIGURED( "path `%s` is a file, not a directory", path );
193 0 : if( FD_UNLIKELY( !expected_dir && S_ISDIR( st.st_mode ) ) )
194 0 : PARTIALLY_CONFIGURED( "path `%s` is a directory, not a file", path );
195 :
196 0 : if( FD_UNLIKELY( st.st_uid != expected_uid ) )
197 0 : PARTIALLY_CONFIGURED( "path `%s` has uid %u, expected %u", path, st.st_uid, expected_uid );
198 0 : if( FD_UNLIKELY( st.st_gid != expected_gid ) )
199 0 : PARTIALLY_CONFIGURED( "path `%s` has gid %u, expected %u", path, st.st_gid, expected_gid );
200 0 : if( FD_UNLIKELY( st.st_mode != expected_mode ) )
201 0 : PARTIALLY_CONFIGURED( "path `%s` has mode %o, expected %o", path, st.st_mode, expected_mode );
202 :
203 0 : CONFIGURE_OK();
204 0 : }
205 :
206 : configure_result_t
207 : check_dir( const char * path,
208 : uint uid,
209 : uint gid,
210 0 : uint mode ) {
211 0 : return check_path( path, uid, gid, mode, 1 );
212 0 : }
213 :
214 : configure_result_t
215 : check_file( const char * path,
216 : uint uid,
217 : uint gid,
218 0 : uint mode ) {
219 0 : return check_path( path, uid, gid, mode, 0 );
220 0 : }
|