2011-04-24 07:58:01 +00:00
|
|
|
#!/usr/bin/perl -w
|
|
|
|
#
|
2013-05-14 23:42:12 +00:00
|
|
|
# Copyright (C) 2010-2013 Red Hat, Inc.
|
|
|
|
#
|
|
|
|
# This library 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.
|
|
|
|
#
|
|
|
|
# This library 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 this library. If not, see
|
|
|
|
# <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
2011-04-24 07:58:01 +00:00
|
|
|
# This script parses remote_protocol.x or qemu_protocol.x and produces lots of
|
|
|
|
# boilerplate code for both ends of the remote connection.
|
|
|
|
#
|
|
|
|
# The first non-option argument specifies the prefix to be searched for, and
|
|
|
|
# output to, the boilerplate code. The second non-option argument is the
|
|
|
|
# file you want to operate on. For instance, to generate the dispatch table
|
|
|
|
# for both remote_protocol.x and qemu_protocol.x, you would run the
|
|
|
|
# following:
|
|
|
|
#
|
2011-07-19 12:16:47 +00:00
|
|
|
# gendispatch.pl -t remote ../src/remote/remote_protocol.x
|
2011-07-17 04:41:39 +00:00
|
|
|
# gendispatch.pl -t qemu ../src/remote/qemu_protocol.x
|
2011-04-24 07:58:01 +00:00
|
|
|
#
|
|
|
|
# By Richard Jones <rjones@redhat.com>
|
2011-04-22 18:35:34 +00:00
|
|
|
# Extended by Matthias Bolte <matthias.bolte@googlemail.com>
|
2011-04-24 07:58:01 +00:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
use Getopt::Long;
|
2011-04-24 07:58:01 +00:00
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
my $mode = "debug";
|
|
|
|
my $res = GetOptions("mode=s" => \$mode);
|
|
|
|
|
|
|
|
die "cannot parse command line options" unless $res;
|
|
|
|
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
die "unknown mode '$mode', expecting 'client', 'server', " .
|
|
|
|
"'aclheader', 'aclbody', 'aclsym' or 'debug'"
|
|
|
|
unless $mode =~ /^(client|server|aclheader|aclbody|aclsym|debug)$/;
|
2011-04-24 07:58:01 +00:00
|
|
|
|
2012-07-20 14:31:46 +00:00
|
|
|
my $structprefix = shift or die "missing struct prefix argument";
|
|
|
|
my $procprefix = shift or die "missing procedure prefix argument";
|
2011-05-11 19:28:39 +00:00
|
|
|
my $protocol = shift or die "missing protocol argument";
|
|
|
|
my @autogen;
|
|
|
|
|
2012-07-20 14:31:46 +00:00
|
|
|
|
|
|
|
sub fixup_name {
|
|
|
|
my $name = shift;
|
|
|
|
|
|
|
|
$name =~ s/Nwfilter/NWFilter/;
|
|
|
|
$name =~ s/Xml$/XML/;
|
|
|
|
$name =~ s/Uri$/URI/;
|
|
|
|
$name =~ s/Uuid$/UUID/;
|
|
|
|
$name =~ s/Id$/ID/;
|
|
|
|
$name =~ s/Mac$/MAC/;
|
|
|
|
$name =~ s/Cpu$/CPU/;
|
|
|
|
$name =~ s/Os$/OS/;
|
|
|
|
$name =~ s/Nmi$/NMI/;
|
|
|
|
$name =~ s/Pm/PM/;
|
2012-11-20 18:01:21 +00:00
|
|
|
$name =~ s/Fstrim$/FSTrim/;
|
2013-02-04 13:03:10 +00:00
|
|
|
$name =~ s/Scsi/SCSI/;
|
|
|
|
$name =~ s/Wwn$/WWN/;
|
2012-07-20 14:31:46 +00:00
|
|
|
|
|
|
|
return $name;
|
|
|
|
}
|
2011-04-24 07:58:01 +00:00
|
|
|
|
|
|
|
# Convert name_of_call to NameOfCall.
|
|
|
|
sub name_to_ProcName {
|
|
|
|
my $name = shift;
|
2012-07-20 14:31:46 +00:00
|
|
|
|
|
|
|
my @elems;
|
|
|
|
if ($name =~ /_/ || (lc $name) eq "open" || (lc $name) eq "close") {
|
2012-07-27 12:51:28 +00:00
|
|
|
@elems = split /_/, $name;
|
|
|
|
@elems = map lc, @elems;
|
|
|
|
@elems = map ucfirst, @elems;
|
2012-07-20 14:31:46 +00:00
|
|
|
} else {
|
2012-07-27 12:51:28 +00:00
|
|
|
@elems = $name;
|
2012-07-20 14:31:46 +00:00
|
|
|
}
|
|
|
|
@elems = map { fixup_name($_) } @elems;
|
|
|
|
my $procname = join "", @elems;
|
|
|
|
|
|
|
|
return $procname;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub name_to_TypeName {
|
|
|
|
my $name = shift;
|
|
|
|
|
2011-04-24 07:58:01 +00:00
|
|
|
my @elems = split /_/, $name;
|
2012-07-20 14:31:46 +00:00
|
|
|
@elems = map lc, @elems;
|
2011-04-24 07:58:01 +00:00
|
|
|
@elems = map ucfirst, @elems;
|
2012-07-20 14:31:46 +00:00
|
|
|
@elems = map { fixup_name($_) } @elems;
|
|
|
|
my $typename = join "", @elems;
|
|
|
|
return $typename;
|
2011-04-24 07:58:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Read the input file (usually remote_protocol.x) and form an
|
|
|
|
# opinion about the name, args and return type of each RPC.
|
2013-04-17 12:04:27 +00:00
|
|
|
my ($name, $ProcName, $id, $flags, %calls, @calls, %opts);
|
2011-04-24 07:58:01 +00:00
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
my $collect_args_members = 0;
|
2011-04-22 15:09:33 +00:00
|
|
|
my $collect_ret_members = 0;
|
2013-04-17 12:04:27 +00:00
|
|
|
my $collect_opts = 0;
|
2011-04-22 18:35:34 +00:00
|
|
|
my $last_name;
|
|
|
|
|
2011-05-11 19:28:39 +00:00
|
|
|
open PROTOCOL, "<$protocol" or die "cannot open $protocol: $!";
|
|
|
|
|
|
|
|
while (<PROTOCOL>) {
|
2011-04-22 18:35:34 +00:00
|
|
|
if ($collect_args_members) {
|
|
|
|
if (/^};/) {
|
|
|
|
$collect_args_members = 0;
|
|
|
|
} elsif ($_ =~ m/^\s*(.*\S)\s*$/) {
|
|
|
|
push(@{$calls{$name}->{args_members}}, $1);
|
|
|
|
}
|
2011-04-22 15:09:33 +00:00
|
|
|
} elsif ($collect_ret_members) {
|
|
|
|
if (/^};/) {
|
|
|
|
$collect_ret_members = 0;
|
|
|
|
} elsif ($_ =~ m/^\s*(.*\S)\s*$/) {
|
|
|
|
push(@{$calls{$name}->{ret_members}}, $1);
|
|
|
|
}
|
2013-04-17 12:04:27 +00:00
|
|
|
} elsif ($collect_opts) {
|
2013-04-18 11:08:47 +00:00
|
|
|
if (m,^\s*\*\s*\@(\w+)\s*:\s*((?:\w|:|\!|\|)+)\s*$,) {
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
if ($1 eq "acl" ||
|
|
|
|
$1 eq "aclfilter") {
|
|
|
|
$opts{$1} = [] unless exists $opts{$1};
|
|
|
|
push @{$opts{$1}}, $2;
|
|
|
|
} else {
|
|
|
|
$opts{$1} = $2;
|
|
|
|
}
|
2013-04-17 12:04:27 +00:00
|
|
|
} elsif (m,^\s*\*/\s*$,) {
|
|
|
|
$collect_opts = 0;
|
|
|
|
} elsif (m,^\s*\*\s*$,) {
|
|
|
|
# pass
|
|
|
|
} else {
|
|
|
|
die "cannot parse $_";
|
|
|
|
}
|
|
|
|
} elsif (m,/\*\*,) {
|
|
|
|
%opts = ();
|
|
|
|
$collect_opts = 1;
|
2012-07-20 14:31:46 +00:00
|
|
|
} elsif (/^struct (${structprefix}_(.*)_args)/ ||
|
|
|
|
/^struct (${structprefix}(.*)Args)/) {
|
|
|
|
my $structname = $1;
|
|
|
|
$name = $2;
|
2011-04-24 07:58:01 +00:00
|
|
|
$ProcName = name_to_ProcName ($name);
|
2012-07-20 14:31:46 +00:00
|
|
|
$name = lc $name;
|
|
|
|
$name =~ s/_//g;
|
|
|
|
die "duplicate definition of $_"
|
2011-04-24 07:58:01 +00:00
|
|
|
if exists $calls{$name};
|
|
|
|
|
|
|
|
$calls{$name} = {
|
|
|
|
name => $name,
|
|
|
|
ProcName => $ProcName,
|
2012-07-20 14:31:46 +00:00
|
|
|
args => $structname,
|
2011-04-22 18:35:34 +00:00
|
|
|
args_members => [],
|
|
|
|
ret => "void"
|
2011-04-24 07:58:01 +00:00
|
|
|
};
|
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
$collect_args_members = 1;
|
2011-04-22 15:09:33 +00:00
|
|
|
$collect_ret_members = 0;
|
2011-04-22 18:35:34 +00:00
|
|
|
$last_name = $name;
|
2012-07-20 14:31:46 +00:00
|
|
|
} elsif (/^struct (${structprefix}_(.*)_ret)\s+{(.*)$/ ||
|
|
|
|
/^struct (${structprefix}(.*)Ret)\s+{(.*)$/) {
|
|
|
|
my $structname = $1;
|
|
|
|
$name = $2;
|
|
|
|
$flags = $3;
|
2011-04-24 07:58:01 +00:00
|
|
|
$ProcName = name_to_ProcName ($name);
|
2012-07-20 14:31:46 +00:00
|
|
|
$name = lc $name;
|
|
|
|
$name =~ s/_//g;
|
2011-04-24 07:58:01 +00:00
|
|
|
|
|
|
|
if (exists $calls{$name}) {
|
2012-07-20 14:31:46 +00:00
|
|
|
$calls{$name}->{ret} = $structname;
|
2011-04-24 07:58:01 +00:00
|
|
|
} else {
|
|
|
|
$calls{$name} = {
|
|
|
|
name => $name,
|
|
|
|
ProcName => $ProcName,
|
|
|
|
args => "void",
|
2012-07-20 14:31:46 +00:00
|
|
|
ret => $structname,
|
2011-04-22 15:09:33 +00:00
|
|
|
ret_members => []
|
2011-04-24 07:58:01 +00:00
|
|
|
}
|
|
|
|
}
|
2011-04-22 18:35:34 +00:00
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
if ($flags ne "") {
|
2011-06-15 13:38:31 +00:00
|
|
|
if (!($flags =~ m/^\s*\/\*\s*insert@(\d+)\s*\*\/\s*$/)) {
|
|
|
|
die "invalid generator flags for $calls{$name}->{ret}";
|
|
|
|
}
|
|
|
|
|
|
|
|
$calls{$name}->{ret_offset} = int($1);
|
|
|
|
}
|
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
$collect_args_members = 0;
|
2011-04-22 15:09:33 +00:00
|
|
|
$collect_ret_members = 1;
|
|
|
|
$last_name = $name;
|
2012-07-20 14:31:46 +00:00
|
|
|
} elsif (/^struct (${structprefix}_(.*)_msg)/ ||
|
|
|
|
/^struct (${structprefix}(.*)Msg)/) {
|
|
|
|
my $structname = $1;
|
|
|
|
$name = $2;
|
2011-04-24 07:58:01 +00:00
|
|
|
$ProcName = name_to_ProcName ($name);
|
2012-07-20 14:31:46 +00:00
|
|
|
$name = lc $name;
|
|
|
|
$name =~ s/_//g;
|
2011-04-24 07:58:01 +00:00
|
|
|
$calls{$name} = {
|
|
|
|
name => $name,
|
|
|
|
ProcName => $ProcName,
|
2012-07-20 14:31:46 +00:00
|
|
|
msg => $structname,
|
2011-04-22 18:35:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
$collect_args_members = 0;
|
2011-04-22 15:09:33 +00:00
|
|
|
$collect_ret_members = 0;
|
2013-04-17 12:04:27 +00:00
|
|
|
} elsif (/^\s*(${procprefix}_PROC_(.*?))\s*=\s*(\d+)\s*,?\s*$/) {
|
2012-07-20 14:31:46 +00:00
|
|
|
my $constname = $1;
|
|
|
|
$name = $2;
|
|
|
|
$id = $3;
|
2011-04-24 07:58:01 +00:00
|
|
|
$ProcName = name_to_ProcName ($name);
|
2012-07-20 14:31:46 +00:00
|
|
|
$name = lc $name;
|
|
|
|
$name =~ s/_//g;
|
2011-04-24 07:58:01 +00:00
|
|
|
|
2011-07-19 12:16:47 +00:00
|
|
|
if (!exists $calls{$name}) {
|
|
|
|
# that the argument and return value cases have not yet added
|
|
|
|
# this procedure to the calls hash means that it has no arguments
|
|
|
|
# and no return value. add it to the calls hash now because all
|
|
|
|
# procedures have to be listed in the calls hash
|
|
|
|
$calls{$name} = {
|
|
|
|
name => $name,
|
|
|
|
ProcName => $ProcName,
|
|
|
|
args => "void",
|
|
|
|
ret => "void"
|
|
|
|
}
|
|
|
|
}
|
2012-07-20 14:31:46 +00:00
|
|
|
$calls{$name}->{constname} = $constname;
|
2011-07-19 12:16:47 +00:00
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
if (!exists $opts{generate}) {
|
|
|
|
die "'\@generate' annotation missing for $constname";
|
|
|
|
}
|
2011-05-11 19:28:39 +00:00
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
if ($opts{generate} !~ /^(both|server|client|none)$/) {
|
|
|
|
die "'\@generate' annotation value '$opts{generate}' invalid";
|
|
|
|
}
|
2011-05-11 19:28:39 +00:00
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
if ($opts{generate} eq "both") {
|
|
|
|
push(@autogen, $ProcName);
|
|
|
|
} elsif ($mode eq "server" && ($opts{generate} eq "server")) {
|
|
|
|
push(@autogen, $ProcName);
|
|
|
|
} elsif ($mode eq "client" && ($opts{generate} eq "client")) {
|
|
|
|
push(@autogen, $ProcName);
|
|
|
|
}
|
2011-05-21 09:24:28 +00:00
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
if (exists $opts{readstream}) {
|
|
|
|
$calls{$name}->{streamflag} = "read";
|
|
|
|
$calls{$name}->{streamoffset} = int($opts{readstream});
|
|
|
|
} elsif (exists $opts{writestream}) {
|
|
|
|
$calls{$name}->{streamflag} = "write";
|
|
|
|
$calls{$name}->{streamoffset} = int($opts{writestream});
|
|
|
|
} else {
|
|
|
|
$calls{$name}->{streamflag} = "none";
|
|
|
|
}
|
2011-08-12 12:04:31 +00:00
|
|
|
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
$calls{$name}->{acl} = $opts{acl};
|
|
|
|
$calls{$name}->{aclfilter} = $opts{aclfilter};
|
2013-04-17 12:04:27 +00:00
|
|
|
|
2013-04-18 10:29:56 +00:00
|
|
|
# for now, we distinguish only two levels of priority:
|
|
|
|
# low (0) and high (1)
|
|
|
|
if (exists $opts{priority}) {
|
|
|
|
if ($opts{priority} eq "high") {
|
|
|
|
$calls{$name}->{priority} = 1;
|
|
|
|
} elsif ($opts{priority} eq "low") {
|
2013-04-17 12:04:27 +00:00
|
|
|
$calls{$name}->{priority} = 0;
|
2013-04-18 10:29:56 +00:00
|
|
|
} else {
|
|
|
|
die "\@priority annotation value '$opts{priority}' invalid for $constname"
|
2011-08-12 12:04:31 +00:00
|
|
|
}
|
2013-04-18 10:29:56 +00:00
|
|
|
} else {
|
|
|
|
$calls{$name}->{priority} = 0;
|
2011-05-11 19:28:39 +00:00
|
|
|
}
|
|
|
|
|
2011-04-24 07:58:01 +00:00
|
|
|
$calls[$id] = $calls{$name};
|
2011-04-22 18:35:34 +00:00
|
|
|
|
|
|
|
$collect_args_members = 0;
|
2011-04-22 15:09:33 +00:00
|
|
|
$collect_ret_members = 0;
|
2011-04-22 18:35:34 +00:00
|
|
|
} else {
|
|
|
|
$collect_args_members = 0;
|
2011-04-22 15:09:33 +00:00
|
|
|
$collect_ret_members = 0;
|
2011-04-24 07:58:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-11 19:28:39 +00:00
|
|
|
close(PROTOCOL);
|
|
|
|
|
2011-05-30 10:58:57 +00:00
|
|
|
# this hash contains the procedures that are allowed to map [unsigned] hyper
|
|
|
|
# to [unsigned] long for legacy reasons in their signature and return type.
|
|
|
|
# this list is fixed. new procedures and public APIs have to map [unsigned]
|
|
|
|
# hyper to [unsigned] long long
|
|
|
|
my $long_legacy = {
|
|
|
|
DomainGetInfo => { ret => { maxMem => 1, memory => 1 } },
|
|
|
|
DomainMigrate => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrate2 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateBegin3 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateConfirm3 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateDirect => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateFinish => { arg => { flags => 1 } },
|
|
|
|
DomainMigrateFinish2 => { arg => { flags => 1 } },
|
|
|
|
DomainMigrateFinish3 => { arg => { flags => 1 } },
|
|
|
|
DomainMigratePeer2Peer => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigratePerform => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigratePerform3 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigratePrepare => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigratePrepare2 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigratePrepare3 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigratePrepareTunnel => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigratePrepareTunnel3 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateToURI => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateToURI2 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateVersion1 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateVersion2 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateVersion3 => { arg => { flags => 1, resource => 1 } },
|
|
|
|
DomainMigrateSetMaxSpeed => { arg => { bandwidth => 1 } },
|
|
|
|
DomainSetMaxMemory => { arg => { memory => 1 } },
|
|
|
|
DomainSetMemory => { arg => { memory => 1 } },
|
|
|
|
DomainSetMemoryFlags => { arg => { memory => 1 } },
|
2013-04-18 11:07:23 +00:00
|
|
|
ConnectGetLibVersion => { ret => { lib_ver => 1 } },
|
|
|
|
ConnectGetVersion => { ret => { hv_ver => 1 } },
|
2011-05-30 10:58:57 +00:00
|
|
|
NodeGetInfo => { ret => { memory => 1 } },
|
2012-09-17 20:07:18 +00:00
|
|
|
DomainBlockCommit => { arg => { bandwidth => 1 } },
|
2011-07-22 05:31:16 +00:00
|
|
|
DomainBlockPull => { arg => { bandwidth => 1 } },
|
block rebase: add new API virDomainBlockRebase
Qemu is adding the ability to do a partial rebase. That is, given:
base <- intermediate <- current
virDomainBlockPull will produce:
current
but qemu now has the ability to leave base in the chain, to produce:
base <- current
Note that current qemu can only do a forward merge, and only with
the current image as the destination, which is fully described by
this API without flags. But in the future, it may be possible to
enhance this API for additional scenarios by using flags:
Merging the current image back into a previous image (that is,
undoing a live snapshot), could be done by passing base as the
destination and flags with a bit requesting a backward merge.
Merging any other part of the image chain, whether forwards (the
backing image contents are pulled into the newer file) or backwards
(the deltas recorded in the newer file are merged back into the
backing file), could also be done by passing a new flag that says
that base should be treated as an XML snippet rather than an
absolute path name, where the XML could then supply the additional
instructions of which part of the image chain is being merged into
any other part.
* include/libvirt/libvirt.h.in (virDomainBlockRebase): New
declaration.
* src/libvirt.c (virDomainBlockRebase): Implement it.
* src/libvirt_public.syms (LIBVIRT_0.9.10): Export it.
* src/driver.h (virDrvDomainBlockRebase): New driver callback.
* src/rpc/gendispatch.pl (long_legacy): Add exemption.
* docs/apibuild.py (long_legacy_functions): Likewise.
2012-02-01 04:19:51 +00:00
|
|
|
DomainBlockRebase => { arg => { bandwidth => 1 } },
|
2011-07-22 05:31:16 +00:00
|
|
|
DomainBlockJobSetSpeed => { arg => { bandwidth => 1 } },
|
2011-08-26 18:10:21 +00:00
|
|
|
DomainMigrateGetMaxSpeed => { ret => { bandwidth => 1 } },
|
2011-05-30 10:58:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
sub hyper_to_long
|
|
|
|
{
|
|
|
|
my $proc_name = shift;
|
|
|
|
my $ret_or_arg = shift;
|
|
|
|
my $member = shift;
|
|
|
|
|
|
|
|
if ($long_legacy->{$proc_name} and
|
|
|
|
$long_legacy->{$proc_name}->{$ret_or_arg} and
|
|
|
|
$long_legacy->{$proc_name}->{$ret_or_arg}->{$member}) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-24 07:58:01 +00:00
|
|
|
#----------------------------------------------------------------------
|
|
|
|
# Output
|
|
|
|
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
if ($mode eq "aclsym") {
|
|
|
|
print <<__EOF__;
|
|
|
|
# Automatically generated by gendispatch.pl.
|
|
|
|
# Do not edit this file. Any changes you make will be lost.
|
|
|
|
__EOF__
|
|
|
|
} else {
|
|
|
|
print <<__EOF__;
|
2011-07-17 04:41:39 +00:00
|
|
|
/* Automatically generated by gendispatch.pl.
|
2011-04-24 07:58:01 +00:00
|
|
|
* Do not edit this file. Any changes you make will be lost.
|
|
|
|
*/
|
|
|
|
__EOF__
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
}
|
2011-04-24 07:58:01 +00:00
|
|
|
|
|
|
|
# Debugging.
|
2013-04-18 10:29:56 +00:00
|
|
|
if ($mode eq "debug") {
|
2011-04-24 07:58:01 +00:00
|
|
|
my @keys = sort (keys %calls);
|
|
|
|
foreach (@keys) {
|
|
|
|
print "$_:\n";
|
|
|
|
print " name $calls{$_}->{name} ($calls{$_}->{ProcName})\n";
|
|
|
|
print " $calls{$_}->{args} -> $calls{$_}->{ret}\n";
|
2011-08-12 12:04:31 +00:00
|
|
|
print " priority -> $calls{$_}->{priority}\n";
|
2011-04-24 07:58:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-06 19:54:32 +00:00
|
|
|
# Bodies for dispatch functions ("remote_dispatch_bodies.h").
|
2013-04-18 10:29:56 +00:00
|
|
|
elsif ($mode eq "server") {
|
2011-05-11 19:28:39 +00:00
|
|
|
my %generate = map { $_ => 1 } @autogen;
|
2011-04-22 18:35:34 +00:00
|
|
|
my @keys = sort (keys %calls);
|
|
|
|
|
|
|
|
foreach (@keys) {
|
2011-05-15 06:14:35 +00:00
|
|
|
my $call = $calls{$_};
|
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
# skip things which are REMOTE_MESSAGE
|
2011-05-15 06:14:35 +00:00
|
|
|
next if $call->{msg};
|
2011-04-22 18:35:34 +00:00
|
|
|
|
2012-07-27 12:51:28 +00:00
|
|
|
my $name = $structprefix . "Dispatch" . $call->{ProcName};
|
|
|
|
my $argtype = $call->{args};
|
|
|
|
my $rettype = $call->{ret};
|
|
|
|
|
|
|
|
my $argann = $argtype ne "void" ? "" : " ATTRIBUTE_UNUSED";
|
|
|
|
my $retann = $rettype ne "void" ? "" : " ATTRIBUTE_UNUSED";
|
|
|
|
|
|
|
|
# First we print out a function declaration for the
|
|
|
|
# real dispatcher body
|
|
|
|
print "static int ${name}(\n";
|
|
|
|
print " virNetServerPtr server,\n";
|
|
|
|
print " virNetServerClientPtr client,\n";
|
|
|
|
print " virNetMessagePtr msg,\n";
|
|
|
|
print " virNetMessageErrorPtr rerr";
|
|
|
|
if ($argtype ne "void") {
|
|
|
|
print ",\n $argtype *args";
|
|
|
|
}
|
|
|
|
if ($rettype ne "void") {
|
|
|
|
print ",\n $rettype *ret";
|
|
|
|
}
|
|
|
|
print ");\n";
|
|
|
|
|
|
|
|
|
|
|
|
# Next we print out a generic wrapper method which has
|
|
|
|
# fixed function signature, for use in the dispatcher
|
|
|
|
# table. This simply callers the real dispatcher method
|
|
|
|
print "static int ${name}Helper(\n";
|
|
|
|
print " virNetServerPtr server,\n";
|
|
|
|
print " virNetServerClientPtr client,\n";
|
|
|
|
print " virNetMessagePtr msg,\n";
|
|
|
|
print " virNetMessageErrorPtr rerr,\n";
|
|
|
|
print " void *args$argann,\n";
|
|
|
|
print " void *ret$retann)\n";
|
|
|
|
print "{\n";
|
|
|
|
print " VIR_DEBUG(\"server=%p client=%p msg=%p rerr=%p args=%p ret=%p\", server, client, msg, rerr, args, ret);\n";
|
|
|
|
print " return $name(server, client, msg, rerr";
|
|
|
|
if ($argtype ne "void") {
|
|
|
|
print ", args";
|
|
|
|
}
|
|
|
|
if ($rettype ne "void") {
|
|
|
|
print ", ret";
|
|
|
|
}
|
|
|
|
print ");\n";
|
|
|
|
print "}\n";
|
|
|
|
|
|
|
|
# Finally we print out the dispatcher method body impl
|
|
|
|
# (if possible)
|
2011-05-16 17:13:11 +00:00
|
|
|
if (!exists($generate{$call->{ProcName}})) {
|
|
|
|
print "/* ${structprefix}Dispatch$call->{ProcName} body has " .
|
|
|
|
"to be implemented manually */\n\n\n\n";
|
|
|
|
next;
|
|
|
|
}
|
2011-04-22 18:35:34 +00:00
|
|
|
|
|
|
|
my $has_node_device = 0;
|
|
|
|
my @vars_list = ();
|
2011-04-22 18:31:05 +00:00
|
|
|
my @optionals_list = ();
|
2011-04-22 18:35:34 +00:00
|
|
|
my @getters_list = ();
|
|
|
|
my @args_list = ();
|
2011-06-15 18:03:45 +00:00
|
|
|
my @prepare_ret_list = ();
|
2011-04-22 15:09:33 +00:00
|
|
|
my @ret_list = ();
|
2011-04-22 18:35:34 +00:00
|
|
|
my @free_list = ();
|
2011-05-16 17:13:11 +00:00
|
|
|
my @free_list_on_error = ("virNetMessageSaveError(rerr);");
|
2011-04-22 18:35:34 +00:00
|
|
|
|
2011-04-23 07:40:14 +00:00
|
|
|
# handle arguments to the function
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($argtype ne "void") {
|
2011-04-22 18:35:34 +00:00
|
|
|
# node device is special, as it's identified by name
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($argtype =~ m/^remote_node_device_/ and
|
|
|
|
!($argtype =~ m/^remote_node_device_lookup_by_name_/) and
|
2013-02-04 13:03:10 +00:00
|
|
|
!($argtype =~ m/^remote_node_device_create_xml_/) and
|
|
|
|
!($argtype =~ m/^remote_node_device_lookup_scsi_host_by_wwn_/)) {
|
2011-04-22 18:35:34 +00:00
|
|
|
$has_node_device = 1;
|
|
|
|
push(@vars_list, "virNodeDevicePtr dev = NULL");
|
|
|
|
push(@getters_list,
|
2011-05-16 17:13:11 +00:00
|
|
|
" if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))\n" .
|
2011-04-22 18:35:34 +00:00
|
|
|
" goto cleanup;\n");
|
|
|
|
push(@args_list, "dev");
|
|
|
|
push(@free_list,
|
|
|
|
" if (dev)\n" .
|
|
|
|
" virNodeDeviceFree(dev);");
|
|
|
|
}
|
|
|
|
|
2011-05-15 06:14:35 +00:00
|
|
|
foreach my $args_member (@{$call->{args_members}}) {
|
2011-04-22 18:35:34 +00:00
|
|
|
if ($args_member =~ m/^remote_nonnull_string name;/ and $has_node_device) {
|
|
|
|
# ignore the name arg for node devices
|
|
|
|
next
|
2011-04-22 22:19:14 +00:00
|
|
|
} elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter) (\S+);/) {
|
2012-07-20 14:31:46 +00:00
|
|
|
my $type_name = name_to_TypeName($1);
|
2011-04-22 22:19:14 +00:00
|
|
|
|
|
|
|
push(@vars_list, "vir${type_name}Ptr $2 = NULL");
|
2011-04-22 18:35:34 +00:00
|
|
|
push(@getters_list,
|
2011-05-16 17:13:11 +00:00
|
|
|
" if (!($2 = get_nonnull_$1(priv->conn, args->$2)))\n" .
|
2011-04-22 18:35:34 +00:00
|
|
|
" goto cleanup;\n");
|
2011-04-22 22:19:14 +00:00
|
|
|
push(@args_list, "$2");
|
2011-04-22 18:35:34 +00:00
|
|
|
push(@free_list,
|
2011-04-22 22:19:14 +00:00
|
|
|
" if ($2)\n" .
|
|
|
|
" vir${type_name}Free($2);");
|
2011-04-22 18:35:34 +00:00
|
|
|
} elsif ($args_member =~ m/^remote_nonnull_domain_snapshot /) {
|
|
|
|
push(@vars_list, "virDomainPtr dom = NULL");
|
|
|
|
push(@vars_list, "virDomainSnapshotPtr snapshot = NULL");
|
|
|
|
push(@getters_list,
|
2011-05-16 17:13:11 +00:00
|
|
|
" if (!(dom = get_nonnull_domain(priv->conn, args->snap.dom)))\n" .
|
2011-04-22 18:35:34 +00:00
|
|
|
" goto cleanup;\n" .
|
|
|
|
"\n" .
|
|
|
|
" if (!(snapshot = get_nonnull_domain_snapshot(dom, args->snap)))\n" .
|
|
|
|
" goto cleanup;\n");
|
|
|
|
push(@args_list, "snapshot");
|
|
|
|
push(@free_list,
|
|
|
|
" if (snapshot)\n" .
|
|
|
|
" virDomainSnapshotFree(snapshot);\n" .
|
|
|
|
" if (dom)\n" .
|
|
|
|
" virDomainFree(dom);");
|
2011-06-16 09:30:23 +00:00
|
|
|
} elsif ($args_member =~ m/^(?:remote_string|remote_uuid) (\S+)<\S+>;/) {
|
2011-04-22 18:35:34 +00:00
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-04-22 18:35:34 +00:00
|
|
|
}
|
|
|
|
|
2011-06-16 09:30:23 +00:00
|
|
|
push(@args_list, "args->$1.$1_val");
|
|
|
|
push(@args_list, "args->$1.$1_len");
|
|
|
|
} elsif ($args_member =~ m/^(?:opaque|remote_nonnull_string) (\S+)<\S+>;(.*)$/) {
|
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-04-22 18:35:34 +00:00
|
|
|
}
|
|
|
|
|
2011-06-16 09:30:23 +00:00
|
|
|
my $cast = "";
|
|
|
|
my $arg_name = $1;
|
|
|
|
my $annotation = $2;
|
|
|
|
|
|
|
|
if ($annotation ne "") {
|
|
|
|
if ($annotation =~ m/\s*\/\*\s*(.*)\s*\*\//) {
|
|
|
|
$cast = $1;
|
|
|
|
} else {
|
|
|
|
die "malformed cast annotation for argument: $args_member";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
push(@args_list, "${cast}args->$arg_name.${arg_name}_val");
|
|
|
|
push(@args_list, "args->$arg_name.${arg_name}_len");
|
2011-06-07 09:11:11 +00:00
|
|
|
} elsif ($args_member =~ m/^(?:unsigned )?int (\S+)<\S+>;/) {
|
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-06-07 09:11:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
push(@args_list, "args->$1.$1_val");
|
|
|
|
push(@args_list, "args->$1.$1_len");
|
2011-05-30 18:27:37 +00:00
|
|
|
} elsif ($args_member =~ m/^remote_typed_param (\S+)<(\S+)>;/) {
|
|
|
|
push(@vars_list, "virTypedParameterPtr $1 = NULL");
|
2013-05-02 11:35:47 +00:00
|
|
|
push(@vars_list, "int n$1 = 0;");
|
2012-09-14 14:42:15 +00:00
|
|
|
if ($call->{ProcName} eq "NodeSetMemoryParameters") {
|
|
|
|
push(@args_list, "priv->conn");
|
|
|
|
}
|
2011-05-30 18:27:37 +00:00
|
|
|
push(@args_list, "$1");
|
|
|
|
push(@args_list, "n$1");
|
|
|
|
push(@getters_list, " if (($1 = remoteDeserializeTypedParameters(args->$1.$1_val,\n" .
|
|
|
|
" args->$1.$1_len,\n" .
|
|
|
|
" $2,\n" .
|
|
|
|
" &n$1)) == NULL)\n" .
|
|
|
|
" goto cleanup;\n");
|
2013-01-15 23:42:35 +00:00
|
|
|
push(@free_list, " virTypedParamsFree($1, n$1);");
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($args_member =~ m/<\S+>;/ or $args_member =~ m/\[\S+\];/) {
|
|
|
|
# just make all other array types fail
|
|
|
|
die "unhandled type for argument value: $args_member";
|
|
|
|
} elsif ($args_member =~ m/^remote_uuid (\S+);/) {
|
2011-04-22 18:35:34 +00:00
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-04-22 18:35:34 +00:00
|
|
|
}
|
|
|
|
|
2011-05-07 06:15:51 +00:00
|
|
|
push(@args_list, "(unsigned char *) args->$1");
|
|
|
|
} elsif ($args_member =~ m/^remote_string (\S+);/) {
|
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-04-22 16:54:51 +00:00
|
|
|
}
|
2011-05-07 06:15:51 +00:00
|
|
|
|
|
|
|
push(@vars_list, "char *$1");
|
|
|
|
push(@optionals_list, "$1");
|
|
|
|
push(@args_list, "$1");
|
|
|
|
} elsif ($args_member =~ m/^remote_nonnull_string (\S+);/) {
|
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-05-07 06:15:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
push(@args_list, "args->$1");
|
2011-05-30 10:58:57 +00:00
|
|
|
} elsif ($args_member =~ m/^(unsigned )?int (\S+);/) {
|
2011-05-07 06:15:51 +00:00
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-05-07 06:15:51 +00:00
|
|
|
}
|
|
|
|
|
2011-05-30 10:58:57 +00:00
|
|
|
push(@args_list, "args->$2");
|
|
|
|
} elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) {
|
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-05-30 10:58:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
my $arg_name = $2;
|
|
|
|
|
|
|
|
if (hyper_to_long($call->{ProcName}, "arg", $arg_name)) {
|
|
|
|
my $type_name = $1; $type_name .= "long";
|
|
|
|
my $sign = ""; $sign = "U" if ($1);
|
|
|
|
|
|
|
|
push(@vars_list, "$type_name $arg_name");
|
|
|
|
push(@getters_list, " HYPER_TO_${sign}LONG($arg_name, args->$arg_name);\n");
|
|
|
|
push(@args_list, "$arg_name");
|
|
|
|
} else {
|
|
|
|
push(@args_list, "args->$arg_name");
|
|
|
|
}
|
2011-05-07 05:36:21 +00:00
|
|
|
} elsif ($args_member =~ m/^(\/)?\*/) {
|
2011-04-23 07:36:33 +00:00
|
|
|
# ignore comments
|
|
|
|
} else {
|
|
|
|
die "unhandled type for argument value: $args_member";
|
2011-04-22 18:35:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-23 07:40:14 +00:00
|
|
|
# handle return values of the function
|
2011-04-22 15:09:33 +00:00
|
|
|
my $single_ret_var = "undefined";
|
|
|
|
my $single_ret_by_ref = 0;
|
|
|
|
my $single_ret_check = " == undefined";
|
2011-04-22 20:48:25 +00:00
|
|
|
my $single_ret_as_list = 0;
|
|
|
|
my $single_ret_list_name = "undefined";
|
|
|
|
my $single_ret_list_max_var = "undefined";
|
|
|
|
my $single_ret_list_max_define = "undefined";
|
2011-04-23 07:36:33 +00:00
|
|
|
my $multi_ret = 0;
|
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($rettype ne "void" and
|
2011-05-15 06:14:35 +00:00
|
|
|
scalar(@{$call->{ret_members}}) > 1) {
|
2011-04-23 07:36:33 +00:00
|
|
|
$multi_ret = 1;
|
|
|
|
}
|
2011-04-22 15:09:33 +00:00
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($rettype ne "void") {
|
2011-05-15 06:14:35 +00:00
|
|
|
foreach my $ret_member (@{$call->{ret_members}}) {
|
2011-04-23 07:36:33 +00:00
|
|
|
if ($multi_ret) {
|
2011-05-07 06:15:51 +00:00
|
|
|
if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) {
|
2011-05-30 10:58:57 +00:00
|
|
|
if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) {
|
|
|
|
die "legacy [u]long hyper arrays aren't supported";
|
|
|
|
}
|
|
|
|
|
2012-03-29 09:52:04 +00:00
|
|
|
push(@ret_list, "memcpy(ret->$3, tmp.$3, sizeof(ret->$3));");
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) {
|
|
|
|
push(@ret_list, "ret->$3 = tmp.$3;");
|
2011-04-23 07:36:33 +00:00
|
|
|
} else {
|
|
|
|
die "unhandled type for multi-return-value: $ret_member";
|
|
|
|
}
|
2011-05-21 09:16:07 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_string (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) {
|
2011-04-22 20:48:25 +00:00
|
|
|
push(@vars_list, "int len");
|
2011-05-21 09:16:07 +00:00
|
|
|
splice(@args_list, int($3), 0, ("ret->$1.$1_val"));
|
2011-04-22 20:48:25 +00:00
|
|
|
push(@ret_list, "ret->$1.$1_len = len;");
|
2011-04-23 06:35:03 +00:00
|
|
|
push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);");
|
2011-04-22 20:48:25 +00:00
|
|
|
$single_ret_var = "len";
|
|
|
|
$single_ret_by_ref = 0;
|
|
|
|
$single_ret_check = " < 0";
|
|
|
|
$single_ret_as_list = 1;
|
|
|
|
$single_ret_list_name = $1;
|
|
|
|
$single_ret_list_max_var = "max$1";
|
|
|
|
$single_ret_list_max_define = $2;
|
2011-05-21 09:16:07 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_string (\S+)<\S+>;/) {
|
|
|
|
# error out on unannotated arrays
|
|
|
|
die "remote_nonnull_string array without insert@<offset> annotation: $ret_member";
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_string (\S+);/) {
|
2013-04-18 11:07:23 +00:00
|
|
|
if ($call->{ProcName} eq "ConnectGetType") {
|
2011-05-16 18:10:06 +00:00
|
|
|
# SPECIAL: virConnectGetType returns a constant string that must
|
|
|
|
# not be freed. Therefore, duplicate the string here.
|
|
|
|
push(@vars_list, "const char *$1");
|
2013-05-03 12:47:53 +00:00
|
|
|
push(@ret_list, "/* We have to VIR_STRDUP because remoteDispatchClientRequest will");
|
2011-05-16 18:10:06 +00:00
|
|
|
push(@ret_list, " * free this string after it's been serialised. */");
|
2013-05-03 12:47:53 +00:00
|
|
|
push(@ret_list, "if (VIR_STRDUP(ret->type, type) < 0)");
|
2011-05-16 18:10:06 +00:00
|
|
|
push(@ret_list, " goto cleanup;");
|
|
|
|
} else {
|
|
|
|
push(@vars_list, "char *$1");
|
|
|
|
push(@ret_list, "ret->$1 = $1;");
|
|
|
|
}
|
|
|
|
|
2011-06-15 18:03:45 +00:00
|
|
|
$single_ret_var = $1;
|
|
|
|
$single_ret_by_ref = 0;
|
|
|
|
$single_ret_check = " == NULL";
|
|
|
|
} elsif ($ret_member =~ m/^remote_string (\S+);/) {
|
|
|
|
push(@vars_list, "char *$1 = NULL");
|
|
|
|
push(@vars_list, "char **$1_p = NULL");
|
|
|
|
push(@ret_list, "ret->$1 = $1_p;");
|
|
|
|
push(@free_list, " VIR_FREE($1);");
|
|
|
|
push(@free_list_on_error, "VIR_FREE($1_p);");
|
|
|
|
push(@prepare_ret_list,
|
2013-07-04 10:15:05 +00:00
|
|
|
"if (VIR_ALLOC($1_p) < 0)\n" .
|
2011-06-15 18:03:45 +00:00
|
|
|
" goto cleanup;\n" .
|
|
|
|
" \n" .
|
2013-05-03 12:47:53 +00:00
|
|
|
" if (VIR_STRDUP(*$1_p, $1) < 0)\n".
|
|
|
|
" goto cleanup;\n");
|
2011-06-15 18:03:45 +00:00
|
|
|
|
2011-04-22 15:09:33 +00:00
|
|
|
$single_ret_var = $1;
|
|
|
|
$single_ret_by_ref = 0;
|
|
|
|
$single_ret_check = " == NULL";
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|node_device|secret|nwfilter|domain_snapshot) (\S+);/) {
|
2012-07-20 14:31:46 +00:00
|
|
|
my $type_name = name_to_TypeName($1);
|
2011-04-22 22:19:14 +00:00
|
|
|
|
2011-05-20 15:58:34 +00:00
|
|
|
if ($call->{ProcName} eq "DomainCreateWithFlags") {
|
|
|
|
# SPECIAL: virDomainCreateWithFlags updates the given
|
|
|
|
# domain object instead of returning a new one
|
|
|
|
push(@ret_list, "make_nonnull_$1(&ret->$2, $2);");
|
|
|
|
$single_ret_var = undef;
|
|
|
|
$single_ret_by_ref = 1;
|
|
|
|
} else {
|
|
|
|
push(@vars_list, "vir${type_name}Ptr $2 = NULL");
|
|
|
|
push(@ret_list, "make_nonnull_$1(&ret->$2, $2);");
|
|
|
|
push(@free_list,
|
|
|
|
" if ($2)\n" .
|
|
|
|
" vir${type_name}Free($2);");
|
|
|
|
$single_ret_var = $2;
|
|
|
|
$single_ret_by_ref = 0;
|
|
|
|
$single_ret_check = " == NULL";
|
|
|
|
}
|
2011-05-21 09:16:07 +00:00
|
|
|
} elsif ($ret_member =~ m/^int (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) {
|
2011-04-22 20:48:25 +00:00
|
|
|
push(@vars_list, "int len");
|
2011-05-21 09:16:07 +00:00
|
|
|
splice(@args_list, int($3), 0, ("ret->$1.$1_val"));
|
2011-04-22 20:48:25 +00:00
|
|
|
push(@ret_list, "ret->$1.$1_len = len;");
|
2011-04-23 06:35:03 +00:00
|
|
|
push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);");
|
2011-04-22 20:48:25 +00:00
|
|
|
$single_ret_var = "len";
|
|
|
|
$single_ret_by_ref = 0;
|
|
|
|
$single_ret_check = " < 0";
|
|
|
|
$single_ret_as_list = 1;
|
|
|
|
$single_ret_list_name = $1;
|
|
|
|
$single_ret_list_max_var = "max$1";
|
|
|
|
$single_ret_list_max_define = $2;
|
2011-05-21 09:16:07 +00:00
|
|
|
} elsif ($ret_member =~ m/^int (\S+)<\S+>;/) {
|
|
|
|
# error out on unannotated arrays
|
|
|
|
die "int array without insert@<offset> annotation: $ret_member";
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^int (\S+);/) {
|
2011-04-22 15:09:33 +00:00
|
|
|
push(@vars_list, "int $1");
|
|
|
|
push(@ret_list, "ret->$1 = $1;");
|
|
|
|
$single_ret_var = $1;
|
|
|
|
|
2011-05-15 06:14:35 +00:00
|
|
|
if ($call->{ProcName} =~ m/GetAutostart$/) {
|
2011-04-22 15:09:33 +00:00
|
|
|
$single_ret_by_ref = 1;
|
|
|
|
} else {
|
|
|
|
$single_ret_by_ref = 0;
|
2011-04-23 06:19:46 +00:00
|
|
|
|
2011-05-15 06:14:35 +00:00
|
|
|
if ($call->{ProcName} eq "CPUCompare") {
|
2011-04-23 06:19:46 +00:00
|
|
|
$single_ret_check = " == VIR_CPU_COMPARE_ERROR";
|
|
|
|
} else {
|
|
|
|
$single_ret_check = " < 0";
|
|
|
|
}
|
2011-04-22 15:09:33 +00:00
|
|
|
}
|
2011-05-21 10:24:40 +00:00
|
|
|
} elsif ($ret_member =~ m/^(?:unsigned )?hyper (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) {
|
2011-05-30 10:58:57 +00:00
|
|
|
if (hyper_to_long($call->{ProcName}, "ret", $1)) {
|
|
|
|
die "legacy [u]long hyper arrays aren't supported";
|
|
|
|
}
|
|
|
|
|
2011-04-22 20:48:25 +00:00
|
|
|
push(@vars_list, "int len");
|
|
|
|
push(@ret_list, "ret->$1.$1_len = len;");
|
2011-04-23 06:35:03 +00:00
|
|
|
push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);");
|
2011-04-22 20:48:25 +00:00
|
|
|
$single_ret_var = "len";
|
|
|
|
$single_ret_by_ref = 0;
|
|
|
|
$single_ret_as_list = 1;
|
|
|
|
$single_ret_list_name = $1;
|
2011-05-21 07:52:19 +00:00
|
|
|
$single_ret_list_max_var = "max$1";
|
2011-04-22 20:48:25 +00:00
|
|
|
$single_ret_list_max_define = $2;
|
|
|
|
|
2011-05-15 06:14:35 +00:00
|
|
|
if ($call->{ProcName} eq "NodeGetCellsFreeMemory") {
|
2011-04-22 20:48:25 +00:00
|
|
|
$single_ret_check = " <= 0";
|
2011-05-21 09:16:07 +00:00
|
|
|
splice(@args_list, int($3), 0, ("(unsigned long long *)ret->$1.$1_val"));
|
2011-04-22 20:48:25 +00:00
|
|
|
} else {
|
|
|
|
$single_ret_check = " < 0";
|
2011-05-21 09:16:07 +00:00
|
|
|
splice(@args_list, int($3), 0, ("ret->$1.$1_val"));
|
2011-04-22 20:48:25 +00:00
|
|
|
}
|
2011-05-21 10:24:40 +00:00
|
|
|
} elsif ($ret_member =~ m/^(?:unsigned )?hyper (\S+)<\S+>;/) {
|
2011-05-21 09:16:07 +00:00
|
|
|
# error out on unannotated arrays
|
|
|
|
die "hyper array without insert@<offset> annotation: $ret_member";
|
2011-08-26 17:46:41 +00:00
|
|
|
} elsif ($ret_member =~ m/^(unsigned )?hyper (\S+);(?:\s*\/\*\s*insert@(\d+)\s*\*\/)?/) {
|
2011-05-30 10:58:57 +00:00
|
|
|
my $type_name = $1;
|
2011-05-07 06:15:51 +00:00
|
|
|
my $ret_name = $2;
|
2011-05-30 10:58:57 +00:00
|
|
|
my $ret_assign;
|
2011-08-26 17:46:41 +00:00
|
|
|
my $insert = $3;
|
2011-05-07 06:15:51 +00:00
|
|
|
|
2011-05-30 10:58:57 +00:00
|
|
|
if (hyper_to_long($call->{ProcName}, "ret", $ret_name)) {
|
|
|
|
my $sign = ""; $sign = "U" if ($1);
|
|
|
|
|
|
|
|
$type_name .= "long";
|
|
|
|
$ret_assign = "HYPER_TO_${sign}LONG(ret->$ret_name, $ret_name);";
|
|
|
|
} else {
|
|
|
|
$type_name .= "long long";
|
|
|
|
$ret_assign = "ret->$ret_name = $ret_name;";
|
|
|
|
}
|
2011-05-07 06:15:51 +00:00
|
|
|
|
|
|
|
push(@vars_list, "$type_name $ret_name");
|
2011-05-30 10:58:57 +00:00
|
|
|
push(@ret_list, $ret_assign);
|
2011-08-26 17:46:41 +00:00
|
|
|
|
|
|
|
if ($insert) {
|
|
|
|
splice(@args_list, int($insert), 0, "&$ret_name");
|
|
|
|
$single_ret_var = undef;
|
|
|
|
} else {
|
|
|
|
$single_ret_var = $ret_name;
|
|
|
|
}
|
2011-04-22 15:09:33 +00:00
|
|
|
|
2011-05-15 06:14:35 +00:00
|
|
|
if ($call->{ProcName} eq "DomainGetMaxMemory" or
|
|
|
|
$call->{ProcName} eq "NodeGetFreeMemory") {
|
2011-05-07 06:15:51 +00:00
|
|
|
# SPECIAL: virDomainGetMaxMemory and virNodeGetFreeMemory
|
|
|
|
# return the actual value directly and 0 indicates
|
|
|
|
# an error
|
2011-04-22 15:09:33 +00:00
|
|
|
$single_ret_by_ref = 0;
|
|
|
|
$single_ret_check = " == 0";
|
|
|
|
} else {
|
|
|
|
$single_ret_by_ref = 1;
|
|
|
|
}
|
2011-05-21 09:24:28 +00:00
|
|
|
} elsif ($ret_member =~ m/^opaque (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) {
|
|
|
|
push(@vars_list, "char *$1 = NULL");
|
|
|
|
push(@vars_list, "int $1_len = 0");
|
|
|
|
splice(@args_list, int($3), 0, ("&$1", "&$1_len"));
|
|
|
|
push(@ret_list, "ret->$1.$1_val = $1;");
|
|
|
|
push(@ret_list, "ret->$1.$1_len = $1_len;");
|
|
|
|
push(@free_list_on_error, "VIR_FREE($1);");
|
|
|
|
$single_ret_var = undef;
|
|
|
|
$single_ret_by_ref = 1;
|
|
|
|
} elsif ($ret_member =~ m/^opaque (\S+)<\S+>;/) {
|
|
|
|
# error out on unannotated arrays
|
|
|
|
die "opaque array without insert@<offset> annotation: $ret_member";
|
2011-05-11 19:28:39 +00:00
|
|
|
} elsif ($ret_member =~ m/^(\/)?\*/) {
|
|
|
|
# ignore comments
|
2011-04-23 07:36:33 +00:00
|
|
|
} else {
|
|
|
|
die "unhandled type for return value: $ret_member";
|
2011-04-22 15:09:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-23 07:40:14 +00:00
|
|
|
# select struct type for multi-return-value functions
|
2011-04-23 07:36:33 +00:00
|
|
|
if ($multi_ret) {
|
2011-06-15 13:38:31 +00:00
|
|
|
if (!(defined $call->{ret_offset})) {
|
|
|
|
die "multi-return-value without insert@<offset> annotation: $call->{ret}";
|
|
|
|
}
|
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if (! @args_list) {
|
|
|
|
push(@args_list, "priv->conn");
|
2011-04-23 07:36:33 +00:00
|
|
|
}
|
|
|
|
|
2011-05-15 06:14:35 +00:00
|
|
|
my $struct_name = $call->{ProcName};
|
2011-04-23 07:36:33 +00:00
|
|
|
$struct_name =~ s/Get//;
|
|
|
|
|
2011-06-15 13:38:31 +00:00
|
|
|
splice(@args_list, $call->{ret_offset}, 0, ("&tmp"));
|
|
|
|
|
|
|
|
if ($call->{ProcName} eq "DomainBlockStats" ||
|
|
|
|
$call->{ProcName} eq "DomainInterfaceStats") {
|
2011-05-07 06:15:51 +00:00
|
|
|
# SPECIAL: virDomainBlockStats and virDomainInterfaceStats
|
|
|
|
# have a 'Struct' suffix on the actual struct name
|
|
|
|
# and take the struct size as additional argument
|
2011-04-23 07:36:33 +00:00
|
|
|
$struct_name .= "Struct";
|
2012-03-29 09:52:04 +00:00
|
|
|
splice(@args_list, $call->{ret_offset} + 1, 0, ("sizeof(tmp)"));
|
2011-04-23 07:36:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
push(@vars_list, "vir$struct_name tmp");
|
|
|
|
}
|
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if ($call->{streamflag} ne "none") {
|
2011-05-16 17:13:11 +00:00
|
|
|
splice(@args_list, $call->{streamoffset}, 0, ("st"));
|
2011-05-21 09:24:28 +00:00
|
|
|
push(@free_list_on_error, "if (stream) {");
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@free_list_on_error, " virStreamAbort(st);");
|
|
|
|
push(@free_list_on_error, " daemonFreeClientStream(client, stream);");
|
|
|
|
push(@free_list_on_error, "} else {");
|
|
|
|
push(@free_list_on_error, " virStreamFree(st);");
|
2011-05-21 09:24:28 +00:00
|
|
|
push(@free_list_on_error, "}");
|
|
|
|
}
|
|
|
|
|
2011-04-23 07:40:14 +00:00
|
|
|
# print functions signature
|
2012-07-27 12:51:28 +00:00
|
|
|
print "static int $name(\n";
|
|
|
|
print " virNetServerPtr server ATTRIBUTE_UNUSED,\n";
|
|
|
|
print " virNetServerClientPtr client,\n";
|
|
|
|
print " virNetMessagePtr msg ATTRIBUTE_UNUSED,\n";
|
|
|
|
print " virNetMessageErrorPtr rerr";
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($argtype ne "void") {
|
2012-07-27 12:51:28 +00:00
|
|
|
print ",\n $argtype *args";
|
|
|
|
}
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($rettype ne "void") {
|
2012-07-27 12:51:28 +00:00
|
|
|
print ",\n $rettype *ret";
|
|
|
|
}
|
|
|
|
print ")\n";
|
2011-04-23 07:40:14 +00:00
|
|
|
|
|
|
|
# print function body
|
|
|
|
print "{\n";
|
|
|
|
print " int rv = -1;\n";
|
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
foreach my $var (@vars_list) {
|
|
|
|
print " $var;\n";
|
|
|
|
}
|
2012-07-27 12:51:28 +00:00
|
|
|
print " struct daemonClientPrivate *priv =\n";
|
2011-05-16 17:13:11 +00:00
|
|
|
print " virNetServerClientGetPrivateData(client);\n";
|
2011-04-22 18:35:34 +00:00
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if ($call->{streamflag} ne "none") {
|
2011-05-16 17:13:11 +00:00
|
|
|
print " virStreamPtr st = NULL;\n";
|
|
|
|
print " daemonClientStreamPtr stream = NULL;\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
print "\n";
|
2011-05-16 17:13:11 +00:00
|
|
|
print " if (!priv->conn) {\n";
|
2012-07-18 18:30:53 +00:00
|
|
|
print " virReportError(VIR_ERR_INTERNAL_ERROR, \"%s\", _(\"connection not open\"));\n";
|
2011-04-22 18:35:34 +00:00
|
|
|
print " goto cleanup;\n";
|
|
|
|
print " }\n";
|
|
|
|
print "\n";
|
|
|
|
|
2011-04-22 20:48:25 +00:00
|
|
|
if ($single_ret_as_list) {
|
|
|
|
print " if (args->$single_ret_list_max_var > $single_ret_list_max_define) {\n";
|
2012-07-18 18:30:53 +00:00
|
|
|
print " virReportError(VIR_ERR_INTERNAL_ERROR,\n";
|
|
|
|
print " \"%s\", _(\"max$single_ret_list_name > $single_ret_list_max_define\"));\n";
|
2011-04-22 20:48:25 +00:00
|
|
|
print " goto cleanup;\n";
|
|
|
|
print " }\n";
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
print join("\n", @getters_list);
|
|
|
|
|
2011-04-22 15:09:33 +00:00
|
|
|
if (@getters_list) {
|
|
|
|
print "\n";
|
|
|
|
}
|
2011-04-22 18:35:34 +00:00
|
|
|
|
2011-04-22 18:31:05 +00:00
|
|
|
foreach my $optional (@optionals_list) {
|
|
|
|
print " $optional = args->$optional ? *args->$optional : NULL;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (@optionals_list) {
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if ($call->{streamflag} ne "none") {
|
2011-05-16 17:13:11 +00:00
|
|
|
print " if (!(st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK)))\n";
|
|
|
|
print " goto cleanup;\n";
|
|
|
|
print "\n";
|
2011-10-21 11:12:28 +00:00
|
|
|
print " if (!(stream = daemonCreateClientStream(client, st, remoteProgram, &msg->header)))\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
print " goto cleanup;\n";
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($rettype eq "void") {
|
2011-05-15 06:14:35 +00:00
|
|
|
print " if (vir$call->{ProcName}(";
|
2011-04-22 18:35:34 +00:00
|
|
|
print join(', ', @args_list);
|
|
|
|
print ") < 0)\n";
|
|
|
|
print " goto cleanup;\n";
|
|
|
|
print "\n";
|
2011-04-23 07:36:33 +00:00
|
|
|
} elsif (!$multi_ret) {
|
2011-04-22 15:09:33 +00:00
|
|
|
my $prefix = "";
|
2011-05-15 06:14:35 +00:00
|
|
|
my $proc_name = $call->{ProcName};
|
2011-04-22 15:09:33 +00:00
|
|
|
|
|
|
|
if (! @args_list) {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@args_list, "priv->conn");
|
2011-04-22 15:09:33 +00:00
|
|
|
}
|
|
|
|
|
2013-04-18 11:07:23 +00:00
|
|
|
if ($structprefix eq "qemu" && $call->{ProcName} =~ /^Domain/) {
|
2011-05-05 16:31:58 +00:00
|
|
|
$proc_name =~ s/^(Domain)/${1}Qemu/;
|
2011-04-22 15:09:33 +00:00
|
|
|
}
|
2013-04-18 11:07:23 +00:00
|
|
|
if ($structprefix eq "lxc" && $call->{ProcName} =~ /^Domain/) {
|
|
|
|
$proc_name =~ s/^(Domain)/${1}Lxc/;
|
|
|
|
}
|
2011-04-22 15:09:33 +00:00
|
|
|
|
2011-04-22 20:48:25 +00:00
|
|
|
if ($single_ret_as_list) {
|
|
|
|
print " /* Allocate return buffer. */\n";
|
|
|
|
print " if (VIR_ALLOC_N(ret->$single_ret_list_name.${single_ret_list_name}_val," .
|
2013-07-04 10:15:05 +00:00
|
|
|
" args->$single_ret_list_max_var) < 0)\n";
|
2011-04-22 20:48:25 +00:00
|
|
|
print " goto cleanup;\n";
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-04-22 15:09:33 +00:00
|
|
|
if ($single_ret_by_ref) {
|
|
|
|
print " if (vir$prefix$proc_name(";
|
|
|
|
print join(', ', @args_list);
|
2011-05-20 15:58:34 +00:00
|
|
|
|
|
|
|
if (defined $single_ret_var) {
|
|
|
|
print ", &$single_ret_var";
|
|
|
|
}
|
|
|
|
|
|
|
|
print ") < 0)\n";
|
2011-04-22 15:09:33 +00:00
|
|
|
} else {
|
|
|
|
print " if (($single_ret_var = vir$prefix$proc_name(";
|
|
|
|
print join(', ', @args_list);
|
|
|
|
print "))$single_ret_check)\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
print " goto cleanup;\n";
|
|
|
|
print "\n";
|
2011-04-23 07:36:33 +00:00
|
|
|
} else {
|
2011-05-15 06:14:35 +00:00
|
|
|
print " if (vir$call->{ProcName}(";
|
2011-04-23 07:36:33 +00:00
|
|
|
print join(', ', @args_list);
|
|
|
|
print ") < 0)\n";
|
|
|
|
print " goto cleanup;\n";
|
|
|
|
print "\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
}
|
2011-04-23 07:36:33 +00:00
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if ($call->{streamflag} ne "none") {
|
2011-05-16 17:13:11 +00:00
|
|
|
print " if (daemonAddClientStream(client, stream, ";
|
2011-05-21 09:24:28 +00:00
|
|
|
|
|
|
|
if ($call->{streamflag} eq "write") {
|
2011-05-16 17:13:11 +00:00
|
|
|
print "false";
|
2011-05-21 09:24:28 +00:00
|
|
|
} else {
|
2011-05-16 17:13:11 +00:00
|
|
|
print "true";
|
2011-04-23 07:36:33 +00:00
|
|
|
}
|
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
print ") < 0)\n";
|
|
|
|
print " goto cleanup;\n";
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-06-15 18:03:45 +00:00
|
|
|
if (@prepare_ret_list) {
|
|
|
|
print " ";
|
|
|
|
print join("\n ", @prepare_ret_list);
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if (@ret_list) {
|
|
|
|
print " ";
|
2011-04-23 07:36:33 +00:00
|
|
|
print join("\n ", @ret_list);
|
2011-04-22 15:09:33 +00:00
|
|
|
print "\n";
|
2011-04-22 18:35:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
print " rv = 0;\n";
|
|
|
|
print "\n";
|
|
|
|
print "cleanup:\n";
|
2011-04-23 06:35:03 +00:00
|
|
|
print " if (rv < 0)";
|
|
|
|
|
|
|
|
if (scalar(@free_list_on_error) > 1) {
|
|
|
|
print " {";
|
|
|
|
}
|
|
|
|
|
|
|
|
print "\n ";
|
|
|
|
print join("\n ", @free_list_on_error);
|
|
|
|
print "\n";
|
|
|
|
|
|
|
|
if (scalar(@free_list_on_error) > 1) {
|
|
|
|
print " }\n";
|
|
|
|
}
|
2011-04-22 18:35:34 +00:00
|
|
|
|
|
|
|
print join("\n", @free_list);
|
|
|
|
|
2011-04-22 15:09:33 +00:00
|
|
|
if (@free_list) {
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-04-22 18:35:34 +00:00
|
|
|
print " return rv;\n";
|
2011-05-16 17:13:11 +00:00
|
|
|
print "}\n\n\n\n";
|
2011-04-22 18:35:34 +00:00
|
|
|
}
|
2011-05-16 17:13:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Finally we write out the huge dispatch table which lists
|
|
|
|
# the dispatch helper method. the XDR proc for processing
|
|
|
|
# args and return values, and the size of the args and
|
|
|
|
# return value structs. All methods are marked as requiring
|
|
|
|
# authentication. Methods are selectively relaxed in the
|
|
|
|
# daemon code which registers the program.
|
|
|
|
|
|
|
|
print "virNetServerProgramProc ${structprefix}Procs[] = {\n";
|
|
|
|
for ($id = 0 ; $id <= $#calls ; $id++) {
|
2012-07-27 12:51:28 +00:00
|
|
|
my ($comment, $name, $argtype, $arglen, $argfilter, $retlen, $retfilter, $priority);
|
|
|
|
|
|
|
|
if (defined $calls[$id] && !$calls[$id]->{msg}) {
|
|
|
|
$comment = "/* Method $calls[$id]->{ProcName} => $id */";
|
|
|
|
$name = $structprefix . "Dispatch" . $calls[$id]->{ProcName} . "Helper";
|
|
|
|
my $argtype = $calls[$id]->{args};
|
|
|
|
my $rettype = $calls[$id]->{ret};
|
|
|
|
$arglen = $argtype ne "void" ? "sizeof($argtype)" : "0";
|
|
|
|
$retlen = $rettype ne "void" ? "sizeof($rettype)" : "0";
|
|
|
|
$argfilter = $argtype ne "void" ? "xdr_$argtype" : "xdr_void";
|
|
|
|
$retfilter = $rettype ne "void" ? "xdr_$rettype" : "xdr_void";
|
|
|
|
} else {
|
|
|
|
if ($calls[$id]->{msg}) {
|
|
|
|
$comment = "/* Async event $calls[$id]->{ProcName} => $id */";
|
|
|
|
} else {
|
|
|
|
$comment = "/* Unused $id */";
|
|
|
|
}
|
|
|
|
$name = "NULL";
|
|
|
|
$arglen = $retlen = 0;
|
|
|
|
$argfilter = "xdr_void";
|
|
|
|
$retfilter = "xdr_void";
|
|
|
|
}
|
2011-05-16 17:13:11 +00:00
|
|
|
|
2011-08-12 12:04:31 +00:00
|
|
|
$priority = defined $calls[$id]->{priority} ? $calls[$id]->{priority} : 0;
|
|
|
|
|
2012-07-27 12:51:28 +00:00
|
|
|
print "{ $comment\n ${name},\n $arglen,\n (xdrproc_t)$argfilter,\n $retlen,\n (xdrproc_t)$retfilter,\n true,\n $priority\n},\n";
|
2011-05-16 17:13:11 +00:00
|
|
|
}
|
|
|
|
print "};\n";
|
|
|
|
print "size_t ${structprefix}NProcs = ARRAY_CARDINALITY(${structprefix}Procs);\n";
|
2011-04-22 18:35:34 +00:00
|
|
|
}
|
2011-04-23 10:53:57 +00:00
|
|
|
|
2011-05-06 19:54:32 +00:00
|
|
|
# Bodies for client functions ("remote_client_bodies.h").
|
2013-04-18 10:29:56 +00:00
|
|
|
elsif ($mode eq "client") {
|
2011-05-11 19:28:39 +00:00
|
|
|
my %generate = map { $_ => 1 } @autogen;
|
2011-04-23 10:53:57 +00:00
|
|
|
my @keys = sort (keys %calls);
|
|
|
|
|
|
|
|
foreach (@keys) {
|
|
|
|
my $call = $calls{$_};
|
|
|
|
|
|
|
|
# skip things which are REMOTE_MESSAGE
|
|
|
|
next if $call->{msg};
|
|
|
|
|
2011-05-11 19:28:39 +00:00
|
|
|
# skip procedures not on generate list
|
|
|
|
next if ! exists($generate{$call->{ProcName}});
|
2011-04-23 10:53:57 +00:00
|
|
|
|
2012-07-27 12:51:28 +00:00
|
|
|
my $argtype = $call->{args};
|
|
|
|
my $rettype = $call->{ret};
|
2011-05-16 17:13:11 +00:00
|
|
|
|
2011-04-23 19:25:49 +00:00
|
|
|
# handle arguments to the function
|
2011-04-23 10:53:57 +00:00
|
|
|
my @args_list = ();
|
|
|
|
my @vars_list = ();
|
2011-04-24 07:49:42 +00:00
|
|
|
my @args_check_list = ();
|
2011-04-23 10:53:57 +00:00
|
|
|
my @setters_list = ();
|
2011-05-30 18:27:37 +00:00
|
|
|
my @setters_list2 = ();
|
2011-07-27 18:32:25 +00:00
|
|
|
my @free_list = ();
|
2011-04-23 10:53:57 +00:00
|
|
|
my $priv_src = "conn";
|
|
|
|
my $priv_name = "privateData";
|
2011-04-23 14:33:57 +00:00
|
|
|
my $call_args = "&args";
|
2011-04-23 10:53:57 +00:00
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($argtype eq "void") {
|
2011-04-23 14:33:57 +00:00
|
|
|
$call_args = "NULL";
|
2011-04-23 10:53:57 +00:00
|
|
|
} else {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@vars_list, "$argtype args");
|
2011-04-23 10:53:57 +00:00
|
|
|
|
|
|
|
my $is_first_arg = 1;
|
|
|
|
my $has_node_device = 0;
|
|
|
|
|
|
|
|
# node device is special
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($argtype =~ m/^remote_node_/ and
|
|
|
|
!($argtype =~ m/^remote_node_device_lookup_by_name_/) and
|
|
|
|
!($argtype =~ m/^remote_node_device_create_xml_/)) {
|
2011-04-23 10:53:57 +00:00
|
|
|
$has_node_device = 1;
|
2013-04-23 10:15:48 +00:00
|
|
|
$priv_name = "nodeDevicePrivateData";
|
2011-04-23 10:53:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach my $args_member (@{$call->{args_members}}) {
|
|
|
|
if ($args_member =~ m/^remote_nonnull_string name;/ and $has_node_device) {
|
|
|
|
$priv_src = "dev->conn";
|
|
|
|
push(@args_list, "virNodeDevicePtr dev");
|
|
|
|
push(@setters_list, "args.name = dev->name;");
|
|
|
|
} elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter|domain_snapshot) (\S+);/) {
|
|
|
|
my $name = $1;
|
2011-04-23 17:03:14 +00:00
|
|
|
my $arg_name = $2;
|
2012-07-20 14:31:46 +00:00
|
|
|
my $type_name = name_to_TypeName($name);
|
2011-04-23 10:53:57 +00:00
|
|
|
|
|
|
|
if ($is_first_arg) {
|
|
|
|
if ($name eq "domain_snapshot") {
|
2011-04-23 17:03:14 +00:00
|
|
|
$priv_src = "$arg_name->domain->conn";
|
2011-04-23 10:53:57 +00:00
|
|
|
} else {
|
2011-04-23 17:03:14 +00:00
|
|
|
$priv_src = "$arg_name->conn";
|
2011-04-23 10:53:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($name =~ m/^storage_/) {
|
|
|
|
$priv_name = "storagePrivateData";
|
|
|
|
} elsif (!($name =~ m/^domain/)) {
|
|
|
|
$priv_name = "${name}PrivateData";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-23 17:03:14 +00:00
|
|
|
push(@args_list, "vir${type_name}Ptr $arg_name");
|
|
|
|
push(@setters_list, "make_nonnull_$1(&args.$arg_name, $arg_name);");
|
|
|
|
} elsif ($args_member =~ m/^remote_uuid (\S+);/) {
|
|
|
|
push(@args_list, "const unsigned char *$1");
|
|
|
|
push(@setters_list, "memcpy(args.$1, $1, VIR_UUID_BUFLEN);");
|
2011-04-23 14:33:57 +00:00
|
|
|
} elsif ($args_member =~ m/^remote_string (\S+);/) {
|
|
|
|
push(@args_list, "const char *$1");
|
|
|
|
push(@setters_list, "args.$1 = $1 ? (char **)&$1 : NULL;");
|
2011-06-16 09:30:23 +00:00
|
|
|
} elsif ($args_member =~ m/^remote_nonnull_string (\S+)<(\S+)>;(.*)$/) {
|
|
|
|
my $type_name = "const char **";
|
|
|
|
my $arg_name = $1;
|
|
|
|
my $limit = $2;
|
|
|
|
my $annotation = $3;
|
|
|
|
|
|
|
|
if ($annotation ne "") {
|
|
|
|
if ($annotation =~ m/\s*\/\*\s*\((.*)\)\s*\*\//) {
|
|
|
|
$type_name = $1;
|
|
|
|
} else {
|
|
|
|
die "malformed cast annotation for argument: $args_member";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
push(@args_list, "$type_name$arg_name");
|
|
|
|
push(@args_list, "unsigned int ${arg_name}len");
|
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_val = (char **)$arg_name;");
|
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;");
|
|
|
|
push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $2 });
|
2011-04-23 10:53:57 +00:00
|
|
|
} elsif ($args_member =~ m/^remote_nonnull_string (\S+);/) {
|
|
|
|
push(@args_list, "const char *$1");
|
|
|
|
push(@setters_list, "args.$1 = (char *)$1;");
|
2011-06-16 09:30:23 +00:00
|
|
|
} elsif ($args_member =~ m/^opaque (\S+)<(\S+)>;(.*)$/) {
|
|
|
|
my $type_name = "const char *";
|
|
|
|
my $arg_name = $1;
|
|
|
|
my $limit = $2;
|
|
|
|
my $annotation = $3;
|
|
|
|
|
|
|
|
if ($annotation ne "") {
|
|
|
|
if ($annotation =~ m/\s*\/\*\s*\((.*)\)\s*\*\//) {
|
|
|
|
$type_name = $1;
|
|
|
|
} else {
|
|
|
|
die "malformed cast annotation for argument: $args_member";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
push(@args_list, "$type_name$arg_name");
|
2011-05-07 06:15:51 +00:00
|
|
|
|
2011-04-24 07:49:42 +00:00
|
|
|
if ($call->{ProcName} eq "SecretSetValue") {
|
2011-06-16 09:30:23 +00:00
|
|
|
# SPECIAL: virSecretSetValue uses size_t instead of int
|
2011-05-07 06:15:51 +00:00
|
|
|
push(@args_list, "size_t ${arg_name}len");
|
2011-04-24 07:49:42 +00:00
|
|
|
} else {
|
2011-05-07 06:15:51 +00:00
|
|
|
push(@args_list, "int ${arg_name}len");
|
2011-04-24 07:49:42 +00:00
|
|
|
}
|
|
|
|
|
2011-06-16 09:30:23 +00:00
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_val = (char *)$arg_name;");
|
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;");
|
|
|
|
push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $limit });
|
|
|
|
} elsif ($args_member =~ m/^remote_string (\S+)<(\S+)>;/) {
|
|
|
|
my $arg_name = $1;
|
|
|
|
my $limit = $2;
|
|
|
|
|
|
|
|
push(@args_list, "const char *$arg_name");
|
|
|
|
push(@args_list, "int ${arg_name}len");
|
2011-05-07 06:15:51 +00:00
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_val = (char *)$arg_name;");
|
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;");
|
|
|
|
push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $limit });
|
2011-06-07 09:11:11 +00:00
|
|
|
} elsif ($args_member =~ m/^((?:unsigned )?int) (\S+)<(\S+)>;/) {
|
|
|
|
my $type_name = $1;
|
|
|
|
my $arg_name = $2;
|
|
|
|
my $limit = $3;
|
|
|
|
|
|
|
|
push(@args_list, "${type_name} *$arg_name");
|
2011-06-15 16:33:59 +00:00
|
|
|
push(@args_list, "int ${arg_name}len");
|
2011-06-07 09:11:11 +00:00
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_val = $arg_name;");
|
|
|
|
push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;");
|
|
|
|
push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $limit });
|
2011-05-30 18:27:37 +00:00
|
|
|
} elsif ($args_member =~ m/^remote_typed_param (\S+)<(\S+)>;/) {
|
|
|
|
push(@args_list, "virTypedParameterPtr $1");
|
|
|
|
push(@args_list, "int n$1");
|
|
|
|
push(@setters_list2, "if (remoteSerializeTypedParameters($1, n$1, &args.$1.$1_val, &args.$1.$1_len) < 0) {\n" .
|
|
|
|
" xdr_free((xdrproc_t)xdr_$call->{args}, (char *)&args);\n" .
|
|
|
|
" goto done;\n" .
|
|
|
|
" }");
|
2011-07-27 18:32:25 +00:00
|
|
|
push(@free_list, " remoteFreeTypedParameters(args.params.params_val, args.params.params_len);\n");
|
2011-06-15 13:38:31 +00:00
|
|
|
} elsif ($args_member =~ m/^((?:unsigned )?int) (\S+);\s*\/\*\s*call-by-reference\s*\*\//) {
|
|
|
|
my $type_name = "$1 *";
|
2011-05-30 18:27:37 +00:00
|
|
|
my $arg_name = $2;
|
|
|
|
|
|
|
|
push(@args_list, "$type_name $arg_name");
|
|
|
|
push(@setters_list, "args.$arg_name = *$arg_name;");
|
2011-06-15 13:38:31 +00:00
|
|
|
} elsif ($args_member =~ m/^((?:unsigned )?int) (\S+);/) {
|
|
|
|
my $type_name = $1;
|
2011-05-30 10:58:57 +00:00
|
|
|
my $arg_name = $2;
|
|
|
|
|
|
|
|
push(@args_list, "$type_name $arg_name");
|
|
|
|
push(@setters_list, "args.$arg_name = $arg_name;");
|
|
|
|
} elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) {
|
|
|
|
my $type_name = $1;
|
|
|
|
my $arg_name = $2;
|
|
|
|
|
|
|
|
if (hyper_to_long($call->{ProcName}, "arg", $arg_name)) {
|
|
|
|
$type_name .= "long";
|
|
|
|
} else {
|
|
|
|
$type_name .= "long long";
|
2011-04-23 10:53:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
push(@args_list, "$type_name $arg_name");
|
|
|
|
push(@setters_list, "args.$arg_name = $arg_name;");
|
2011-05-07 05:36:21 +00:00
|
|
|
} elsif ($args_member =~ m/^(\/)?\*/) {
|
2011-04-23 10:53:57 +00:00
|
|
|
# ignore comments
|
|
|
|
} else {
|
|
|
|
die "unhandled type for argument value: $args_member";
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($is_first_arg and $priv_src eq "conn") {
|
|
|
|
unshift(@args_list, "virConnectPtr conn");
|
|
|
|
}
|
|
|
|
|
|
|
|
$is_first_arg = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-23 19:25:49 +00:00
|
|
|
if (! @args_list) {
|
|
|
|
push(@args_list, "virConnectPtr conn");
|
|
|
|
}
|
|
|
|
|
2011-04-23 14:33:57 +00:00
|
|
|
# fix priv_name for the NumOf* functions
|
|
|
|
if ($priv_name eq "privateData" and
|
2011-04-23 21:00:26 +00:00
|
|
|
!($call->{ProcName} =~ m/(Domains|DomainSnapshot)/) and
|
|
|
|
($call->{ProcName} =~ m/NumOf(Defined|Domain)*(\S+)s/ or
|
|
|
|
$call->{ProcName} =~ m/List(Defined|Domain)*(\S+)s/)) {
|
2011-04-23 14:33:57 +00:00
|
|
|
my $prefix = lc $2;
|
|
|
|
$prefix =~ s/(pool|vol)$//;
|
|
|
|
$priv_name = "${prefix}PrivateData";
|
|
|
|
}
|
|
|
|
|
2011-04-23 19:25:49 +00:00
|
|
|
# handle return values of the function
|
|
|
|
my @ret_list = ();
|
2011-05-30 18:27:37 +00:00
|
|
|
my @ret_list2 = ();
|
2011-04-23 19:25:49 +00:00
|
|
|
my $call_ret = "&ret";
|
|
|
|
my $single_ret_var = "int rv = -1";
|
|
|
|
my $single_ret_type = "int";
|
2011-04-23 21:00:26 +00:00
|
|
|
my $single_ret_as_list = 0;
|
|
|
|
my $single_ret_list_error_msg_type = "undefined";
|
|
|
|
my $single_ret_list_name = "undefined";
|
|
|
|
my $single_ret_list_max_var = "undefined";
|
|
|
|
my $single_ret_list_max_define = "undefined";
|
2011-05-30 18:27:37 +00:00
|
|
|
my $single_ret_cleanup = 0;
|
2011-04-23 19:25:49 +00:00
|
|
|
my $multi_ret = 0;
|
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($rettype ne "void" and
|
2011-04-23 19:25:49 +00:00
|
|
|
scalar(@{$call->{ret_members}}) > 1) {
|
|
|
|
$multi_ret = 1;
|
|
|
|
}
|
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($rettype eq "void") {
|
2011-04-23 14:33:57 +00:00
|
|
|
$call_ret = "NULL";
|
2011-04-23 10:53:57 +00:00
|
|
|
} else {
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@vars_list, "$rettype ret");
|
2011-04-23 14:33:57 +00:00
|
|
|
|
|
|
|
foreach my $ret_member (@{$call->{ret_members}}) {
|
2011-04-23 19:25:49 +00:00
|
|
|
if ($multi_ret) {
|
2011-05-07 06:15:51 +00:00
|
|
|
if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) {
|
2011-05-30 10:58:57 +00:00
|
|
|
if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) {
|
|
|
|
die "legacy [u]long hyper arrays aren't supported";
|
|
|
|
}
|
|
|
|
|
2012-03-29 09:52:04 +00:00
|
|
|
push(@ret_list, "memcpy(result->$3, ret.$3, sizeof(result->$3));");
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/<\S+>;/ or $ret_member =~ m/\[\S+\];/) {
|
|
|
|
# just make all other array types fail
|
2011-05-11 19:28:39 +00:00
|
|
|
die "unhandled type for multi-return-value for " .
|
|
|
|
"procedure $call->{name}: $ret_member";
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) {
|
2011-05-30 10:58:57 +00:00
|
|
|
if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) {
|
|
|
|
my $sign = ""; $sign = "U" if ($1);
|
|
|
|
|
|
|
|
push(@ret_list, "HYPER_TO_${sign}LONG(result->$3, ret.$3);");
|
|
|
|
} else {
|
|
|
|
push(@ret_list, "result->$3 = ret.$3;");
|
|
|
|
}
|
2011-04-23 19:25:49 +00:00
|
|
|
} else {
|
2011-05-11 19:28:39 +00:00
|
|
|
die "unhandled type for multi-return-value for " .
|
|
|
|
"procedure $call->{name}: $ret_member";
|
2011-04-23 19:25:49 +00:00
|
|
|
}
|
2011-05-21 09:16:07 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_string (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) {
|
|
|
|
splice(@args_list, int($3), 0, ("char **const $1"));
|
|
|
|
push(@ret_list, "rv = ret.$1.$1_len;");
|
|
|
|
$single_ret_var = "int rv = -1";
|
|
|
|
$single_ret_type = "int";
|
2011-04-23 21:00:26 +00:00
|
|
|
$single_ret_as_list = 1;
|
|
|
|
$single_ret_list_name = $1;
|
|
|
|
$single_ret_list_max_var = "max$1";
|
|
|
|
$single_ret_list_max_define = $2;
|
2011-05-21 09:16:07 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_string (\S+)<\S+>;/) {
|
|
|
|
# error out on unannotated arrays
|
|
|
|
die "remote_nonnull_string array without insert@<offset> annotation: $ret_member";
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_string (\S+);/) {
|
2011-04-23 14:33:57 +00:00
|
|
|
push(@ret_list, "rv = ret.$1;");
|
|
|
|
$single_ret_var = "char *rv = NULL";
|
|
|
|
$single_ret_type = "char *";
|
2011-05-14 13:35:27 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_string (\S+);/) {
|
|
|
|
push(@ret_list, "rv = ret.$1 ? *ret.$1 : NULL;");
|
|
|
|
push(@ret_list, "VIR_FREE(ret.$1);");
|
|
|
|
$single_ret_var = "char *rv = NULL";
|
|
|
|
$single_ret_type = "char *";
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|node_device|interface|secret|nwfilter|domain_snapshot) (\S+);/) {
|
2011-04-23 17:03:14 +00:00
|
|
|
my $name = $1;
|
|
|
|
my $arg_name = $2;
|
2012-07-20 14:31:46 +00:00
|
|
|
my $type_name = name_to_TypeName($name);
|
2011-04-23 17:03:14 +00:00
|
|
|
|
|
|
|
if ($name eq "node_device") {
|
2013-04-23 10:15:48 +00:00
|
|
|
$priv_name = "nodeDevicePrivateData";
|
2011-04-23 17:03:14 +00:00
|
|
|
} elsif ($name =~ m/^storage_/) {
|
|
|
|
$priv_name = "storagePrivateData";
|
|
|
|
} elsif (!($name =~ m/^domain/)) {
|
|
|
|
$priv_name = "${name}PrivateData";
|
|
|
|
}
|
|
|
|
|
2011-05-20 15:58:34 +00:00
|
|
|
if ($call->{ProcName} eq "DomainCreateWithFlags") {
|
|
|
|
# SPECIAL: virDomainCreateWithFlags updates the given
|
|
|
|
# domain object instead of returning a new one
|
|
|
|
push(@ret_list, "dom->id = ret.dom.id;");
|
|
|
|
push(@ret_list, "xdr_free((xdrproc_t)xdr_$call->{ret}, (char *)&ret);");
|
|
|
|
push(@ret_list, "rv = 0;");
|
|
|
|
$single_ret_var = "int rv = -1";
|
|
|
|
$single_ret_type = "int";
|
2011-04-23 17:03:14 +00:00
|
|
|
} else {
|
2011-05-20 15:58:34 +00:00
|
|
|
if ($name eq "domain_snapshot") {
|
2011-09-24 19:19:35 +00:00
|
|
|
my $dom = "$priv_src";
|
|
|
|
$dom =~ s/->conn//;
|
|
|
|
push(@ret_list, "rv = get_nonnull_$name($dom, ret.$arg_name);");
|
2011-05-20 15:58:34 +00:00
|
|
|
} else {
|
|
|
|
push(@ret_list, "rv = get_nonnull_$name($priv_src, ret.$arg_name);");
|
|
|
|
}
|
2011-04-23 17:03:14 +00:00
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
push(@ret_list, "xdr_free((xdrproc_t)xdr_$rettype, (char *)&ret);");
|
2011-05-20 15:58:34 +00:00
|
|
|
$single_ret_var = "vir${type_name}Ptr rv = NULL";
|
|
|
|
$single_ret_type = "vir${type_name}Ptr";
|
|
|
|
}
|
2011-05-30 18:27:37 +00:00
|
|
|
} elsif ($ret_member =~ m/^remote_typed_param (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) {
|
|
|
|
splice(@args_list, int($3), 0, ("virTypedParameterPtr $1"));
|
|
|
|
push(@ret_list2, "if (remoteDeserializeTypedParameters(ret.$1.$1_val,\n" .
|
|
|
|
" ret.$1.$1_len,\n" .
|
|
|
|
" $2,\n" .
|
2013-01-30 09:28:54 +00:00
|
|
|
" &$1,\n" .
|
2011-05-30 18:27:37 +00:00
|
|
|
" n$1) < 0)\n" .
|
|
|
|
" goto cleanup;\n");
|
|
|
|
$single_ret_cleanup = 1;
|
|
|
|
} elsif ($ret_member =~ m/^remote_typed_param (\S+)<\S+>;/) {
|
|
|
|
# error out on unannotated arrays
|
|
|
|
die "remote_typed_param array without insert@<offset> annotation: $ret_member";
|
2011-04-23 14:33:57 +00:00
|
|
|
} elsif ($ret_member =~ m/^int (\S+);/) {
|
2011-04-23 21:03:44 +00:00
|
|
|
my $arg_name = $1;
|
|
|
|
|
|
|
|
if ($call->{ProcName} =~ m/GetAutostart$/) {
|
|
|
|
push(@args_list, "int *$arg_name");
|
|
|
|
push(@ret_list, "if ($arg_name) *$arg_name = ret.$arg_name;");
|
|
|
|
push(@ret_list, "rv = 0;");
|
|
|
|
} else {
|
|
|
|
push(@ret_list, "rv = ret.$arg_name;");
|
|
|
|
}
|
|
|
|
|
2011-08-26 17:46:41 +00:00
|
|
|
$single_ret_var = "int rv = -1";
|
|
|
|
$single_ret_type = "int";
|
|
|
|
} elsif ($ret_member =~ m/^(unsigned )?hyper (\S+);\s*\/\*\s*insert@(\d+)\s*\*\//) {
|
|
|
|
my $type_name = $1;
|
|
|
|
my $sign = ""; $sign = "U" if ($1);
|
|
|
|
my $ret_name = $2;
|
|
|
|
my $insert = $3;
|
|
|
|
|
|
|
|
if (hyper_to_long($call->{ProcName}, "ret", $ret_name)) {
|
|
|
|
$type_name .= "long";
|
|
|
|
push(@ret_list, "if ($ret_name) HYPER_TO_${sign}LONG(*$ret_name, ret.$ret_name);");
|
|
|
|
} else {
|
|
|
|
$type_name .= "long long";
|
|
|
|
push(@ret_list, "if ($ret_name) *$ret_name = ret.$ret_name;");
|
|
|
|
}
|
|
|
|
|
|
|
|
splice(@args_list, int($insert), 0, ("$type_name *$ret_name"));
|
|
|
|
push(@ret_list, "rv = 0;");
|
2011-04-23 14:33:57 +00:00
|
|
|
$single_ret_var = "int rv = -1";
|
|
|
|
$single_ret_type = "int";
|
2011-05-07 06:15:51 +00:00
|
|
|
} elsif ($ret_member =~ m/^unsigned hyper (\S+);/) {
|
2011-05-30 10:58:57 +00:00
|
|
|
my $ret_name = $1;
|
2011-05-21 09:24:28 +00:00
|
|
|
|
2011-04-23 21:03:44 +00:00
|
|
|
if ($call->{ProcName} =~ m/Get(Lib)?Version/) {
|
2011-05-30 10:58:57 +00:00
|
|
|
push(@args_list, "unsigned long *$ret_name");
|
|
|
|
push(@ret_list, "if ($ret_name) HYPER_TO_ULONG(*$ret_name, ret.$ret_name);");
|
2011-04-23 21:03:44 +00:00
|
|
|
push(@ret_list, "rv = 0;");
|
|
|
|
$single_ret_var = "int rv = -1";
|
|
|
|
$single_ret_type = "int";
|
2011-05-30 10:58:57 +00:00
|
|
|
} elsif (hyper_to_long($call->{ProcName}, "ret", $ret_name)) {
|
|
|
|
push(@ret_list, "HYPER_TO_ULONG(rv, ret.$ret_name);");
|
2011-05-21 10:24:40 +00:00
|
|
|
$single_ret_var = "unsigned long rv = 0";
|
|
|
|
$single_ret_type = "unsigned long";
|
2011-05-30 10:58:57 +00:00
|
|
|
} else {
|
|
|
|
push(@ret_list, "rv = ret.$ret_name;");
|
|
|
|
$single_ret_var = "unsigned long long rv = 0";
|
|
|
|
$single_ret_type = "unsigned long long";
|
2011-04-23 17:03:14 +00:00
|
|
|
}
|
2011-05-11 19:28:39 +00:00
|
|
|
} elsif ($ret_member =~ m/^(\/)?\*/) {
|
|
|
|
# ignore comments
|
2011-04-23 14:33:57 +00:00
|
|
|
} else {
|
2011-05-11 19:28:39 +00:00
|
|
|
die "unhandled type for return value for procedure " .
|
|
|
|
"$call->{name}: $ret_member";
|
2011-04-23 14:33:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-23 19:25:49 +00:00
|
|
|
# select struct type for multi-return-value functions
|
|
|
|
if ($multi_ret) {
|
2011-06-15 15:34:19 +00:00
|
|
|
if (!(defined $call->{ret_offset})) {
|
|
|
|
die "multi-return-value without insert@<offset> annotation: $call->{ret}";
|
2011-04-23 19:25:49 +00:00
|
|
|
}
|
|
|
|
|
2011-06-15 15:34:19 +00:00
|
|
|
my $struct_name = $call->{ProcName};
|
|
|
|
$struct_name =~ s/Get//;
|
2011-04-23 19:25:49 +00:00
|
|
|
|
2011-06-15 15:34:19 +00:00
|
|
|
splice(@args_list, $call->{ret_offset}, 0, ("vir${struct_name}Ptr result"));
|
2011-04-23 10:53:57 +00:00
|
|
|
}
|
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if ($call->{streamflag} ne "none") {
|
|
|
|
splice(@args_list, $call->{streamoffset}, 0, ("virStreamPtr st"));
|
|
|
|
}
|
|
|
|
|
2011-04-23 10:53:57 +00:00
|
|
|
# print function
|
|
|
|
print "\n";
|
2011-04-23 14:33:57 +00:00
|
|
|
print "static $single_ret_type\n";
|
2013-04-23 12:50:18 +00:00
|
|
|
if ($structprefix eq "remote") {
|
|
|
|
print "$structprefix$call->{ProcName}(";
|
|
|
|
} else {
|
|
|
|
my $proc = $call->{ProcName};
|
|
|
|
my $extra = $structprefix;
|
|
|
|
$extra =~ s/^(\w)/uc $1/e;
|
|
|
|
$proc =~ s/^(Domain)(.*)/$1 . $extra . $2/e;
|
|
|
|
print "remote$proc(";
|
|
|
|
}
|
2011-04-23 10:53:57 +00:00
|
|
|
|
|
|
|
print join(", ", @args_list);
|
|
|
|
|
|
|
|
print ")\n";
|
|
|
|
print "{\n";
|
2011-04-23 14:33:57 +00:00
|
|
|
print " $single_ret_var;\n";
|
2011-04-23 10:53:57 +00:00
|
|
|
print " struct private_data *priv = $priv_src->$priv_name;\n";
|
|
|
|
|
|
|
|
foreach my $var (@vars_list) {
|
|
|
|
print " $var;\n";
|
|
|
|
}
|
|
|
|
|
2011-04-23 21:00:26 +00:00
|
|
|
if ($single_ret_as_list) {
|
Convert 'int i' to 'size_t i' in src/rpc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
print " size_t i;\n";
|
2011-04-23 21:00:26 +00:00
|
|
|
}
|
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if ($call->{streamflag} ne "none") {
|
2010-12-01 16:46:36 +00:00
|
|
|
print " virNetClientStreamPtr netst = NULL;\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-23 10:53:57 +00:00
|
|
|
print "\n";
|
|
|
|
print " remoteDriverLock(priv);\n";
|
|
|
|
|
2011-05-21 09:24:28 +00:00
|
|
|
if ($call->{streamflag} ne "none") {
|
|
|
|
print "\n";
|
2012-07-20 14:31:46 +00:00
|
|
|
print " if (!(netst = virNetClientStreamNew(priv->remoteProgram, $call->{constname}, priv->counter)))\n";
|
2011-07-08 22:10:04 +00:00
|
|
|
print " goto done;\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
print "\n";
|
2011-07-08 22:10:04 +00:00
|
|
|
print " if (virNetClientAddStream(priv->client, netst) < 0) {\n";
|
2012-07-30 09:14:56 +00:00
|
|
|
print " virObjectUnref(netst);\n";
|
2011-07-08 22:10:04 +00:00
|
|
|
print " goto done;\n";
|
2010-12-01 16:46:36 +00:00
|
|
|
print " }";
|
|
|
|
print "\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
print " st->driver = &remoteStreamDrv;\n";
|
2010-12-01 16:46:36 +00:00
|
|
|
print " st->privateData = netst;\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
}
|
|
|
|
|
2011-05-14 13:56:03 +00:00
|
|
|
if ($call->{ProcName} eq "SupportsFeature") {
|
|
|
|
# SPECIAL: VIR_DRV_FEATURE_REMOTE feature is handled directly
|
|
|
|
print "\n";
|
|
|
|
print " if (feature == VIR_DRV_FEATURE_REMOTE) {\n";
|
|
|
|
print " rv = 1;\n";
|
|
|
|
print " goto done;\n";
|
|
|
|
print " }\n";
|
|
|
|
}
|
|
|
|
|
2011-04-24 07:49:42 +00:00
|
|
|
foreach my $args_check (@args_check_list) {
|
|
|
|
print "\n";
|
|
|
|
print " if ($args_check->{arg} > $args_check->{limit}) {\n";
|
2012-07-18 13:35:21 +00:00
|
|
|
print " virReportError(VIR_ERR_RPC,\n";
|
|
|
|
print " _(\"%s length greater than maximum: %d > %d\"),\n";
|
|
|
|
print " $args_check->{name}, (int)$args_check->{arg}, $args_check->{limit});\n";
|
2011-04-24 07:49:42 +00:00
|
|
|
print " goto done;\n";
|
|
|
|
print " }\n";
|
|
|
|
}
|
|
|
|
|
2011-04-23 21:00:26 +00:00
|
|
|
if ($single_ret_as_list) {
|
|
|
|
print "\n";
|
|
|
|
print " if ($single_ret_list_max_var > $single_ret_list_max_define) {\n";
|
2012-07-18 13:35:21 +00:00
|
|
|
print " virReportError(VIR_ERR_RPC,\n";
|
|
|
|
print " _(\"too many remote ${single_ret_list_error_msg_type}s: %d > %d\"),\n";
|
|
|
|
print " $single_ret_list_max_var, $single_ret_list_max_define);\n";
|
2011-04-23 21:00:26 +00:00
|
|
|
print " goto done;\n";
|
|
|
|
print " }\n";
|
|
|
|
}
|
|
|
|
|
2011-04-23 10:53:57 +00:00
|
|
|
if (@setters_list) {
|
2011-04-23 14:33:57 +00:00
|
|
|
print "\n";
|
2011-04-23 10:53:57 +00:00
|
|
|
print " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
print join("\n ", @setters_list);
|
|
|
|
|
|
|
|
if (@setters_list) {
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-05-30 18:27:37 +00:00
|
|
|
if (@setters_list2) {
|
|
|
|
print "\n";
|
|
|
|
print " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
print join("\n ", @setters_list2);
|
|
|
|
|
|
|
|
if (@setters_list2) {
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-05-16 17:13:11 +00:00
|
|
|
if ($rettype ne "void") {
|
2011-04-23 14:33:57 +00:00
|
|
|
print "\n";
|
2012-03-29 09:52:04 +00:00
|
|
|
print " memset(&ret, 0, sizeof(ret));\n";
|
2011-04-23 14:33:57 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 16:31:58 +00:00
|
|
|
my $callflags = "0";
|
|
|
|
if ($structprefix eq "qemu") {
|
|
|
|
$callflags = "REMOTE_CALL_QEMU";
|
|
|
|
}
|
2013-04-18 11:07:23 +00:00
|
|
|
if ($structprefix eq "lxc") {
|
|
|
|
$callflags = "REMOTE_CALL_LXC";
|
|
|
|
}
|
2011-05-05 16:31:58 +00:00
|
|
|
|
2011-04-23 10:53:57 +00:00
|
|
|
print "\n";
|
2012-07-20 14:31:46 +00:00
|
|
|
print " if (call($priv_src, priv, $callflags, $call->{constname},\n";
|
2011-05-16 17:13:11 +00:00
|
|
|
print " (xdrproc_t)xdr_$argtype, (char *)$call_args,\n";
|
|
|
|
print " (xdrproc_t)xdr_$rettype, (char *)$call_ret) == -1) {\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
|
|
|
|
if ($call->{streamflag} ne "none") {
|
2010-12-01 16:46:36 +00:00
|
|
|
print " virNetClientRemoveStream(priv->client, netst);\n";
|
2012-07-30 09:14:56 +00:00
|
|
|
print " virObjectUnref(netst);\n";
|
2011-10-01 01:39:14 +00:00
|
|
|
print " st->driver = NULL;\n";
|
|
|
|
print " st->privateData = NULL;\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-23 10:53:57 +00:00
|
|
|
print " goto done;\n";
|
2011-05-21 09:24:28 +00:00
|
|
|
print " }\n";
|
2011-04-23 10:53:57 +00:00
|
|
|
print "\n";
|
2011-04-23 14:33:57 +00:00
|
|
|
|
2011-04-23 21:00:26 +00:00
|
|
|
if ($single_ret_as_list) {
|
|
|
|
print " if (ret.$single_ret_list_name.${single_ret_list_name}_len > $single_ret_list_max_var) {\n";
|
2012-07-18 13:35:21 +00:00
|
|
|
print " virReportError(VIR_ERR_RPC,\n";
|
|
|
|
print " _(\"too many remote ${single_ret_list_error_msg_type}s: %d > %d\"),\n";
|
|
|
|
print " ret.$single_ret_list_name.${single_ret_list_name}_len, $single_ret_list_max_var);\n";
|
2011-04-23 21:00:26 +00:00
|
|
|
print " goto cleanup;\n";
|
|
|
|
print " }\n";
|
|
|
|
print "\n";
|
|
|
|
print " /* This call is caller-frees (although that isn't clear from\n";
|
|
|
|
print " * the documentation). However xdr_free will free up both the\n";
|
2013-05-03 12:47:53 +00:00
|
|
|
print " * names and the list of pointers, so we have to VIR_STRDUP the\n";
|
2011-04-23 21:00:26 +00:00
|
|
|
print " * names here. */\n";
|
|
|
|
print " for (i = 0; i < ret.$single_ret_list_name.${single_ret_list_name}_len; ++i) {\n";
|
2013-05-03 12:47:53 +00:00
|
|
|
print " if (VIR_STRDUP(${single_ret_list_name}[i],\n";
|
|
|
|
print " ret.$single_ret_list_name.${single_ret_list_name}_val[i]) < 0) {\n";
|
Convert 'int i' to 'size_t i' in src/rpc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
print " size_t j;\n";
|
|
|
|
print " for (j = 0; j < i; j++)\n";
|
|
|
|
print " VIR_FREE(${single_ret_list_name}[j]);\n";
|
2011-04-23 21:00:26 +00:00
|
|
|
print "\n";
|
|
|
|
print " goto cleanup;\n";
|
|
|
|
print " }\n";
|
|
|
|
print " }\n";
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-05-30 18:27:37 +00:00
|
|
|
if (@ret_list2) {
|
|
|
|
print " ";
|
|
|
|
print join("\n ", @ret_list2);
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
2011-04-23 14:33:57 +00:00
|
|
|
if (@ret_list) {
|
|
|
|
print " ";
|
|
|
|
print join("\n ", @ret_list);
|
|
|
|
print "\n";
|
2011-04-23 19:25:49 +00:00
|
|
|
}
|
|
|
|
|
2011-06-02 13:42:21 +00:00
|
|
|
if ($call->{ProcName} eq "DomainDestroy" ||
|
2012-07-27 12:51:28 +00:00
|
|
|
$call->{ProcName} eq "DomainSave" ||
|
|
|
|
$call->{ProcName} eq "DomainManagedSave") {
|
2011-06-02 13:42:21 +00:00
|
|
|
# SPECIAL: virDomain{Destroy|Save|ManagedSave} need to reset
|
2012-07-27 12:51:28 +00:00
|
|
|
# the domain id explicitly on success
|
2011-05-14 13:56:03 +00:00
|
|
|
print " dom->id = -1;\n";
|
|
|
|
}
|
|
|
|
|
2011-04-23 19:25:49 +00:00
|
|
|
if ($multi_ret or !@ret_list) {
|
2011-04-23 14:33:57 +00:00
|
|
|
print " rv = 0;\n";
|
|
|
|
}
|
|
|
|
|
2011-05-30 18:27:37 +00:00
|
|
|
if ($single_ret_as_list or $single_ret_cleanup) {
|
2011-04-23 21:00:26 +00:00
|
|
|
print "\n";
|
|
|
|
print "cleanup:\n";
|
2012-07-20 14:31:46 +00:00
|
|
|
print " xdr_free((xdrproc_t)xdr_$call->{ret}, (char *)&ret);\n";
|
2011-04-23 21:00:26 +00:00
|
|
|
}
|
|
|
|
|
2011-04-23 10:53:57 +00:00
|
|
|
print "\n";
|
|
|
|
print "done:\n";
|
2011-07-27 18:32:25 +00:00
|
|
|
|
|
|
|
print join("\n", @free_list);
|
|
|
|
|
2011-04-23 10:53:57 +00:00
|
|
|
print " remoteDriverUnlock(priv);\n";
|
|
|
|
print " return rv;\n";
|
|
|
|
print "}\n";
|
|
|
|
}
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
} elsif ($mode eq "aclheader" ||
|
|
|
|
$mode eq "aclbody" ||
|
|
|
|
$mode eq "aclsym") {
|
|
|
|
my %generate = map { $_ => 1 } @autogen;
|
|
|
|
my @keys = keys %calls;
|
|
|
|
|
|
|
|
if ($mode eq "aclsym") {
|
|
|
|
@keys = sort { my $c = $a . "ensureacl";
|
|
|
|
my $d = $b . "ensureacl";
|
|
|
|
$c cmp $d } @keys;
|
|
|
|
} else {
|
|
|
|
@keys = sort { $a cmp $b } @keys;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($mode eq "aclheader") {
|
|
|
|
my @headers = (
|
|
|
|
"internal.h",
|
|
|
|
"domain_conf.h",
|
|
|
|
"network_conf.h",
|
|
|
|
"secret_conf.h",
|
|
|
|
"storage_conf.h",
|
|
|
|
"nwfilter_conf.h",
|
|
|
|
"node_device_conf.h",
|
|
|
|
"interface_conf.h"
|
|
|
|
);
|
|
|
|
foreach my $hdr (@headers) {
|
|
|
|
print "#include \"$hdr\"\n";
|
|
|
|
}
|
|
|
|
} elsif ($mode eq "aclbody") {
|
|
|
|
my $header = shift;
|
|
|
|
print "#include <config.h>\n";
|
|
|
|
print "#include \"$header\"\n";
|
|
|
|
print "#include \"access/viraccessmanager.h\"\n";
|
|
|
|
print "#include \"datatypes.h\"\n";
|
|
|
|
print "#include \"virerror.h\"\n";
|
|
|
|
print "\n";
|
|
|
|
print "#define VIR_FROM_THIS VIR_FROM_ACCESS\n";
|
|
|
|
}
|
|
|
|
print "\n";
|
|
|
|
|
|
|
|
foreach (@keys) {
|
|
|
|
my $call = $calls{$_};
|
|
|
|
|
|
|
|
die "missing 'acl' option for $call->{ProcName}"
|
|
|
|
unless exists $call->{acl} &&
|
|
|
|
$#{$call->{acl}} != -1;
|
|
|
|
|
|
|
|
next if $call->{acl}->[0] eq "none";
|
|
|
|
|
|
|
|
if ($mode eq "aclsym") {
|
|
|
|
my $apiname = "vir" . $call->{ProcName};
|
|
|
|
if ($structprefix eq "qemu") {
|
|
|
|
$apiname =~ s/virDomain/virDomainQemu/;
|
|
|
|
} elsif ($structprefix eq "lxc") {
|
|
|
|
$apiname =~ s/virDomain/virDomainLxc/;
|
|
|
|
}
|
|
|
|
if (defined $call->{aclfilter}) {
|
|
|
|
print $apiname . "CheckACL;\n";
|
|
|
|
}
|
|
|
|
print $apiname . "EnsureACL;\n";
|
|
|
|
} else {
|
|
|
|
&generate_acl($call, $call->{acl}, "Ensure");
|
|
|
|
if (defined $call->{aclfilter}) {
|
|
|
|
&generate_acl($call, $call->{aclfilter}, "Check");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub generate_acl {
|
|
|
|
my $call = shift;
|
|
|
|
my $acl = shift;
|
|
|
|
my $action = shift;
|
|
|
|
|
|
|
|
my @acl;
|
|
|
|
foreach (@{$acl}) {
|
|
|
|
my @bits = split /:/;
|
|
|
|
push @acl, { object => $bits[0], perm => $bits[1], flags => $bits[2] }
|
|
|
|
}
|
|
|
|
|
|
|
|
my $checkflags = 0;
|
|
|
|
for (my $i = 1 ; $i <= $#acl ; $i++) {
|
|
|
|
if ($acl[$i]->{object} ne $acl[0]->{object}) {
|
|
|
|
die "acl for '$call->{ProcName}' cannot check different objects";
|
|
|
|
}
|
|
|
|
if (defined $acl[$i]->{flags}) {
|
|
|
|
$checkflags = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my $apiname = "vir" . $call->{ProcName};
|
|
|
|
if ($structprefix eq "qemu") {
|
|
|
|
$apiname =~ s/virDomain/virDomainQemu/;
|
|
|
|
} elsif ($structprefix eq "lxc") {
|
|
|
|
$apiname =~ s/virDomain/virDomainLxc/;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $object = $acl[0]->{object};
|
|
|
|
my $arg = $acl[0]->{object};
|
|
|
|
$arg =~ s/^.*_(\w+)$/$1/;
|
|
|
|
$object =~ s/^(\w)/uc $1/e;
|
|
|
|
$object =~ s/_(\w)/uc $1/e;
|
|
|
|
$object =~ s/Nwfilter/NWFilter/;
|
|
|
|
my $objecttype = "vir" . $object . "DefPtr";
|
|
|
|
$apiname .= $action . "ACL";
|
|
|
|
|
|
|
|
if ($arg eq "interface") {
|
|
|
|
$arg = "iface";
|
|
|
|
}
|
|
|
|
|
|
|
|
my @argdecls;
|
|
|
|
push @argdecls, "virConnectPtr conn";
|
|
|
|
if ($object ne "Connect") {
|
|
|
|
if ($object eq "StorageVol") {
|
|
|
|
push @argdecls, "virStoragePoolDefPtr pool";
|
|
|
|
}
|
|
|
|
push @argdecls, "$objecttype $arg";
|
|
|
|
}
|
|
|
|
if ($checkflags) {
|
|
|
|
push @argdecls, "unsigned int flags";
|
|
|
|
}
|
|
|
|
|
2013-07-03 14:32:01 +00:00
|
|
|
my $ret;
|
|
|
|
my $pass;
|
|
|
|
my $fail;
|
|
|
|
if ($action eq "Check") {
|
|
|
|
$ret = "bool";
|
|
|
|
$pass = "true";
|
|
|
|
$fail = "false";
|
|
|
|
} else {
|
|
|
|
$ret = "int";
|
|
|
|
$pass = "0";
|
|
|
|
$fail = "-1";
|
|
|
|
}
|
|
|
|
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
if ($mode eq "aclheader") {
|
2013-07-03 14:32:01 +00:00
|
|
|
print "extern $ret $apiname(" . join(", ", @argdecls) . ");\n";
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
} else {
|
|
|
|
my @argvars;
|
|
|
|
push @argvars, "mgr";
|
|
|
|
push @argvars, "conn->driver->name";
|
|
|
|
if ($object ne "Connect") {
|
|
|
|
if ($object eq "StorageVol") {
|
|
|
|
push @argvars, "pool";
|
|
|
|
}
|
|
|
|
push @argvars, $arg;
|
|
|
|
}
|
|
|
|
|
2013-07-03 14:32:01 +00:00
|
|
|
print "/* Returns: $fail on error/denied, $pass on allowed */\n";
|
|
|
|
print "$ret $apiname(" . join(", ", @argdecls) . ")\n";
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
print "{\n";
|
|
|
|
print " virAccessManagerPtr mgr;\n";
|
|
|
|
print " int rv;\n";
|
|
|
|
print "\n";
|
2013-07-03 14:32:01 +00:00
|
|
|
print " if (!(mgr = virAccessManagerGetDefault())) {\n";
|
|
|
|
if ($action eq "Check") {
|
|
|
|
print " virResetLastError();\n";
|
|
|
|
}
|
|
|
|
print " return $fail;\n";
|
|
|
|
print " }\n";
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
print "\n";
|
|
|
|
|
|
|
|
foreach my $acl (@acl) {
|
|
|
|
my $perm = "vir_access_perm_" . $acl->{object} . "_" . $acl->{perm};
|
|
|
|
$perm =~ tr/a-z/A-Z/;
|
|
|
|
|
|
|
|
my $method = "virAccessManagerCheck" . $object;
|
|
|
|
my $space = ' ' x length($method);
|
|
|
|
print " if (";
|
|
|
|
if (defined $acl->{flags}) {
|
|
|
|
my $flags = $acl->{flags};
|
|
|
|
if ($flags =~ /^\!/) {
|
|
|
|
$flags = substr $flags, 1;
|
|
|
|
print "((flags & ($flags)) == 0) &&\n";
|
|
|
|
} else {
|
|
|
|
print "((flags & ($flags)) == ($flags)) &&\n";
|
|
|
|
}
|
|
|
|
print " ";
|
|
|
|
}
|
|
|
|
print "(rv = $method(" . join(", ", @argvars, $perm) . ")) <= 0) {\n";
|
|
|
|
print " virObjectUnref(mgr);\n";
|
|
|
|
if ($action eq "Ensure") {
|
|
|
|
print " if (rv == 0)\n";
|
|
|
|
print " virReportError(VIR_ERR_ACCESS_DENIED, NULL);\n";
|
2013-07-03 14:32:01 +00:00
|
|
|
print " return $fail;\n";
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
} else {
|
2013-07-03 14:32:01 +00:00
|
|
|
print " virResetLastError();\n";
|
|
|
|
print " return $fail;\n";
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
}
|
|
|
|
print " }";
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
print " virObjectUnref(mgr);\n";
|
2013-07-03 14:32:01 +00:00
|
|
|
print " return $pass;\n";
|
Auto-generate helpers for checking access control rules
Extend the 'gendispatch.pl' script to be able to generate
three new types of file.
- 'aclheader' - defines signatures of helper APIs for
doing authorization checks. There is one helper API
for each API requiring an auth check. Any @acl
annotations result in a method being generated with
a suffix of 'EnsureACL'. If the ACL check requires
examination of flags, an extra 'flags' param will be
present. Some examples
extern int virConnectBaselineCPUEnsureACL(void);
extern int virConnectDomainEventDeregisterEnsureACL(virDomainDefPtr domain);
extern int virDomainAttachDeviceFlagsEnsureACL(virDomainDefPtr domain, unsigned int flags);
Any @aclfilter annotations resuilt in a method being
generated with a suffix of 'CheckACL'.
extern int virConnectListAllDomainsCheckACL(virDomainDefPtr domain);
These are used for filtering individual objects from APIs
which return a list of objects
- 'aclbody' - defines the actual implementation of the
methods described above. This calls into the access
manager APIs. A complex example:
/* Returns: -1 on error (denied==error), 0 on allowed */
int virDomainAttachDeviceFlagsEnsureACL(virConnectPtr conn,
virDomainDefPtr domain,
unsigned int flags)
{
virAccessManagerPtr mgr;
int rv;
if (!(mgr = virAccessManagerGetDefault()))
return -1;
if ((rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_WRITE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE)) == 0) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
if (((flags & (VIR_DOMAIN_AFFECT_CONFIG)) == (VIR_DOMAIN_AFFECT_CONFIG)) &&
(rv = virAccessManagerCheckDomain(mgr,
conn->driver->name,
domain,
VIR_ACCESS_PERM_DOMAIN_SAVE)) <= 0) {
virObjectUnref(mgr);
if (rv == 0)
virReportError(VIR_ERR_ACCESS_DENIED, NULL);
return -1;
}
virObjectUnref(mgr);
return 0;
}
- 'aclsyms' - generates a linker script to export the
APIs to drivers. Some examples
virConnectBaselineCPUEnsureACL;
virConnectCompareCPUEnsureACL;
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-04-18 16:49:41 +00:00
|
|
|
print "}\n\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-23 10:53:57 +00:00
|
|
|
}
|