Imported Upstream version 3.3.3
[debian/amanda] / perl / Amanda / Disklist.swg
1 /*
2  * Copyright (c) 2008-2012 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21
22 %module "Amanda::Disklist"
23 %include "amglue/amglue.swg"
24 %include "exception.i"
25 %import "Amanda/Config.swg"
26
27 %include "Amanda/Disklist.pod"
28
29 %{
30 #include "conffile.h"
31 #include "diskfile.h"
32 #include "amglue.h"
33 %}
34
35 %perlcode %{
36 use Amanda::Debug qw( :logging );
37 use Amanda::Config qw( :getconf config_dir_relative );
38 %}
39
40 /* handle creation of opaque objects from Amanda::Config */
41 %types(interface_t *, dumptype_t *);
42
43 %{
44 /* Utility functions for read_disklist_internal */
45 #define hv_store_const(h, k, v) hv_store((h), (k), sizeof((k))-1, (v), 0)
46 #define safe_newSVpv(str) ((str)? newSVpv((str), 0) : &PL_sv_undef)
47
48 static SV *
49 get_iface(
50     HV *ifaces,
51     char *ifaceclass,
52     netif_t *iface)
53 {
54     char *name = interface_name(iface->config);
55     HV *ifaceclass_stash = NULL;
56     SV **svp;
57
58     svp = hv_fetch(ifaces, name, strlen(name), TRUE);
59     if (!svp)
60         croak("internal error"); /* shouldn't happen with lval = TRUE */
61
62     if (!SvOK(*svp)) {
63         /* no existing iface, so set up a new one */
64         HV *h;
65         SV *ref;
66
67         /* make a new hashref and bless it */
68         h = newHV();
69         ref = newRV_noinc((SV *)h);
70         if (!ifaceclass_stash) {
71             ifaceclass_stash = gv_stashpv(ifaceclass, GV_ADD);
72         }
73         sv_bless(ref, ifaceclass_stash);
74         sv_setsv(*svp, ref);
75
76         /* fill in the relevant value - a reference to the config */
77         hv_store_const(h, "config",
78           SvREFCNT_inc(
79             SWIG_NewPointerObj(iface->config,
80                                /* can't use $descriptor here.. */
81                                SWIGTYPE_p_interface_t, 0)));
82     }
83
84     return *svp;
85 }
86
87 static SV *
88 get_host(
89     HV *hosts,
90     char *hostclass,
91     HV *ifaces,
92     char *ifaceclass,
93     disk_t *dp)
94 {
95     HV *hostclass_stash = NULL;
96     SV **svp;
97     SV *sv;
98     AV *disksarray;
99
100     svp = hv_fetch(hosts, dp->hostname, strlen(dp->hostname), TRUE);
101     if (!svp)
102         croak("internal error"); /* shouldn't happen with lval = TRUE */
103
104     if (SvOK(*svp)) {
105         /* this host already exists */
106     } else {
107         /* no existing host, so set up a new one */
108         HV *h;
109         SV *ref;
110
111         /* make a new hashref and bless it */
112         h = newHV();
113         ref = newRV_noinc((SV *)h);
114         g_assert(SvREFCNT((SV *)h) == 1);
115         if (!hostclass_stash) {
116             hostclass_stash = gv_stashpv(hostclass, GV_ADD);
117         }
118         sv_bless(ref, hostclass_stash);
119         sv_setsv(*svp, ref);
120         g_assert(SvREFCNT(*svp) == 1);
121
122         /* fill in the relevant values */
123         hv_store_const(h, "hostname", safe_newSVpv(dp->hostname));
124         hv_store_const(h, "amandad_path", safe_newSVpv(dp->amandad_path));
125         hv_store_const(h, "client_username", safe_newSVpv(dp->client_username));
126         hv_store_const(h, "ssh_keys", safe_newSVpv(dp->ssh_keys));
127         hv_store_const(h, "auth", safe_newSVpv(dp->auth));
128         hv_store_const(h, "maxdumps", newSViv(dp->host->maxdumps));
129         hv_store_const(h, "disks", newRV_noinc((SV *)newAV()));
130
131         /* and make a link to the relevant interface object */
132         ref = get_iface(ifaces, ifaceclass, dp->host->netif);
133         SvREFCNT_inc(ref);
134         hv_store_const(h, "interface", ref);
135     }
136
137     /* push the name of the disk into @{$self->{disks}}; we don't store
138      * a ref to the disk object, as that would create a circular link */
139     g_assert(SvROK(*svp));
140     g_assert(SvTYPE(SvRV(*svp)) == SVt_PVHV);
141     sv = *hv_fetch((HV *)SvRV(*svp), "disks", sizeof("disks")-1, 0);
142
143     g_assert(SvROK(sv));
144     g_assert(SvTYPE(SvRV(sv)) == SVt_PVAV);
145     av_push((AV *)SvRV(sv), safe_newSVpv(dp->name));
146
147     return *svp;
148 }
149 %}
150
151 /* typemaps to pass AV's and HV's in directly (as perl refs) */
152 %typemap(in) HV * {
153     if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVHV) {
154         SWIG_exception_fail(SWIG_TypeError, "must provide a hashref");
155     }
156
157     $1 = (HV *)SvRV($input);
158 }
159
160 %typemap(in) AV * {
161     if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
162         SWIG_exception_fail(SWIG_TypeError, "must provide an arrayref");
163     }
164
165     $1 = (AV *)SvRV($input);
166 }
167
168 %inline %{
169 static cfgerr_level_t
170 read_disklist_internal(
171         char *filename,
172         HV *disks, char *diskclass,
173         HV *hosts, char *hostclass,
174         HV *ifaces, char *ifaceclass)
175 {
176     cfgerr_level_t errlev;
177     disklist_t list;
178     disk_t *dp;
179     HV *diskclass_stash = NULL;
180
181     hv_clear(hosts);
182     hv_clear(disks);
183     hv_clear(ifaces);
184
185     errlev = read_diskfile(filename, &list);
186     if (errlev >= CFGERR_ERRORS)
187         return errlev;
188
189     for (dp = list.head; dp; dp = dp->next) {
190         HV *h = newHV();
191         SV *diskref;
192         SV *hostref;
193         SV **svp;
194
195         /* make a new hashref and bless it */
196         h = newHV();
197         diskref = newRV_noinc((SV *)h);
198         if (!diskclass_stash) {
199             diskclass_stash = gv_stashpv(diskclass, GV_ADD);
200         }
201         sv_bless(diskref, diskclass_stash);
202
203         hv_store_const(h, "name", safe_newSVpv(dp->name));
204         hv_store_const(h, "device", safe_newSVpv(dp->device));
205         hv_store_const(h, "spindle", newSViv(dp->spindle));
206
207         hv_store_const(h, "config",
208           SvREFCNT_inc(
209             SWIG_NewPointerObj(lookup_dumptype(dp->dtype_name),
210                                /* can't use $descriptor here.. */
211                                SWIGTYPE_p_dumptype_t, 0)));
212
213         /* create an uplink ref to the host object */
214         hostref = get_host(hosts, hostclass, ifaces, ifaceclass, dp);
215         SvREFCNT_inc(hostref);
216         hv_store_const(h, "host", hostref);
217
218         /* and store this disk in the two-level %disks hash */
219         svp = hv_fetch(disks, dp->hostname, strlen(dp->hostname), 1);
220         if (!SvOK(*svp)) {
221             /* make a new hash for this host */
222             SV *href;
223             h = newHV();
224             href = newRV_noinc((SV *)h);
225             sv_setsv(*svp, href);
226         } else {
227             g_assert(SvROK(*svp));
228             g_assert(SvTYPE(SvRV(*svp)) == SVt_PVHV);
229             h = (HV *)SvRV(*svp);
230         }
231
232         g_assert(SvROK(*svp));
233         g_assert(SvTYPE(SvRV(*svp)) == SVt_PVHV);
234         SvREFCNT_inc(diskref);
235         hv_store(h, dp->name, strlen(dp->name), diskref, 0);
236     }
237
238     /* free_disklist frees the globals, too, which is not what we want.
239      * So this leaks memory. */
240     /* free_disklist(&list); */
241
242     return 0;
243 }
244 %}
245
246 %perlcode %{
247
248 package Amanda::Disklist::Disk;
249
250 # methods
251
252 package Amanda::Disklist::Host;
253
254 sub get_disk {
255     my ($self, $disk) = @_;
256     return $Amanda::Disklist::disks{$self->{'hostname'}}{$disk};
257 }
258
259 sub all_disks {
260     my ($self) = @_;
261     return values %{$Amanda::Disklist::disks{$self->{'hostname'}}};
262 }
263
264 package Amanda::Disklist::Interface;
265
266 # methods
267
268 package Amanda::Disklist;
269
270 our (%disks, %hosts, %interfaces);
271
272 sub read_disklist {
273     my %params = @_;
274
275     return read_disklist_internal(
276         ($params{filename} or config_dir_relative(getconf($CNF_DISKFILE))),
277         \%disks, ($params{disk_class} or "Amanda::Disklist::Disk"),
278         \%hosts, ($params{host_class} or "Amanda::Disklist::Host"),
279         \%interfaces, ($params{interface_class} or "Amanda::Disklist::Interface"),
280     );
281 }
282
283 sub get_host {
284     my ($hostname) = @_;
285     return $hosts{$hostname};
286 }
287
288 sub all_hosts {
289     return values %hosts;
290 }
291
292 sub get_disk {
293     my ($hostname, $diskname) = @_;
294     return $disks{$hostname}->{$diskname};
295 }
296
297 sub all_disks {
298     my @rv;
299     foreach my $disk (values %disks) {
300         push @rv, (values %$disk);
301     }
302     return @rv;
303 }
304
305 sub get_interface {
306     my ($interfacename) = @_;
307     return $interfaces{$interfacename};
308 }
309
310 sub all_interfaces {
311     return values %interfaces;
312 }
313
314 push @EXPORT_OK, qw( read_disklist
315         get_host all_hosts
316         get_disk all_disks
317         get_interface all_interfaces);
318
319 %}
320 char *clean_dle_str_for_client(char *dle_str, am_feature_t *their_features);