1/* 2 * Copyright (c) 2003 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <stdio.h> 25#include <unistd.h> 26#include <stdlib.h> 27#include <fcntl.h> 28#include <sys/mount.h> 29#include <sys/errno.h> 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <sys/fcntl.h> 33#include <string.h> 34#include <sys/syslimits.h> 35#include <dirent.h> 36 37#include "dynarray.h" 38#include "NetBootServer.h" 39#include "nbsp.h" 40 41static void 42NBSPEntry_print(NBSPEntryRef entry) 43{ 44 printf("%s: path %s%s\n", entry->name, entry->path, 45 entry->is_readonly ? " [read-only]" : ""); 46 return; 47} 48 49int 50NBSPList_count(NBSPListRef list) 51{ 52 dynarray_t * dlist = (dynarray_t *)list; 53 54 return (dynarray_count(dlist)); 55} 56 57NBSPEntryRef 58NBSPList_element(NBSPListRef list, int i) 59{ 60 dynarray_t * dlist = (dynarray_t *)list; 61 62 return (dynarray_element(dlist, i)); 63} 64 65 66void 67NBSPList_print(NBSPListRef list) 68{ 69 dynarray_t * dlist = (dynarray_t *)list; 70 int i; 71 72 for (i = 0; i < dynarray_count(dlist); i++) { 73 NBSPEntryRef entry = (NBSPEntryRef)dynarray_element(dlist, i); 74 NBSPEntry_print(entry); 75 } 76 return; 77} 78 79void 80NBSPList_free(NBSPListRef * l) 81{ 82 dynarray_t * list; 83 if (l == NULL) 84 return; 85 list = *((dynarray_t * *)l); 86 if (list == NULL) 87 return; 88 dynarray_free(list); 89 free(list); 90 *l = NULL; 91 return; 92} 93 94static struct statfs * 95get_fsstat_list(int * number) 96{ 97 int n; 98 struct statfs * stat_p; 99 100 n = getfsstat(NULL, 0, MNT_NOWAIT); 101 if (n <= 0) 102 return (NULL); 103 104 stat_p = (struct statfs *)malloc(n * sizeof(*stat_p)); 105 if (stat_p == NULL) 106 return (NULL); 107 108 if (getfsstat(stat_p, n * sizeof(*stat_p), MNT_NOWAIT) <= 0) { 109 free(stat_p); 110 return (NULL); 111 } 112 *number = n; 113 return (stat_p); 114} 115 116static int 117lookup_symlink(const char * symlink_dir, 118 const char * dir_name, 119 char * link_name, int link_name_len) 120{ 121 DIR * dir_p; 122 int len = 0; 123 char path[PATH_MAX]; 124 struct dirent * scan; 125 126 dir_p = opendir(symlink_dir); 127 if (dir_p == NULL) { 128 goto done; 129 } 130 while ((scan = readdir(dir_p)) != NULL) { 131 char symlink[MAXNAMLEN]; 132 ssize_t symlink_len; 133 134 if (scan->d_type != DT_LNK) { 135 continue; 136 } 137 snprintf(path, sizeof(path), "%s/%s", 138 symlink_dir, scan->d_name); 139 symlink_len = readlink(path, symlink, sizeof(symlink) - 1); 140 if (symlink_len <= 0) { 141 continue; 142 } 143 symlink[symlink_len] = '\0'; 144 if (strcmp(symlink, dir_name) == 0) { 145 strlcpy(link_name, scan->d_name, link_name_len); 146 len = strlen(link_name); 147 break; 148 } 149 } 150 done: 151 if (dir_p != NULL) { 152 closedir(dir_p); 153 } 154 return (len); 155} 156 157NBSPListRef 158NBSPList_init(const char * symlink_name, bool readonly_ok) 159{ 160 int i; 161 dynarray_t * list = NULL; 162 struct statfs * stat_p; 163 int stat_number; 164 165 stat_p = get_fsstat_list(&stat_number); 166 if (stat_p == NULL || stat_number == 0) { 167 goto done; 168 } 169 170 for (i = 0; i < stat_number; i++) { 171 NBSPEntryRef entry; 172 struct statfs * p = stat_p + i; 173 char sharename[MAXNAMLEN]; 174 int sharename_len = 0; 175 char sharedir[PATH_MAX]; 176 int sharedir_len = 0; 177 char sharelink[PATH_MAX]; 178 char * root; 179 struct stat sb; 180 181 if ((p->f_flags & MNT_LOCAL) == 0) { 182 /* skip non-local filesystems */ 183 continue; 184 } 185 if ((p->f_flags & MNT_RDONLY) != 0 && readonly_ok == FALSE) { 186 /* skip read-only filesystems if not explicitly allowed */ 187 continue; 188 } 189 if (strcmp(p->f_fstypename, "devfs") == 0 190 || strcmp(p->f_fstypename, "fdesc") == 0) { 191 /* don't bother with devfs, fdesc */ 192 continue; 193 } 194 root = p->f_mntonname; 195 if (strcmp(root, "/") == 0) 196 root = ""; 197 snprintf(sharelink, sizeof(sharelink), 198 "%s" NETBOOT_DIRECTORY "/%s", root, symlink_name); 199 if (lstat(sharelink, &sb) < 0) { 200 continue; /* doesn't exist */ 201 } 202 if ((sb.st_mode & S_IFLNK) == 0) { 203 continue; /* not a symlink */ 204 } 205 if (stat(sharelink, &sb) < 0) { 206 continue; 207 } 208 sharename_len = readlink(sharelink, sharename, sizeof(sharename) - 1); 209 if (sharename_len <= 0) { 210 continue; 211 } 212 sharename[sharename_len] = '\0'; 213 214 /* remember the actual directory name */ 215 snprintf(sharedir, sizeof(sharedir), 216 "%s" NETBOOT_DIRECTORY "/%s", root, sharename); 217 sharedir_len = strlen(sharedir); 218 219 if (readonly_ok) { 220 int tftp_symlink_len; 221 222 /* 223 * Lookup the directory in the TFTP directory, assume that 224 * it is the sharename we want to use for both TFTP and HTTP. 225 * This isn't a safe assumption, we should independently 226 * check/remember the TFTP/HTTP symlink names. 227 */ 228 tftp_symlink_len 229 = lookup_symlink(NETBOOT_TFTP_PATH "/" NETBOOT_TFTP_DIRECTORY, 230 sharedir, sharename, sizeof(sharename)); 231 if (tftp_symlink_len != 0) { 232 sharename_len = tftp_symlink_len; 233 } 234 } 235 if (list == NULL) { 236 list = (dynarray_t *)malloc(sizeof(*list)); 237 if (list == NULL) { 238 goto done; 239 } 240 bzero(list, sizeof(*list)); 241 dynarray_init(list, free, NULL); 242 } 243 entry = malloc(sizeof(*entry) + sharename_len + sharedir_len + 2); 244 if (entry == NULL) { 245 continue; 246 } 247 bzero(entry, sizeof(*entry)); 248 if (strcmp(p->f_fstypename, "hfs") == 0) { 249 entry->is_hfs = TRUE; 250 } 251 if ((p->f_flags & MNT_RDONLY) != 0) { 252 entry->is_readonly = TRUE; 253 } 254 entry->name = (char *)(entry + 1); 255 strncpy(entry->name, sharename, sharename_len); 256 entry->name[sharename_len] = '\0'; 257 entry->path = entry->name + sharename_len + 1; 258 strncpy(entry->path, sharedir, sharedir_len); 259 entry->path[sharedir_len] = '\0'; 260 dynarray_add((dynarray_t *)list, entry); 261 } 262 done: 263 if (list) { 264 if (dynarray_count((dynarray_t *)list) == 0) { 265 free(list); 266 list = NULL; 267 } 268 } 269 if (stat_p != NULL) { 270 free(stat_p); 271 } 272 return ((NBSPListRef)list); 273} 274 275#ifdef TEST_NBSP 276 277int 278main(int argc, char * argv[]) 279{ 280 bool allow_readonly; 281 NBSPListRef list; 282 const char * which; 283 284 if (argc == 1) { 285 which = ".sharepoint"; 286 allow_readonly = NBSP_READONLY_OK; 287 } 288 else { 289 which = ".clients"; 290 allow_readonly = NBSP_NO_READONLY; 291 } 292 list = NBSPList_init(which, allow_readonly); 293 294 if (list != NULL) { 295 NBSPList_print(list); 296 NBSPList_free(&list); 297 } 298 299 exit(0); 300} 301 302#endif /* TEST_NBSP */ 303