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