emile-map-set: manage only one driver
[emile:mainline.git] / tools / emile-map-set.c
1 /*
2  *
3  * (c) 2004 Laurent Vivier <Laurent@Vivier.EU>
4  *
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <getopt.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include "libmap.h"
17 #include "libemile.h"
18 #include "device.h"
19
20 int verbose = 0;
21
22 extern void scanbus(void);
23 extern void diskinfo(char*);
24
25
26 enum {
27         ACTION_NONE =    0x00,
28         ACTION_FLAGS =   0x01,
29         ACTION_TYPE =    0x02,
30         ACTION_STARTUP = 0x04,
31         ACTION_SCANBUS = 0x08,
32         ACTION_GET =     0x10,
33         ACTION_PUT =     0x20,
34 };
35
36 enum {
37         ARG_NONE = 0,
38         ARG_SCANBUS,
39         ARG_HELP = 'h',
40         ARG_FLAGS = 'f',
41         ARG_TYPE ='t',
42         ARG_STARTUP ='s',
43         ARG_VERBOSE = 'v',
44         ARG_GET = 'g',
45         ARG_PUT = 'p',
46 };
47
48 static struct option long_options[] =
49 {
50         {"help",        0, NULL,        ARG_HELP        },
51         {"flags",       1, NULL,        ARG_FLAGS       },
52         {"type",        1, NULL,        ARG_TYPE        },
53         {"startup",     0, NULL,        ARG_STARTUP     },
54         {"scanbus",     0, NULL,        ARG_SCANBUS     },
55         {"verbose",     0, NULL,        ARG_VERBOSE     },
56         {"get-driver",  1, NULL,        ARG_GET         },
57         {"put-driver",  1, NULL,        ARG_PUT         },
58         {NULL,          0, NULL,        0               },
59 };
60
61 static void usage(int argc, char** argv)
62 {
63         fprintf(stderr, "Usage: %s [OPTIONS] [<disk>]\n", argv[0]);
64         fprintf(stderr, "       %s [OPTIONS] [<partition>|<disk> <part number>]\n", argv[0]);
65         fprintf(stderr, "   -h, --help             display this text\n");
66         fprintf(stderr, "   -v, --verbose          verbose mode\n");
67         fprintf(stderr, "       --scanbus          "
68                         "scan all available SCSI devices\n");
69         fprintf(stderr, "   -s, --startup          "
70                         "set the startup partition\n");
71         fprintf(stderr, "   -t, --type=TYPE        "
72                         "set the type of the partition\n");
73         fprintf(stderr, "   -f, --flags=FLAGS      "
74                         "set the type of the partition\n");
75         fprintf(stderr, "   -g, --get-driver=FILE  "
76                         "get the driver from the partition\n");
77         fprintf(stderr, "   -p, --put-driver=FILE  "
78                         "put the driver to the partition\n");
79         fprintf(stderr, "\nbuild: \n%s\n", SIGNATURE);
80 }
81
82 static int get_driver(map_t *map, int partition, char* appledriver)
83 {
84         int driver;
85         int block_size, block_count;
86         int driver_number;
87         int block, size, type, part;
88         int partition_base, partition_size;
89         int bootstart, bootsize, bootaddr, bootentry, checksum;
90         char processor[16];
91         unsigned char *code;
92         int fd;
93         int ret;
94
95         map_read(map, partition);
96         if (strncmp(map_get_partition_type(map), 
97                     "Apple_Driver", strlen("Apple_Driver")) != 0)
98         {
99                 fprintf(stderr, 
100         "ERROR: the type of the partition must begin with \"Apple_Driver\"\n");
101                 return -1;
102         }
103         if (strcmp(map_get_partition_name(map), "Macintosh") != 0)
104         {
105                 fprintf(stderr, 
106                 "ERROR: the name of the partition must be \"Macintosh\"\n");
107                 return -1;
108         }
109
110         map_geometry(map, &block_size, &block_count);
111         printf("block size: %d\n", block_size);
112
113         map_get_partition_geometry(map, &partition_base, &partition_size);
114         printf("partition base: %d, size %d\n", partition_base, partition_size);
115
116         driver_number = map_get_driver_number(map);
117         if (driver_number == 0)
118         {
119                 fprintf(stderr, "ERROR: no driver on this device\n");
120                 return -1;
121         }
122
123         for (driver = 0; driver < driver_number; driver++)
124         {
125                 map_get_driver_info(map, driver, &block, &size, &type);
126                 part  = map_seek_driver_partition(map, 
127                                                 block * block_size / 512 );
128                 if (part == partition)
129                 {
130                         map_read(map, part);
131                         if (emile_is_apple_driver(map))
132                                 break;
133                 }
134                 part  = map_seek_driver_partition(map, block);
135                 if (part == partition)
136                 {
137                         map_read(map, part);
138                         if (emile_is_apple_driver(map))
139                                 break;
140                 }
141         }
142         if (part != partition)
143         {
144                 fprintf(stderr, 
145                         "ERROR: cannot find partition in driver table\n");
146                 return -1;
147         }
148         printf("Found driver %d for partition %d\n", driver, partition + 1);
149         printf("base: %d size: %d type: %d\n", block * block_size / 512, 
150                                              size * block_size / 512 , type);
151         map_get_bootinfo(map, &bootstart, &bootsize, &bootaddr, 
152                                     &bootentry, &checksum, processor);
153         printf("Bootstart: %d, Bootsize: %d, Bootaddr: %d, Bootentry: %d\n",
154                 bootstart, bootsize, bootaddr, bootentry);
155         printf("Checksum: 0x%04x, Processor: %s\n", checksum, processor);
156
157         if (strcmp(processor, "68000") != 0)
158         {
159                 fprintf( stderr, 
160                 "ERROR: cannot manage processor %s (not 68000)\n", processor);
161                 return -1;
162         }
163
164         code = (unsigned char*)malloc(partition_size * 512);
165         if (code == NULL)
166         {
167                 fprintf(stderr, "ERROR: cannot malloc() to load driver in memory\n");
168                 return -1;
169         }
170
171         ret = map_read_sector(map, 0, (char*)code, partition_size * 512);
172         if (ret == -1)
173         {
174                 fprintf(stderr, "ERROR: cannot read driver (read())\n");
175                 free(code);
176                 return -1;
177         }
178
179         ret = emile_checksum(code, bootsize);
180         if (ret != checksum)
181                 fprintf(stderr, "WARNING: checksum is invalid (0x%x)\n",
182                                 ret);
183         else
184                 printf("Checksum OK\n");
185
186         fd = open(appledriver, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR);
187         if (fd == -1)
188         {
189                 fprintf(stderr, "ERROR: cannot open %s to save driver\n",
190                                 appledriver);
191                 free(code);
192                 return -1;
193         }
194
195         ret = write(fd, code, bootsize);
196         close(fd);
197         free(code);
198
199         if (ret != bootsize)
200         {
201                 fprintf(stderr, "ERROR: cannot save driver to %s\n", 
202                                 appledriver);
203                 return -1;
204         }
205         return 0;
206 }
207
208 static int put_driver(map_t *map, int partition, char* appledriver)
209 {
210         int block_size, block_count;
211         int fd;
212         int ret;
213         unsigned char* code;
214         struct stat st;
215         int driver_number;
216         int block, count, checksum;
217
218         map_read(map, partition);
219
220         if (strncmp(map_get_partition_type(map), 
221                     "Apple_Driver", strlen("Apple_Driver")) != 0)
222         {
223                 fprintf(stderr, 
224         "ERROR: the type of the partition must begin with \"Apple_Driver\"\n");
225                 return -1;
226         }
227         if (strcmp(map_get_partition_name(map), "Macintosh") != 0)
228         {
229                 fprintf(stderr, 
230                 "ERROR: the name of the partition must be \"Macintosh\"\n");
231                 return -1;
232         }
233
234         map_geometry(map, &block_size, &block_count);
235
236         /* read driver from file */
237
238         fd = open(appledriver, O_RDONLY);
239         if (fd == -1)
240         {
241                 fprintf(stderr, "ERROR: cannot open file %s\n", appledriver);
242                 return -1;
243         }
244
245         ret = fstat(fd, &st);
246         if (ret == -1)
247         {
248                 fprintf(stderr, "ERROR: cannot stat file %s\n", appledriver);
249                 return -1;
250         }
251
252         code = malloc(st.st_size);
253         if (code == NULL)
254         {
255                 fprintf(stderr, "ERROR: cannot malloc %ld\n", st.st_size);
256                 return -1;
257         }
258
259         ret = read(fd, code, st.st_size);
260
261         close(fd);
262
263         if (ret != st.st_size)
264         {
265                 fprintf(stderr, "ERROR: cannot read file %s\n", appledriver);
266                 return -1;
267         }
268
269         /* compute driver checksum */
270
271         checksum = emile_checksum(code, st.st_size);
272         printf("Driver checksum: 0x%x\n", checksum);
273
274         /* write file in partition */
275
276         ret = map_write_sector(map, 0, (char*)code, st.st_size);
277         free(code);
278
279         if (ret == -1)
280         {
281                 fprintf(stderr, "ERROR: cannot write driver (write())\n");
282                 return -1;
283         }
284
285         /* set bootinfo */
286
287         map_set_bootinfo(map, 0, st.st_size, 0, 0, checksum, "68000");
288         map_partition_set_flags(map, 0x17F);
289         
290         /* add driver in drivers list */
291
292         driver_number = map_get_driver_number(map);
293         if (driver_number == -1)
294         {
295                 fprintf(stderr, "ERROR: cannot read drivers number\n");
296                 return -1;
297         }
298         if (driver_number != 1) {
299                 fprintf(stderr, "ERROR: cannot manage more than one driver\n");
300                 return -1;
301         }
302
303         ret = map_get_partition_geometry(map, &block, &count);
304         if (ret == -1)
305         {
306                 fprintf(stderr, "ERROR: cannot read partition geometry\n");
307                 return -1;
308         }
309
310         ret = map_set_driver_info(map, driver_number - 1,
311                                         block / (block_size / 512) , 
312                                         count / (block_size / 512), 1);
313         if (ret == -1)
314         {
315                 fprintf(stderr, "ERROR: cannot set driver info\n");
316                 return -1;
317         }
318
319         ret = map_write(map, partition);
320         if (ret != partition)
321         {
322                 fprintf(stderr, "ERROR: cannot set partition information\n");
323                 return -1;
324         }
325
326         ret = map_block0_write(map);
327         if (ret == -1)
328         {
329                 fprintf(stderr, "ERROR: cannot set drivers information\n");
330                 return -1;
331         }
332
333         return 0;
334 }
335
336 int main(int argc, char** argv)
337 {
338         map_t *map;
339         int ret;
340         int disk;
341         int partition = 0;
342         char *disk_name;
343         char buffer[16];
344         int driver;
345         int action = ACTION_NONE;
346         char *dev_name = NULL;
347         char *appledriver = NULL;
348         int c;
349         int option_index;
350         int flags;
351         char *type;
352         device_io_t device;
353         int open_flags;
354
355         open_flags = O_RDONLY;
356         while(1)
357         {
358                 c = getopt_long(argc, argv, "hvg:p:sf:t:", long_options,
359                                 &option_index);
360                 if (c == -1)
361                         break;
362                 switch(c)
363                 {
364                 case ARG_VERBOSE:
365                         verbose++;
366                         break;
367                 case ARG_HELP:
368                         usage(argc, argv);
369                         return 0;
370                 case ARG_FLAGS:
371                         action |= ACTION_FLAGS;
372                         flags = strtol(optarg, NULL, 0);
373                         break;
374                 case ARG_TYPE:
375                         action |= ACTION_TYPE;
376                         type = optarg;
377                         break;
378                 case ARG_STARTUP:
379                         action |= ACTION_STARTUP;
380                         open_flags = O_RDWR;
381                         break;
382                 case ARG_SCANBUS:
383                         action |= ACTION_SCANBUS;
384                         break;
385                 case ARG_GET:
386                         action |= ACTION_GET;
387                         appledriver = optarg;
388                         break;
389                 case ARG_PUT:
390                         action |= ACTION_PUT;
391                         appledriver = optarg;
392                         open_flags = O_RDWR;
393                         break;
394                 }
395         }
396         if (optind < argc)
397                 dev_name = argv[optind++];
398         if (optind < argc)
399         {
400                 partition = strtol(argv[optind++], NULL, 0);
401                 if (partition == 0)
402                 {
403                         fprintf(stderr,
404         "ERROR: partition number cannot be 0 !\n");
405                         return 1;
406                 }
407         }
408
409         if ( !action && dev_name)
410         {
411                 diskinfo(dev_name);
412                 return 0;
413         }
414         if (action & ACTION_SCANBUS) {
415                 if (action & ~ACTION_SCANBUS) {
416                         fprintf(stderr,
417         "ERROR: \"--scanbus\" cannot be used with other arguments\n");
418                         return 1;
419                 }
420
421                 scanbus();
422                 return 0;
423         }
424         if ((action & ACTION_GET) && (action & ACTION_PUT)) {
425                 fprintf(stderr, "You should use --get-driver OR --put-driver\n");
426                 return 1;
427         }
428
429         if (dev_name == NULL)
430         {
431                 fprintf(stderr, "ERROR: you must specify a device\n");
432                 return 1;
433         }
434
435         if (partition == 0)
436                 ret = emile_scsi_get_rdev(dev_name, &driver, &disk, &partition);
437         else
438                 ret = emile_scsi_get_rdev(dev_name, &driver, &disk, NULL);
439
440         if (ret == -1)
441         {
442                 disk_name = dev_name;
443                 driver = 0;
444                 disk = 0;
445         }
446         else if (ret == -1)
447         {
448                 fprintf(stderr, "ERROR: cannot find disk of %s\n", dev_name);
449                 return 1;
450         }
451         else
452         {
453                 emile_get_dev_name(buffer, driver, disk, 0);
454                 disk_name = buffer;
455         }
456
457         if (partition == 0)
458         {
459                 fprintf(stderr, 
460                         "ERROR: you must provide device of a partition\n");
461                 return 1;
462         }
463
464         device_sector_size = 512;
465         device.write_sector = (stream_write_sector_t)device_write_sector;
466         device.read_sector = (stream_read_sector_t)device_read_sector;
467         device.close = (stream_close_t)device_close;
468         device.get_blocksize = (stream_get_blocksize_t)device_get_blocksize;
469         device.data = (void*)device_open(disk_name, open_flags);
470
471         map = map_open(&device);
472         if (map == NULL)
473         {
474                 fprintf(stderr, "ERROR: cannot open partition map\n");
475                 return 4;
476         }
477
478         if (action & ACTION_STARTUP)
479         {
480                 if (action & ~ACTION_STARTUP)
481                 {
482                         fprintf(stderr, 
483                         "ERROR: don't use --startup with other flags\n");
484                         return 2;
485                 }
486
487                 ret = map_set_startup(map, partition - 1);
488                 if (ret == -1)
489                         return 3;
490         }
491
492         if (action & ACTION_GET)
493         {
494                 if (appledriver == NULL) {
495                         fprintf(stderr, "ERROR: filename missing\n");
496                         map_close(map);
497                         return 6;
498                 }
499
500                 ret = get_driver(map, partition - 1, appledriver);
501                 if (ret == -1) {
502                         fprintf(stderr, 
503                 "ERROR: cannot put driver from partition %d to file %s\n", 
504                                 partition, appledriver);
505                         map_close(map);
506                         return 6;
507                 }
508
509                 map_close(map);
510                 return 0;
511         }
512
513         if (action & ACTION_PUT)
514         {
515                 if (appledriver == NULL) {
516                         fprintf(stderr, "ERROR: filename missing\n");
517                         map_close(map);
518                         return 6;
519                 }
520
521                 ret = put_driver(map, partition - 1, appledriver);
522                 if (ret == -1) {
523                         fprintf(stderr, 
524                 "ERROR: cannot put driver to partition %d from file %s\n", 
525                                 partition, appledriver);
526                         map_close(map);
527                         return 6;
528                 }
529
530                 map_close(map);
531                 return 0;
532         }
533
534
535         ret = map_read(map, partition - 1);
536         if (ret != partition - 1)
537         {
538                 fprintf(stderr, 
539                         "ERROR: cannot read partition %d info\n", partition);
540                 return 5;
541         }
542
543         if (action & ACTION_FLAGS)
544         {
545                 map_partition_set_flags(map, flags);
546         }
547
548         if (action & ACTION_TYPE)
549         {
550                 ret = map_set_partition_type(map, type);
551                 if (ret == -1)
552                 {
553                         fprintf(stderr, 
554                         "ERROR: cannot set partition type to %s\n", type);
555                         return 7;
556                 }
557         }
558
559         ret = map_write(map,  partition - 1);
560         if (ret != partition - 1)
561         {
562                 fprintf(stderr, 
563                         "ERROR: cannot write partition %d info\n", partition);
564                 return 8;
565         }
566
567         map_close(map);
568
569         return 0;
570 }