]>
git.ipfire.org Git - ipfire-2.x.git/blob - src/misc-progs/addonctrl.c
1 /* This file is part of the IPFire Firewall.
3 * This program is distributed under the terms of the GNU General Public
4 * Licence. See the file COPYING for details.
12 #include <sys/types.h>
20 #define BUFFER_SIZE 1024
22 const char * initd_path
= "/etc/rc.d/init.d" ;
23 const char * enabled_path
= "/etc/rc.d/rc3.d" ;
24 const char * disabled_path
= "/etc/rc.d/rc3.d/off" ;
28 " addonctrl <addon> (start|stop|restart|reload|enable|disable|status|boot-status|list-services) [<service>] \n "
31 " <addon> \t\t Name of the addon to control \n "
32 " <service> \t\t Specific service of the addon to control (optional) \n "
33 " \t\t\t By default the requested action is performed on all related services. See also 'list-services'. \n "
34 " start \t\t\t Start service(s) of the addon \n "
35 " stop \t\t\t Stop service(s) of the addon \n "
36 " restart \t\t Restart service(s) of the addon \n "
37 " enable \t\t Enable service(s) of the addon to start at boot \n "
38 " disable \t\t Disable service(s) of the addon to start at boot \n "
39 " status \t\t Display current state of addon service(s) \n "
40 " boot-status \t\t Display wether service(s) is enabled on boot or not \n "
41 " list-services \t\t Display a list of services related to the addon" ;
43 // Find a file <path> using <filepattern> as glob pattern.
44 // Returns the found filename or NULL if not found
45 char * find_file_in_dir ( const char * path
, const char * filepattern
)
54 while (! found
&& entry
) {
55 if ( fnmatch ( filepattern
, entry
-> d_name
, FNM_PATHNAME
) == 0 )
56 found
= strdup ( entry
-> d_name
);
67 // Reads Services metadata for <addon>.
68 // Returns pointer to array of strings containing the services for <addon>,
69 // sets <servicescnt> to the number of found services and
70 // sets <returncode> to
71 // -1 - system error occured, check errno
72 // 0 - success - if returned array is NULL, there are no services for <addon>
73 // 1 - addon was not found
74 char ** get_addon_services ( const char * addon
, int * servicescnt
, const char * filter
, int * returncode
) {
75 const char * metafile_prefix
= "/opt/pakfire/db/installed/meta-" ;
76 const char * metadata_key
= "Services" ;
77 const char * keyvalue_delim
= ":" ;
78 const char * service_delim
= " " ;
80 char ** services
= NULL
;
85 char * metafile
= NULL
;
95 * returncode
= asprintf (& metafile
, "%s%s" , metafile_prefix
, addon
);
96 if (* returncode
== - 1 )
99 FILE * fp
= fopen ( metafile
, "r" );
101 if ( errno
== ENOENT
) {
109 // Get initscript(s) for addon from meta-file
110 while ( getline (& line
, & line_len
, fp
) != - 1 && ! services
) {
112 char * newline
= strchr ( line
, ' \n ' );
113 if ( newline
) * newline
= 0 ;
115 // Split line in key and values; Check for required key.
116 token
= strtok ( line
, keyvalue_delim
);
117 if (! token
|| strcmp ( token
, metadata_key
) != 0 )
120 // Get values for matched key. Stop if no values are present.
121 token
= strtok ( NULL
, keyvalue_delim
);
125 // Split values and put each service in services array
126 service
= strtok ( token
, service_delim
);
128 if (! filter
|| strcmp ( filter
, service
) == 0 ) {
129 services
= reallocarray ( services
, i
+ 1 , sizeof ( char *));
135 services
[ i
] = strdup ( service
);
136 if (! services
[ i
++]) {
142 service
= strtok ( NULL
, service_delim
);
146 if ( line
) free ( line
);
155 // Calls initscript <service> with parameter <action>
156 int initscript_action ( const char * service
, const char * action
) {
157 char * initscript
= NULL
;
164 r
= asprintf (& initscript
, "%s/%s" , initd_path
, service
);
166 r
= run ( initscript
, argv
);
168 if ( initscript
) free ( initscript
);
173 // Move an initscript with filepattern from <src_path> to <dest_path>
175 // -1: Error during move or memory allocation. Details in errno
177 // 1: file was not moved, but is already in <dest_path>
178 // 2: file does not exist in either in <src_path> or <dest_path>
179 int move_initscript_by_pattern ( const char * src_path
, const char * dest_path
, const char * filepattern
) {
183 char * filename
= NULL
;
185 filename
= find_file_in_dir ( src_path
, filepattern
);
188 r
= asprintf (& src
, "%s/%s" , src_path
, filename
);
190 r
= asprintf (& dest
, "%s/%s" , dest_path
, filename
);
192 r
= rename ( src
, dest
);
196 if ( dest
) free ( dest
);
198 // check if file is already in dest
199 filename
= find_file_in_dir ( dest_path
, filepattern
);
204 if ( filename
) free ( filename
);
209 // Enable/Disable addon service(s) by moving initscript symlink from/to disabled_path
211 // -1 - System error occured. Check errno.
213 // 1 - Service was already enabled/disabled
214 // 2 - Service has no valid runlevel symlink
215 int toggle_service ( const char * service
, const char * action
) {
216 const char * src_path
, * dest_path
;
217 char * filepattern
= NULL
;
220 if ( asprintf (& filepattern
, "S??%s" , service
) == - 1 )
223 if ( strcmp ( action
, "enable" ) == 0 ) {
224 src_path
= disabled_path
;
225 dest_path
= enabled_path
;
227 src_path
= enabled_path
;
228 dest_path
= disabled_path
;
231 // Ensure disabled_path exists
232 r
= mkdir ( disabled_path
, S_IRWXU
+ S_IRGRP
+ S_IXGRP
+ S_IROTH
+ S_IXOTH
);
233 if ( r
!= - 1 || errno
== EEXIST
)
234 r
= move_initscript_by_pattern ( src_path
, dest_path
, filepattern
);
241 // Return whether <service> is enabled or disabled on boot
243 // -1 - System error occured. Check errno.
244 // 0 - <service> is disabled on boot
245 // 1 - <service> is enabled on boot
246 // 2 - Runlevel suymlink for <service> was not found
247 int get_boot_status ( char * service
) {
248 char * filepattern
= NULL
;
249 char * filename
= NULL
;
252 if ( asprintf (& filepattern
, "S??%s" , service
) == - 1 )
255 filename
= find_file_in_dir ( enabled_path
, filepattern
);
259 filename
= find_file_in_dir ( disabled_path
, filepattern
);
266 if ( filename
) free ( filename
);
272 int main ( int argc
, char * argv
[]) {
273 char ** services
= NULL
;
275 char * addon
= argv
[ 1 ];
276 char * action
= argv
[ 2 ];
277 char * service_filter
= NULL
;
284 fprintf ( stderr
, " \n Missing arguments. \n\n %s \n\n " , usage
);
288 // Ignore filter when list of services is requested
289 if ( argc
== 4 && strcmp ( action
, "list-services" ) != 0 )
290 service_filter
= argv
[ 3 ];
292 if ( strlen ( addon
) > 32 ) {
293 fprintf ( stderr
, " \n String too large. \n\n %s \n\n " , usage
);
297 // Check if the input argument is valid
298 if (! is_valid_argument_alnum ( addon
)) {
299 fprintf ( stderr
, "Invalid add-on name: %s. \n " , addon
);
303 // Get initscript name(s) from addon metadata
305 services
= get_addon_services ( addon
, & servicescnt
, service_filter
, & rc
);
309 fprintf ( stderr
, " \n System error occured. (Error: %m) \n\n " );
314 fprintf ( stderr
, " \n No service '%s' found for addon '%s'. Use 'list-services' to get a list of available services \n\n %s \n\n " , service_filter
, addon
, usage
);
316 fprintf ( stderr
, " \n Addon '%s' has no services. \n\n " , addon
);
320 fprintf ( stderr
, " \n Addon '%s' not found. \n\n %s \n\n " , addon
, usage
);
326 // Handle requested action
327 if ( strcmp ( action
, "start" ) == 0 ||
328 strcmp ( action
, "stop" ) == 0 ||
329 strcmp ( action
, "restart" ) == 0 ||
330 strcmp ( action
, "reload" ) == 0 ||
331 strcmp ( action
, "status" ) == 0 ) {
333 for ( int i
= 0 ; i
< servicescnt
; i
++) {
334 if ( initscript_action ( services
[ i
], action
) < 0 ) {
336 fprintf ( stderr
, " \n System error occured. (Error: %m) \n\n " );
341 } else if ( strcmp ( action
, "enable" ) == 0 ||
342 strcmp ( action
, "disable" ) == 0 ) {
344 for ( int i
= 0 ; i
< servicescnt
; i
++) {
345 switch ( r
= toggle_service ( services
[ i
], action
)) {
347 fprintf ( stderr
, " \n System error occured. (Error: %m) \n\n " );
351 printf ( "%sd service %s \n " , action
, services
[ i
]);
355 fprintf ( stderr
, "Service %s is already %sd. Skipping... \n " , services
[ i
], action
);
359 fprintf ( stderr
, " \n Unable to %s service %s. (Service has no valid runlevel symlink). \n\n " , action
, services
[ i
]);
363 // Break from for loop in case of a system error.
370 } else if ( strcmp ( action
, "boot-status" ) == 0 ) {
371 // Print boot status for each service
372 for ( int i
= 0 ; i
< servicescnt
; i
++) {
373 switch ( get_boot_status ( services
[ i
])) {
376 fprintf ( stderr
, " \n System error occured. (Error: %m) \n\n " );
380 printf ( "%s is disabled on boot. \n " , services
[ i
]);
384 printf ( "%s is enabled on boot. \n " , services
[ i
]);
388 printf ( "%s is not available for boot. (Service has no valid symlink in either %s or %s). \n " , services
[ i
], enabled_path
, disabled_path
);
392 // Break from for loop in case of an error
398 } else if ( strcmp ( action
, "list-services" ) == 0 ) {
399 // List all services for addon
400 printf ( " \n Services for addon %s: \n " , addon
);
401 for ( int i
= 0 ; i
< servicescnt
; i
++) {
402 printf ( " %s \n " , services
[ i
]);
407 fprintf ( stderr
, " \n Bad argument given. \n\n %s \n\n " , usage
);
412 for ( int i
= 0 ; i
< servicescnt
; i
++)