]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/CLIHandler.pm
print_bash_completion: correctly handle shell quoting
[pve-common.git] / src / PVE / CLIHandler.pm
index 8bab06b391f7aed139ded7e9826bea12919d69a7..48798ba9a804c6f7b7a729d5ffddf27752ea2ea7 100644 (file)
@@ -34,6 +34,19 @@ my $expand_command_name = sub {
     return $cmd;
 };
 
+my $complete_command_names = sub {
+    my $res = [];
+
+    return if ref($cmddef) ne 'HASH';
+
+    foreach my $cmd (keys %$cmddef) {
+       next if $cmd eq 'help';
+       push @$res, $cmd;
+    }
+
+    return $res;
+};
+
 __PACKAGE__->register_method ({
     name => 'help', 
     path => 'help',
@@ -46,6 +59,7 @@ __PACKAGE__->register_method ({
                description => "Command name",
                type => 'string',
                optional => 1,
+               completion => $complete_command_names,
            },
            verbose => {
                description => "Verbose output format.",
@@ -185,8 +199,7 @@ my $print_bash_completion = sub {
     my $cmdline = substr($ENV{COMP_LINE}, 0, $ENV{COMP_POINT});
     print STDERR "\nCMDLINE: $ENV{COMP_LINE}\n" if $debug;
 
-    # fixme: shell quoting??
-    my @args = split(/\s+/, $cmdline);
+    my @args = PVE::Tools::split_args($cmdline);
     my $pos = scalar(@args) - 2;
     $pos += 1 if $cmdline =~ m/\s+$/;
 
@@ -283,13 +296,22 @@ sub verify_api {
     PVE::RESTHandler::validate_method_schemas();
 }
 
+my $get_exe_name = sub {
+    my ($class) = @_;
+    
+    my $name = $class;
+    $name =~ s/^.*:://;
+    $name =~ s/_/-/g;
+
+    return $name;
+};
+
 sub generate_bash_completions {
     my ($class) = @_;
 
     # generate bash completion config
 
-    $exename = $class;
-    $exename =~ s/^.*:://;
+    $exename = &$get_exe_name($class);
 
     print <<__EOD__;
 # $exename bash completion
@@ -304,17 +326,23 @@ __EOD__
 }
 
 sub find_cli_class_source {
-    my ($exename) = @_;
+    my ($name) = @_;
 
     my $filename;
 
-    my $cpath = "PVE/CLI/${exename}.pm";
+    $name =~ s/-/_/g;
+
+    my $cpath = "PVE/CLI/${name}.pm";
+    my $spath = "PVE/Service/${name}.pm";
     foreach my $p (@INC) {
-       my $testfn = "$p/$cpath";
-       if (-f $testfn) {
-           $filename = $testfn;
-           last;
+       foreach my $s (($cpath, $spath)) {
+           my $testfn = "$p/$s";
+           if (-f $testfn) {
+               $filename = $testfn;
+               last;
+           }
        }
+       last if defined($filename);
     }
 
     return $filename;
@@ -323,8 +351,7 @@ sub find_cli_class_source {
 sub generate_pod_manpage {
     my ($class, $podfn) = @_;
 
-    $exename = $class;
-    $exename =~ s/^.*:://;
+    $exename = &$get_exe_name($class);
 
     $podfn = find_cli_class_source($exename) if !defined($podfn);
 
@@ -333,32 +360,37 @@ sub generate_pod_manpage {
     no strict 'refs';
     my $def = ${"${class}::cmddef"};
 
-    if (ref($def eq 'ARRAY')) {
+    if (ref($def) eq 'ARRAY') {
        print_simple_pod_manpage($podfn, @$def);
     } else {
        $cmddef = $def;
+
+       $cmddef->{help} = [ __PACKAGE__, 'help', ['cmd'] ];
+
        print_pod_manpage($podfn);
     }
 }
 
-sub run {
+sub run_cli {
     my ($class, $pwcallback, $podfn, $preparefunc) = @_;
 
     $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
 
-    $exename = $class;
-    $exename =~ s/^.*:://;
+    $exename = &$get_exe_name($class);
 
     initlog($exename);
 
-    die "please run as root\n" if $> != 0;
 
-    PVE::INotify::inotify_init();
+    if ($class !~ m/^PVE::Service::/) {
+       die "please run as root\n" if $> != 0;
 
-    my $rpcenv = PVE::RPCEnvironment->init('cli');
-    $rpcenv->init_request();
-    $rpcenv->set_language($ENV{LANG});
-    $rpcenv->set_user('root@pam');
+       PVE::INotify::inotify_init();
+
+       my $rpcenv = PVE::RPCEnvironment->init('cli');
+       $rpcenv->init_request();
+       $rpcenv->set_language($ENV{LANG});
+       $rpcenv->set_user('root@pam');
+    }
 
     no strict 'refs';
     my $def = ${"${class}::cmddef"};
@@ -389,6 +421,7 @@ sub handle_cmd {
        PVE::RESTHandler::validate_method_schemas();
        return;
     } elsif ($cmd eq 'printmanpod') {
+       $podfn = find_cli_class_source($exename) if !defined($podfn);
        print_pod_manpage($podfn);
        return;
     } elsif ($cmd eq 'bashcomplete') {