xref: /dragonfly/stand/boot/common/rel_open.c (revision 22cd51fe)
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