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 arguments provided in the imagepath and fill it in result.
66 * Returns 1 on success, 0 on failure.
69 extract_args_from_netdev_path(char *imagepath, struct boot_fspec_t *result)
71 char *tmp, *args, *str, *start;
73 DEBUG_F("imagepath = %s\n", imagepath);
78 args = strrchr(imagepath, ':');
82 start = args; /* used to see if we read any optional parameters */
84 /* The obp-tftp device arguments should be at the end of
85 * the argument list. Skip over any extra arguments (promiscuous,
86 * speed, duplex, bootp, rarp).
89 tmp = strstr(args, "promiscuous");
90 if (tmp && tmp > args)
91 args = tmp + strlen("promiscuous");
93 tmp = strstr(args, "speed=");
94 if (tmp && tmp > args)
95 args = tmp + strlen("speed=");
97 tmp = strstr(args, "duplex=");
98 if (tmp && tmp > args)
99 args = tmp + strlen("duplex=");
101 tmp = strstr(args, "bootp");
102 if (tmp && tmp > args)
103 args = tmp + strlen("bootp");
105 tmp = strstr(args, "rarp");
106 if (tmp && tmp > args)
107 args = tmp + strlen("rarp");
109 if (args != start) /* we read some parameters, so go past the next comma(,) */
110 args = strchr(args, ',');
114 str = malloc(strlen(args) + 1); /*long enough to hold all strings */
119 args++; /* If comma(,) is not immediately followed by ':' then go past the , */
122 * read the arguments in order: siaddr,filename,ciaddr,giaddr,
123 * bootp-retries,tftp-retries,addl_prameters
125 result->siaddr = scopy(&str, &args);
126 result->file = scopy(&str, &args);
127 result->ciaddr = scopy(&str, &args);
128 result->giaddr = scopy(&str, &args);
129 result->bootp_retries = scopy(&str, &args);
130 result->tftp_retries = scopy(&str, &args);
132 result->addl_params = strdup(args);
133 if (!result->addl_params)
137 DEBUG_F("siaddr = <%s>\n", result->siaddr);
138 DEBUG_F("file = <%s>\n", result->file);
139 DEBUG_F("ciaddr = <%s>\n", result->ciaddr);
140 DEBUG_F("giaddr = <%s>\n", result->giaddr);
141 DEBUG_F("bootp_retries = <%s>\n", result->bootp_retries);
142 DEBUG_F("tftp_retries = <%s>\n", result->tftp_retries);
143 DEBUG_F("addl_params = <%s>\n", result->addl_params);
147 static char *netdev_path_to_dev(const char *path)
152 DEBUG_F("path = %s\n", path);
157 tmp = strchr(path, ':');
162 len = tmp - path + 1;
166 strncpy(dev, path, len);
172 /* This function follows the device path in the devtree and separates
173 the device name, partition number, and other datas (mostly file name)
174 the string passed in parameters is changed since 0 are put in place
175 of some separators to terminate the various strings.
177 when a default device is supplied imagepath will be assumed to be a
178 plain filename unless it contains a : otherwise if defaultdev is
179 NULL imagepath will be assumed to be a device path.
181 returns 1 on success 0 on failure.
184 - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4
185 - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4,/boot/vmlinux
187 - enet:10.0.0.1,/tftpboot/vmlinux
188 - enet:,/tftpboot/vmlinux
191 - arguments for obp-tftp open as specified in section 4.1 of
192 http://playground.sun.com/1275/practice/obp-tftp/tftp1_0.pdf
193 [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries
194 ex: enet:bootp,10.0.0.11,bootme,10.0.0.12,10.0.0.1,5,5
195 Supported only if defdevice == NULL
197 - any other device path lacking a :
198 Unsupported examples:
199 - hd:2,\\:tbxi <- no filename will be detected due to the extra :
200 - enet:192.168.2.1,bootme,c-iaddr,g-iaddr,subnet-mask,bootp-retries,tftp-retries */
203 parse_device_path(char *imagepath, char *defdevice, int defpart,
204 char *deffile, struct boot_fspec_t *result)
209 int device_kind = -1;
211 DEBUG_F("imagepath = %s; defdevice %s; defpart %d, deffile %s\n",
212 imagepath, defdevice, defpart, deffile);
222 * Do preliminary checking for an iscsi device; it may appear as
223 * pure a network device (device_type == "network") if this is
224 * ISWI. This is the case on IBM systems doing an iscsi OFW
227 if (strstr(imagepath, TOK_ISCSI)) {
229 * get the virtual device information from the
230 * "nas-bootdevice" property.
232 if (prom_get_chosen("nas-bootdevice", bootdevice, BOOTDEVSZ)) {
233 DEBUG_F("reset boot-device to"
234 " /chosen/nas-bootdevice = %s\n", bootdevice);
235 device_kind = FILE_DEVICE_ISCSI;
236 ipath = strdup(bootdevice);
243 else if (!(ipath = strdup(imagepath)))
247 defdev = strdup(defdevice);
248 device_kind = prom_get_devtype(defdev);
249 } else if (device_kind == -1)
250 device_kind = prom_get_devtype(ipath);
253 * When an iscsi iqn is present, it may have embedded colons, so
254 * don't parse off anything.
256 if (device_kind != FILE_DEVICE_NET &&
257 device_kind != FILE_DEVICE_ISCSI &&
258 strchr(defdev, ':') != NULL) {
259 if ((ptr = strrchr(defdev, ':')) != NULL)
260 *ptr = 0; /* remove trailing : from defdevice if necessary */
263 /* This will not properly handle an obp-tftp argument list
264 * with elements after the filename; that is handled below.
266 if (device_kind != FILE_DEVICE_NET &&
267 device_kind != FILE_DEVICE_ISCSI &&
268 strchr(ipath, ':') != NULL) {
269 if ((ptr = strrchr(ipath, ',')) != NULL) {
270 char *colon = strrchr(ipath, ':');
271 /* If a ':' occurs *after* a ',', then we assume that there is
273 if (!colon || colon < ptr) {
274 result->file = strdup(ptr+1);
275 /* Trim the filename off */
281 if (device_kind == FILE_DEVICE_NET) {
282 if (strchr(ipath, ':')) {
283 if (extract_args_from_netdev_path(ipath, result) == 0)
286 result->file = strdup(ipath);
289 result->dev = netdev_path_to_dev(ipath);
290 } else if (device_kind != FILE_DEVICE_ISCSI &&
291 (ptr = strrchr(ipath, ':')) != NULL) {
293 result->dev = strdup(ipath);
295 result->part = simple_strtol(ptr+1, NULL, 10);
296 } else if (!defdev) {
297 result->dev = strdup(ipath);
298 } else if (strlen(ipath)) {
299 result->file = strdup(ipath);
305 if (!result->dev && defdev)
306 result->dev = strdup(defdev);
308 if (result->part < 0)
309 result->part = defpart;
312 result->file = strdup(deffile);
322 file_block_open( struct boot_file_t* file,
323 struct boot_fspec_t* fspec,
326 struct partition_t* parts;
327 struct partition_t* p;
328 struct partition_t* found;
330 parts = partitions_lookup(fspec->dev);
335 prom_printf("partitions:\n");
337 prom_printf("no partitions found.\n");
339 for (p = parts; p && !found; p=p->next) {
340 DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
341 p->part_number, p->part_start, p->part_size );
342 if (partition == -1) {
343 file->fs = fs_open( file, p, fspec );
344 if (file->fs == NULL || fserrorno != FILE_ERR_OK)
347 partition = p->part_number;
351 if ((partition >= 0) && (partition == p->part_number))
355 prom_printf(" (match)\n");
359 /* Note: we don't skip when found is NULL since we can, in some
360 * cases, let OF figure out a default partition.
362 DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
363 file->fs = fs_open( file, found, fspec );
367 partitions_free(parts);
373 file_net_open(struct boot_file_t* file, struct boot_fspec_t *fspec)
375 file->fs = fs_of_netboot;
376 return fs_of_netboot->open(file, NULL, fspec);
380 default_read( struct boot_file_t* file,
384 prom_printf("WARNING ! default_read called !\n");
389 default_seek( struct boot_file_t* file,
392 prom_printf("WARNING ! default_seek called !\n");
397 default_close( struct boot_file_t* file)
399 prom_printf("WARNING ! default_close called !\n");
403 static struct fs_t fs_default =
413 int open_file(struct boot_fspec_t* spec, struct boot_file_t* file)
417 memset(file, 0, sizeof(struct boot_file_t*));
418 file->fs = &fs_default;
420 DEBUG_F("dev_path = %s\nfile_name = %s\npartition = %d\n",
421 spec->dev, spec->file, spec->part);
423 result = prom_get_devtype(spec->dev);
425 file->device_kind = result;
429 switch(file->device_kind) {
430 case FILE_DEVICE_BLOCK:
431 DEBUG_F("device is a block device\n");
432 return file_block_open(file, spec, spec->part);
433 case FILE_DEVICE_NET:
434 DEBUG_F("device is a network device\n");
435 return file_net_open(file, spec);
442 * c-file-style: "k&r"