cast device_write_sector() to stream_write_sector_t
[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
299         ret = map_get_partition_geometry(map, &block, &count);
300         if (ret == -1)
301         {
302                 fprintf(stderr, "ERROR: cannot read partition geometry\n");
303                 return -1;
304         }
305
306         ret = map_set_driver_info(map, driver_number, 
307                                         block / (block_size / 512) , 
308                                         count / (block_size / 512), 1);
309         if (ret == -1)
310         {
311                 fprintf(stderr, "ERROR: cannot set driver info\n");
312                 return -1;
313         }
314
315         ret = map_set_driver_number(map, driver_number + 1);
316         if (driver_number == -1)
317         {
318                 fprintf(stderr, "ERROR: cannot set drivers number\n");
319                 return -1;
320         }
321
322         ret = map_write(map, partition);
323         if (ret != partition)
324         {
325                 fprintf(stderr, "ERROR: cannot set partition information\n");
326                 return -1;
327         }
328
329         ret = map_block0_write(map);
330         if (ret == -1)
331         {
332                 fprintf(stderr, "ERROR: cannot set drivers information\n");
333                 return -1;
334         }
335
336         return 0;
337 }
338
339 int main(int argc, char** argv)
340 {
341         map_t *map;
342         int ret;
343         int disk;
344         int partition = 0;
345         char *disk_name;
346         char buffer[16];
347         int driver;
348         int action = ACTION_NONE;
349         char *dev_name = NULL;
350         char *appledriver = NULL;
351         int c;
352         int option_index;
353         int flags;
354         char *type;
355         device_io_t device;
356
357         while(1)
358         {
359                 c = getopt_long(argc, argv, "hvg:p:sf:t:", long_options,
360                                 &option_index);
361                 if (c == -1)
362                         break;
363                 switch(c)
364                 {
365                 case ARG_VERBOSE:
366                         verbose++;
367                         break;
368                 case ARG_HELP:
369                         usage(argc, argv);
370                         return 0;
371                 case ARG_FLAGS:
372                         action |= ACTION_FLAGS;
373                         flags = strtol(optarg, NULL, 0);
374                         break;
375                 case ARG_TYPE:
376                         action |= ACTION_TYPE;
377                         type = optarg;
378                         break;
379                 case ARG_STARTUP:
380                         action |= ACTION_STARTUP;
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                         break;
393                 }
394         }
395         if (optind < argc)
396                 dev_name = argv[optind++];
397         if (optind < argc)
398         {
399                 partition = strtol(argv[optind++], NULL, 0);
400                 if (partition == 0)
401                 {
402                         fprintf(stderr,
403         "ERROR: partition number cannot be 0 !\n");
404                         return 1;
405                 }
406         }
407
408         if ( !action && dev_name)
409         {
410                 diskinfo(dev_name);
411                 return 0;
412         }
413         if (action & ACTION_SCANBUS) {
414                 if (action & ~ACTION_SCANBUS) {
415                         fprintf(stderr,
416         "ERROR: \"--scanbus\" cannot be used with other arguments\n");
417                         return 1;
418                 }
419
420                 scanbus();
421                 return 0;
422         }
423         if ((action & ACTION_GET) && (action & ACTION_PUT)) {
424                 fprintf(stderr, "You should use --get-driver OR --put-driver\n");
425                 return 1;
426         }
427
428         if (dev_name == NULL)
429         {
430                 fprintf(stderr, "ERROR: you must specify a device\n");
431                 return 1;
432         }
433
434         if (partition == 0)
435                 ret = emile_scsi_get_rdev(dev_name, &driver, &disk, &partition);
436         else
437                 ret = emile_scsi_get_rdev(dev_name, &driver, &disk, NULL);
438
439         if (ret == -1)
440         {
441                 disk_name = dev_name;
442                 driver = 0;
443                 disk = 0;
444         }
445         else if (ret == -1)
446         {
447                 fprintf(stderr, "ERROR: cannot find disk of %s\n", dev_name);
448                 return 1;
449         }
450         else
451         {
452                 emile_get_dev_name(buffer, driver, disk, 0);
453                 disk_name = buffer;
454         }
455
456         if (partition == 0)
457         {
458                 fprintf(stderr, 
459                         "ERROR: you must provide device of a partition\n");
460                 return 1;
461         }
462
463         device_sector_size = 512;
464         device.write_sector = (stream_write_sector_t)device_write_sector;
465         device.read_sector = (stream_read_sector_t)device_read_sector;
466         device.close = (stream_close_t)device_close;
467         device.get_blocksize = (stream_get_blocksize_t)device_get_blocksize;
468         device.data = (void*)device_open(disk_name, O_RDONLY);
469
470         map = map_open(&device);
471         if (map == NULL)
472         {
473                 fprintf(stderr, "ERROR: cannot open partition map\n");
474                 return 4;
475         }
476
477         if (action & ACTION_STARTUP)
478         {
479                 if (action & ~ACTION_STARTUP)
480                 {
481                         fprintf(stderr, 
482                         "ERROR: don't use --startup with other flags\n");
483                         return 2;
484                 }
485
486                 ret = map_set_startup(map, partition - 1);
487                 if (ret == -1)
488                         return 3;
489         }
490
491         if (action & ACTION_GET)
492         {
493                 if (appledriver == NULL) {
494                         fprintf(stderr, "ERROR: filename missing\n");
495                         map_close(map);
496                         return 6;
497                 }
498
499                 ret = get_driver(map, partition - 1, appledriver);
500                 if (ret == -1) {
501                         fprintf(stderr, 
502                 "ERROR: cannot put driver from partition %d to file %s\n", 
503                                 partition, appledriver);
504                         map_close(map);
505                         return 6;
506                 }
507
508                 map_close(map);
509                 return 0;
510         }
511
512         if (action & ACTION_PUT)
513         {
514                 if (appledriver == NULL) {
515                         fprintf(stderr, "ERROR: filename missing\n");
516                         map_close(map);
517                         return 6;
518                 }
519
520                 ret = put_driver(map, partition - 1, appledriver);
521                 if (ret == -1) {
522                         fprintf(stderr, 
523                 "ERROR: cannot put driver to partition %d from file %s\n", 
524                                 partition, appledriver);
525                         map_close(map);
526                         return 6;
527                 }
528
529                 map_close(map);
530                 return 0;
531         }
532
533
534         ret = map_read(map, partition - 1);
535         if (ret != partition - 1)
536         {
537                 fprintf(stderr, 
538                         "ERROR: cannot read partition %d info\n", partition);
539                 return 5;
540         }
541
542         if (action & ACTION_FLAGS)
543         {
544                 map_partition_set_flags(map, flags);
545         }
546
547         if (action & ACTION_TYPE)
548         {
549                 ret = map_set_partition_type(map, type);
550                 if (ret == -1)
551                 {
552                         fprintf(stderr, 
553                         "ERROR: cannot set partition type to %s\n", type);
554                         return 7;
555                 }
556         }
557
558         ret = map_write(map,  partition - 1);
559         if (ret != partition - 1)
560         {
561                 fprintf(stderr, 
562                         "ERROR: cannot write partition %d info\n", partition);
563                 return 8;
564         }
565
566         map_close(map);
567
568         return 0;
569 }