728999c313f67bc546389f4eb3cbb151bfae94ec
[dragonfly.git] / sys / boot / common / rel_open.c
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 #include "bootstrap.h"
40
41 char *DirBase;
42
43 COMMAND_SET(cd, "cd", "Change directory", command_chdir);
44 COMMAND_SET(optcd, "optcd", "Change directory", command_optchdir);
45
46 int
47 command_chdir(int ac, char **av)
48 {
49         if (ac != 2) {
50                 sprintf(command_errbuf, "Missing path");
51                 return(CMD_ERROR);
52         }
53         return(chdir(av[1]));
54 }
55
56 int
57 command_optchdir(int ac, char **av)
58 {
59         if (ac == 2)
60                 chdir(av[1]);
61         return(CMD_OK);
62 }
63
64 int
65 chdir(const char *path)
66 {
67         struct stat st;
68         char *base;
69         char *p;
70         char *b;
71         char *s;
72         char *w;
73         int len;
74         int dlen;
75         int res;
76
77         if (DirBase == NULL)
78                 DirBase = strdup("/");
79
80         len = strlen(path);
81         if (path[0] == '/') {
82                 base = malloc(len + 2);         /* room for trailing / */
83                 bcopy(path, base, len + 1);
84         } else {
85                 while (len && path[len-1] == '/')
86                         --len;
87                 dlen = strlen(DirBase);
88                 base = malloc(dlen + len + 2);  /* room for trailing / */
89                 bcopy(DirBase, base, dlen);
90                 bcopy(path, base + dlen, len);
91                 base[dlen + len] = 0;
92         }
93
94         if (stat(base, &st) == 0 && S_ISDIR(st.st_mode)) {
95                 p = b = w = s = base;
96                 while (*s) {
97                         if (*s == '/') {
98                                 if (s - b == 2 && b[0] == '.' && b[1] == '.') {
99                                         w = p;
100                                 } else {
101                                         p = b;
102                                         b = s + 1;
103                                 }
104                                 while (s[1] == '/')
105                                         ++s;
106                         }
107                         *w = *s;
108                         ++w;
109                         ++s;
110                 }
111                 if (s - b == 2 && b[0] == '.' && b[1] == '.')
112                         w = p;
113                 while (w > base && w[-1] == '/')
114                         --w;
115                 *w++ = '/';
116                 *w = 0;
117
118                 if (DirBase)
119                         free(DirBase);
120                 DirBase = base;
121                 res = CMD_OK;
122         } else {
123                 free(base);
124                 sprintf(command_errbuf, "Unable to find directory");
125                 res = CMD_ERROR;
126         }
127         return (res);
128 }
129
130 COMMAND_SET(pwd, "pwd", "Get current directory", command_pwd);
131
132 int
133 command_pwd(int ac, char **av)
134 {
135         printf("%s\n", DirBase ? DirBase : "/");
136         return(0);
137 }
138
139 int
140 rel_open(const char *path, char **abspathp, int flags)
141 {
142         int fd;
143         char *ptr;
144
145         if (DirBase == NULL)
146                 DirBase = strdup("/");
147
148         if (path[0] != '/') {
149                 ptr = malloc(strlen(DirBase) + strlen(path) + 1);
150                 sprintf(ptr, "%s%s", DirBase, path);
151                 fd = open(ptr, flags);
152                 if (abspathp && fd >= 0)
153                         *abspathp = ptr;
154                 else if (abspathp)
155                         *abspathp = NULL;
156                 else
157                         free(ptr);
158         } else {
159                 fd = open(path, flags);
160                 if (abspathp && fd >= 0)
161                         *abspathp = strdup(path);
162                 else if (abspathp)
163                         *abspathp = NULL;
164         }
165         return(fd);
166 }
167
168 int
169 rel_stat(const char *path, struct stat *st)
170 {
171         char *ptr;
172         int res;
173
174         if (DirBase == NULL)
175                 DirBase = strdup("/");
176
177         if (path[0] != '/') {
178                 ptr = malloc(strlen(DirBase) + strlen(path) + 1);
179                 sprintf(ptr, "%s%s", DirBase, path);
180                 res = stat(ptr, st);
181                 free(ptr);
182         } else {
183                 res = stat(path, st);
184         }
185         return(res);
186 }
187