Commit yaboot 1.3.6-pre1
[yaboot.git] / second / file.c
1 /* File related stuff
2    
3    Copyright (C) 1999 Benjamin Herrenschmidt
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
18
19 #include "ctype.h"
20 #include "types.h"
21 #include "stddef.h"
22 #include "stdlib.h"
23 #include "file.h"
24 #include "prom.h"
25 #include "string.h"
26 #include "partition.h"
27 #include "fs.h"
28 #include "errors.h"
29 #include "debug.h"
30
31 extern char bootdevice[1024];
32
33 /* This function follows the device path in the devtree and separates
34    the device name, partition number, and other datas (mostly file name)
35    the string passed in parameters is changed since 0 are put in place
36    of some separators to terminate the various strings.  
37
38    when a default device is supplied imagepath will be assumed to be a
39    plain filename unless it contains a : otherwise if defaultdev is
40    NULL imagepath will be assumed to be a device path.
41
42    returns 1 on success 0 on failure.
43
44    Supported examples:
45     - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4
46     - /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4,/boot/vmlinux
47     - hd:3,/boot/vmlinux
48     - enet:10.0.0.1,/tftpboot/vmlinux
49     - enet:,/tftpboot/vmlinux
50     - enet:bootp
51     - enet:0
52    Supported only if defdevice == NULL
53     - disc
54     - any other device path lacking a :
55    Unsupported examples:
56     - hd:2,\\:tbxi <- no filename will be detected due to the extra :
57     - enet:192.168.2.1,bootme,c-iaddr,g-iaddr,subnet-mask,bootp-retries,tftp-retries */
58
59 int
60 parse_device_path(char *imagepath, char *defdevice, int defpart,
61                   char *deffile, struct boot_fspec_t *result)
62 {
63      char *ptr;
64      char *ipath = NULL;
65      char *defdev = NULL;
66
67      result->dev = NULL;
68      result->part = -1;
69      result->file = NULL;
70
71      if (!imagepath)
72           return 0;
73      else
74           ipath = strdup(imagepath);
75
76      if (defdevice)
77           defdev = strdup(defdevice);
78
79      if (defdev) {
80           if (!strstr(defdev, "ethernet") && !strstr(defdev, "enet")) {
81                if ((ptr = strrchr(defdev, ':')) != NULL)
82                     *ptr = 0; /* remove trailing : from defdevice if necessary */
83           }
84      }
85
86      if ((ptr = strrchr(ipath, ',')) != NULL) {
87           char *colon = strrchr(ipath, ':');
88           /* If a ':' occurs *after* a ',', then we assume that there is
89              no filename */
90           if (!colon || colon < ptr) {
91                result->file = strdup(ptr+1);
92                /* Trim the filename off */
93                *ptr = 0;
94           }
95      }
96
97      if (strstr(ipath, "ethernet") || strstr(ipath, "enet"))
98           if ((ptr = strstr(ipath, "bootp")) != NULL) { /* `n' key booting boots enet:bootp */
99                *ptr = 0;
100                result->dev = strdup(ipath);
101           } else
102                result->dev = strdup(ipath);
103      else if ((ptr = strchr(ipath, ':')) != NULL) {
104           *ptr = 0;
105           result->dev = strdup(ipath);
106           if (*(ptr+1))
107                result->part = simple_strtol(ptr+1, NULL, 10);
108      } else if (!defdev) {
109           result->dev = strdup(ipath); 
110      } else if (strlen(ipath)) {
111           result->file = strdup(ipath);
112      } else {
113           return 0;
114      }
115
116      if (!result->dev && defdev)
117           result->dev = strdup(defdev);
118      
119      if (result->part < 0)
120           result->part = defpart;
121      
122      if (!result->file)
123           result->file = strdup(deffile);
124
125      free(ipath);
126      if (defdev)
127           free(defdev);
128      return 1;
129 }
130
131
132 static int
133 file_block_open(        struct boot_file_t*     file,
134                         const char*             dev_name,
135                         const char*             file_name,
136                         int                     partition)
137 {
138      struct partition_t*        parts;
139      struct partition_t*        p;
140      struct partition_t*        found;
141         
142      parts = partitions_lookup(dev_name);
143      found = NULL;
144                         
145 #if DEBUG
146      if (parts)
147           prom_printf("partitions:\n");
148      else
149           prom_printf("no partitions found.\n");
150 #endif
151      for (p = parts; p && !found; p=p->next) {
152           DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
153                   p->part_number, p->part_start, p->part_size );
154           if (partition == -1) {
155                file->fs = fs_open( file, dev_name, p, file_name );
156                if (file->fs != NULL)
157                     goto bail;
158           }
159           if ((partition >= 0) && (partition == p->part_number))
160                found = p;
161 #if DEBUG
162           if (found)
163                prom_printf(" (match)\n");
164 #endif                                          
165      }
166
167      /* Note: we don't skip when found is NULL since we can, in some
168       * cases, let OF figure out a default partition.
169       */
170      DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
171      file->fs = fs_open( file, dev_name, found, file_name );
172
173 bail:
174      if (parts)
175           partitions_free(parts);
176
177      return fserrorno;
178 }
179
180 static int
181 file_net_open(  struct boot_file_t*     file,
182                 const char*             dev_name,
183                 const char*             file_name)
184 {
185      file->fs = fs_of_netboot;
186      return fs_of_netboot->open(file, dev_name, NULL, file_name);
187 }
188
189 static int
190 default_read(   struct boot_file_t*     file,
191                 unsigned int            size,
192                 void*                   buffer)
193 {
194      prom_printf("WARNING ! default_read called !\n");
195      return FILE_ERR_EOF;
196 }
197
198 static int
199 default_seek(   struct boot_file_t*     file,
200                 unsigned int            newpos)
201 {
202      prom_printf("WARNING ! default_seek called !\n");
203      return FILE_ERR_EOF;
204 }
205
206 static int
207 default_close(  struct boot_file_t*     file)
208 {
209      prom_printf("WARNING ! default_close called !\n");
210      return FILE_ERR_OK;
211 }
212
213 static struct fs_t fs_default =
214 {
215      "defaults",
216      NULL,
217      default_read,
218      default_seek,
219      default_close
220 };
221
222
223 int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file)
224 {
225      int result;
226         
227      memset(file, 0, sizeof(struct boot_file_t*));
228      file->fs        = &fs_default;
229
230      DEBUG_F("dev_path = %s\nfile_name = %s\npartition = %d\n",
231              spec->dev, spec->file, spec->part);
232
233      result = prom_get_devtype(spec->dev);
234      if (result > 0)
235           file->device_kind = result;
236      else
237           return result;
238         
239      switch(file->device_kind) {
240      case FILE_DEVICE_BLOCK:
241           DEBUG_F("device is a block device\n");
242           return file_block_open(file, spec->dev, spec->file, spec->part);
243      case FILE_DEVICE_NET:
244           DEBUG_F("device is a network device\n");
245           return file_net_open(file, spec->dev, spec->file);
246      }
247      return 0;
248 }
249
250 /* 
251  * Local variables:
252  * c-file-style: "k&r"
253  * c-basic-offset: 5
254  * End:
255  */