2 * Copyright (c) 2008,2009 Zmanda, Inc. All Rights Reserved.
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.
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
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
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 %module "Amanda::Disklist"
22 %include "amglue/amglue.swg"
23 %include "exception.i"
24 %import "Amanda/Config.swg"
26 %include "Amanda/Disklist.pod"
35 use Amanda::Debug qw( :logging );
36 use Amanda::Config qw( :getconf config_dir_relative );
39 /* handle creation of opaque objects from Amanda::Config */
40 %types(interface_t *, dumptype_t *);
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)
53 char *name = interface_name(iface->config);
54 HV *ifaceclass_stash = NULL;
57 svp = hv_fetch(ifaces, name, strlen(name), TRUE);
59 croak("internal error"); /* shouldn't happen with lval = TRUE */
62 /* no existing iface, so set up a new one */
66 /* make a new hashref and bless it */
68 ref = newRV_noinc((SV *)h);
69 if (!ifaceclass_stash) {
70 ifaceclass_stash = gv_stashpv(ifaceclass, GV_ADD);
72 sv_bless(ref, ifaceclass_stash);
75 /* fill in the relevant value - a reference to the config */
76 hv_store_const(h, "config",
78 SWIG_NewPointerObj(iface->config,
79 /* can't use $descriptor here.. */
80 SWIGTYPE_p_interface_t, 0)));
94 HV *hostclass_stash = NULL;
99 svp = hv_fetch(hosts, dp->hostname, strlen(dp->hostname), TRUE);
101 croak("internal error"); /* shouldn't happen with lval = TRUE */
104 /* this host already exists */
106 /* no existing host, so set up a new one */
110 /* make a new hashref and bless it */
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);
117 sv_bless(ref, hostclass_stash);
119 g_assert(SvREFCNT(*svp) == 1);
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()));
130 /* and make a link to the relevant interface object */
131 ref = get_iface(ifaces, ifaceclass, dp->host->netif);
133 hv_store_const(h, "interface", ref);
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);
143 g_assert(SvTYPE(SvRV(sv)) == SVt_PVAV);
144 av_push((AV *)SvRV(sv), safe_newSVpv(dp->name));
150 /* typemaps to pass AV's and HV's in directly (as perl refs) */
152 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVHV) {
153 SWIG_exception_fail(SWIG_TypeError, "must provide a hashref");
156 $1 = (HV *)SvRV($input);
160 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
161 SWIG_exception_fail(SWIG_TypeError, "must provide an arrayref");
164 $1 = (AV *)SvRV($input);
168 static cfgerr_level_t
169 read_disklist_internal(
171 HV *disks, char *diskclass,
172 HV *hosts, char *hostclass,
173 HV *ifaces, char *ifaceclass)
175 cfgerr_level_t errlev;
178 HV *diskclass_stash = NULL;
184 errlev = read_diskfile(filename, &list);
185 if (errlev >= CFGERR_ERRORS)
188 for (dp = list.head; dp; dp = dp->next) {
194 /* make a new hashref and bless it */
196 diskref = newRV_noinc((SV *)h);
197 if (!diskclass_stash) {
198 diskclass_stash = gv_stashpv(diskclass, GV_ADD);
200 sv_bless(diskref, diskclass_stash);
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));
206 hv_store_const(h, "config",
208 SWIG_NewPointerObj(lookup_dumptype(dp->dtype_name),
209 /* can't use $descriptor here.. */
210 SWIGTYPE_p_dumptype_t, 0)));
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);
217 /* and store this disk in the two-level %disks hash */
218 svp = hv_fetch(disks, dp->hostname, strlen(dp->hostname), 1);
220 /* make a new hash for this host */
223 href = newRV_noinc((SV *)h);
224 sv_setsv(*svp, href);
226 g_assert(SvROK(*svp));
227 g_assert(SvTYPE(SvRV(*svp)) == SVt_PVHV);
228 h = (HV *)SvRV(*svp);
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);
237 /* free_disklist frees the globals, too, which is not what we want.
238 * So this leaks memory. */
239 /* free_disklist(&list); */
247 package Amanda::Disklist::Disk;
251 package Amanda::Disklist::Host;
254 my ($self, $disk) = @_;
255 return $Amanda::Disklist::disks{$self->{'hostname'}}{$disk};
260 return values %{$Amanda::Disklist::disks{$self->{'hostname'}}};
263 package Amanda::Disklist::Interface;
267 package Amanda::Disklist;
269 our (%disks, %hosts, %interfaces);
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"),
284 return $hosts{$hostname};
288 return values %hosts;
292 my ($hostname, $diskname) = @_;
293 return $disks{$hostname}->{$diskname};
298 foreach my $disk (values %disks) {
299 push @rv, (values %$disk);
305 my ($interfacename) = @_;
306 return $interfaces{$interfacename};
310 return values %interfaces;
313 push @EXPORT_OK, qw( read_disklist
316 get_interface all_interfaces);