mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-24 00:20:53 +00:00
aff1db9fab
This patch just covers the simple functions without explicit return values. There is more to be handled. The generator collects the members of the XDR argument structs and uses this information to generate the function bodies. Exclude the generated files from offending syntax-checks. Suggested by Richard W.M. Jones
440 lines
16 KiB
Perl
Executable File
440 lines
16 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
#
|
|
# 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:
|
|
#
|
|
# remote_generator.pl -c -t remote ../src/remote/remote_protocol.x
|
|
# remote_generator.pl -t qemu ../src/remote/qemu_protocol.x
|
|
#
|
|
# By Richard Jones <rjones@redhat.com>
|
|
# Extended by Matthias Bolte <matthias.bolte@googlemail.com>
|
|
|
|
use strict;
|
|
|
|
use Getopt::Std;
|
|
|
|
# Command line options.
|
|
our ($opt_p, $opt_t, $opt_a, $opt_r, $opt_d, $opt_c, $opt_b);
|
|
getopts ('ptardcb');
|
|
|
|
my $structprefix = $ARGV[0];
|
|
my $procprefix = uc $structprefix;
|
|
shift;
|
|
|
|
# Convert name_of_call to NameOfCall.
|
|
sub name_to_ProcName {
|
|
my $name = shift;
|
|
my @elems = split /_/, $name;
|
|
@elems = map ucfirst, @elems;
|
|
@elems = map { $_ eq "Nwfilter" ? "NWFilter" : $_ } @elems;
|
|
join "", @elems
|
|
}
|
|
|
|
# Read the input file (usually remote_protocol.x) and form an
|
|
# opinion about the name, args and return type of each RPC.
|
|
my ($name, $ProcName, $id, %calls, @calls);
|
|
|
|
# only generate a close method if -c was passed
|
|
if ($opt_c) {
|
|
# REMOTE_PROC_CLOSE has no args or ret.
|
|
$calls{close} = {
|
|
name => "close",
|
|
ProcName => "Close",
|
|
UC_NAME => "CLOSE",
|
|
args => "void",
|
|
ret => "void",
|
|
};
|
|
}
|
|
|
|
my $collect_args_members = 0;
|
|
my $last_name;
|
|
|
|
while (<>) {
|
|
if ($collect_args_members) {
|
|
if (/^};/) {
|
|
$collect_args_members = 0;
|
|
} elsif ($_ =~ m/^\s*(.*\S)\s*$/) {
|
|
push(@{$calls{$name}->{args_members}}, $1);
|
|
}
|
|
} elsif (/^struct ${structprefix}_(.*)_args/) {
|
|
$name = $1;
|
|
$ProcName = name_to_ProcName ($name);
|
|
|
|
die "duplicate definition of ${structprefix}_${name}_args"
|
|
if exists $calls{$name};
|
|
|
|
$calls{$name} = {
|
|
name => $name,
|
|
ProcName => $ProcName,
|
|
UC_NAME => uc $name,
|
|
args => "${structprefix}_${name}_args",
|
|
args_members => [],
|
|
ret => "void"
|
|
};
|
|
|
|
$collect_args_members = 1;
|
|
$last_name = $name;
|
|
} elsif (/^struct ${structprefix}_(.*)_ret/) {
|
|
$name = $1;
|
|
$ProcName = name_to_ProcName ($name);
|
|
|
|
if (exists $calls{$name}) {
|
|
$calls{$name}->{ret} = "${structprefix}_${name}_ret";
|
|
} else {
|
|
$calls{$name} = {
|
|
name => $name,
|
|
ProcName => $ProcName,
|
|
UC_NAME => uc $name,
|
|
args => "void",
|
|
ret => "${structprefix}_${name}_ret"
|
|
}
|
|
}
|
|
|
|
$collect_args_members = 0;
|
|
} elsif (/^struct ${structprefix}_(.*)_msg/) {
|
|
$name = $1;
|
|
$ProcName = name_to_ProcName ($name);
|
|
|
|
$calls{$name} = {
|
|
name => $name,
|
|
ProcName => $ProcName,
|
|
UC_NAME => uc $name,
|
|
msg => "${structprefix}_${name}_msg"
|
|
};
|
|
|
|
$collect_args_members = 0;
|
|
} elsif (/^\s*${procprefix}_PROC_(.*?)\s+=\s+(\d+),?$/) {
|
|
$name = lc $1;
|
|
$id = $2;
|
|
$ProcName = name_to_ProcName ($name);
|
|
|
|
$calls[$id] = $calls{$name};
|
|
|
|
$collect_args_members = 0;
|
|
} else {
|
|
$collect_args_members = 0;
|
|
}
|
|
}
|
|
|
|
#----------------------------------------------------------------------
|
|
# Output
|
|
|
|
print <<__EOF__;
|
|
/* Automatically generated by remote_generator.pl.
|
|
* Do not edit this file. Any changes you make will be lost.
|
|
*/
|
|
|
|
__EOF__
|
|
|
|
# Debugging.
|
|
if ($opt_d) {
|
|
my @keys = sort (keys %calls);
|
|
foreach (@keys) {
|
|
print "$_:\n";
|
|
print " name $calls{$_}->{name} ($calls{$_}->{ProcName})\n";
|
|
print " $calls{$_}->{args} -> $calls{$_}->{ret}\n";
|
|
}
|
|
}
|
|
|
|
# Prototypes for dispatch functions ("remote_dispatch_prototypes.h").
|
|
elsif ($opt_p) {
|
|
my @keys = sort (keys %calls);
|
|
foreach (@keys) {
|
|
# Skip things which are REMOTE_MESSAGE
|
|
next if $calls{$_}->{msg};
|
|
|
|
print "static int ${structprefix}Dispatch$calls{$_}->{ProcName}(\n";
|
|
print " struct qemud_server *server,\n";
|
|
print " struct qemud_client *client,\n";
|
|
print " virConnectPtr conn,\n";
|
|
print " remote_message_header *hdr,\n";
|
|
print " remote_error *rerr,\n";
|
|
print " $calls{$_}->{args} *args,\n";
|
|
print " $calls{$_}->{ret} *ret);\n";
|
|
}
|
|
}
|
|
|
|
# Union of all arg types
|
|
# ("remote_dispatch_args.h").
|
|
elsif ($opt_a) {
|
|
for ($id = 0 ; $id <= $#calls ; $id++) {
|
|
if (defined $calls[$id] &&
|
|
!$calls[$id]->{msg} &&
|
|
$calls[$id]->{args} ne "void") {
|
|
print " $calls[$id]->{args} val_$calls[$id]->{args};\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
# Union of all arg types
|
|
# ("remote_dispatch_ret.h").
|
|
elsif ($opt_r) {
|
|
for ($id = 0 ; $id <= $#calls ; $id++) {
|
|
if (defined $calls[$id] &&
|
|
!$calls[$id]->{msg} &&
|
|
$calls[$id]->{ret} ne "void") {
|
|
print " $calls[$id]->{ret} val_$calls[$id]->{ret};\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
# Inside the switch statement, prepare the 'fn', 'args_filter', etc
|
|
# ("remote_dispatch_table.h").
|
|
elsif ($opt_t) {
|
|
for ($id = 0 ; $id <= $#calls ; $id++) {
|
|
if (defined $calls[$id] && !$calls[$id]->{msg}) {
|
|
print "{ /* $calls[$id]->{ProcName} => $id */\n";
|
|
print " .fn = (dispatch_fn) ${structprefix}Dispatch$calls[$id]->{ProcName},\n";
|
|
if ($calls[$id]->{args} ne "void") {
|
|
print " .args_filter = (xdrproc_t) xdr_$calls[$id]->{args},\n";
|
|
} else {
|
|
print " .args_filter = (xdrproc_t) xdr_void,\n";
|
|
}
|
|
if ($calls[$id]->{ret} ne "void") {
|
|
print " .ret_filter = (xdrproc_t) xdr_$calls[$id]->{ret},\n";
|
|
} else {
|
|
print " .ret_filter = (xdrproc_t) xdr_void,\n";
|
|
}
|
|
print "},\n";
|
|
} else {
|
|
if ($calls[$id]->{msg}) {
|
|
print "{ /* Async event $calls[$id]->{ProcName} => $id */\n";
|
|
} else {
|
|
print "{ /* (unused) => $id */\n";
|
|
}
|
|
print " .fn = NULL,\n";
|
|
print " .args_filter = (xdrproc_t) xdr_void,\n";
|
|
print " .ret_filter = (xdrproc_t) xdr_void,\n";
|
|
print "},\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
# Bodies for dispatch functions ("remote_dispatch_bodies.c").
|
|
elsif ($opt_b) {
|
|
# list of functions that currently are not generatable
|
|
my @ungeneratable;
|
|
|
|
if ($structprefix eq "remote") {
|
|
@ungeneratable = ("Close",
|
|
"DomainEventsDeregisterAny",
|
|
"DomainEventsRegisterAny",
|
|
"DomainMigratePerform",
|
|
"DomainMigratePrepareTunnel",
|
|
"DomainOpenConsole",
|
|
"DomainPinVcpu",
|
|
"DomainSetSchedulerParameters",
|
|
"DomainSetMemoryParameters",
|
|
"DomainSetBlkioParameters",
|
|
"Open",
|
|
"StorageVolUpload",
|
|
"StorageVolDownload");
|
|
} elsif ($structprefix eq "qemu") {
|
|
@ungeneratable = ("MonitorCommand");
|
|
}
|
|
|
|
my %ug = map { $_ => 1 } @ungeneratable;
|
|
my @keys = sort (keys %calls);
|
|
|
|
foreach (@keys) {
|
|
# skip things which are REMOTE_MESSAGE
|
|
next if $calls{$_}->{msg};
|
|
|
|
# FIXME: skip functions with explicit return value for now
|
|
if ($calls{$_}->{ret} ne "void" or exists($ug{$calls{$_}->{ProcName}})) {
|
|
print "\n/* ${structprefix}Dispatch$calls{$_}->{ProcName} has to be implemented manually */\n";
|
|
next;
|
|
}
|
|
|
|
print "\n";
|
|
print "static int\n";
|
|
print "${structprefix}Dispatch$calls{$_}->{ProcName}(\n";
|
|
print " struct qemud_server *server ATTRIBUTE_UNUSED,\n";
|
|
print " struct qemud_client *client ATTRIBUTE_UNUSED,\n";
|
|
print " virConnectPtr conn,\n";
|
|
print " remote_message_header *hdr ATTRIBUTE_UNUSED,\n";
|
|
print " remote_error *rerr,\n";
|
|
print " $calls{$_}->{args} *args";
|
|
|
|
if ($calls{$_}->{args} eq "void") {
|
|
print " ATTRIBUTE_UNUSED"
|
|
}
|
|
|
|
print ",\n";
|
|
print " $calls{$_}->{ret} *ret";
|
|
|
|
if ($calls{$_}->{ret} eq "void") {
|
|
print " ATTRIBUTE_UNUSED"
|
|
}
|
|
|
|
print ")\n";
|
|
print "{\n";
|
|
print " int rv = -1;\n";
|
|
|
|
my $has_node_device = 0;
|
|
my @vars_list = ();
|
|
my @getters_list = ();
|
|
my @args_list = ();
|
|
my @free_list = ();
|
|
|
|
if ($calls{$_}->{args} ne "void") {
|
|
# node device is special, as it's identified by name
|
|
if ($calls{$_}->{args} =~ m/^remote_node_device/) {
|
|
$has_node_device = 1;
|
|
push(@vars_list, "virNodeDevicePtr dev = NULL");
|
|
push(@getters_list,
|
|
" if (!(dev = virNodeDeviceLookupByName(conn, args->name)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "dev");
|
|
push(@free_list,
|
|
" if (dev)\n" .
|
|
" virNodeDeviceFree(dev);");
|
|
}
|
|
|
|
foreach my $args_member (@{$calls{$_}->{args_members}}) {
|
|
if ($args_member =~ m/^remote_nonnull_string name;/ and $has_node_device) {
|
|
# ignore the name arg for node devices
|
|
next
|
|
} elsif ($args_member =~ m/^remote_nonnull_domain /) {
|
|
push(@vars_list, "virDomainPtr dom = NULL");
|
|
push(@getters_list,
|
|
" if (!(dom = get_nonnull_domain(conn, args->dom)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "dom");
|
|
push(@free_list,
|
|
" if (dom)\n" .
|
|
" virDomainFree(dom);");
|
|
} elsif ($args_member =~ m/^remote_nonnull_network /) {
|
|
push(@vars_list, "virNetworkPtr net = NULL");
|
|
push(@getters_list,
|
|
" if (!(net = get_nonnull_network(conn, args->net)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "net");
|
|
push(@free_list,
|
|
" if (net)\n" .
|
|
" virNetworkFree(net);");
|
|
} elsif ($args_member =~ m/^remote_nonnull_storage_pool /) {
|
|
push(@vars_list, "virStoragePoolPtr pool = NULL");
|
|
push(@getters_list,
|
|
" if (!(pool = get_nonnull_storage_pool(conn, args->pool)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "pool");
|
|
push(@free_list,
|
|
" if (pool)\n" .
|
|
" virStoragePoolFree(pool);");
|
|
} elsif ($args_member =~ m/^remote_nonnull_storage_vol /) {
|
|
push(@vars_list, "virStorageVolPtr vol = NULL");
|
|
push(@getters_list,
|
|
" if (!(vol = get_nonnull_storage_vol(conn, args->vol)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "vol");
|
|
push(@free_list,
|
|
" if (vol)\n" .
|
|
" virStorageVolFree(vol);");
|
|
} elsif ($args_member =~ m/^remote_nonnull_interface /) {
|
|
push(@vars_list, "virInterfacePtr iface = NULL");
|
|
push(@getters_list,
|
|
" if (!(iface = get_nonnull_interface(conn, args->iface)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "iface");
|
|
push(@free_list,
|
|
" if (iface)\n" .
|
|
" virInterfaceFree(iface);");
|
|
} elsif ($args_member =~ m/^remote_nonnull_secret /) {
|
|
push(@vars_list, "virSecretPtr secret = NULL");
|
|
push(@getters_list,
|
|
" if (!(secret = get_nonnull_secret(conn, args->secret)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "secret");
|
|
push(@free_list,
|
|
" if (secret)\n" .
|
|
" virSecretFree(secret);");
|
|
} elsif ($args_member =~ m/^remote_nonnull_nwfilter /) {
|
|
push(@vars_list, "virNWFilterPtr nwfilter = NULL");
|
|
push(@getters_list,
|
|
" if (!(nwfilter = get_nonnull_nwfilter(conn, args->nwfilter)))\n" .
|
|
" goto cleanup;\n");
|
|
push(@args_list, "nwfilter");
|
|
push(@free_list,
|
|
" if (nwfilter)\n" .
|
|
" virNWFilterFree(nwfilter);");
|
|
} elsif ($args_member =~ m/^remote_nonnull_domain_snapshot /) {
|
|
push(@vars_list, "virDomainPtr dom = NULL");
|
|
push(@vars_list, "virDomainSnapshotPtr snapshot = NULL");
|
|
push(@getters_list,
|
|
" if (!(dom = get_nonnull_domain(conn, args->snap.domain)))\n" .
|
|
" 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);");
|
|
} elsif ($args_member =~ m/(\S+)<\S+>;/) {
|
|
if (! @args_list) {
|
|
push(@args_list, "conn");
|
|
}
|
|
|
|
if ($calls{$_}->{ProcName} eq "SecretSetValue") {
|
|
push(@args_list, "(const unsigned char *)args->$1.$1_val");
|
|
} else {
|
|
push(@args_list, "args->$1.$1_val");
|
|
}
|
|
|
|
push(@args_list, "args->$1.$1_len");
|
|
} elsif ($args_member =~ m/.* (\S+);/) {
|
|
if (! @args_list) {
|
|
push(@args_list, "conn");
|
|
}
|
|
|
|
push(@args_list, "args->$1");
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach my $var (@vars_list) {
|
|
print " $var;\n";
|
|
}
|
|
|
|
print "\n";
|
|
print " if (!conn) {\n";
|
|
print " virNetError(VIR_ERR_INTERNAL_ERROR, \"%s\", _(\"connection not open\"));\n";
|
|
print " goto cleanup;\n";
|
|
print " }\n";
|
|
print "\n";
|
|
|
|
print join("\n", @getters_list);
|
|
|
|
print "\n";
|
|
|
|
if ($calls{$_}->{ret} eq "void") {
|
|
print " if (vir$calls{$_}->{ProcName}(";
|
|
print join(', ', @args_list);
|
|
print ") < 0)\n";
|
|
print " goto cleanup;\n";
|
|
print "\n";
|
|
}
|
|
|
|
print " rv = 0;\n";
|
|
print "\n";
|
|
print "cleanup:\n";
|
|
print " if (rv < 0)\n";
|
|
print " remoteDispatchError(rerr);\n";
|
|
|
|
print join("\n", @free_list);
|
|
|
|
print "\n";
|
|
print " return rv;\n";
|
|
print "}\n";
|
|
}
|
|
}
|