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