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