Commit yaboot 1.3.4-pre3
[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
39 int
40 parse_device_path(char *imagepath, char *defdevice, int defpart,
41                   char *deffile, struct boot_fspec_t *result)
42 {
43      char *ptr;
44      char *ipath = strdup(imagepath);
45      char *defdev = strdup(defdevice);
46
47      result->dev = NULL;
48      result->part = -1;
49      result->file = NULL;
50
51      if (!strstr(defdev, "ethernet") && !strstr(defdev, "enet")) {
52           if ((ptr = strrchr(defdev, ':')) != NULL)
53                *ptr = 0; /* remove trailing : from defdevice if necessary */
54      }
55
56      if (!imagepath)
57           goto punt;
58
59      if ((ptr = strrchr(ipath, ',')) != NULL) {
60           result->file = strdup(ptr+1);
61           /* Trim the filename off */
62           *ptr = 0;
63      }
64
65      if (strstr(ipath, "ethernet") || strstr(ipath, "enet"))
66           if ((ptr = strstr(ipath, "bootp")) != NULL) { /* `n' key booting boots enet:bootp */
67                *ptr = 0;
68                result->dev = strdup(ipath);
69           } else
70           result->dev = strdup(ipath);
71      else if ((ptr = strchr(ipath, ':')) != NULL) {
72           *ptr = 0;
73           result->dev = strdup(ipath);
74           if (*(ptr+1))
75                result->part = simple_strtol(ptr+1, NULL, 10);
76      } else if (strlen(ipath)) {
77           result->file = strdup(ipath);
78      } else {
79           return 0;
80      }
81      
82  punt:
83      if (!result->dev)
84           result->dev = strdup(defdev);
85      
86      if (result->part < 0)
87           result->part = defpart;
88      
89      if (!result->file)
90           result->file = strdup(deffile);
91      free(ipath);
92      return 1;
93 }
94
95
96 static int
97 file_block_open(        struct boot_file_t*     file,
98                         const char*             dev_name,
99                         const char*             file_name,
100                         int                     partition)
101 {
102         struct partition_t*     parts;
103         struct partition_t*     p;
104         struct partition_t*     found;
105         
106         parts = partitions_lookup(dev_name);
107         found = NULL;
108                         
109 #if DEBUG
110         if (parts)
111                 prom_printf("partitions:\n");
112         else
113                 prom_printf("no partitions found.\n");
114 #endif
115         for (p = parts; p && !found; p=p->next) {
116                 DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
117                         p->part_number, p->part_start, p->part_size );
118                 if (partition == -1) {
119                         file->fs = fs_open( file, dev_name, p, file_name );
120                         if (file->fs != NULL)
121                                 goto bail;
122                 }
123                 if ((partition >= 0) && (partition == p->part_number))
124                         found = p;
125 #if DEBUG
126                 if (found)
127                         prom_printf(" (match)\n");
128 #endif                                          
129         }
130
131         /* Note: we don't skip when found is NULL since we can, in some
132          * cases, let OF figure out a default partition.
133          */
134         DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
135         file->fs = fs_open( file, dev_name, found, file_name );
136
137 bail:
138         if (parts)
139                 partitions_free(parts);
140
141         return fserrorno;
142 }
143
144 static int
145 file_net_open(  struct boot_file_t*     file,
146                 const char*             dev_name,
147                 const char*             file_name)
148 {
149     file->fs = fs_of_netboot;
150     return fs_of_netboot->open(file, dev_name, NULL, file_name);
151 }
152
153 static int
154 default_read(   struct boot_file_t*     file,
155                 unsigned int            size,
156                 void*                   buffer)
157 {
158         prom_printf("WARNING ! default_read called !\n");
159         return FILE_ERR_EOF;
160 }
161
162 static int
163 default_seek(   struct boot_file_t*     file,
164                 unsigned int            newpos)
165 {
166         prom_printf("WARNING ! default_seek called !\n");
167         return FILE_ERR_EOF;
168 }
169
170 static int
171 default_close(  struct boot_file_t*     file)
172 {
173         prom_printf("WARNING ! default_close called !\n");
174         return FILE_ERR_OK;
175 }
176
177 static struct fs_t fs_default =
178 {
179     "defaults",
180     NULL,
181     default_read,
182     default_seek,
183     default_close
184 };
185
186
187 int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file)
188 {
189         int             result;
190         
191         memset(file, 0, sizeof(struct boot_file_t*));
192         file->fs        = &fs_default;
193
194         DEBUG_F("dev_path = %s\nfile_name = %s\npartition = %d\n",
195                 spec->dev, spec->file, spec->part);
196
197         result = prom_get_devtype(spec->dev);
198         if (result > 0)
199              file->device_kind = result;
200         else
201              return result;
202         
203         switch(file->device_kind) {
204             case FILE_DEVICE_BLOCK:
205                 DEBUG_F("device is a block device\n");
206                 return file_block_open(file, spec->dev, spec->file, spec->part);
207             case FILE_DEVICE_NET:
208                 DEBUG_F("device is a network device\n");
209                 return file_net_open(file, spec->dev, spec->file);
210         }
211         return 0;
212 }
213
214 /* 
215  * Local variables:
216  * c-file-style: "K&R"
217  * c-basic-offset: 5
218  * End:
219  */