2 * file.c - Filesystem related interfaces
4 * Copyright (C) 2001, 2002 Ethan Benson
8 * Copyright (C) 2001 Colin Walters
10 * Copyright (C) 1999 Benjamin Herrenschmidt
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include "partition.h"
39 extern char bootdevice[];
41 static char *netdev_path_to_filename(const char *path)
43 char *tmp, *args, *filename;
46 DEBUG_F("path = %s\n", path);
51 args = strrchr(path, ':');
55 /* The obp-tftp device arguments should be at the end of
56 * the argument list. Skip over any extra arguments (promiscuous,
57 * speed, duplex, bootp, rarp).
60 tmp = strstr(args, "promiscuous");
61 if (tmp && tmp > args)
62 args = tmp + strlen("promiscuous");
64 tmp = strstr(args, "speed=");
65 if (tmp && tmp > args)
66 args = tmp + strlen("speed=");
68 tmp = strstr(args, "duplex=");
69 if (tmp && tmp > args)
70 args = tmp + strlen("duplex=");
72 tmp = strstr(args, "bootp");
73 if (tmp && tmp > args)
74 args = tmp + strlen("bootp");
76 tmp = strstr(args, "rarp");
77 if (tmp && tmp > args)
78 args = tmp + strlen("rarp");
80 args = strchr(args, ',');
86 /* If the preceding character is ':' then there were no
87 * non-obp-tftp arguments and we know we're right up to the
88 * filename. Otherwise, we must advance args once more.
92 args = strchr(args, ',');
98 /* filename may be empty; e.g. enet:192.168.1.1,,192.168.1.2 */
100 DEBUG_F("null filename\n");
104 /* Now see whether there are more args following the filename. */
105 tmp = strchr(args, ',');
107 len = strlen(args) + 1;
109 len = tmp - args + 1;
111 filename = malloc(len);
115 strncpy(filename, args, len);
116 filename[len - 1] = '\0';
118 DEBUG_F("filename = %s\n", filename);
122 static char *netdev_path_to_dev(const char *path)
127 DEBUG_F("path = %s\n", path);
132 tmp = strchr(path, ':');
137 len = tmp - path + 1;
141 strncpy(dev, path, len);
147 /* This function follows the device path in the devtree and separates
148 the device name, partition number, and other datas (mostly file name)
149 the string passed in parameters is changed since 0 are put in place
150 of some separators to terminate the various strings.
152 when a default device is supplied imagepath will be assumed to be a
153 plain filename unless it contains a : otherwise if defaultdev is
154 NULL imagepath will be assumed to be a device path.
156 returns 1 on success 0 on failure.
159 - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4
160 - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4,/boot/vmlinux
162 - enet:10.0.0.1,/tftpboot/vmlinux
163 - enet:,/tftpboot/vmlinux
166 Supported only if defdevice == NULL
168 - any other device path lacking a :
169 Unsupported examples:
170 - hd:2,\\:tbxi <- no filename will be detected due to the extra :
171 - enet:192.168.2.1,bootme,c-iaddr,g-iaddr,subnet-mask,bootp-retries,tftp-retries */
174 parse_device_path(char *imagepath, char *defdevice, int defpart,
175 char *deffile, struct boot_fspec_t *result)
180 int device_kind = -1;
190 * Do preliminary checking for an iscsi device; it may appear as
191 * pure a network device (device_type == "network") if this is
192 * ISWI. This is the case on IBM systems doing an iscsi OFW
195 if (strstr(imagepath, TOK_ISCSI)) {
197 * get the virtual device information from the
198 * "nas-bootdevice" property.
200 if (prom_get_chosen("nas-bootdevice", bootdevice, BOOTDEVSZ)) {
201 DEBUG_F("reset boot-device to"
202 " /chosen/nas-bootdevice = %s\n", bootdevice);
203 device_kind = FILE_DEVICE_ISCSI;
204 ipath = strdup(bootdevice);
211 else if (!(ipath = strdup(imagepath)))
215 defdev = strdup(defdevice);
216 device_kind = prom_get_devtype(defdev);
217 } else if (device_kind == -1)
218 device_kind = prom_get_devtype(ipath);
221 * When an iscsi iqn is present, it may have embedded colons, so
222 * don't parse off anything.
224 if (device_kind != FILE_DEVICE_NET &&
225 device_kind != FILE_DEVICE_ISCSI &&
226 strchr(defdev, ':') != NULL) {
227 if ((ptr = strrchr(defdev, ':')) != NULL)
228 *ptr = 0; /* remove trailing : from defdevice if necessary */
231 /* This will not properly handle an obp-tftp argument list
232 * with elements after the filename; that is handled below.
234 if (device_kind != FILE_DEVICE_NET &&
235 device_kind != FILE_DEVICE_ISCSI &&
236 strchr(ipath, ':') != NULL) {
237 if ((ptr = strrchr(ipath, ',')) != NULL) {
238 char *colon = strrchr(ipath, ':');
239 /* If a ':' occurs *after* a ',', then we assume that there is
241 if (!colon || colon < ptr) {
242 result->file = strdup(ptr+1);
243 /* Trim the filename off */
249 if (device_kind == FILE_DEVICE_NET) {
250 if (strchr(ipath, ':'))
251 result->file = netdev_path_to_filename(ipath);
253 result->file = strdup(ipath);
256 result->dev = netdev_path_to_dev(ipath);
257 } else if (device_kind != FILE_DEVICE_ISCSI &&
258 (ptr = strrchr(ipath, ':')) != NULL) {
260 result->dev = strdup(ipath);
262 result->part = simple_strtol(ptr+1, NULL, 10);
263 } else if (!defdev) {
264 result->dev = strdup(ipath);
265 } else if (strlen(ipath)) {
266 result->file = strdup(ipath);
272 if (!result->dev && defdev)
273 result->dev = strdup(defdev);
275 if (result->part < 0)
276 result->part = defpart;
279 result->file = strdup(deffile);
289 file_block_open( struct boot_file_t* file,
290 struct boot_fspec_t* fspec,
293 struct partition_t* parts;
294 struct partition_t* p;
295 struct partition_t* found;
297 parts = partitions_lookup(fspec->dev);
302 prom_printf("partitions:\n");
304 prom_printf("no partitions found.\n");
306 for (p = parts; p && !found; p=p->next) {
307 DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
308 p->part_number, p->part_start, p->part_size );
309 if (partition == -1) {
310 file->fs = fs_open( file, p, fspec );
311 if (file->fs == NULL || fserrorno != FILE_ERR_OK)
314 partition = p->part_number;
318 if ((partition >= 0) && (partition == p->part_number))
322 prom_printf(" (match)\n");
326 /* Note: we don't skip when found is NULL since we can, in some
327 * cases, let OF figure out a default partition.
329 DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
330 file->fs = fs_open( file, found, fspec );
334 partitions_free(parts);
340 file_net_open(struct boot_file_t* file, struct boot_fspec_t *fspec)
342 file->fs = fs_of_netboot;
343 return fs_of_netboot->open(file, NULL, fspec);
347 default_read( struct boot_file_t* file,
351 prom_printf("WARNING ! default_read called !\n");
356 default_seek( struct boot_file_t* file,
359 prom_printf("WARNING ! default_seek called !\n");
364 default_close( struct boot_file_t* file)
366 prom_printf("WARNING ! default_close called !\n");
370 static struct fs_t fs_default =
380 int open_file(struct boot_fspec_t* spec, struct boot_file_t* file)
384 memset(file, 0, sizeof(struct boot_file_t*));
385 file->fs = &fs_default;
387 DEBUG_F("dev_path = %s\nfile_name = %s\npartition = %d\n",
388 spec->dev, spec->file, spec->part);
390 result = prom_get_devtype(spec->dev);
392 file->device_kind = result;
396 switch(file->device_kind) {
397 case FILE_DEVICE_BLOCK:
398 DEBUG_F("device is a block device\n");
399 return file_block_open(file, spec, spec->part);
400 case FILE_DEVICE_NET:
401 DEBUG_F("device is a network device\n");
402 return file_net_open(file, spec);
409 * c-file-style: "k&r"