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[];
42 * Copy the string from source to dest till newline or comma(,) is seen
44 * Move source and dest pointers respectively.
45 * Returns pointer to the start of the string that has just been copied.
48 scopy(char **dest, char **source)
55 while (**source != ',' && **source != '\0')
56 *(*dest)++ = *(*source)++;
65 * Extract all the ipv4 arguments from the bootpath provided and fill result
66 * Returns 1 on success, 0 on failure.
69 extract_ipv4_args(char *imagepath, struct boot_fspec_t *result)
71 char *tmp, *args, *str, *start;
73 args = strrchr(imagepath, ':');
77 start = args; /* used to see if we read any optional parameters */
79 /* The obp-tftp device arguments should be at the end of
80 * the argument list. Skip over any extra arguments (promiscuous,
81 * speed, duplex, bootp, rarp).
84 tmp = strstr(args, "promiscuous");
85 if (tmp && tmp > args)
86 args = tmp + strlen("promiscuous");
88 tmp = strstr(args, "speed=");
89 if (tmp && tmp > args)
90 args = tmp + strlen("speed=");
92 tmp = strstr(args, "duplex=");
93 if (tmp && tmp > args)
94 args = tmp + strlen("duplex=");
96 tmp = strstr(args, "bootp");
97 if (tmp && tmp > args)
98 args = tmp + strlen("bootp");
100 tmp = strstr(args, "rarp");
101 if (tmp && tmp > args)
102 args = tmp + strlen("rarp");
104 if (args != start) /* we read some parameters, so go past the next comma(,) */
105 args = strchr(args, ',');
109 str = malloc(strlen(args) + 1); /*long enough to hold all strings */
114 args++; /* If comma(,) is not immediately followed by ':' then go past the , */
117 * read the arguments in order: siaddr,filename,ciaddr,giaddr,
118 * bootp-retries,tftp-retries,addl_prameters
120 result->siaddr = scopy(&str, &args);
121 result->file = scopy(&str, &args);
122 result->ciaddr = scopy(&str, &args);
123 result->giaddr = scopy(&str, &args);
124 result->bootp_retries = scopy(&str, &args);
125 result->tftp_retries = scopy(&str, &args);
127 result->addl_params = strdup(args);
128 if (!result->addl_params)
135 * Extract all the arguments provided in the imagepath and fill it in result.
136 * Returns 1 on success, 0 on failure.
139 extract_args_from_netdev_path(char *imagepath, struct boot_fspec_t *result)
143 DEBUG_F("imagepath = %s\n", imagepath);
148 ret = extract_ipv4_args(imagepath, result);
150 DEBUG_F("siaddr = <%s>\n", result->siaddr);
151 DEBUG_F("file = <%s>\n", result->file);
152 DEBUG_F("ciaddr = <%s>\n", result->ciaddr);
153 DEBUG_F("giaddr = <%s>\n", result->giaddr);
154 DEBUG_F("bootp_retries = <%s>\n", result->bootp_retries);
155 DEBUG_F("tftp_retries = <%s>\n", result->tftp_retries);
156 DEBUG_F("addl_params = <%s>\n", result->addl_params);
160 static char *netdev_path_to_dev(const char *path)
165 DEBUG_F("path = %s\n", path);
170 tmp = strchr(path, ':');
175 len = tmp - path + 1;
179 strncpy(dev, path, len);
185 /* This function follows the device path in the devtree and separates
186 the device name, partition number, and other datas (mostly file name)
187 the string passed in parameters is changed since 0 are put in place
188 of some separators to terminate the various strings.
190 when a default device is supplied imagepath will be assumed to be a
191 plain filename unless it contains a : otherwise if defaultdev is
192 NULL imagepath will be assumed to be a device path.
194 returns 1 on success 0 on failure.
197 - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4
198 - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4,/boot/vmlinux
200 - enet:10.0.0.1,/tftpboot/vmlinux
201 - enet:,/tftpboot/vmlinux
204 - arguments for obp-tftp open as specified in section 4.1 of
205 http://playground.sun.com/1275/practice/obp-tftp/tftp1_0.pdf
206 [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries
207 ex: enet:bootp,10.0.0.11,bootme,10.0.0.12,10.0.0.1,5,5
208 Supported only if defdevice == NULL
210 - any other device path lacking a :
211 Unsupported examples:
212 - hd:2,\\:tbxi <- no filename will be detected due to the extra :
213 - enet:192.168.2.1,bootme,c-iaddr,g-iaddr,subnet-mask,bootp-retries,tftp-retries */
216 parse_device_path(char *imagepath, char *defdevice, int defpart,
217 char *deffile, struct boot_fspec_t *result)
222 int device_kind = -1;
224 DEBUG_F("imagepath = %s; defdevice %s; defpart %d, deffile %s\n",
225 imagepath, defdevice, defpart, deffile);
235 * Do preliminary checking for an iscsi device; it may appear as
236 * pure a network device (device_type == "network") if this is
237 * ISWI. This is the case on IBM systems doing an iscsi OFW
240 if (strstr(imagepath, TOK_ISCSI)) {
242 * get the virtual device information from the
243 * "nas-bootdevice" property.
245 if (prom_get_chosen("nas-bootdevice", bootdevice, BOOTDEVSZ)) {
246 DEBUG_F("reset boot-device to"
247 " /chosen/nas-bootdevice = %s\n", bootdevice);
248 device_kind = FILE_DEVICE_ISCSI;
249 ipath = strdup(bootdevice);
256 else if (!(ipath = strdup(imagepath)))
260 defdev = strdup(defdevice);
261 device_kind = prom_get_devtype(defdev);
262 } else if (device_kind == -1)
263 device_kind = prom_get_devtype(ipath);
266 * When an iscsi iqn is present, it may have embedded colons, so
267 * don't parse off anything.
269 if (device_kind != FILE_DEVICE_NET &&
270 device_kind != FILE_DEVICE_ISCSI &&
271 strchr(defdev, ':') != NULL) {
272 if ((ptr = strrchr(defdev, ':')) != NULL)
273 *ptr = 0; /* remove trailing : from defdevice if necessary */
276 /* This will not properly handle an obp-tftp argument list
277 * with elements after the filename; that is handled below.
279 if (device_kind != FILE_DEVICE_NET &&
280 device_kind != FILE_DEVICE_ISCSI &&
281 strchr(ipath, ':') != NULL) {
282 if ((ptr = strrchr(ipath, ',')) != NULL) {
283 char *colon = strrchr(ipath, ':');
284 /* If a ':' occurs *after* a ',', then we assume that there is
286 if (!colon || colon < ptr) {
287 result->file = strdup(ptr+1);
288 /* Trim the filename off */
294 if (device_kind == FILE_DEVICE_NET) {
295 if (strchr(ipath, ':')) {
296 if (extract_args_from_netdev_path(ipath, result) == 0)
299 result->file = strdup(ipath);
302 result->dev = netdev_path_to_dev(ipath);
303 } else if (device_kind != FILE_DEVICE_ISCSI &&
304 (ptr = strrchr(ipath, ':')) != NULL) {
306 result->dev = strdup(ipath);
308 result->part = simple_strtol(ptr+1, NULL, 10);
309 } else if (!defdev) {
310 result->dev = strdup(ipath);
311 } else if (strlen(ipath)) {
312 result->file = strdup(ipath);
318 if (!result->dev && defdev)
319 result->dev = strdup(defdev);
321 if (result->part < 0)
322 result->part = defpart;
325 result->file = strdup(deffile);
335 file_block_open( struct boot_file_t* file,
336 struct boot_fspec_t* fspec,
339 struct partition_t* parts;
340 struct partition_t* p;
341 struct partition_t* found;
343 parts = partitions_lookup(fspec->dev);
348 prom_printf("partitions:\n");
350 prom_printf("no partitions found.\n");
352 for (p = parts; p && !found; p=p->next) {
353 DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
354 p->part_number, p->part_start, p->part_size );
355 if (partition == -1) {
356 file->fs = fs_open( file, p, fspec );
357 if (file->fs == NULL || fserrorno != FILE_ERR_OK)
360 partition = p->part_number;
364 if ((partition >= 0) && (partition == p->part_number))
368 prom_printf(" (match)\n");
372 /* Note: we don't skip when found is NULL since we can, in some
373 * cases, let OF figure out a default partition.
375 DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
376 file->fs = fs_open( file, found, fspec );
380 partitions_free(parts);
386 file_net_open(struct boot_file_t* file, struct boot_fspec_t *fspec)
388 file->fs = fs_of_netboot;
389 return fs_of_netboot->open(file, NULL, fspec);
393 default_read( struct boot_file_t* file,
397 prom_printf("WARNING ! default_read called !\n");
402 default_seek( struct boot_file_t* file,
405 prom_printf("WARNING ! default_seek called !\n");
410 default_close( struct boot_file_t* file)
412 prom_printf("WARNING ! default_close called !\n");
416 static struct fs_t fs_default =
426 int open_file(struct boot_fspec_t* spec, struct boot_file_t* file)
430 memset(file, 0, sizeof(struct boot_file_t*));
431 file->fs = &fs_default;
433 DEBUG_F("dev_path = %s\nfile_name = %s\npartition = %d\n",
434 spec->dev, spec->file, spec->part);
436 result = prom_get_devtype(spec->dev);
438 file->device_kind = result;
442 switch(file->device_kind) {
443 case FILE_DEVICE_BLOCK:
444 DEBUG_F("device is a block device\n");
445 return file_block_open(file, spec, spec->part);
446 case FILE_DEVICE_NET:
447 DEBUG_F("device is a network device\n");
448 return file_net_open(file, spec);
455 * c-file-style: "k&r"