1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 2004,2007  Free Software Foundation, Inc.
4  *
5  *  GRUB 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 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <grub/misc.h>
20 #include <grub/mm.h>
21 #include <grub/partition.h>
22 #include <grub/disk.h>
23 
24 GRUB_EXPORT(grub_partition_map_list);
25 GRUB_EXPORT(grub_partition_get_name);
26 GRUB_EXPORT(grub_partition_iterate);
27 GRUB_EXPORT(grub_partition_probe);
28 
29 grub_partition_map_t grub_partition_map_list;
30 
31 struct find_func_closure
32 {
33   int partnum;
34   grub_partition_t p;
35 };
36 
37 static int
find_func(grub_disk_t d,const grub_partition_t partition,void * closure)38 find_func (grub_disk_t d ,
39 	   const grub_partition_t partition, void *closure)
40 {
41   struct find_func_closure *c = closure;
42   if (c->partnum == partition->number)
43     {
44       c->p = (grub_partition_t) grub_malloc (sizeof (*c->p));
45       if (! c->p)
46 	return 1;
47 
48       grub_memcpy (c->p, partition, sizeof (*c->p));
49       return 1;
50     }
51 
52   return 0;
53 }
54 
55 static grub_partition_t
grub_partition_map_probe(const grub_partition_map_t partmap,grub_disk_t disk,int partnum)56 grub_partition_map_probe (const grub_partition_map_t partmap,
57 			  grub_disk_t disk, int partnum)
58 {
59   struct find_func_closure c;
60 
61   c.partnum = partnum;
62   c.p = 0;
63   partmap->iterate (disk, find_func, &c);
64   if (grub_errno)
65     goto fail;
66 
67   return c.p;
68 
69  fail:
70   grub_free (c.p);
71   return 0;
72 }
73 
74 grub_partition_t
grub_partition_probe(struct grub_disk * disk,const char * str)75 grub_partition_probe (struct grub_disk *disk, const char *str)
76 {
77   grub_partition_t part = 0;
78   grub_partition_t curpart = 0;
79   grub_partition_t tail;
80   const char *ptr;
81 
82   part = tail = disk->partition;
83 
84   for (ptr = str; *ptr;)
85     {
86       grub_partition_map_t partmap;
87       int num;
88       const char *partname, *partname_end;
89 
90       partname = ptr;
91       while (*ptr && grub_isalpha (*ptr))
92 	ptr++;
93       partname_end = ptr;
94       num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
95 
96       curpart = 0;
97       /* Use the first partition map type found.  */
98       FOR_PARTITION_MAPS(partmap)
99       {
100 	if (partname_end != partname &&
101 	    (grub_strncmp (partmap->name, partname, partname_end - partname)
102 	     != 0 || partmap->name[partname_end - partname] != 0))
103 	  continue;
104 
105 	disk->partition = part;
106 	curpart = grub_partition_map_probe (partmap, disk, num);
107 	disk->partition = tail;
108 	if (curpart)
109 	  break;
110 
111 	if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
112 	  {
113 	    /* Continue to next partition map type.  */
114 	    grub_errno = GRUB_ERR_NONE;
115 	    continue;
116 	  }
117 
118 	break;
119       }
120 
121       if (! curpart)
122 	{
123 	  while (part)
124 	    {
125 	      curpart = part->parent;
126 	      grub_free (part);
127 	      part = curpart;
128 	    }
129 	  return 0;
130 	}
131       curpart->parent = part;
132       part = curpart;
133       if (! ptr || *ptr != ',')
134 	break;
135       ptr++;
136     }
137 
138   return part;
139 }
140 
141 struct part_iterate_closure
142 {
143   int (*hook) (grub_disk_t disk, const grub_partition_t partition,
144 	       void *closure);
145   void *closure;
146   int ret;
147 };
148 
149 static int
part_iterate(grub_disk_t dsk,const grub_partition_t partition,void * closure)150 part_iterate (grub_disk_t dsk,
151 	      const grub_partition_t partition, void *closure)
152 {
153   struct part_iterate_closure *c = closure;
154   struct grub_partition p = *partition;
155   p.parent = dsk->partition;
156   dsk->partition = 0;
157   if (c->hook (dsk, &p, c->closure))
158     {
159       c->ret = 1;
160       return 1;
161     }
162   if (p.start != 0)
163     {
164       const struct grub_partition_map *partmap;
165       dsk->partition = &p;
166       FOR_PARTITION_MAPS(partmap)
167 	{
168 	  grub_err_t err;
169 	  err = partmap->iterate (dsk, part_iterate, closure);
170 	  if (err)
171 	    grub_errno = GRUB_ERR_NONE;
172 	  if (c->ret)
173 	    break;
174 	}
175     }
176   dsk->partition = p.parent;
177   return c->ret;
178 }
179 
180 int
grub_partition_iterate(struct grub_disk * disk,int (* hook)(grub_disk_t disk,const grub_partition_t partition,void * closure),void * closure)181 grub_partition_iterate (struct grub_disk *disk,
182 			int (*hook) (grub_disk_t disk,
183 				     const grub_partition_t partition,
184 				     void *closure),
185 			void *closure)
186 {
187   struct part_iterate_closure c;
188   const struct grub_partition_map *partmap;
189 
190   c.hook = hook;
191   c.closure = closure;
192   c.ret = 0;
193   FOR_PARTITION_MAPS(partmap)
194     {
195       grub_err_t err;
196       err = partmap->iterate (disk, part_iterate, &c);
197       if (err)
198 	grub_errno = GRUB_ERR_NONE;
199       if (c.ret)
200 	break;
201     }
202 
203   return c.ret;
204 }
205 
206 char *
grub_partition_get_name(const grub_partition_t partition)207 grub_partition_get_name (const grub_partition_t partition)
208 {
209   char *out = 0;
210   int curlen = 0;
211   grub_partition_t part;
212   for (part = partition; part; part = part->parent)
213     {
214       /* Even on 64-bit machines this buffer is enough to hold
215 	 longest number.  */
216 #ifndef _MSC_VER
217 	  char buf[grub_strlen (part->partmap->name) + 25];
218 #else
219 	  char * buf = grub_malloc(grub_strlen (part->partmap->name) + 25);
220 #endif
221 	  int strl;
222       grub_snprintf (buf, sizeof (buf), "%s%d", part->partmap->name,
223 		     part->number + 1);
224       strl = grub_strlen (buf);
225       if (curlen)
226 	{
227 	  out = grub_realloc (out, curlen + strl + 2);
228 	  grub_memcpy (out + strl + 1, out, curlen);
229 	  out[curlen + 1 + strl] = 0;
230 	  grub_memcpy (out, buf, strl);
231 	  out[strl] = ',';
232 	  curlen = curlen + 1 + strl;
233 	}
234       else
235 	{
236 		if (out){
237 		  grub_free(out);
238 		  out = NULL;
239 		}
240 	  curlen = strl;
241 	  out = grub_strdup (buf);
242 	}
243     }
244   return out;
245 }
246