1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/boot/common/rel_open.c,v 1.2 2008/09/04 17:30:52 swildner Exp $ 35 */ 36 37 #include <stand.h> 38 #include <string.h> 39 40 #include "bootstrap.h" 41 42 char *DirBase; 43 44 COMMAND_SET(cd, "cd", "Change directory", command_chdir); 45 46 static int 47 command_chdir(int ac, char **av) 48 { 49 int result; 50 51 if (ac == 1) { 52 result = chdir(getenv("base")); 53 } else if (ac == 2) { 54 result = chdir(av[1]); 55 } else { 56 sprintf(command_errbuf, "usage: cd [<directory>]"); 57 result = CMD_ERROR; 58 } 59 return result; 60 } 61 62 COMMAND_SET(optcd, "optcd", 63 "Change directory; ignore exit status", command_optchdir); 64 65 static int 66 command_optchdir(int ac, char **av) 67 { 68 if (ac == 1) { 69 chdir(getenv("base")); 70 } else if (ac == 2) { 71 chdir(av[1]); 72 } else { 73 sprintf(command_errbuf, "usage: optcd [<directory>]"); 74 } 75 return(CMD_OK); 76 } 77 78 int 79 chdir(const char *path) 80 { 81 struct stat st; 82 char *base; 83 char *p; 84 char *b; 85 char *s; 86 char *w; 87 int len; 88 int dlen; 89 int res; 90 91 if (DirBase == NULL) 92 DirBase = strdup("/"); 93 94 len = strlen(path); 95 if (path[0] == '/') { 96 base = malloc(len + 2); /* room for trailing / */ 97 bcopy(path, base, len + 1); 98 } else { 99 while (len && path[len-1] == '/') 100 --len; 101 dlen = strlen(DirBase); 102 base = malloc(dlen + len + 2); /* room for trailing / */ 103 bcopy(DirBase, base, dlen); 104 bcopy(path, base + dlen, len); 105 base[dlen + len] = 0; 106 } 107 108 if (stat(base, &st) == 0 && S_ISDIR(st.st_mode)) { 109 p = b = w = s = base; 110 while (*s) { 111 if (*s == '/') { 112 if (s - b == 2 && b[0] == '.' && b[1] == '.') { 113 w = p; 114 } else { 115 p = b; 116 b = s + 1; 117 } 118 while (s[1] == '/') 119 ++s; 120 } 121 *w = *s; 122 ++w; 123 ++s; 124 } 125 if (s - b == 2 && b[0] == '.' && b[1] == '.') 126 w = p; 127 while (w > base && w[-1] == '/') 128 --w; 129 *w++ = '/'; 130 *w = 0; 131 132 if (DirBase) 133 free(DirBase); 134 DirBase = base; 135 res = CMD_OK; 136 } else { 137 free(base); 138 sprintf(command_errbuf, "Unable to find directory"); 139 res = CMD_ERROR; 140 } 141 return (res); 142 } 143 144 COMMAND_SET(pwd, "pwd", "Get current directory", command_pwd); 145 146 static int 147 command_pwd(int ac, char **av) 148 { 149 printf("%s\n", DirBase ? DirBase : "/"); 150 return(0); 151 } 152 153 int 154 rel_open(const char *path, char **abspathp, int flags) 155 { 156 int fd; 157 char *ptr; 158 159 if (DirBase == NULL) 160 DirBase = strdup("/"); 161 162 if (path[0] != '/') { 163 ptr = malloc(strlen(DirBase) + strlen(path) + 1); 164 sprintf(ptr, "%s%s", DirBase, path); 165 fd = open(ptr, flags); 166 if (abspathp && fd >= 0) { 167 *abspathp = ptr; 168 } else if (abspathp) { 169 *abspathp = NULL; 170 free(ptr); 171 } else { 172 free(ptr); 173 } 174 } else { 175 fd = open(path, flags); 176 if (abspathp && fd >= 0) { 177 *abspathp = strdup(path); 178 } else if (abspathp) { 179 *abspathp = NULL; 180 } 181 } 182 return(fd); 183 } 184 185 int 186 rel_stat(const char *path, struct stat *st) 187 { 188 char *ptr; 189 int res; 190 191 if (DirBase == NULL) 192 DirBase = strdup("/"); 193 194 if (path[0] != '/') { 195 ptr = malloc(strlen(DirBase) + strlen(path) + 1); 196 sprintf(ptr, "%s%s", DirBase, path); 197 res = stat(ptr, st); 198 free(ptr); 199 } else { 200 res = stat(path, st); 201 } 202 return(res); 203 } 204 205 /* 206 * Return the root path of (path) with the "/boot" prefix prepended if 207 * not present. This is required by the kernel after bootstrap, e.g., 208 * kldstat(), preload_delete_name(). 209 */ 210 char * 211 rel_rootpath(const char *path) 212 { 213 char *rootpath; 214 215 if (DirBase == NULL) 216 DirBase = strdup("/"); 217 218 if (strncmp(path, "/boot/", sizeof("/boot/")-1) == 0) { 219 rootpath = strdup(path); 220 } else if (path[0] == '/') { 221 rootpath = malloc(strlen(path) + sizeof("/boot")); 222 sprintf(rootpath, "/boot%s", path); 223 } else { 224 rootpath = malloc(strlen(DirBase) + strlen(path) + 225 sizeof("/boot")); 226 sprintf(rootpath, "/boot%s%s", DirBase, path); 227 } 228 229 return (rootpath); 230 } 231