2014-12-19 03:59:52 +03:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2014 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <getopt.h>
# include "sd-event.h"
# include "event-util.h"
# include "verbs.h"
# include "build.h"
2014-12-24 18:44:56 +03:00
# include "import-gpt.h"
2014-12-22 21:42:27 +03:00
# include "import-dkr.h"
2014-12-19 03:59:52 +03:00
static bool arg_force = false ;
2014-12-26 21:21:09 +03:00
static const char * arg_image_root = " /var/lib/container " ;
2014-12-19 03:59:52 +03:00
2014-12-22 21:42:27 +03:00
static const char * arg_dkr_index_url = DEFAULT_DKR_INDEX_URL ;
2014-12-24 18:44:56 +03:00
static void on_gpt_finished ( GptImport * import , int error , void * userdata ) {
sd_event * event = userdata ;
assert ( import ) ;
if ( error = = 0 )
log_info ( " Operation completed successfully. " ) ;
else
log_info_errno ( error , " Operation failed: %m " ) ;
sd_event_exit ( event , error ) ;
}
static int pull_gpt ( int argc , char * argv [ ] , void * userdata ) {
_cleanup_ ( gpt_import_unrefp ) GptImport * import = NULL ;
_cleanup_event_unref_ sd_event * event = NULL ;
const char * url , * local , * suffix ;
int r ;
url = argv [ 1 ] ;
if ( ! gpt_url_is_valid ( url ) ) {
log_error ( " URL '%s' is not valid. " , url ) ;
return - EINVAL ;
}
2014-12-26 19:10:31 +03:00
if ( argc > = 3 )
local = argv [ 2 ] ;
else {
2014-12-24 18:44:56 +03:00
const char * e , * p ;
e = url + strlen ( url ) ;
while ( e > url & & e [ - 1 ] = = ' / ' )
e - - ;
p = e ;
while ( p > url & & p [ - 1 ] ! = ' / ' )
p - - ;
2014-12-26 19:10:31 +03:00
local = strndupa ( p , e - p ) ;
2014-12-24 18:44:56 +03:00
}
2014-12-26 19:10:31 +03:00
if ( isempty ( local ) | | streq ( local , " - " ) )
local = NULL ;
2014-12-24 18:44:56 +03:00
2014-12-26 19:10:31 +03:00
if ( local ) {
const char * p ;
2014-12-24 18:44:56 +03:00
2014-12-26 19:10:31 +03:00
suffix = endswith ( local , " .gpt " ) ;
if ( suffix )
local = strndupa ( local , suffix - local ) ;
if ( ! machine_name_is_valid ( local ) ) {
log_error ( " Local image name '%s' is not valid. " , local ) ;
return - EINVAL ;
}
2014-12-26 21:21:09 +03:00
p = strappenda ( arg_image_root , " / " , local , " .gpt " ) ;
2014-12-26 19:10:31 +03:00
if ( laccess ( p , F_OK ) > = 0 ) {
if ( ! arg_force ) {
log_info ( " Image '%s' already exists. " , local ) ;
return 0 ;
}
} else if ( errno ! = ENOENT )
return log_error_errno ( errno , " Can't check if image '%s' already exists: %m " , local ) ;
2014-12-24 18:44:56 +03:00
2014-12-26 19:10:31 +03:00
log_info ( " Pulling '%s', saving as '%s'. " , url , local ) ;
} else
log_info ( " Pulling '%s'. " , url ) ;
2014-12-24 18:44:56 +03:00
r = sd_event_default ( & event ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to allocate event loop: %m " ) ;
assert_se ( sigprocmask_many ( SIG_BLOCK , SIGTERM , SIGINT , - 1 ) = = 0 ) ;
sd_event_add_signal ( event , NULL , SIGTERM , NULL , NULL ) ;
sd_event_add_signal ( event , NULL , SIGINT , NULL , NULL ) ;
2014-12-26 21:21:09 +03:00
r = gpt_import_new ( & import , event , arg_image_root , on_gpt_finished , event ) ;
2014-12-24 18:44:56 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to allocate importer: %m " ) ;
r = gpt_import_pull ( import , url , local , arg_force ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to pull image: %m " ) ;
r = sd_event_loop ( event ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to run event loop: %m " ) ;
log_info ( " Exiting. " ) ;
return 0 ;
}
static void on_dkr_finished ( DkrImport * import , int error , void * userdata ) {
2014-12-19 03:59:52 +03:00
sd_event * event = userdata ;
assert ( import ) ;
if ( error = = 0 )
log_info ( " Operation completed successfully. " ) ;
else
log_info_errno ( error , " Operation failed: %m " ) ;
sd_event_exit ( event , error ) ;
}
2014-12-22 21:42:27 +03:00
static int pull_dkr ( int argc , char * argv [ ] , void * userdata ) {
_cleanup_ ( dkr_import_unrefp ) DkrImport * import = NULL ;
2014-12-19 03:59:52 +03:00
_cleanup_event_unref_ sd_event * event = NULL ;
const char * name , * tag , * local ;
int r ;
2014-12-22 21:42:27 +03:00
if ( ! arg_dkr_index_url ) {
log_error ( " Please specify an index URL with --dkr-index-url= " ) ;
return - EINVAL ;
}
2014-12-19 03:59:52 +03:00
tag = strchr ( argv [ 1 ] , ' : ' ) ;
if ( tag ) {
name = strndupa ( argv [ 1 ] , tag - argv [ 1 ] ) ;
tag + + ;
} else {
name = argv [ 1 ] ;
tag = " latest " ;
}
2014-12-26 19:10:31 +03:00
if ( ! dkr_name_is_valid ( name ) ) {
log_error ( " Remote name '%s' is not valid. " , name ) ;
return - EINVAL ;
}
if ( ! dkr_tag_is_valid ( tag ) ) {
log_error ( " Tag name '%s' is not valid. " , tag ) ;
return - EINVAL ;
}
2014-12-19 03:59:52 +03:00
if ( argc > = 3 )
local = argv [ 2 ] ;
else {
local = strchr ( name , ' / ' ) ;
if ( local )
local + + ;
else
local = name ;
}
2014-12-24 18:43:46 +03:00
if ( isempty ( local ) | | streq ( local , " - " ) )
2014-12-19 03:59:52 +03:00
local = NULL ;
if ( local ) {
const char * p ;
2014-12-24 18:43:46 +03:00
if ( ! machine_name_is_valid ( local ) ) {
2014-12-19 03:59:52 +03:00
log_error ( " Local image name '%s' is not valid. " , local ) ;
return - EINVAL ;
}
2014-12-26 21:21:09 +03:00
p = strappenda ( arg_image_root , " / " , local ) ;
2014-12-19 03:59:52 +03:00
if ( laccess ( p , F_OK ) > = 0 ) {
if ( ! arg_force ) {
log_info ( " Image '%s' already exists. " , local ) ;
return 0 ;
}
} else if ( errno ! = ENOENT )
return log_error_errno ( errno , " Can't check if image '%s' already exists: %m " , local ) ;
log_info ( " Pulling '%s' with tag '%s', saving as '%s'. " , name , tag , local ) ;
} else
log_info ( " Pulling '%s' with tag '%s'. " , name , tag ) ;
r = sd_event_default ( & event ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to allocate event loop: %m " ) ;
assert_se ( sigprocmask_many ( SIG_BLOCK , SIGTERM , SIGINT , - 1 ) = = 0 ) ;
sd_event_add_signal ( event , NULL , SIGTERM , NULL , NULL ) ;
sd_event_add_signal ( event , NULL , SIGINT , NULL , NULL ) ;
2014-12-26 21:21:09 +03:00
r = dkr_import_new ( & import , event , arg_dkr_index_url , arg_image_root , on_dkr_finished , event ) ;
2014-12-19 03:59:52 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to allocate importer: %m " ) ;
2014-12-24 18:41:51 +03:00
r = dkr_import_pull ( import , name , tag , local , arg_force ) ;
2014-12-19 03:59:52 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to pull image: %m " ) ;
r = sd_event_loop ( event ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to run event loop: %m " ) ;
log_info ( " Exiting. " ) ;
return 0 ;
}
static int help ( int argc , char * argv [ ] , void * userdata ) {
printf ( " %s [OPTIONS...] {COMMAND} ... \n \n "
" Import container or virtual machine image. \n \n "
" -h --help Show this help \n "
" --version Show package version \n "
2014-12-22 21:42:27 +03:00
" --force Force creation of image \n "
2014-12-26 21:21:09 +03:00
" --image-root= Image root directory \n "
2014-12-22 21:42:27 +03:00
" --dkr-index-url=URL Specify index URL to use for downloads \n \n "
2014-12-19 03:59:52 +03:00
" Commands: \n "
2014-12-24 18:44:56 +03:00
" pull-dkr REMOTE [NAME] Download a DKR image \n "
" pull-gpt URL [NAME] Download a GPT image \n " ,
2014-12-19 03:59:52 +03:00
program_invocation_short_name ) ;
return 0 ;
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_VERSION = 0x100 ,
ARG_FORCE ,
2014-12-22 21:42:27 +03:00
ARG_DKR_INDEX_URL ,
2014-12-26 21:21:09 +03:00
ARG_IMAGE_ROOT ,
2014-12-19 03:59:52 +03:00
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
{ " version " , no_argument , NULL , ARG_VERSION } ,
{ " force " , no_argument , NULL , ARG_FORCE } ,
2014-12-22 21:42:27 +03:00
{ " dkr-index-url " , required_argument , NULL , ARG_DKR_INDEX_URL } ,
2014-12-26 21:21:09 +03:00
{ " image-root " , required_argument , NULL , ARG_IMAGE_ROOT } ,
2014-12-19 03:59:52 +03:00
{ }
} ;
int c ;
assert ( argc > = 0 ) ;
assert ( argv ) ;
while ( ( c = getopt_long ( argc , argv , " h " , options , NULL ) ) > = 0 )
switch ( c ) {
case ' h ' :
2014-12-19 21:18:48 +03:00
return help ( 0 , NULL , NULL ) ;
2014-12-19 03:59:52 +03:00
case ARG_VERSION :
puts ( PACKAGE_STRING ) ;
puts ( SYSTEMD_FEATURES ) ;
return 0 ;
case ARG_FORCE :
arg_force = true ;
break ;
2014-12-22 21:42:27 +03:00
case ARG_DKR_INDEX_URL :
if ( ! dkr_url_is_valid ( optarg ) ) {
log_error ( " Index URL is not valid: %s " , optarg ) ;
return - EINVAL ;
}
arg_dkr_index_url = optarg ;
break ;
2014-12-26 21:21:09 +03:00
case ARG_IMAGE_ROOT :
arg_image_root = optarg ;
break ;
2014-12-19 03:59:52 +03:00
case ' ? ' :
return - EINVAL ;
default :
assert_not_reached ( " Unhandled option " ) ;
}
return 1 ;
}
static int import_main ( int argc , char * argv [ ] ) {
2014-12-19 21:18:48 +03:00
static const Verb verbs [ ] = {
2014-12-19 03:59:52 +03:00
{ " help " , VERB_ANY , VERB_ANY , 0 , help } ,
2014-12-22 21:42:27 +03:00
{ " pull-dkr " , 2 , 3 , 0 , pull_dkr } ,
2014-12-24 18:44:56 +03:00
{ " pull-gpt " , 2 , 3 , 0 , pull_gpt } ,
2014-12-19 03:59:52 +03:00
{ }
} ;
return dispatch_verb ( argc , argv , verbs , NULL ) ;
}
int main ( int argc , char * argv [ ] ) {
int r ;
setlocale ( LC_ALL , " " ) ;
log_parse_environment ( ) ;
log_open ( ) ;
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
goto finish ;
r = import_main ( argc , argv ) ;
finish :
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
}