2017-11-18 19:09:20 +03:00
/* SPDX-License-Identifier: LGPL-2.1+ */
2014-06-04 03:57:11 +04:00
2015-09-23 04:01:06 +03:00
# include <getopt.h>
2014-06-04 03:57:11 +04:00
# include <stdio.h>
# include <stdlib.h>
2015-10-27 05:01:06 +03:00
# include "alloc-util.h"
2014-06-04 03:57:11 +04:00
# include "log.h"
2015-10-24 23:58:24 +03:00
# include "string-util.h"
2014-07-08 00:23:00 +04:00
# include "strv.h"
2015-09-23 04:01:06 +03:00
# include "unit-name.h"
2014-06-04 03:57:11 +04:00
2014-07-08 00:23:00 +04:00
static enum {
ACTION_ESCAPE ,
ACTION_UNESCAPE ,
ACTION_MANGLE
} arg_action = ACTION_ESCAPE ;
static const char * arg_suffix = NULL ;
static const char * arg_template = NULL ;
static bool arg_path = false ;
2016-10-31 01:49:15 +03:00
static bool arg_instance = false ;
2014-07-08 00:23:00 +04:00
2014-08-02 19:12:21 +04:00
static void help ( void ) {
2014-07-08 00:23:00 +04:00
printf ( " %s [OPTIONS...] [NAME...] \n \n "
2017-07-14 19:39:18 +03:00
" Escape strings for usage in systemd unit names. \n \n "
2014-07-08 00:23:00 +04:00
" -h --help Show this help \n "
" --version Show package version \n "
" --suffix=SUFFIX Unit suffix to append to escaped strings \n "
" --template=TEMPLATE Insert strings as instance into template \n "
2016-10-31 01:49:15 +03:00
" --instance With --unescape, show just the instance part \n "
2014-07-08 00:23:00 +04:00
" -u --unescape Unescape strings \n "
" -m --mangle Mangle strings \n "
2014-08-02 19:12:21 +04:00
" -p --path When escaping/unescaping assume the string is a path \n "
, program_invocation_short_name ) ;
2014-07-08 00:23:00 +04:00
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_VERSION = 0x100 ,
ARG_SUFFIX ,
ARG_TEMPLATE
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
{ " version " , no_argument , NULL , ARG_VERSION } ,
{ " suffix " , required_argument , NULL , ARG_SUFFIX } ,
{ " template " , required_argument , NULL , ARG_TEMPLATE } ,
{ " unescape " , no_argument , NULL , ' u ' } ,
{ " mangle " , no_argument , NULL , ' m ' } ,
{ " path " , no_argument , NULL , ' p ' } ,
2016-10-31 01:49:15 +03:00
{ " instance " , no_argument , NULL , ' i ' } ,
2014-07-08 00:23:00 +04:00
{ }
} ;
int c ;
assert ( argc > = 0 ) ;
assert ( argv ) ;
2014-08-02 19:12:21 +04:00
while ( ( c = getopt_long ( argc , argv , " hump " , options , NULL ) ) > = 0 )
2014-07-08 00:23:00 +04:00
switch ( c ) {
case ' h ' :
2014-08-02 19:12:21 +04:00
help ( ) ;
return 0 ;
2014-07-08 00:23:00 +04:00
case ARG_VERSION :
2015-09-23 04:01:06 +03:00
return version ( ) ;
2014-07-08 00:23:00 +04:00
case ARG_SUFFIX :
if ( unit_type_from_string ( optarg ) < 0 ) {
log_error ( " Invalid unit suffix type %s. " , optarg ) ;
return - EINVAL ;
}
arg_suffix = optarg ;
break ;
case ARG_TEMPLATE :
2015-04-30 21:21:00 +03:00
if ( ! unit_name_is_valid ( optarg , UNIT_NAME_TEMPLATE ) ) {
2014-07-08 00:23:00 +04:00
log_error ( " Template name %s is not valid. " , optarg ) ;
return - EINVAL ;
}
arg_template = optarg ;
break ;
case ' u ' :
arg_action = ACTION_UNESCAPE ;
break ;
case ' m ' :
arg_action = ACTION_MANGLE ;
break ;
case ' p ' :
arg_path = true ;
break ;
2016-10-31 01:49:15 +03:00
case ' i ' :
arg_instance = true ;
break ;
2014-07-08 00:23:00 +04:00
case ' ? ' :
return - EINVAL ;
default :
assert_not_reached ( " Unhandled option " ) ;
}
2014-06-04 03:57:11 +04:00
2014-07-08 00:23:00 +04:00
if ( optind > = argc ) {
log_error ( " Not enough arguments. " ) ;
return - EINVAL ;
2014-06-04 03:57:11 +04:00
}
2014-07-08 00:23:00 +04:00
if ( arg_template & & arg_suffix ) {
log_error ( " --suffix= and --template= may not be combined. " ) ;
return - EINVAL ;
}
2016-10-30 17:43:01 +03:00
if ( ( arg_template | | arg_suffix ) & & arg_action = = ACTION_MANGLE ) {
log_error ( " --suffix= and --template= are not compatible with --mangle. " ) ;
return - EINVAL ;
}
if ( arg_suffix & & arg_action = = ACTION_UNESCAPE ) {
log_error ( " --suffix is not compatible with --unescape. " ) ;
2014-07-08 00:23:00 +04:00
return - EINVAL ;
}
if ( arg_path & & ! IN_SET ( arg_action , ACTION_ESCAPE , ACTION_UNESCAPE ) ) {
log_error ( " --path may not be combined with --mangle. " ) ;
return - EINVAL ;
}
2016-10-31 01:49:15 +03:00
if ( arg_instance & & arg_action ! = ACTION_UNESCAPE ) {
log_error ( " --instance must be used in conjunction with --unescape. " ) ;
return - EINVAL ;
}
if ( arg_instance & & arg_template ) {
log_error ( " --instance may not be combined with --template. " ) ;
return - EINVAL ;
}
2014-07-08 00:23:00 +04:00
return 1 ;
}
int main ( int argc , char * argv [ ] ) {
char * * i ;
int r ;
log_parse_environment ( ) ;
log_open ( ) ;
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
goto finish ;
STRV_FOREACH ( i , argv + optind ) {
_cleanup_free_ char * e = NULL ;
switch ( arg_action ) {
case ACTION_ESCAPE :
2015-04-30 21:21:00 +03:00
if ( arg_path ) {
r = unit_name_path_escape ( * i , & e ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to escape string: %m " ) ;
goto finish ;
}
} else {
2014-07-08 00:23:00 +04:00
e = unit_name_escape ( * i ) ;
2015-04-30 21:21:00 +03:00
if ( ! e ) {
r = log_oom ( ) ;
goto finish ;
}
2014-07-08 00:23:00 +04:00
}
if ( arg_template ) {
char * x ;
2015-04-30 21:21:00 +03:00
r = unit_name_replace_instance ( arg_template , e , & x ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to replace instance: %m " ) ;
2014-07-08 00:23:00 +04:00
goto finish ;
}
free ( e ) ;
e = x ;
} else if ( arg_suffix ) {
char * x ;
2016-10-23 18:43:27 +03:00
x = strjoin ( e , " . " , arg_suffix ) ;
2014-07-08 00:23:00 +04:00
if ( ! x ) {
r = log_oom ( ) ;
goto finish ;
}
free ( e ) ;
e = x ;
}
break ;
2016-10-30 17:43:01 +03:00
case ACTION_UNESCAPE : {
_cleanup_free_ char * name = NULL ;
2016-10-31 01:49:15 +03:00
if ( arg_template | | arg_instance ) {
2016-10-30 17:43:01 +03:00
_cleanup_free_ char * template = NULL ;
r = unit_name_to_instance ( * i , & name ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to extract instance: %m " ) ;
goto finish ;
}
if ( isempty ( name ) ) {
log_error ( " Unit %s is missing the instance name. " , * i ) ;
r = - EINVAL ;
goto finish ;
}
r = unit_name_template ( * i , & template ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to extract template: %m " ) ;
goto finish ;
}
2016-10-31 01:49:15 +03:00
if ( arg_template & & ! streq ( arg_template , template ) ) {
2016-10-30 17:43:01 +03:00
log_error ( " Unit %s template %s does not match specified template %s. " , * i , template , arg_template ) ;
r = - EINVAL ;
goto finish ;
}
} else {
name = strdup ( * i ) ;
if ( ! name ) {
r = log_oom ( ) ;
goto finish ;
}
}
2014-07-08 00:23:00 +04:00
if ( arg_path )
2016-10-30 17:43:01 +03:00
r = unit_name_path_unescape ( name , & e ) ;
2014-07-08 00:23:00 +04:00
else
2016-10-30 17:43:01 +03:00
r = unit_name_unescape ( name , & e ) ;
2014-07-08 00:23:00 +04:00
2015-04-30 21:21:00 +03:00
if ( r < 0 ) {
log_error_errno ( r , " Failed to unescape string: %m " ) ;
2014-07-08 00:23:00 +04:00
goto finish ;
}
break ;
2016-10-30 17:43:01 +03:00
}
2014-07-08 00:23:00 +04:00
case ACTION_MANGLE :
2018-03-21 17:26:47 +03:00
r = unit_name_mangle ( * i , 0 , & e ) ;
2015-04-30 21:21:00 +03:00
if ( r < 0 ) {
log_error_errno ( r , " Failed to mangle name: %m " ) ;
2014-07-08 00:23:00 +04:00
goto finish ;
}
break ;
}
if ( i ! = argv + optind )
fputc ( ' ' , stdout ) ;
2014-06-04 03:57:11 +04:00
2014-07-08 00:23:00 +04:00
fputs ( e , stdout ) ;
2014-06-04 03:57:11 +04:00
}
2014-07-08 00:23:00 +04:00
fputc ( ' \n ' , stdout ) ;
2014-06-04 03:57:11 +04:00
2014-07-08 00:23:00 +04:00
finish :
2015-07-02 09:46:42 +03:00
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
2014-06-04 03:57:11 +04:00
}