root/trunk/freewrt/tools/afdisk/afdisk.c

Revision 1146, 8.8 kB (checked in by n0-1, 6 years ago)

Initially imported afdisk (neither the Linux, nor the FreeBSD one).
Designed for automated hard disk partitioning it should fit perfect
for FreeWRT to provide a portable and flexible tool for paritioning
CompactFlash? disks as target devices inside a script.
Still needs some rework, anyway thanks alot to David Roetzel (the
author of afdisk).

Line 
1 /* afdisk - automatic fdisk
2  * Copyright (C) 2002 by David Roetzel <david@roetzel.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <ctype.h>
21 #include <string.h>
22 #include <fcntl.h>
23
24 #include "detect.h"
25 #include "conf.h"
26 #include "partx86.h"
27
28 #define VERSION  "0.0.1"
29
30 /* Converts strings like "200MB" into kilobytes
31  * Note that i follow the SI norm which means
32  * that 1MB = 1000KB etc.
33  * I assume that long is sufficient for modern
34  * hard disks
35  */
36 long to_kbytes(const char *string) {
37         int i,mult;
38         long result;
39         char c;
40
41         if (string == 0) return 0; /* Maybe -1 would be more apropriate but could mess up calculations */
42         for (i = 0;;i++) {
43                 c = *(string+i);
44                 if (isdigit(c)) continue;
45                 c = tolower(c);
46                 switch (c) {
47                         case 'k' :
48                         case '\0' : mult = 0; break;
49                         case 'm' : mult = 1; break;
50                         case 'g' : mult = 2; break;
51                 }
52                 break;
53         }
54
55         /* *(string+i) = '\0'; */
56         result = atol(string);
57
58         for (i = 0; i < mult; i++) result = result * 1000;
59
60         return result;
61 }
62
63 /* Test if configuration makes any sense */
64
65 int check_config(const struct config *conf_ptr, struct hdlist *devices) {
66         struct config conf = *conf_ptr;
67         long sum = 0;
68         struct partconf *curr, *ahead, *acurr, *aprev;
69         struct hdlist *hdcurr;
70
71         /* Get free space on detected hard drives */
72         hdcurr = devices;
73         while (hdcurr != NULL) {
74                 set_device((*hdcurr).dev);
75                 if (conf.overwrite == 0) del_part_table();
76                 (*hdcurr).size = get_free_space();
77                 sum += (*hdcurr).size;
78                 hdcurr = (*hdcurr).next;
79         }
80         if (sum < to_kbytes(conf.min_size)) {
81                 printf("%ld < %ld\n", sum, to_kbytes(conf.min_size));
82                 return -1; /* Not enough free space */
83         }
84         /* Copy partition data into agenda */
85
86         curr = conf.partinfo;
87         ahead = NULL;
88         while (curr != NULL) {
89                 if (ahead == NULL) {
90                         ahead = malloc(sizeof(*ahead));
91                         memcpy(ahead, curr, sizeof(*ahead));
92                         acurr = ahead;
93                 }
94                 else {
95                         (*acurr).next = malloc(sizeof(*acurr));
96                         acurr = (*acurr).next;
97                         memcpy(acurr,curr,sizeof(*acurr));
98                 }
99                 curr = (*curr).next;
100         }
101
102         /* Check if there's space for the partitions that have a device specified
103          */
104         hdcurr = devices;
105         while (hdcurr != NULL) {
106                 acurr = ahead;
107                 while (acurr != NULL) {
108                         if ((*acurr).device != NULL && strcmp((*acurr).device, (*hdcurr).dev)) {
109                                 if ((*hdcurr).size < to_kbytes((*acurr).min_size)) return -1; /* Not enough free space */
110                                 (*hdcurr).size -= to_kbytes((*acurr).min_size);
111                                 if (acurr == ahead) ahead = (*acurr).next;
112                                 else (*aprev).next = (*acurr).next;
113                         }
114                         else aprev = acurr;
115
116                         acurr = (*acurr).next;
117                 }
118                 hdcurr = (*hdcurr).next;
119         }
120
121         /* And finally check, whether there is space for the other partitions */
122        
123         hdcurr = devices;
124         while (hdcurr != NULL) {
125                 acurr = ahead;
126                 while (acurr != NULL) {
127                         if ((*hdcurr).size >= to_kbytes((*acurr).min_size)) {
128                                 (*hdcurr).size -= to_kbytes((*acurr).min_size);
129                                 if (acurr == ahead) ahead = (*acurr).next;
130                                 else (*aprev).next = (*acurr).next;
131                         }
132                         else aprev = acurr;
133
134                         acurr = (*acurr).next;
135                 }
136                 if (ahead == NULL) break;
137                 hdcurr = (*hdcurr).next;
138         }
139
140         if (ahead != NULL) return -1; /* There are still partitions left, that we found no space for */
141         return 0;
142 }
143
144
145 /* The function that performs the abstract partitioning
146  *
147  */
148
149 int partition(struct config *conf_ptr, struct hdlist *devices) {
150         struct config conf = *conf_ptr;
151         struct partconf *first, *previous, *current, *tbc_first, *tbc_curr;
152         int count,tbc;
153         long space, max, part;
154        
155         first = conf.partinfo;
156         previous = NULL;
157         current = first;
158         count = conf.partcount;
159        
160         while (count > 0) {
161                 tbc_first = NULL;
162                 if (devices == NULL) return -1;
163                 set_device((*devices).dev);
164                 tbc = 0;
165                 if (conf.overwrite == 0) del_part_table();
166                 space = get_free_space();
167                 /* Check which partitions _have to_ be created on current device */
168                 while (current != NULL) {
169                         if ((*current).device != NULL && strcmp((*current).device, (*devices).dev)) {
170                                 if (to_kbytes((*current).min_size) > space) return -2; /* Not enough free space, which should never happen */
171                                 /* enlist in current devices-to-be-created list */
172                                 if (tbc_first == NULL) {
173                                         tbc_first = current;
174                                         tbc_curr = tbc_first;
175                                 }
176                                 else {
177                                         (*tbc_curr).next = current;
178                                         tbc_curr = current;
179                                 }
180                                 tbc++;
181                                 /* remove from list of partitions */
182                                 if (current == first) first = (*current).next;
183                                 else (*previous).next = (*current).next;
184                                 (*current).next = NULL;
185                                 /* Decrement free space */
186                                 space -= to_kbytes((*current).min_size);
187                                 /* Decrement counter of partitions that have no device yet */
188                                 count--;
189                         }
190                         else previous = current;
191                         if (previous == NULL) current = first;
192                         else current = (*previous).next;
193                 }
194                 /* Check if there is space left for other partitions */
195                 current = first;
196                 previous = NULL;
197                 while (current != NULL) {
198                         if (to_kbytes((*current).min_size) <= space) {
199                                 /* enlist in current devices-to-be-created list */
200                                 if (tbc_first == NULL) {
201                                         tbc_first = current;
202                                         tbc_curr = tbc_first;
203                                 }
204                                 else {
205                                         (*tbc_curr).next = current;
206                                         tbc_curr = current;
207                                 }
208                                 tbc++;
209                                 /* remove from list of partitions */
210                                 if (current == first) first = (*current).next;
211                                 else (*previous).next = (*current).next;
212                                 (*current).next = NULL;
213                                 /* Decrement free space */
214                                 space -= to_kbytes((*current).min_size);
215                                 /* Decrement counter of partitions that have no device yet */
216                                 count--;
217                         }
218                         else previous = current;
219                         if (previous == NULL) current = first;
220                         else current = (*previous).next;
221                 }
222                 /* so right now tbc_first includes all partitions we want to create on the current device
223                  * so let's see if we can use all the free space */
224                 tbc_curr = tbc_first;
225                 part = space / tbc;
226                 while (tbc_curr != NULL) {
227                         if ((*tbc_curr).max_size != NULL) {
228                                 if (to_kbytes((*tbc_curr).max_size) > to_kbytes((*tbc_curr).min_size)) {
229                                         max = to_kbytes((*tbc_curr).max_size) - to_kbytes((*tbc_curr).min_size);
230                                         if (max > part) max = part;
231                                         (*tbc_curr).exact_size = malloc(11);
232                                         sprintf((*tbc_curr).exact_size, "%ld", max + to_kbytes((*tbc_curr).min_size));
233                                         space -= max;
234                                 }
235                                 else (*tbc_curr).exact_size = (*tbc_curr).min_size;
236                                 tbc--;
237                                 if (tbc > 0) part = space / tbc;
238                         }
239                         tbc_curr = (*tbc_curr).next;
240                 }
241                 tbc_curr = tbc_first;
242                 while (tbc_curr != NULL) {
243                         if ((*tbc_curr).max_size == NULL) {
244                                 (*tbc_curr).exact_size = malloc(11);
245                                 sprintf((*tbc_curr).exact_size, "%ld", part + to_kbytes((*tbc_curr).min_size));
246                         }
247                         tbc_curr = (*tbc_curr).next;
248                 }
249                 /* Now we can add the partitions */
250                 tbc_curr = tbc_first;
251                 while (tbc_curr != NULL) {
252                         if ((*tbc_curr).exact_size == NULL) (*tbc_curr).exact_size = (*tbc_curr).min_size;
253                         add_partition((*tbc_curr).type, tbc_curr->name, to_kbytes((*tbc_curr).exact_size), 0);
254                         tbc_curr = (*tbc_curr).next;
255                 }
256                 /* Now let's write the partition table */
257                 if (write_part_table(conf_ptr) != 0) return -3;
258                 devices = (*devices).next;
259         }
260        
261         return 0;       
262 }
263
264 int main(int argc, char **argv) {
265         /* Test Code */
266         int i,ret;
267         struct hdlist *list,*head;
268         struct config *conf;
269        
270         //list = detect(&hdcount);
271         list = malloc(sizeof(struct hdlist));
272         head = list;
273
274         if(argc != 2) {
275                 printf("Usage\n%s <device>\n", argv[0]);
276                 return -1;
277         }
278         if(strncmp(argv[1], "/dev/", 5) != 0) {
279                 list->dev = malloc(sizeof(char) * (strlen("/dev/") + strlen(argv[1]) + 1));
280                 snprintf(list->dev, sizeof(char)*(strlen("/dev/")+strlen(argv[1])+1), "/dev/%s", argv[1]);
281         } else {
282                 list->dev = argv[1];
283         }
284         if((i=open(list->dev, O_RDWR)) == -1) {
285                 printf("Error opening device %s, maybe no privileges?\n", list->dev);
286                 return -1;
287         } else {
288                 close(i);
289         }
290
291         // printf("Using disk %s. This will destroy ALL data on the device!\nContinue? [Ny] ");
292         // fflush(stdout);
293         // i = getchar();
294         // while(getchar() != '\n');
295         // if(i != 'y' && i != 'Y') return 0;
296
297
298
299         conf = get_config();
300
301         ret = check_config(conf, head);
302
303         if (check_config(conf, head) == -1) {
304                 printf("Can't proceed with current configuration : Not enough free disk space.\n");
305                 return -1;
306         }
307
308         i = partition(conf, head);
309
310         switch (i) {
311                 case -1: printf("No devices to partition.\n"); break;
312                 case -2: printf("Not enough free disk space.\n"); break;
313                 case -3: printf("Error writing partition table."); break;
314         }
315
316         return i;
317 }
318
Note: See TracBrowser for help on using the browser.