cast device_write_sector() to stream_write_sector_t
[emile:mainline.git] / tools / emile.c
1 /*
2  *
3  * (c) 2004-2007 Laurent Vivier <Laurent@Vivier.EU>
4  *
5  */
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <getopt.h>
16 #include <libgen.h>
17
18 #include <libconfig.h>
19
20 #include "libemile.h"
21 #include "libmap.h"
22 #include "device.h"
23
24 int verbose = 0;
25
26 extern void scanbus(void);
27
28 static enum {
29         ACTION_NONE =           0x00000000,
30         ACTION_SCANBUS =        0x00000001,
31         ACTION_SET_HFS =        0x00000002,
32         ACTION_RESTORE =        0x00000004,
33         ACTION_BACKUP =         0x00000008,
34         ACTION_TEST =           0x00000010,
35         ACTION_CONFIG =         0x00000020,
36         ACTION_NO_FS =          0x00000040,
37 } action = ACTION_NONE;
38
39 enum {
40         ARG_NONE = 0,
41         ARG_SCANBUS,
42         ARG_SET_HFS,
43         ARG_RESTORE,
44         ARG_BACKUP,
45         ARG_VERBOSE ='v',
46         ARG_TEST = 't',
47         ARG_HELP = 'h',
48         ARG_CONFIG = 'c',
49         ARG_NO_FS = 'n',
50 };
51
52 static struct option long_options[] =
53 {
54         {"scanbus",     0, NULL,        ARG_SCANBUS             },
55         {"set-hfs",     0, NULL,        ARG_SET_HFS             },
56         {"restore",     2, NULL,        ARG_RESTORE             },
57         {"backup",      2,  NULL,       ARG_BACKUP              },
58         {"verbose",     0, NULL,        ARG_VERBOSE             },
59         {"help",        0, NULL,        ARG_HELP                },
60         {"test",        0, NULL,        ARG_TEST                },
61         {"config",      1, NULL,        ARG_CONFIG              },
62         {"no-fs",       0, NULL,        ARG_NO_FS               },
63         {NULL,          0, NULL,        0                       }
64 };
65
66 static void usage(int argc, char** argv)
67 {
68         fprintf(stderr, "Usage: %s [OPTION]\n", argv[0]);
69         fprintf(stderr, "Update and install EMILE stuff on your SCSI disk.\n");
70         fprintf(stderr, "EMILE allows to boot linux directly from linux partition\n");
71         fprintf(stderr,"  -h, --help        display this text\n");
72         fprintf(stderr,"  -v, --verbose     active verbose mode\n");
73         fprintf(stderr,"  -t, --test        active test mode (don't write to disk)\n");
74         fprintf(stderr,"  --scanbus         "
75                        "display information about all disks and partitions\n");
76         fprintf(stderr,"  --restore[=FILE]  restore boot block from FILE\n");
77         fprintf(stderr,"  --backup[=FILE]   save current boot block to FILE\n");
78         fprintf(stderr,"  --set-hfs         "
79                        "set type of partition DEV to Apple_HFS\n"
80                        "                    (needed to be bootable)\n");
81         fprintf(stderr,"  -c, --config FILE use config file FILE\n");
82         fprintf(stderr,"  -n, --no-fs       "
83                        "don't use EMILE embededed filesystems\n");
84         fprintf(stderr, "\nbuild: \n%s\n", SIGNATURE);
85 }
86
87 static int open_map_of( char *dev_name, int flags, 
88                         map_t **map, int *partition)
89 {
90         int ret;
91         int disk;
92         char disk_name[16];
93         int driver;
94         device_io_t device;
95
96         ret = emile_scsi_get_rdev(dev_name, &driver, &disk, partition);
97         if (ret == -1)
98                 return -2;
99
100         emile_get_dev_name(disk_name, driver, disk, 0);
101
102         device_sector_size = 512;
103         device.data = (void*)device_open(disk_name, flags);
104         device.write_sector = (stream_write_sector_t)device_write_sector;
105         device.read_sector = (stream_read_sector_t)device_read_sector;
106         device.close = (stream_close_t)device_close;
107         device.get_blocksize = (stream_get_blocksize_t)device_get_blocksize;
108
109         *map = map_open(&device);
110         if (*map == NULL)
111                 return -1;
112
113         return 0;
114 }
115
116 static int check_has_apple_driver(char *dev_name)
117 {
118         map_t *map;
119         int partition;
120         int ret;
121
122         ret = open_map_of(dev_name, O_RDONLY, &map, &partition);
123         if (ret < 0)
124                 return ret;
125
126         ret = map_has_apple_driver(map);
127         map_close(map);
128
129         return ret;
130 }
131
132 static int check_is_hfs(char *dev_name)
133 {
134         map_t *map;
135         int ret;
136         int partition;
137         char *part_type;
138
139         ret = open_map_of(dev_name, O_RDONLY, &map, &partition);
140         if (ret < 0)
141                 return ret;
142
143         ret = map_read(map, partition - 1);
144         if (ret == -1)
145                 return -1;
146
147         part_type = map_get_partition_type(map);
148         ret = (strcmp("Apple_HFS", part_type) == 0);
149
150         map_close(map);
151
152         return ret;
153 }
154
155 static int check_is_EMILE_bootblock(char *dev_name)
156 {
157         map_t *map;
158         int ret;
159         int partition;
160         char bootblock[BOOTBLOCK_SIZE];
161         int bootblock_type;
162
163         ret = open_map_of(dev_name, O_RDONLY, &map, &partition);
164         if (ret < 0)
165                 return ret;
166
167         ret = map_read(map, partition - 1);
168         if (ret == -1)
169                 return -1;
170
171         ret = map_bootblock_read(map, bootblock);
172         if (ret == -1)
173                 return -1;
174
175         bootblock_type = map_bootblock_get_type(bootblock);
176
177         map_close(map);
178
179         return EMILE_BOOTBLOCK == bootblock_type;
180 }
181
182 static int backup_bootblock(char *dev_name, char *filename)
183 {
184         map_t *map;
185         int ret;
186         int partition;
187         char bootblock[BOOTBLOCK_SIZE];
188         int fd;
189
190         ret = open_map_of(dev_name, O_RDONLY, &map, &partition);
191         if (ret < 0)
192                 return ret;
193
194         ret = map_read(map, partition - 1);
195         if (ret == -1)
196                 return -1;
197
198         ret = map_bootblock_read(map, bootblock);
199         if (ret == -1)
200                 return -1;
201
202         map_close(map);
203
204         /* save bootblock */
205
206         fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
207         if (fd == -1)
208         {
209                 if (errno == EEXIST)
210                 {
211                         fprintf(stderr, "ERROR: \"%s\" already exists.\n",
212                                         filename);
213                 }
214                 return -1;
215         }
216
217         ret = write(fd, bootblock, BOOTBLOCK_SIZE);
218         if (ret != BOOTBLOCK_SIZE)
219                 return -1;
220
221         close(fd);
222
223         return 0;
224 }
225
226 static int restore_bootblock(char *dev_name, char *filename)
227 {
228         map_t *map;
229         int ret;
230         int partition;
231         char bootblock[BOOTBLOCK_SIZE];
232         int fd;
233
234         if (!check_is_EMILE_bootblock(dev_name))
235         {
236                 fprintf(stderr, "ERROR: cannot restore bootblock over non-EMILE bootblock\n");
237                 return -1;
238         }
239
240         /* read bootblock */
241
242         fd = open(filename, O_RDONLY);
243         if (fd == -1)
244                 return -1;
245
246         ret = read(fd, bootblock, BOOTBLOCK_SIZE);
247         if (ret != BOOTBLOCK_SIZE)
248                 return -1;
249
250         close(fd);
251
252         /* write bootblock */
253
254         ret = open_map_of(dev_name, O_RDWR, &map, &partition);
255         if (ret < 0)
256                 return -1;
257
258         ret = map_read(map, partition - 1);
259         if (ret == -1)
260                 return -1;
261
262         ret = map_bootblock_write(map, bootblock);
263         if (ret == -1)
264                 return -1;
265
266         map_close(map);
267
268         return 0;
269 }
270
271 static int copy_file_to_bootblock(char* first_path, char* dev_name)
272 {
273         map_t *map;
274         int ret;
275         int partition;
276         char bootblock[BOOTBLOCK_SIZE];
277         int fd;
278
279         /* read first level */
280
281         fd = open(first_path, O_RDONLY);
282         if (fd == -1)
283                 return -1;
284
285         ret = read(fd, bootblock, BOOTBLOCK_SIZE);
286         if (ret != BOOTBLOCK_SIZE)
287                 return -1;
288
289         close(fd);
290
291         /* write bootblock to partition */
292
293         ret = open_map_of(dev_name, O_RDWR, &map, &partition);
294         if (ret < 0)
295                 return -1;
296
297         ret = map_read(map, partition - 1);
298         if (ret == -1)
299                 return -1;
300
301         ret = map_bootblock_write(map, bootblock);
302         if (ret == -1)
303                 return -1;
304
305         map_close(map);
306
307         return 0;
308 }
309
310 static int set_HFS(char *dev_name)
311 {
312         map_t *map;
313         int ret;
314         int partition;
315
316         ret = open_map_of(dev_name, O_RDWR, &map, &partition);
317         if (ret < 0)
318                 return -1;
319
320         ret = map_read(map, partition - 1);
321         if (ret == -1)
322                 return -1;
323
324         ret = map_set_partition_type(map, "Apple_HFS");
325         if (ret == -1)
326                 return -1;
327
328         ret = map_partition_set_bootable(map, 1);
329         if (ret == -1)
330                 return -1;
331
332         ret = map_write(map, partition - 1);
333         if (ret == -1)
334                 return -1;
335
336         map_close(map);
337
338         return 0;
339 }
340
341 static char *get_map_name(char *filename)
342 {
343         char *a, *b;
344         char *base, *dir;
345         char *map_name;
346
347         a = strdup(filename);
348         base = basename(a);
349
350         b = strdup(filename);
351         dir = dirname(b);
352
353         map_name = (char*)malloc(strlen(filename) + 6);
354         if (map_name == NULL)
355                 return NULL;
356         sprintf(map_name, "%s/.%s.map", dir, base);
357         free(a);
358         free(b);
359
360         return map_name;
361 }
362
363
364 static int add_file(int8_t *configuration,
365                     char *index, char *property, char *path, char *map_path)
366 {
367         struct emile_container *container;
368         unsigned short unit_id;
369         char map_info[64];
370
371         if (emile_is_url(path))
372         {
373                 if (verbose)
374                         printf("    %s %s\n", property, path);
375
376                 config_set_indexed_property(configuration,
377                                             "title", index,
378                                             property, path);
379                 return 0;
380         }
381
382         if ((action & ACTION_TEST) != 0)
383         {
384                 map_path = tempnam(NULL, "emile-map_path-");
385         }
386         else if (map_path == NULL)
387         {
388                 map_path = get_map_name(path);
389                 if (map_path == NULL)
390                         return -1;
391         }
392         else
393                 map_path = strdup(map_path);
394
395         /* get block mapping of kernel in filesystem */
396
397         container = emile_second_create_mapfile(&unit_id, map_path, path);
398         if (container == NULL)
399         {
400                 free(map_path);
401                 return -1;
402         }
403
404         sprintf(map_info, 
405                 "container:(sd%d)0x%x,0x%x", unit_id, 
406                 container->blocks[0].offset, 
407                 container->blocks[0].count);
408
409         free(container);
410
411         if (verbose)
412                 printf("    %s %s (%s = %s)\n", property, path, map_path, map_info);
413
414         config_set_indexed_property(configuration,
415                                     "title", index,
416                                     property, map_info);
417
418         if ((action & ACTION_TEST) != 0)
419                 fprintf(stderr, "WARNING: test mode, you must remove manually %s\n", map_path);
420
421         free(map_path);
422         return 0;
423 }
424
425 static int8_t *set_config_no_fs(char *config_path)
426 {
427         int8_t *conffile;
428         int fd;
429         int i;
430         int current;
431         int ret;
432         struct stat st;
433         int8_t *configuration;
434         char property[1024];
435         char property2[1024];
436         char property3[1024];
437         static char *prolog[] = {
438                 "gestaltID",
439                 "default",
440                 "timeout",
441                 "vga",
442                 "modem",
443                 "printer"
444                 };
445
446         configuration = malloc(65536);
447         if (configuration == NULL)
448         {
449                 fprintf(stderr, 
450                         "ERROR: cannot allocate memory for configuration\n");
451                 return NULL;
452         }
453
454         memset(configuration, 0, 65536);
455
456         /* open configuration file */
457
458         fd = open(config_path, O_RDONLY);
459         if (fd == -1)
460         {
461                 fprintf(stderr, "ERROR: cannot open %s\n", config_path);
462                 return NULL;
463         }
464         if (fstat(fd, &st) == -1)
465         {
466                 fprintf(stderr, "ERROR: cannot fstat %s\n", config_path);
467                 return NULL;
468         }
469         conffile = (int8_t*)malloc(st.st_size);
470         if (conffile == NULL)
471         {
472                 fprintf(stderr, "ERROR: cannot malloc() %s\n", config_path);
473                 return NULL;
474         }
475
476         if (read(fd, conffile, st.st_size) != st.st_size)
477         {
478                 fprintf(stderr, "ERROR: cannot read() %s\n", config_path);
479                 return NULL;
480         }
481         close(fd);
482
483         /* copy prolog */
484
485         for (i = 0; i < sizeof(prolog) / sizeof(char*); i++)
486         {
487                 if (config_get_property(conffile,
488                                         prolog[i],
489                                         property) != -1)
490                         config_set_property(configuration, prolog[i], property);
491         }
492
493         current = 0;
494         while (1) {
495                 ret = config_get_property(conffile + current,
496                                           "title", property);
497                 if (ret == -1)
498                         break;
499                 config_add_property(configuration, "title", property);
500                 if (verbose)
501                         printf("title %s\n", property);
502
503                 current += ret;
504                 current = config_get_next_property(conffile, current,
505                                                    NULL, NULL);
506
507                 ret = config_get_indexed_property(conffile,
508                                                   "title",
509                                                   property,
510                                                   "chainloader",
511                                                   property2);
512                 if (ret != -1)
513                 {
514                         if (emile_is_url(property2))
515                         {
516                                 config_set_indexed_property(configuration,
517                                                 "title", property,
518                                                 "chainloader", property2);
519                         }
520                         else
521                         {
522                                 int fd;
523                                 unsigned short unit_id;
524                                 struct emile_container *container;
525                                 struct stat st;
526                                 char *chainloader;
527
528                                 fd = open(property2, O_RDONLY);
529                                 if (fd == -1)
530                                 {
531                                         fprintf(stderr,
532                                                 "ERROR: cannot open %s\n",
533                                                  property2);
534                                         return NULL;
535                                 }
536                                 fstat(fd, &st);
537
538                                 container = malloc(
539                                                 sizeof(struct emile_container) +
540                                                 sizeof(struct emile_block));
541                                 if (container == NULL)
542                                 {
543                                         fprintf(stderr,
544                                                 "ERROR: cannot malloc container"
545                                                 "\n");
546                                         close(fd);
547                                         return NULL;
548                                 }
549                                 ret = emile_scsi_create_container(fd,
550                                                                   &unit_id,
551                                                                   container,
552                                                                   2);
553                                 close(fd);
554                                 if (ret == -1)
555                                 {
556                                         fprintf(stderr,
557                                                 "ERROR: cannot create container"
558                                                 "\n");
559                                         free(container);
560                                         return NULL;
561                                 }
562                                 chainloader = malloc(32);
563                                 if (chainloader == NULL)
564                                 {
565                                         fprintf(stderr,
566                                           "ERROR: cannot malloc chainloader\n");
567                                         free(container);
568                                         return NULL;
569                                 }
570                                 sprintf(chainloader,
571                                         "block:(sd%d)0x%x,0x%lx", unit_id,
572                                         container->blocks[0].offset,
573                                         st.st_size);
574                                 free(container);
575                                 config_set_indexed_property(configuration,
576                                                 "title", property,
577                                                 "chainloader", chainloader);
578                                 free(chainloader);
579                         }
580                 }
581
582                 ret = config_get_indexed_property(conffile,
583                                                   "title",
584                                                   property,
585                                                   "kernel",
586                                                   property2);
587                 if (ret != -1)
588                 {
589                         ret = config_get_indexed_property(conffile,
590                                                           "title",
591                                                           property,
592                                                           "kernel_map",
593                                                           property3);
594
595                         ret = add_file(configuration, property, 
596                                         "kernel", property2, 
597                                         ret == -1 ? NULL : property3);
598                         if (ret == -1)
599                         {
600                                 fprintf(stderr, 
601                                         "ERROR: cannot add kernel %s\n",
602                                         property2);
603                                 free(conffile);
604                                 free(configuration);
605                                 return NULL;
606                         }
607                 }
608                 else
609                         fprintf(stderr, 
610                                 "WARNING: missing kernel entry for %s\n",
611                                 property);
612
613                 ret = config_get_indexed_property(conffile,
614                                                   "title",
615                                                   property,
616                                                   "initrd",
617                                                   property2);
618                 if (ret != -1)
619                 {
620                         ret = config_get_indexed_property(conffile,
621                                                           "title",
622                                                           property,
623                                                           "initrd_map",
624                                                           property3);
625
626                         ret = add_file(configuration, property,
627                                        "initrd", property2,
628                                         ret == -1 ? NULL : property3);
629                         if (ret == -1)
630                         {
631                                 free(configuration);
632                                 fprintf(stderr, 
633                                         "ERROR: cannot add initrd %s\n",
634                                         property3);
635                                 fprintf(stderr, 
636                                 "ERROR: missing kernel entry for %s\n", property);
637                                 return NULL;
638                         }
639                 }
640
641                 ret = config_get_indexed_property(conffile,
642                                                   "title",
643                                                   property,
644                                                   "args",
645                                                   property2);
646                 if (ret != -1)
647                 {
648                         config_set_indexed_property(configuration,
649                                                     "title", property,
650                                                     "args", property2);
651                         if (verbose)
652                                 printf("    args %s\n", property2);
653                 }
654         }
655
656         if (strlen((char*)configuration) > 1023)
657         {
658                 int fd;
659                 char* bootconfig = "/boot/emile/.bootconfig";
660
661                 /* do not fit in second paramstring */
662
663                 fd = creat(bootconfig, S_IWUSR);
664                 if (fd == -1)
665                 {
666                         free(configuration);
667                         fprintf(stderr, 
668                         "ERROR: cannot create /boot/emile/.bootconfig\n");
669                         return NULL;
670                         
671                 }
672
673                 write(fd, configuration, strlen((char*)configuration) + 1);
674                 close(fd);
675                 free(configuration);
676
677                 configuration = malloc(1024);
678                 if (configuration == NULL)
679                 {
680                         fprintf(stderr, 
681                         "ERROR: cannot allocate memory for configuration\n");
682                         return NULL;
683                 }
684                 ret = add_file(configuration, NULL, 
685                                  "configuration", bootconfig, NULL);
686                 if (ret == -1)
687                 {
688                         free(configuration);
689                         fprintf(stderr, 
690                         "ERROR: cannot add %s to configuration\n", bootconfig);
691                         return NULL;
692                 }
693         }
694         return configuration;
695 }
696
697 static int8_t *set_config(char *config_path)
698 {
699         int8_t *configuration;
700         int driver, disk, partition;
701         int fd, ret;
702
703         fd = open(config_path, O_RDONLY);
704         if (fd == -1)
705         {
706                 fprintf(stderr, "ERROR: cannot open %s\n", config_path);
707                 return NULL;
708         }
709         ret = emile_scsi_get_dev(fd, &driver, &disk, &partition);
710         close(fd);
711         if (ret == -1)
712         {
713                 fprintf(stderr, "cannot find partition and disk of %s\n",
714                         config_path);
715                 return NULL;
716         }
717
718         configuration = (int8_t*)malloc(65536);
719         if (configuration == NULL)
720         {
721                 fprintf(stderr, 
722                         "ERROR: cannot allocate memory for configuration\n");
723                 return NULL;
724         }
725         memset(configuration, 0, 65536);
726
727         sprintf((char*)configuration, "configuration (sd%d,%d)%s\n",
728                 disk, partition - 1, config_path);
729         if (verbose)
730                 printf("    configuration (sd%d,%d)%s\n",
731                        disk, partition - 1, config_path);
732
733         return configuration;
734 }
735
736 int main(int argc, char **argv)
737 {
738         char property[1024];
739         char *backup_path = PREFIX "/boot/emile/bootblock.backup";
740         char *config_path = PREFIX "/boot/emile/emile.conf";
741         char *first_path;
742         char *second_path;
743         int ret;
744         int c;
745         char *partition;
746         int option_index = 0;
747         int drive, second, size;
748         int fd;
749         int8_t *configuration;
750         int8_t *config;
751         struct stat st;
752
753         while(1)
754         {
755                 c = getopt_long(argc, argv, "vhtc:", long_options, &option_index);
756                 if (c == -1)
757                         break;
758                 switch(c)
759                 {
760                 case ARG_VERBOSE:
761                         verbose++;
762                         break;
763                 case ARG_HELP:
764                         usage(argc, argv);
765                         return 0;
766                 case ARG_SCANBUS:
767                         action |= ACTION_SCANBUS;
768                         break;
769                 case ARG_SET_HFS:
770                         action |= ACTION_SET_HFS;
771                         break;
772                 case ARG_RESTORE:
773                         action |= ACTION_RESTORE;
774                         if (optarg != NULL)
775                                 backup_path = optarg;
776                         break;
777                 case ARG_BACKUP:
778                         action |= ACTION_BACKUP;
779                         if (optarg != NULL)
780                                 backup_path = optarg;
781                         break;
782                 case ARG_TEST:
783                         action |= ACTION_TEST;
784                         break;
785                 case ARG_CONFIG:
786                         action |= ACTION_CONFIG;
787                         config_path = optarg;
788                         break;
789                 case ARG_NO_FS:
790                         action |= ACTION_NO_FS;
791                         break;
792                 default:
793                         fprintf(stderr, "ERROR: unknown option %s (%d, %c)\n",
794                                         argv[optind], c, c);
795                         return 1;
796                 }
797         }
798
799         if (action & ACTION_SCANBUS) {
800
801                 if (action & ~ACTION_SCANBUS) {
802                         fprintf(stderr, 
803         "ERROR: \"--scanbus\" cannot be used with other arguments\n");
804                         return 1;
805                 }
806
807                 scanbus();
808                 return 0;
809         }
810
811         /* read config file */
812
813         fd = open(config_path, O_RDONLY);
814         if (fd == -1)
815         {
816                 fprintf(stderr,
817                         "ERROR: cannot open config file %s\n", config_path);
818                 return 2;
819         }
820         if (fstat(fd, &st) == -1)
821         {
822                 fprintf(stderr,
823                         "ERROR: cannot fstat file %s\n", config_path);
824                 return 2;
825         }
826         config = (int8_t*)malloc(st.st_size);
827         if (config == NULL)
828         {
829                 fprintf(stderr,
830                         "ERROR: cannot malloc %s\n", config_path);
831                 return 2;
832         }
833         if (read(fd, config, st.st_size) != st.st_size)
834         {
835                 fprintf(stderr, "ERROR: cannot read() %s\n", config_path);
836                 return 5;
837         }
838         close(fd);
839
840         /* get partition */
841
842         ret = config_get_property(config, "partition", property);
843         if (ret == -1)
844         {
845                 fprintf(stderr, "ERROR: you must specify in %s a partition to set\n"
846                                 "       EMILE bootblock\n", config_path);
847                 fprintf(stderr,
848         "       you can have the list of available partitions with \"--scanbus\".\n");
849                 free(config);
850                 return 3;
851         }
852         partition = strdup(property);
853
854         if (action & ACTION_RESTORE)
855         {
856                 char* new_name;
857
858                 if (action & ~ACTION_RESTORE)
859                 {
860                         fprintf(stderr, 
861         "ERROR: \"--restore\" cannot be used with other arguments\n");
862                         free(config);
863                         return 13;
864                 }
865
866                 ret = restore_bootblock(partition, backup_path);
867                 if (ret == -1)
868                 {
869                         fprintf(stderr, 
870                         "ERROR: cannot restore bootblock %s from %s\n", 
871                         partition, backup_path);
872                         free(config);
873                         return 14;
874                 }
875                 printf("Bootblock restore successfully done.\n");
876
877                 /* rename backup file to .old */
878                 
879                 new_name = (char*)malloc(strlen(backup_path) + 4 + 1);
880
881                 sprintf(new_name, "%s.old", new_name);
882
883                 unlink(new_name);
884                 rename(backup_path, new_name);
885
886                 free(new_name);
887
888                 free(config);
889                 return 0;
890         }
891
892         ret = check_has_apple_driver(partition);
893         if (ret != -2)
894         {
895                 if (ret == -1)
896                 {
897                         fprintf(stderr, "ERROR: cannot check if Apple_Driver exists\n");
898                         fprintf(stderr, "       you should try as root\n");
899                         if ((action & ACTION_TEST) == 0)
900                         {
901                                 free(config);
902                                 return 4;
903                         }
904                 }
905                 if (ret == 0)
906                 {
907                         fprintf(stderr,
908                 "ERROR: to be bootable a disk must have an Apple Driver on it\n");
909                         fprintf(stderr,
910                 "       You must partition this disk with Apple Disk utility\n");
911                         fprintf(stderr,
912                 "       or wait a release of EMILE allowing you to add this driver\n");
913                         if ((action & ACTION_TEST) == 0)
914                         {
915                                 free(config);
916                                 return 5;
917                         }
918                 }
919
920                 ret = check_is_hfs(partition);
921                 if (ret == -1)
922                 {
923                         fprintf(stderr,
924                                 "ERROR: cannot check if partition is Apple_HFS\n");
925                         fprintf(stderr, "       you should try as root\n");
926                         if ((action & ACTION_TEST) == 0)
927                         {
928                                 free(config);
929                                 return 6;
930                         }
931                 }
932                 if ( (ret == 0) && !(action & ACTION_SET_HFS) )
933                 {
934                         fprintf(stderr,
935                 "ERROR: to be bootable a partition must be of type Apple_HFS\n");
936                         fprintf(stderr,
937                 "       you can change it to Apple_HFS using \"--set-hfs\" argument\n");
938                         if ((action & ACTION_TEST) == 0)
939                         {
940                                 free(config);
941                                 return 7;
942                         }
943                 }
944
945                 ret = check_is_EMILE_bootblock(partition);
946                 if (ret == -1)
947                 {
948                         fprintf(stderr, "ERROR: cannot check bootblock type\n");
949                         fprintf(stderr, "       you should try as root\n");
950                         if ((action & ACTION_TEST) == 0)
951                         {
952                                 free(config);
953                                 return 8;
954                         }
955                 }
956         }
957         if ( (ret == 0) && ((action & ACTION_BACKUP) == 0) )
958         {
959                 fprintf(stderr,
960         "ERROR: there is already a bootblock on \"%s\"\n", partition);
961                 fprintf(stderr,
962         "       you must use \"--backup\" to save it\n");
963                 if ((action & ACTION_TEST) == 0)
964                 {
965                         free(config);
966                         return 9;
967                 }
968         }
969         
970         if (action & ACTION_BACKUP)
971         {
972                 if (action & ACTION_TEST)
973                 {
974                         fprintf(stderr, 
975         "ERROR: \"--backup\" cannot be used with \"--test\"\n");
976                         free(config);
977                         return 13;
978                 }
979
980                 ret = backup_bootblock(partition, backup_path);
981                 if (ret == -1)
982                 {
983                         fprintf(stderr, 
984                         "ERROR: cannot backup bootblock %s to %s\n", 
985                         partition, backup_path);
986                         free(config);
987                         return 14;
988                 }
989                 printf("Bootblock backup successfully done.\n");
990         }
991
992         ret = config_get_property(config, "first_level", property);
993         if (ret == -1)
994                 return 2;
995         first_path = strdup(property);
996
997         ret = config_get_property(config, "second_level", property);
998         if (ret == -1)
999                 return 2;
1000         second_path = strdup(property);
1001
1002         fd = open(first_path, O_RDONLY);
1003         if (fd == -1)
1004         {
1005                 fprintf(stderr, 
1006                         "ERROR: cannot open \"%s\".\n", first_path);
1007                 free(config);
1008                 return 20;
1009         }
1010
1011         ret = emile_first_get_param(fd, &drive, &second, &size);
1012
1013         close(fd);
1014
1015         if ((action & ACTION_NO_FS) == 0)
1016                 configuration = set_config(config_path);
1017         else
1018                 configuration = set_config_no_fs(config_path);
1019         if (ret)
1020                 return ret;
1021
1022         if ((action & ACTION_TEST) == 0)
1023         {
1024                 /* set configuration in second level */
1025
1026                 fd = open(second_path, O_RDWR);
1027                 emile_second_set_configuration(fd, configuration);
1028                 close(fd);
1029
1030                 /* set second info in first level */
1031
1032                 fd = open(first_path, O_RDWR);
1033
1034                 ret = emile_first_set_param_scsi(fd, second_path);
1035                 if (ret == -1)
1036                 {
1037                         fprintf(stderr, 
1038                 "ERROR: cannot set \"%s\" information into \"%s\".\n", 
1039                                 second_path, first_path);
1040                         free(first_path);
1041                         free(second_path);
1042                         free(config);
1043                         free(configuration);
1044                         return 21;
1045                 }
1046                 free(second_path);
1047
1048                 close(fd);
1049
1050                 /* copy first level to boot block */
1051
1052                 ret = copy_file_to_bootblock(first_path, partition);
1053                 if (ret == -1)
1054                 {
1055                         fprintf(stderr,
1056                 "ERROR: cannot write \"%s\" to bootblock of \"%s\".\n", 
1057                                         first_path, partition);
1058                         fprintf(stderr,
1059                 "       %s\n", strerror(errno));
1060                         free(first_path);
1061                         free(config);
1062                         free(configuration);
1063                         return 22;
1064                 }
1065                 free(first_path);
1066
1067                 /* set HFS if needed */
1068
1069                 if (action & ACTION_SET_HFS)
1070                 {
1071                         ret = set_HFS(partition);
1072                         if (ret == -1)
1073                         {
1074                                 fprintf( stderr, 
1075                         "ERROR: cannot set partition type of \"%s\" to Apple_HFS.\n"
1076                                         , partition);
1077                                 free(config);
1078                                 free(configuration);
1079                                 return 23;
1080                         }
1081                 }
1082         }
1083         
1084         free(partition);
1085         free(config);
1086         free(configuration);
1087         return 0;
1088 }