#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <string.h>
#include <sys/syslimits.h>
#include <dirent.h>
#include "dynarray.h"
#include "nbimages.h"
#include "cfutil.h"
#include "NetBootServer.h"
#include "NetBootImageInfo.h"
#include <arpa/inet.h>
#include <netdb.h>
#include <SystemConfiguration/SCValidation.h>
struct NBImageList_s {
dynarray_t list;
};
extern void
my_log(int priority, const char *message, ...);
static Boolean
myCFStringArrayToCStringArray(CFArrayRef arr, char * buffer, int * buffer_size,
int * ret_count)
{
int count = CFArrayGetCount(arr);
int i;
char * offset = NULL;
int space;
char * * strlist = NULL;
space = count * sizeof(char *);
if (buffer != NULL) {
if (*buffer_size < space) {
return (FALSE);
}
strlist = (char * *)buffer;
offset = buffer + space;
}
for (i = 0; i < count; i++) {
CFIndex len = 0;
CFStringRef str;
str = CFArrayGetValueAtIndex(arr, i);
if (buffer != NULL) {
len = *buffer_size - space;
if (len < 0) {
return (FALSE);
}
}
CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)),
kCFStringEncodingASCII, '\0',
FALSE, offset, len - 1, &len);
if (buffer != NULL) {
strlist[i] = offset;
offset[len] = '\0';
offset += len + 1;
}
space += len + 1;
}
*buffer_size = space;
*ret_count = count;
return (TRUE);
}
static int
cfstring_to_cstring(CFStringRef cfstr, char * str, int len)
{
if (CFStringGetCString(cfstr, str, len, kCFStringEncodingUTF8)) {
return (TRUE);
}
*str = '\0';
return (FALSE);
}
static __inline__ char *
find_colon(char * str)
{
char * start = str;
char * colon;
while ((colon = strchr(start, ':')) != NULL) {
if (colon == start) {
break;
}
if (colon[-1] != '\\')
break;
start = colon;
}
return (colon);
}
static __inline__ boolean_t
parse_nfs_path(char * path, struct in_addr * iaddr_p,
char * * mount_dir, char * * image_path)
{
char * start;
char * colon;
start = path;
colon = strchr(start, ':');
if (colon == NULL) {
return (FALSE);
}
*colon = '\0';
if (inet_aton(start, iaddr_p) != 1) {
struct in_addr * * addr;
struct hostent * ent;
ent = gethostbyname(start);
if (ent == NULL) {
return (FALSE);
}
addr = (struct in_addr * *)ent->h_addr_list;
if (*addr == NULL)
return (FALSE);
*iaddr_p = **addr;
}
start = colon + 1;
colon = find_colon(start);
*mount_dir = start;
if (colon == NULL) {
*image_path = NULL;
}
else {
*colon = '\0';
start = colon + 1;
(void)find_colon(start);
*image_path = start;
}
return (TRUE);
}
static __inline__ boolean_t
parse_http_path(char * path, struct in_addr * iaddr_p,
char * * username, char * * password, int * port,
char * * image_path)
{
char * atchar;
char * colon;
char * slash;
char * start;
*username = NULL;
*password = NULL;
*port = 0;
#define HTTP_URL_PREFIX "http://"
#define HTTP_URL_PREFIX_LEN 7
start = path;
if (strncmp(HTTP_URL_PREFIX, start, HTTP_URL_PREFIX_LEN) != 0) {
return (FALSE);
}
start += HTTP_URL_PREFIX_LEN;
slash = strchr(start, '/');
if (slash == NULL) {
return (FALSE);
}
*slash = '\0';
*image_path = slash + 1;
atchar = strchr(start, '@');
if (atchar != NULL && atchar < slash) {
*atchar = '\0';
*username = start;
*password = strsep(username, ":");
if (*password == NULL) {
return (FALSE);
}
start = atchar + 1;
}
colon = strchr(start, ':');
if (colon) {
*colon = '\0';
*port = atoi(colon + 1);
}
if (inet_aton(start, iaddr_p) != 1) {
struct in_addr * * addr;
struct hostent * ent;
ent = gethostbyname(start);
if (ent == NULL) {
return (FALSE);
}
addr = (struct in_addr * *)ent->h_addr_list;
if (*addr == NULL)
return (FALSE);
*iaddr_p = **addr;
}
return (TRUE);
}
int
NBImageList_count(NBImageListRef image_list)
{
dynarray_t * dlist = &image_list->list;
return (dynarray_count(dlist));
}
NBImageEntryRef
NBImageList_element(NBImageListRef image_list, int i)
{
dynarray_t * dlist = &image_list->list;
return (dynarray_element(dlist, i));
}
NBImageEntryRef
NBImageList_elementWithID(NBImageListRef image_list, bsdp_image_id_t image_id)
{
dynarray_t * dlist = &image_list->list;
int i;
int count;
count = dynarray_count(dlist);
for (i = 0; i < count; i++) {
NBImageEntryRef entry = dynarray_element(dlist, i);
if (image_id == entry->image_id) {
return (entry);
}
}
return (NULL);
}
void
NBImageList_free(NBImageListRef * l)
{
NBImageListRef image_list;
if (l == NULL) {
return;
}
image_list = *l;
if (image_list == NULL) {
return;
}
dynarray_free(&image_list->list);
free(image_list);
*l = NULL;
return;
}
static boolean_t
stat_file(char * dir, char * file)
{
char path[PATH_MAX];
struct stat sb;
snprintf(path, sizeof(path), "%s/%s", dir, file);
if (stat(path, &sb) < 0) {
fprintf(stderr, "stat %s failed, %s\n",
path, strerror(errno));
return (FALSE);
}
if ((sb.st_mode & S_IFREG) == 0) {
fprintf(stderr, "%s is not a file\n", path);
return (FALSE);
}
return (TRUE);
}
static const char *
NBImageTypeStr(NBImageType type)
{
switch (type) {
case kNBImageTypeClassic:
return "Classic";
case kNBImageTypeNFS:
return "NFS";
case kNBImageTypeHTTP:
return "HTTP";
case kNBImageTypeBootFileOnly:
return "BootFile";
default:
return "<unknown>";
}
}
static void
dump_strlist(const char * * strlist, int count)
{
int i;
for (i = 0; i < count; i++) {
printf("%s%s", (i != 0) ? ", " : "", strlist[i]);
}
return;
}
static void
NBImageEntry_print(NBImageEntryRef entry)
{
printf("%-12s %-35.*s 0x%08x %-9s %-12s",
entry->sharepoint.name,
entry->name_length, entry->name,
entry->image_id,
NBImageTypeStr(entry->type),
entry->bootfile);
switch (entry->type) {
case kNBImageTypeClassic:
printf(" %-12s", entry->type_info.classic.shared);
if (entry->type_info.classic.private != NULL) {
printf(" %-12s", entry->type_info.classic.private);
}
break;
case kNBImageTypeNFS:
printf(" %-12s%s", entry->type_info.nfs.root_path,
(entry->type_info.nfs.indirect == TRUE)? " [indirect]" : "");
break;
case kNBImageTypeHTTP:
printf(" %-12s%s", entry->type_info.http.root_path,
(entry->type_info.http.indirect == TRUE)? " [indirect]" : "");
break;
default:
break;
}
if (entry->sysids != NULL) {
printf(" [ ");
dump_strlist(entry->sysids, entry->sysids_count);
printf(" ]");
}
if (entry->filter_only) {
printf(" <filter>");
}
printf("\n");
return;
}
static boolean_t
S_get_plist_boolean(CFDictionaryRef plist, CFStringRef key, boolean_t d)
{
CFBooleanRef b;
boolean_t ret = d;
b = CFDictionaryGetValue(plist, key);
if (isA_CFBoolean(b) != NULL) {
ret = CFBooleanGetValue(b);
}
return (ret);
}
static int
my_ptrstrcmp(const void * v1, const void * v2)
{
const char * * s1 = (const char * *)v1;
const char * * s2 = (const char * *)v2;
return (strcmp(*s1, *s2));
}
static NBImageEntryRef
NBImageEntry_create(NBSPEntryRef sharepoint, char * dir_name,
char * dir_path, char * info_plist_path)
{
u_int16_t attr = 0;
CFStringRef bootfile;
boolean_t diskless;
NBImageEntryRef entry = NULL;
char * ent_bootfile = NULL;
char * ent_name = NULL;
CFIndex ent_name_len = 0;
char * ent_private = NULL;
char * ent_root_path = NULL;
char * ent_shared = NULL;
char * ent_tftp_path = NULL;
boolean_t filter_only;
int32_t idx_val = -1;
CFNumberRef idx;
char * image_file = NULL;
boolean_t image_is_default;
boolean_t indirect = FALSE;
CFNumberRef kind;
int32_t kind_val = -1;
char * mount_point = NULL;
CFStringRef name;
char * offset;
char path[PATH_MAX];
CFPropertyListRef plist;
CFStringRef private;
CFStringRef root_path;
struct in_addr server_ip;
char * server_password;
int server_port;
char * server_username;
CFStringRef shared;
int string_space = 0;
int sysids_space = 0;
CFArrayRef sysids_prop;
char tmp[PATH_MAX];
CFStringRef type;
NBImageType type_val = kNBImageTypeNone;
string_space = strlen(dir_name) + strlen(sharepoint->path)
+ strlen(sharepoint->name) + 3;
plist = my_CFPropertyListCreateFromFile(info_plist_path);
if (isA_CFDictionary(plist) == NULL) {
goto failed;
}
if (S_get_plist_boolean(plist, kNetBootImageInfoIsEnabled, TRUE) == FALSE) {
goto failed;
}
if (S_get_plist_boolean(plist, kNetBootImageInfoIsInstall, FALSE) == TRUE) {
attr |= BSDP_IMAGE_ATTRIBUTES_INSTALL;
}
image_is_default = S_get_plist_boolean(plist, kNetBootImageInfoIsDefault,
FALSE);
diskless = S_get_plist_boolean(plist, kNetBootImageInfoSupportsDiskless,
FALSE);
filter_only = S_get_plist_boolean(plist, kNetBootImageInfoFilterOnly,
FALSE);
name = CFDictionaryGetValue(plist, kNetBootImageInfoName);
if (isA_CFString(name) == NULL) {
fprintf(stderr, "missing/invalid Name property\n");
goto failed;
}
ent_name_len = CFStringGetLength(name);
CFStringGetBytes(name, CFRangeMake(0, ent_name_len),
kCFStringEncodingUTF8, '?', TRUE,
tmp, BSDP_IMAGE_NAME_MAX,
&ent_name_len);
if (ent_name_len == 0) {
printf("zero name length\n");
goto failed;
}
ent_name = malloc(ent_name_len);
if (ent_name == NULL) {
goto failed;
}
bcopy(tmp, ent_name, ent_name_len);
string_space += ent_name_len;
idx = CFDictionaryGetValue(plist, kNetBootImageInfoIndex);
if (isA_CFNumber(idx) == NULL
|| CFNumberGetValue(idx, kCFNumberSInt32Type, &idx_val) == FALSE
|| idx_val <= 0 || idx_val > BSDP_IMAGE_INDEX_MAX) {
fprintf(stderr, "missing/invalid Index property\n");
goto failed;
}
kind = CFDictionaryGetValue(plist, kNetBootImageInfoKind);
if (isA_CFNumber(kind) != NULL) {
if (CFNumberGetValue(kind, kCFNumberSInt32Type, &kind_val) == FALSE
|| kind_val < 0 || kind_val > BSDP_IMAGE_ATTRIBUTES_KIND_MAX) {
kind_val = -1;
}
}
type = CFDictionaryGetValue(plist, kNetBootImageInfoType);
if (isA_CFString(type) == NULL) {
fprintf(stderr, "missing/invalid Type property\n");
goto failed;
}
if (CFEqual(type, kNetBootImageInfoTypeClassic)) {
type_val = kNBImageTypeClassic;
if (kind_val == -1) {
kind_val = bsdp_image_kind_MacOS9;
}
diskless = TRUE;
}
else if (CFEqual(type, kNetBootImageInfoTypeNFS)) {
type_val = kNBImageTypeNFS;
if (kind_val == -1) {
kind_val = bsdp_image_kind_MacOSX;
}
}
else if (CFEqual(type, kNetBootImageInfoTypeHTTP)) {
type_val = kNBImageTypeHTTP;
if (kind_val == -1) {
kind_val = bsdp_image_kind_MacOSX;
}
}
else if (CFEqual(type, kNetBootImageInfoTypeBootFileOnly)) {
type_val = kNBImageTypeBootFileOnly;
diskless = FALSE;
}
if (type_val == kNBImageTypeNone) {
fprintf(stderr, "unrecognized Type property\n");
goto failed;
}
if (kind_val == -1) {
fprintf(stderr, "missing/unrecognized Kind value\n");
goto failed;
}
if (kind_val == bsdp_image_kind_Diagnostics) {
if (CFDictionaryContainsKey(plist,
kNetBootImageInfoFilterOnly) == FALSE) {
filter_only = TRUE;
}
}
attr |= bsdp_image_attributes_from_kind(kind_val);
bootfile = CFDictionaryGetValue(plist, kNetBootImageInfoBootFile);
if (isA_CFString(bootfile) == NULL) {
fprintf(stderr, "missing/invalid BootFile property\n");
goto failed;
}
if (cfstring_to_cstring(bootfile, tmp, sizeof(tmp)) == FALSE) {
fprintf(stderr, "BootFile could not be converted\n");
goto failed;
}
if (stat_file(dir_path, tmp) == FALSE) {
fprintf(stderr, "BootFile does not exist\n");
goto failed;
}
ent_bootfile = strdup(tmp);
if (ent_bootfile == NULL) {
goto failed;
}
string_space += strlen(ent_bootfile) + 1;
snprintf(tmp, sizeof(tmp),
NETBOOT_TFTP_DIRECTORY "/%s/%s/%s", sharepoint->name,
dir_name, ent_bootfile);
ent_tftp_path = strdup(tmp);
string_space += strlen(ent_tftp_path) + 1;
sysids_prop
= CFDictionaryGetValue(plist,
kNetBootImageInfoEnabledSystemIdentifiers);
if (sysids_prop != NULL) {
int sysids_count;
if (isA_CFArray(sysids_prop) == NULL) {
fprintf(stderr, "EnabledSystemIdentifiers isn't an array\n");
goto failed;
}
if (myCFStringArrayToCStringArray(sysids_prop, NULL, &sysids_space,
&sysids_count) == FALSE) {
fprintf(stderr,
"Couldn't calculate EnabledSystemIdentifiers length\n");
goto failed;
}
string_space += sysids_space;
}
switch (type_val) {
case kNBImageTypeClassic:
shared = CFDictionaryGetValue(plist, kNetBootImageInfoSharedImage);
if (isA_CFString(shared) == NULL) {
fprintf(stderr, "missing/invalid SharedImage property\n");
goto failed;
}
if (cfstring_to_cstring(shared, tmp, sizeof(tmp)) == FALSE) {
fprintf(stderr, "SharedImage could not be converted\n");
goto failed;
}
if (stat_file(dir_path, tmp) == FALSE) {
fprintf(stderr, "SharedImage does not exist\n");
goto failed;
}
ent_shared = strdup(tmp);
if (ent_shared == NULL) {
goto failed;
}
string_space += strlen(ent_shared) + 1;
private
= isA_CFString(CFDictionaryGetValue(plist,
kNetBootImageInfoPrivateImage));
if (private != NULL) {
if (cfstring_to_cstring(private, tmp, sizeof(tmp))
&& stat_file(dir_path, tmp)) {
ent_private = strdup(tmp);
if (ent_private == NULL) {
goto failed;
}
string_space += strlen(ent_private) + 1;
}
}
break;
case kNBImageTypeNFS:
root_path = CFDictionaryGetValue(plist, kNetBootImageInfoRootPath);
if (isA_CFString(root_path) == NULL) {
fprintf(stderr, "missing/invalid RootPath property\n");
goto failed;
}
if (cfstring_to_cstring(root_path, tmp, sizeof(tmp)) == FALSE) {
fprintf(stderr, "RootPath could not be converted\n");
goto failed;
}
if (stat_file(dir_path, tmp) == TRUE) {
ent_root_path = strdup(tmp);
}
else if (parse_nfs_path(tmp, &server_ip, &mount_point,
&image_file) == TRUE) {
if (image_file) {
snprintf(path, sizeof(path), "nfs:%s:%s:%s",
inet_ntoa(server_ip), mount_point,
image_file);
}
else {
snprintf(path, sizeof(path), "nfs:%s:%s",
inet_ntoa(server_ip), mount_point);
}
indirect = TRUE;
ent_root_path = strdup(path);
}
if (ent_root_path == NULL) {
goto failed;
}
string_space += strlen(ent_root_path) + 1;
break;
case kNBImageTypeHTTP:
root_path = CFDictionaryGetValue(plist, kNetBootImageInfoRootPath);
if (isA_CFString(root_path) == NULL) {
fprintf(stderr, "missing/invalid RootPath property\n");
goto failed;
}
if (cfstring_to_cstring(root_path, tmp, sizeof(tmp)) == FALSE) {
fprintf(stderr, "RootPath could not be converted\n");
goto failed;
}
if (stat_file(dir_path, tmp) == TRUE) {
ent_root_path = strdup(tmp);
}
else if (parse_http_path(tmp, &server_ip, &server_username,
&server_password, &server_port,
&image_file) == TRUE) {
if (server_username && server_password) {
if (server_port != 0) {
snprintf(path, sizeof(path), "http://%s:%s@%s:%d/%s",
server_username, server_password,
inet_ntoa(server_ip),
server_port, image_file);
}
else {
snprintf(path, sizeof(path), "http://%s:%s@%s/%s",
server_username, server_password,
inet_ntoa(server_ip),
image_file);
}
}
else {
if (server_port != 0) {
snprintf(path, sizeof(path), "http://%s:%d/%s",
inet_ntoa(server_ip), server_port,
image_file);
}
else {
snprintf(path, sizeof(path), "http://%s/%s",
inet_ntoa(server_ip), image_file);
}
}
indirect = TRUE;
ent_root_path = strdup(path);
}
if (ent_root_path == NULL) {
goto failed;
}
string_space += strlen(ent_root_path) + 1;
break;
case kNBImageTypeBootFileOnly:
default:
break;
}
entry = (NBImageEntryRef)malloc(sizeof(*entry) + string_space);
if (entry == NULL) {
goto failed;
}
bzero(entry, sizeof(*entry));
entry->image_id = bsdp_image_id_make(idx_val, attr);
entry->type = type_val;
entry->is_default = image_is_default;
entry->diskless = diskless;
entry->filter_only = filter_only;
offset = (char *)(entry + 1);
entry->sharepoint.path = offset;
strcpy(entry->sharepoint.path, sharepoint->path);
offset += strlen(sharepoint->path) + 1;
entry->sharepoint.name = offset;
strcpy(entry->sharepoint.name, sharepoint->name);
offset += strlen(sharepoint->name) + 1;
entry->dir_name = offset;
strcpy(entry->dir_name, dir_name);
offset += strlen(dir_name) + 1;
entry->name = offset;
entry->name_length = ent_name_len;
bcopy(ent_name, entry->name, ent_name_len);
offset += ent_name_len;
entry->bootfile = offset;
strcpy(entry->bootfile, ent_bootfile);
offset += strlen(ent_bootfile) + 1;
entry->tftp_path = offset;
strcpy(entry->tftp_path, ent_tftp_path);
offset += strlen(ent_tftp_path) + 1;
if (sysids_space > 0) {
entry->sysids = (const char * *)offset;
(void)myCFStringArrayToCStringArray(sysids_prop, offset, &sysids_space,
&entry->sysids_count);
qsort(entry->sysids, entry->sysids_count, sizeof(char *),
my_ptrstrcmp);
offset += sysids_space;
}
switch (type_val) {
case kNBImageTypeClassic:
entry->type_info.classic.shared = offset;
strcpy(entry->type_info.classic.shared, ent_shared);
offset += strlen(ent_shared) + 1;
if (ent_private != NULL) {
entry->type_info.classic.private = offset;
strcpy(entry->type_info.classic.private, ent_private);
offset += strlen(ent_private) + 1;
}
break;
case kNBImageTypeNFS:
entry->type_info.nfs.root_path = offset;
strcpy(entry->type_info.nfs.root_path, ent_root_path);
offset += strlen(ent_root_path) + 1;
entry->type_info.nfs.indirect = indirect;
break;
case kNBImageTypeHTTP:
entry->type_info.http.root_path = offset;
strcpy(entry->type_info.http.root_path, ent_root_path);
offset += strlen(ent_root_path) + 1;
entry->type_info.http.indirect = indirect;
break;
default:
break;
}
failed:
if (ent_name != NULL) {
free(ent_name);
}
if (ent_bootfile != NULL) {
free(ent_bootfile);
}
if (ent_tftp_path != NULL) {
free(ent_tftp_path);
}
if (ent_shared != NULL) {
free(ent_shared);
}
if (ent_private != NULL) {
free(ent_private);
}
if (ent_root_path != NULL) {
free(ent_root_path);
}
my_CFRelease(&plist);
return (entry);
}
boolean_t
NBImageEntry_supported_sysid(NBImageEntryRef entry,
const char * sysid)
{
if (entry->sysids == NULL) {
return (TRUE);
}
return (bsearch(&sysid, entry->sysids, entry->sysids_count,
sizeof(char *), my_ptrstrcmp) != NULL);
}
boolean_t
NBImageEntry_attributes_match(NBImageEntryRef entry,
const u_int16_t * attrs_list, int n_attrs_list)
{
u_int16_t attrs;
int i;
if (attrs_list == NULL) {
return (!entry->filter_only);
}
attrs = bsdp_image_attributes(entry->image_id);
for (i = 0; i < n_attrs_list; i++) {
if (attrs_list[i] == attrs) {
return (TRUE);
}
}
return (FALSE);
}
static void
NBImageList_add_default_entry(NBImageListRef image_list,
NBImageEntryRef entry)
{
dynarray_t * dlist = &image_list->list;
int i;
int count;
if (entry->sysids == NULL) {
dynarray_insert(dlist, entry, 0);
return;
}
count = dynarray_count(dlist);
for (i = 0; i < count; i++) {
NBImageEntryRef scan = dynarray_element(dlist, i);
if (scan->is_default == FALSE
|| scan->sysids != NULL) {
dynarray_insert(dlist, entry, i);
return;
}
}
dynarray_add(dlist, entry);
return;
}
static void
NBImageList_add_entry(NBImageListRef image_list, NBImageEntryRef entry)
{
NBImageEntryRef scan;
scan = NBImageList_elementWithID(image_list, entry->image_id);
if (scan != NULL) {
fprintf(stderr,
"Ignoring image with non-unique image index %d:\n",
bsdp_image_index(entry->image_id));
NBImageEntry_print(entry);
free(entry);
return;
}
if (entry->is_default) {
NBImageList_add_default_entry(image_list, entry);
}
else {
dynarray_add(&image_list->list, entry);
}
return;
}
static void
NBImageList_add_images(NBImageListRef image_list, NBSPEntryRef sharepoint)
{
char dir[PATH_MAX];
DIR * dir_p;
NBImageEntryRef entry;
char info_path[PATH_MAX];
int suffix_len;
struct dirent * scan;
struct stat sb;
dir_p = opendir(sharepoint->path);
if (dir_p == NULL) {
goto done;
}
suffix_len = strlen(NETBOOT_IMAGE_SUFFIX);
while ((scan = readdir(dir_p)) != NULL) {
int entry_len = strlen(scan->d_name);
if (entry_len < suffix_len
|| strcmp(scan->d_name + entry_len - suffix_len,
NETBOOT_IMAGE_SUFFIX) != 0) {
continue;
}
snprintf(dir, sizeof(dir), "%s/%s",
sharepoint->path, scan->d_name);
if (stat(dir, &sb) != 0 || (sb.st_mode & S_IFDIR) == 0) {
continue;
}
snprintf(info_path, sizeof(info_path),
"%s/" NETBOOT_IMAGE_INFO_PLIST, dir);
if (stat(info_path, &sb) != 0 || (sb.st_mode & S_IFREG) == 0) {
continue;
}
entry = NBImageEntry_create(sharepoint, scan->d_name, dir, info_path);
if (entry != NULL) {
NBImageList_add_entry(image_list, entry);
}
}
done:
if (dir_p)
closedir(dir_p);
return;
}
NBImageEntryRef
NBImageList_default(NBImageListRef image_list, const char * sysid,
const u_int16_t * attrs, int n_attrs)
{
int count;
dynarray_t * dlist = &image_list->list;
int i;
count = dynarray_count(dlist);
for (i = 0; i < count; i++) {
NBImageEntryRef scan = dynarray_element(dlist, i);
if (NBImageEntry_supported_sysid(scan, sysid)
&& NBImageEntry_attributes_match(scan, attrs, n_attrs)) {
return (scan);
}
}
return (NULL);
}
NBImageListRef
NBImageList_init(NBSPListRef sharepoints)
{
int count;
int i;
NBImageListRef image_list = NULL;
boolean_t needs_free = FALSE;
if (sharepoints == NULL) {
needs_free = TRUE;
sharepoints = NBSPList_init(NETBOOT_SHAREPOINT_LINK);
if (sharepoints == NULL) {
goto done;
}
}
image_list = (NBImageListRef)malloc(sizeof(*image_list));
if (image_list == NULL) {
goto done;
}
bzero(image_list, sizeof(*image_list));
dynarray_init(&image_list->list, free, NULL);
count = NBSPList_count(sharepoints);
for (i = 0; i < count; i++) {
NBSPEntryRef entry = NBSPList_element(sharepoints, i);
NBImageList_add_images(image_list, entry);
}
done:
if (image_list != NULL) {
if (dynarray_count(&image_list->list) == 0) {
dynarray_free(&image_list->list);
free(image_list);
image_list = NULL;
}
}
if (sharepoints != NULL && needs_free) {
NBSPList_free(&sharepoints);
}
return (image_list);
}
void
NBImageList_print(NBImageListRef image_list)
{
int count;
int i;
printf("%-12s %-35s %-10s %-9s %-12s Image(s)\n", "Sharepoint", "Name",
"Identifier", "Type", "BootFile");
count = dynarray_count(&image_list->list);
for (i = 0; i < count; i++) {
NBImageEntryRef entry;
entry = (NBImageEntryRef)dynarray_element(&image_list->list, i);
NBImageEntry_print(entry);
}
return;
}
#ifdef TEST_NBIMAGES
#if 0
#include <stdarg.h>
#include <syslog.h>
void
my_log(int priority, const char *message, ...)
{
va_list ap;
if (priority == LOG_DEBUG) {
if (G_verbose == FALSE)
return;
priority = LOG_INFO;
}
va_start(ap, message);
vsyslog(priority, message, ap);
return;
}
#endif 0
int
main()
{
NBImageListRef images = NBImageList_init(NULL);
if (images != NULL) {
NBImageList_print(images);
NBImageList_free(&images);
}
exit(0);
}
#endif TEST_NBIMAGES