1fcf3ce4John Forte/*
2fcf3ce4John Forte * CDDL HEADER START
3fcf3ce4John Forte *
4fcf3ce4John Forte * The contents of this file are subject to the terms of the
5fcf3ce4John Forte * Common Development and Distribution License (the "License").
6fcf3ce4John Forte * You may not use this file except in compliance with the License.
7fcf3ce4John Forte *
8fcf3ce4John Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce4John Forte * or http://www.opensolaris.org/os/licensing.
10fcf3ce4John Forte * See the License for the specific language governing permissions
11fcf3ce4John Forte * and limitations under the License.
12fcf3ce4John Forte *
13fcf3ce4John Forte * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce4John Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce4John Forte * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce4John Forte * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce4John Forte * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce4John Forte *
19fcf3ce4John Forte * CDDL HEADER END
20fcf3ce4John Forte */
21fcf3ce4John Forte/*
22fcf3ce4John Forte * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce4John Forte * Use is subject to license terms.
24fcf3ce4John Forte */
25fcf3ce4John Forte
26fcf3ce4John Forte
27fcf3ce4John Forte
28fcf3ce4John Forte#include "HBAList.h"
29fcf3ce4John Forte#include "Exceptions.h"
30fcf3ce4John Forte#include "Trace.h"
31fcf3ce4John Forte#include "sun_fc_version.h"
32fcf3ce4John Forte#include <string>
33fcf3ce4John Forte#include <sstream>
34fcf3ce4John Forte#include "FCHBA.h"
35fcf3ce4John Forte#include "TgtFCHBA.h"
36f3aaec0Richard Lowe#include <cstring>
37f3aaec0Richard Lowe#include <climits>
38f3aaec0Richard Lowe#include <cstdlib>
39fcf3ce4John Forte
40fcf3ce4John Forteusing namespace std;
41fcf3ce4John Forte
42fcf3ce4John Forte/**
43fcf3ce4John Forte * @memo	    Private constructor (used to create singleton instance)
44fcf3ce4John Forte * @see		    HBAList::instance
45fcf3ce4John Forte */
46fcf3ce4John ForteHBAList::HBAList() { }
47fcf3ce4John Forte
48fcf3ce4John Forte/**
49fcf3ce4John Forte * Internal singleton instance
50fcf3ce4John Forte */
51fcf3ce4John ForteHBAList* HBAList::_instance = 0;
52fcf3ce4John Forte
53fcf3ce4John Forte/**
54fcf3ce4John Forte * Max number of adapters that this class supports.
55fcf3ce4John Forte */
56fcf3ce4John Forteconst int32_t HBAList::HBA_MAX_PER_LIST = INT_MAX;
57fcf3ce4John Forte
58fcf3ce4John Forte/**
59fcf3ce4John Forte * @memo	    Free up resources held by this HBA list
60fcf3ce4John Forte * @postcondition   All memory used by this list will be freed
61fcf3ce4John Forte * @return	    HBA_STATUS_OK on success
62fcf3ce4John Forte *
63fcf3ce4John Forte */
64fcf3ce4John ForteHBA_STATUS HBAList::unload() {
65fcf3ce4John Forte	Trace log("HBAList::unload");
66fcf3ce4John Forte	lock();
67fcf3ce4John Forte	_instance = NULL;
68fcf3ce4John Forte	unlock();
69fcf3ce4John Forte	return (HBA_STATUS_OK);
70fcf3ce4John Forte}
71fcf3ce4John Forte
72fcf3ce4John Forte/**
73fcf3ce4John Forte * @memo	    Fetch the singleton instance
74fcf3ce4John Forte * @return	    The singleton instance
75fcf3ce4John Forte *
76fcf3ce4John Forte * @doc		    Only one instance of HBAList must be present
77fcf3ce4John Forte *		    per address space at a time.  The singleton design pattern
78fcf3ce4John Forte *		    is used to enforce this behavior.
79fcf3ce4John Forte */
80fcf3ce4John ForteHBAList* HBAList::instance() {
81fcf3ce4John Forte	Trace log("HBAList::instance");
82fcf3ce4John Forte	if (_instance == 0) {
83fcf3ce4John Forte	    _instance = new HBAList();
84fcf3ce4John Forte	}
85fcf3ce4John Forte	return (_instance);
86fcf3ce4John Forte}
87fcf3ce4John Forte
88fcf3ce4John Forte/**
89fcf3ce4John Forte * @memo	    Fetch an HBA based on name.
90fcf3ce4John Forte *		    Always returns  non-null or throw an Exception.
91fcf3ce4John Forte * @precondition    HBAs must be loaded in the list
92fcf3ce4John Forte * @postcondition   A handle will be opened.  The caller must close the handle
93fcf3ce4John Forte *		    at some later time to prevent leakage.
94fcf3ce4John Forte * @exception	    BadArgumentException if the name is not properly formatted
95fcf3ce4John Forte * @exception	    IllegalIndexException if the name does not match any
96fcf3ce4John Forte *		    present HBAs within this list.
97fcf3ce4John Forte * @return	    A valid handle for future API calls
98fcf3ce4John Forte * @param	    name The name of the HBA to open
99fcf3ce4John Forte *
100fcf3ce4John Forte * @doc		    This routine will always return a handle (ie, non null)
101fcf3ce4John Forte *		    or will throw an exception.
102fcf3ce4John Forte */
103fcf3ce4John ForteHandle* HBAList::openHBA(string name) {
104fcf3ce4John Forte	Trace log("HBAList::openHBA(name)");
105fcf3ce4John Forte	int index = -1;
106fcf3ce4John Forte	try {
107fcf3ce4John Forte	    string::size_type offset = name.find_last_of("-");
108fcf3ce4John Forte	    if (offset >= 0) {
109fcf3ce4John Forte		string indexString = name.substr(offset+1);
110fcf3ce4John Forte		index = atoi(indexString.c_str());
111fcf3ce4John Forte	    }
112fcf3ce4John Forte	} catch (...) {
113fcf3ce4John Forte	    throw BadArgumentException();
114fcf3ce4John Forte	}
115fcf3ce4John Forte	lock();
116fcf3ce4John Forte	if (index < 0 || index > hbas.size()) {
117fcf3ce4John Forte	    unlock();
118fcf3ce4John Forte	    throw IllegalIndexException();
119fcf3ce4John Forte	} else {
120fcf3ce4John Forte	    HBA *tmp = hbas[index];
121fcf3ce4John Forte	    unlock();
122fcf3ce4John Forte	    tmp->validatePresent();
123fcf3ce4John Forte	    return (new Handle(tmp));
124fcf3ce4John Forte	}
125fcf3ce4John Forte}
126fcf3ce4John Forte
127fcf3ce4John Forte/**
128fcf3ce4John Forte * @memo	    Fetch an target mode FC HBA based on name.
129fcf3ce4John Forte *		    Always returns  non-null or throw an Exception.
130fcf3ce4John Forte * @precondition    Target mode HBAs must be loaded in the list
131fcf3ce4John Forte * @postcondition   A handle will be opened.  The caller must close the handle
132fcf3ce4John Forte *		    at some later time to prevent leakage.
133fcf3ce4John Forte * @exception	    BadArgumentException if the name is not properly formatted
134fcf3ce4John Forte * @exception	    IllegalIndexException if the name does not match any
135fcf3ce4John Forte *		    present HBAs within this list.
136fcf3ce4John Forte * @return	    A valid handle for future API calls
137fcf3ce4John Forte * @param	    name The name of the target mode HBA to open
138fcf3ce4John Forte *
139fcf3ce4John Forte * @doc		    This routine will always return a handle (ie, non null)
140fcf3ce4John Forte *		    or will throw an exception.
141fcf3ce4John Forte */
142fcf3ce4John ForteHandle* HBAList::openTgtHBA(string name) {
143fcf3ce4John Forte	Trace log("HBAList::openHBA(name)");
144fcf3ce4John Forte	int index = -1;
145fcf3ce4John Forte	try {
146fcf3ce4John Forte	    string::size_type offset = name.find_last_of("-");
147fcf3ce4John Forte	    if (offset >= 0) {
148fcf3ce4John Forte		string indexString = name.substr(offset+1);
149fcf3ce4John Forte		index = atoi(indexString.c_str());
150fcf3ce4John Forte	    }
151fcf3ce4John Forte	} catch (...) {
152fcf3ce4John Forte	    throw BadArgumentException();
153fcf3ce4John Forte	}
154fcf3ce4John Forte	lock();
155fcf3ce4John Forte	if (index < 0 || index > tgthbas.size()) {
156fcf3ce4John Forte	    unlock();
157fcf3ce4John Forte	    throw IllegalIndexException();
158fcf3ce4John Forte	} else {
159fcf3ce4John Forte	    HBA *tmp = tgthbas[index];
160fcf3ce4John Forte	    unlock();
161fcf3ce4John Forte	    tmp->validatePresent();
162fcf3ce4John Forte	    return (new Handle(tmp));
163fcf3ce4John Forte	}
164fcf3ce4John Forte}
165fcf3ce4John Forte
166fcf3ce4John Forte/**
167fcf3ce4John Forte * @memo	    Get the name of an HBA at the given index
168fcf3ce4John Forte * @precondition    HBAs must be loaded in the list
169fcf3ce4John Forte * @exception	    IllegalIndexException Thrown if the index doesn't match any
170fcf3ce4John Forte *		    HBA in the list
171fcf3ce4John Forte * @return	    The name of the specified HBA
172fcf3ce4John Forte * @param	    index The zero based index of the desired HBA
173fcf3ce4John Forte *
174fcf3ce4John Forte */
175fcf3ce4John Fortestring HBAList::getHBAName(int index) {
176fcf3ce4John Forte	Trace log("HBAList::getHBAName");
177fcf3ce4John Forte	lock();
178fcf3ce4John Forte	if (index < 0 || index > hbas.size()) {
179fcf3ce4John Forte	    unlock();
180fcf3ce4John Forte	    throw IllegalIndexException();
181fcf3ce4John Forte	} else {
182fcf3ce4John Forte	    HBA *tmp = hbas[index];
183fcf3ce4John Forte	    unlock();
184fcf3ce4John Forte	    tmp->validatePresent();
185fcf3ce4John Forte	    char buf[128];
186fcf3ce4John Forte	    snprintf(buf, 128, "%s-%d", tmp->getName().c_str(), index);
187fcf3ce4John Forte	    string name = buf;
188fcf3ce4John Forte	    return (name);
189fcf3ce4John Forte	}
190fcf3ce4John Forte}
191fcf3ce4John Forte
192fcf3ce4John Forte/**
193fcf3ce4John Forte * @memo	    Get the name of an target mode HBA at the given index
194fcf3ce4John Forte * @precondition    Target mode HBAs must be loaded in the list
195fcf3ce4John Forte * @exception	    IllegalIndexException Thrown if the index doesn't match any
196fcf3ce4John Forte *		    HBA in the list
197fcf3ce4John Forte * @return	    The name of the specified target mode HBA
198fcf3ce4John Forte * @param	    index The zero based index of the desired target mode HBA
199fcf3ce4John Forte *
200fcf3ce4John Forte */
201fcf3ce4John Fortestring HBAList::getTgtHBAName(int index) {
202fcf3ce4John Forte	Trace log("HBAList::getTgtHBAName");
203fcf3ce4John Forte	lock();
204fcf3ce4John Forte	if (index < 0 || index > tgthbas.size()) {
205fcf3ce4John Forte	    unlock();
206fcf3ce4John Forte	    throw IllegalIndexException();
207fcf3ce4John Forte	} else {
208fcf3ce4John Forte	    HBA *tmp = tgthbas[index];
209fcf3ce4John Forte	    unlock();
210fcf3ce4John Forte	    tmp->validatePresent();
211fcf3ce4John Forte	    char buf[128];
212fcf3ce4John Forte	    snprintf(buf, 128, "%s-%d", tmp->getName().c_str(), index);
213fcf3ce4John Forte	    string name = buf;
214fcf3ce4John Forte	    return (name);
215fcf3ce4John Forte	}
216fcf3ce4John Forte}
217fcf3ce4John Forte
218fcf3ce4John Forte/**
219fcf3ce4John Forte * @memo	    Open an HBA based on a WWN
220fcf3ce4John Forte * @precondition    HBAs must be loaded in the list
221fcf3ce4John Forte * @postcondition   A handle will be opened.  The caller must close the handle
222fcf3ce4John Forte *		    at some later time to prevent leakage.
223fcf3ce4John Forte * @exception	    IllegalWWNException Thrown if the wwn doesn't match any
224fcf3ce4John Forte *		    HBA in the list
225fcf3ce4John Forte * @return	    A valid Handle for later use by API calls
226fcf3ce4John Forte * @param	    wwn The node or any port WWN of HBA to open
227fcf3ce4John Forte * @see		    HBA::containsWWN
228fcf3ce4John Forte *
229fcf3ce4John Forte * @doc		    This routine will accept both Node and Port WWNs based
230fcf3ce4John Forte *		    on the HBA routine containsWWN
231fcf3ce4John Forte */
232fcf3ce4John ForteHandle* HBAList::openHBA(uint64_t wwn) {
233fcf3ce4John Forte
234fcf3ce4John Forte	Trace log("HBAList::openHBA(wwn)");
235fcf3ce4John Forte	lock();
236fcf3ce4John Forte	HBA *tmp;
237fcf3ce4John Forte	for (int i = 0; i < hbas.size(); i++) {
238fcf3ce4John Forte	    if (hbas[i]->containsWWN(wwn)) {
239fcf3ce4John Forte		tmp = hbas[i];
240fcf3ce4John Forte		unlock();
241fcf3ce4John Forte		tmp->validatePresent();
242fcf3ce4John Forte		return (new Handle(tmp));
243fcf3ce4John Forte	    }
244fcf3ce4John Forte	}
245fcf3ce4John Forte	unlock();
246fcf3ce4John Forte	throw IllegalWWNException();
247fcf3ce4John Forte}
248fcf3ce4John Forte
249fcf3ce4John Forte/**
250fcf3ce4John Forte * @memo	    Open an target mode HBA based on a WWN
251fcf3ce4John Forte * @precondition    Targee mode HBAs must be loaded in the list
252fcf3ce4John Forte * @postcondition   A handle will be opened.  The caller must close the handle
253fcf3ce4John Forte *		    at some later time to prevent leakage.
254fcf3ce4John Forte * @exception	    IllegalWWNException Thrown if the wwn doesn't match any
255fcf3ce4John Forte *		    target mode HBA in the list
256fcf3ce4John Forte * @return	    A valid Handle for later use by API calls
257fcf3ce4John Forte * @param	    The node WWN or any port WWN of target mode HBA to open
258fcf3ce4John Forte * @see		    HBA::containsWWN
259fcf3ce4John Forte *
260fcf3ce4John Forte * @doc		    This routine will accept both Node and Port WWNs based
261fcf3ce4John Forte *		    on the HBA routine containsWWN
262fcf3ce4John Forte */
263fcf3ce4John ForteHandle* HBAList::openTgtHBA(uint64_t wwn) {
264fcf3ce4John Forte
265fcf3ce4John Forte	Trace log("HBAList::openTgtHBA(wwn)");
266fcf3ce4John Forte	lock();
267fcf3ce4John Forte	HBA *tmp;
268fcf3ce4John Forte	for (int i = 0; i < tgthbas.size(); i++) {
269fcf3ce4John Forte	    if (tgthbas[i]->containsWWN(wwn)) {
270fcf3ce4John Forte		tmp = tgthbas[i];
271fcf3ce4John Forte		unlock();
272fcf3ce4John Forte		tmp->validatePresent();
273fcf3ce4John Forte		return (new Handle(tmp));
274fcf3ce4John Forte	    }
275fcf3ce4John Forte	}
276fcf3ce4John Forte	unlock();
277fcf3ce4John Forte	throw IllegalWWNException();
278fcf3ce4John Forte}
279fcf3ce4John Forte
280fcf3ce4John Forte/**
281fcf3ce4John Forte * @memo	    Get the number of adapters present in the list
282fcf3ce4John Forte * @postcondition   List of HBAs will be loaded
283fcf3ce4John Forte * @exception	    ... Underlying exceptions will be thrown
284fcf3ce4John Forte * @return	    The number of adapters in the list
285fcf3ce4John Forte *
286fcf3ce4John Forte * @doc		    This routine will triger discovery of HBAs on the system.
287fcf3ce4John Forte *		    It will also handle addition/removal of HBAs in the list
288fcf3ce4John Forte *		    based on dynamic reconfiguration operations.  The max
289fcf3ce4John Forte *		    number of HBAs that HBA API supports is up to the
290fcf3ce4John Forte *		    uint32_t size.  VSL supports up to int32_t size thus
291fcf3ce4John Forte *		    it gives enough room for the HBA API library
292fcf3ce4John Forte *		    to handle up to max uint32_t number if adapters.
293fcf3ce4John Forte */
294fcf3ce4John Forteint HBAList::getNumberofAdapters() {
295fcf3ce4John Forte	Trace log("HBAList::getNumberofAdapters");
296fcf3ce4John Forte	lock();
297fcf3ce4John Forte
298fcf3ce4John Forte	try {
299fcf3ce4John Forte	if (hbas.size() == 0) {
300fcf3ce4John Forte	    // First pass, just store them all blindly
301fcf3ce4John Forte	    FCHBA::loadAdapters(hbas);
302fcf3ce4John Forte	} else {
303fcf3ce4John Forte	    // Second pass, do the update operation
304fcf3ce4John Forte	    vector<HBA*> tmp;
305fcf3ce4John Forte	    FCHBA::loadAdapters(tmp);
306fcf3ce4John Forte	    bool matched;
307fcf3ce4John Forte	    for (int i = 0; i < tmp.size(); i++) {
308fcf3ce4John Forte		matched = false;
309fcf3ce4John Forte		for (int j = 0; j < hbas.size(); j++) {
310fcf3ce4John Forte		    if (*tmp[i] == *hbas[j]) {
311fcf3ce4John Forte			matched = true;
312fcf3ce4John Forte			break;
313fcf3ce4John Forte		    }
314fcf3ce4John Forte		}
315fcf3ce4John Forte		if (matched) {
316fcf3ce4John Forte		    delete (tmp[i]);
317fcf3ce4John Forte		} else {
318fcf3ce4John Forte		    hbas.insert(hbas.end(), tmp[i]);
319fcf3ce4John Forte		}
320fcf3ce4John Forte	    }
321fcf3ce4John Forte	}
322fcf3ce4John Forte	} catch (...) {
323fcf3ce4John Forte	    unlock();
324fcf3ce4John Forte	    throw;
325fcf3ce4John Forte	}
326fcf3ce4John Forte
327fcf3ce4John Forte	unlock();
328fcf3ce4John Forte
329fcf3ce4John Forte	// When there is more than HBA_MAX_PER_LIST(= int32_max)
330fcf3ce4John Forte	// VSL returns an error so it is safe to cast it here.
331fcf3ce4John Forte	return ((uint32_t)hbas.size());
332fcf3ce4John Forte}
333fcf3ce4John Forte
334fcf3ce4John Forte/**
335fcf3ce4John Forte * @memo	    Get the number of target mode adapters present in the list
336fcf3ce4John Forte * @postcondition   List of TgtHBAs will be loaded
337fcf3ce4John Forte * @exception	    ... Underlying exceptions will be thrown
338fcf3ce4John Forte * @return	    The number of target mode adapters in the list
339fcf3ce4John Forte *
340fcf3ce4John Forte * @doc		    This routine will triger discovery of Target mode HBAs on
341fcf3ce4John Forte *		    the system. It will also handle addition/removal of Target
342fcf3ce4John Forte * 		    mode HBAs in the list based on dynamic reconfiguration
343fcf3ce4John Forte *		    operations. The max number of target mode HBAs that
344fcf3ce4John Forte *		    HBA API supports is up to the
345fcf3ce4John Forte *		    uint32_t size.  VSL supports up to int32_t size thus
346fcf3ce4John Forte *		    it gives enough room for the HBA API library
347fcf3ce4John Forte *		    to handle up to max uint32_t number of adapters.
348fcf3ce4John Forte */
349fcf3ce4John Forteint HBAList::getNumberofTgtAdapters() {
350fcf3ce4John Forte	Trace log("HBAList::getNumberofTgtAdapters");
351fcf3ce4John Forte	lock();
352fcf3ce4John Forte
353fcf3ce4John Forte	try {
354fcf3ce4John Forte	    if (tgthbas.size() == 0) {
355fcf3ce4John Forte		// First pass, just store them all blindly
356fcf3ce4John Forte		TgtFCHBA::loadAdapters(tgthbas);
357fcf3ce4John Forte	    } else {
358fcf3ce4John Forte		// Second pass, do the update operation
359fcf3ce4John Forte		vector<HBA*> tmp;
360fcf3ce4John Forte		TgtFCHBA::loadAdapters(tmp);
361fcf3ce4John Forte		bool matched;
362fcf3ce4John Forte		for (int i = 0; i < tmp.size(); i++) {
363fcf3ce4John Forte		    matched = false;
364fcf3ce4John Forte		    for (int j = 0; j < tgthbas.size(); j++) {
365fcf3ce4John Forte			if (*tmp[i] == *tgthbas[j]) {
366fcf3ce4John Forte			    matched = true;
367fcf3ce4John Forte			    break;
368fcf3ce4John Forte			}
369fcf3ce4John Forte		    }
370fcf3ce4John Forte		    if (matched) {
371fcf3ce4John Forte			delete (tmp[i]);
372fcf3ce4John Forte		    } else {
373fcf3ce4John Forte			tgthbas.insert(tgthbas.end(), tmp[i]);
374fcf3ce4John Forte		    }
375fcf3ce4John Forte		}
376fcf3ce4John Forte	    }
377fcf3ce4John Forte	} catch (...) {
378fcf3ce4John Forte	    unlock();
379fcf3ce4John Forte	    throw;
380fcf3ce4John Forte	}
381fcf3ce4John Forte
382fcf3ce4John Forte	unlock();
383fcf3ce4John Forte
384fcf3ce4John Forte	// When there is more than HBA_MAX_PER_LIST(= int32_max)
385fcf3ce4John Forte	// VSL returns an error so it is safe to cast it here.
386fcf3ce4John Forte	return ((uint32_t)tgthbas.size());
387fcf3ce4John Forte}
388fcf3ce4John Forte
389fcf3ce4John Forte/**
390fcf3ce4John Forte * @memo	    Load the list
391fcf3ce4John Forte * @return	    HBA_STATUS_OK
392fcf3ce4John Forte *
393fcf3ce4John Forte * @doc		    Currently this routine is a no-op and may be a cantidate
394fcf3ce4John Forte *		    for removal in the future.
395fcf3ce4John Forte */
396fcf3ce4John ForteHBA_STATUS HBAList::load() {
397fcf3ce4John Forte	Trace log("HBAList::load");
398fcf3ce4John Forte
399fcf3ce4John Forte	// No lock is required since no VSL specific action requried.
400fcf3ce4John Forte	return (HBA_STATUS_OK);
401fcf3ce4John Forte}
402fcf3ce4John Forte
403fcf3ce4John Forte/**
404fcf3ce4John Forte * @memo	    Free up resources
405fcf3ce4John Forte */
406fcf3ce4John ForteHBAList::~HBAList() {
407fcf3ce4John Forte	Trace log("HBAList::~HBAList");
408fcf3ce4John Forte	for (int i = 0; i < hbas.size(); i++) {
409fcf3ce4John Forte	    delete (hbas[i]);
410fcf3ce4John Forte	}
411fcf3ce4John Forte	for (int i = 0; i < tgthbas.size(); i++) {
412fcf3ce4John Forte	    delete (tgthbas[i]);
413fcf3ce4John Forte	}
414fcf3ce4John Forte}
415fcf3ce4John Forte
416fcf3ce4John ForteHBA_LIBRARYATTRIBUTES HBAList::getVSLAttributes() {
417fcf3ce4John Forte	HBA_LIBRARYATTRIBUTES attrs;
418fcf3ce4John Forte	char	build_time[] = BUILD_TIME;
419fcf3ce4John Forte	attrs.final = 0;
420fcf3ce4John Forte	memset(&attrs, 0, sizeof(attrs));
421fcf3ce4John Forte	strlcpy(attrs.VName, VSL_NAME, sizeof (attrs.VName));
422fcf3ce4John Forte	strlcpy(attrs.VVersion, VSL_STRING_VERSION, sizeof (attrs.VVersion));
423fcf3ce4John Forte	strptime(build_time, "%c", &attrs.build_date);
424fcf3ce4John Forte
425fcf3ce4John Forte	return (attrs);
426fcf3ce4John Forte}
427