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 const char* dev_name,
291 const char* file_name,
294 struct partition_t* parts;
295 struct partition_t* p;
296 struct partition_t* found;
298 parts = partitions_lookup(dev_name);
303 prom_printf("partitions:\n");
305 prom_printf("no partitions found.\n");
307 for (p = parts; p && !found; p=p->next) {
308 DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
309 p->part_number, p->part_start, p->part_size );
310 if (partition == -1) {
311 file->fs = fs_open( file, dev_name, p, file_name );
312 if (file->fs == NULL || fserrorno != FILE_ERR_OK)
315 partition = p->part_number;
319 if ((partition >= 0) && (partition == p->part_number))
323 prom_printf(" (match)\n");
327 /* Note: we don't skip when found is NULL since we can, in some
328 * cases, let OF figure out a default partition.
330 DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
331 file->fs = fs_open( file, dev_name, found, file_name );
335 partitions_free(parts);
341 file_net_open( struct boot_file_t* file,
342 const char* dev_name,
343 const char* file_name)
345 file->fs = fs_of_netboot;
346 return fs_of_netboot->open(file, dev_name, NULL, file_name);
350 default_read( struct boot_file_t* file,
354 prom_printf("WARNING ! default_read called !\n");
359 default_seek( struct boot_file_t* file,
362 prom_printf("WARNING ! default_seek called !\n");
367 default_close( struct boot_file_t* file)
369 prom_printf("WARNING ! default_close called !\n");
373 static struct fs_t fs_default =
383 int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file)
387 memset(file, 0, sizeof(struct boot_file_t*));
388 file->fs = &fs_default;
390 DEBUG_F("dev_path = %s\nfile_name = %s\npartition = %d\n",
391 spec->dev, spec->file, spec->part);
393 result = prom_get_devtype(spec->dev);
395 file->device_kind = result;
399 switch(file->device_kind) {
400 case FILE_DEVICE_BLOCK:
401 DEBUG_F("device is a block device\n");
402 return file_block_open(file, spec->dev, spec->file, spec->part);
403 case FILE_DEVICE_NET:
404 DEBUG_F("device is a network device\n");
405 return file_net_open(file, spec->dev, spec->file);
412 * c-file-style: "k&r"