Home | History | Annotate | Download | only in utils
      1 /*
      2  * isohybrid.c: Post process an ISO 9660 image generated with mkisofs or
      3  * genisoimage to allow - hybrid booting - as a CD-ROM or as a hard
      4  * disk.
      5  *
      6  * This is based on the original Perl script written by H. Peter Anvin. The
      7  * rewrite in C is to avoid dependency on Perl on a system under installation.
      8  *
      9  * Copyright (C) 2010 P J P <pj.pandit (at) yahoo.co.in>
     10  *
     11  * isohybrid is a free software; you can redistribute it and/or modify it
     12  * under the terms of GNU General Public License as published by Free Software
     13  * Foundation; either version 2 of the license, or (at your option) any later
     14  * version.
     15  *
     16  * isohybrid is distributed in the hope that it will be useful, but WITHOUT
     17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     18  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
     19  * more details.
     20  *
     21  * You should have received a copy of the GNU General Public License along
     22  * with isohybrid; if not, see: <http://www.gnu.org/licenses>.
     23  *
     24  */
     25 
     26 #define _FILE_OFFSET_BITS 64
     27 #include <err.h>
     28 #include <time.h>
     29 #include <ctype.h>
     30 #include <fcntl.h>
     31 #include <stdio.h>
     32 #include <alloca.h>
     33 #include <getopt.h>
     34 #include <signal.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <unistd.h>
     38 #include <sys/stat.h>
     39 #include <inttypes.h>
     40 #include <uuid/uuid.h>
     41 
     42 #include "isohybrid.h"
     43 
     44 char *prog = NULL;
     45 extern int opterr, optind;
     46 struct stat isostat;
     47 unsigned int padding = 0;
     48 
     49 uuid_t disk_uuid, part_uuid, iso_uuid;
     50 
     51 uint8_t mode = 0;
     52 enum { VERBOSE = 1 , EFI = 2 , MAC = 4};
     53 
     54 /* user options */
     55 uint16_t head = 64;             /* 1 <= head <= 256 */
     56 uint8_t sector = 32;            /* 1 <= sector <= 63  */
     57 
     58 uint8_t entry = 0;              /* partition number: 1 <= entry <= 4 */
     59 uint8_t offset = 0;             /* partition offset: 0 <= offset <= 64 */
     60 uint16_t type = 0x17;           /* partition type: 0 <= type <= 255 */
     61 uint32_t id = 0;                /* MBR: 0 <= id <= 0xFFFFFFFF(4294967296) */
     62 
     63 uint8_t hd0 = 0;                /* 0 <= hd0 <= 2 */
     64 uint8_t partok = 0;             /* 0 <= partok <= 1 */
     65 
     66 char mbr_template_path[1024] = {0};   /* Path to MBR template */
     67 
     68 uint16_t ve[16];
     69 uint32_t catoffset = 0;
     70 uint32_t c = 0, cc = 0, cs = 0;
     71 
     72 uint32_t psize = 0, isosize = 0;
     73 
     74 /* boot catalogue parameters */
     75 uint32_t de_lba = 0;
     76 uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0;
     77 uint8_t de_boot = 0, de_media = 0, de_sys = 0, de_mbz1 = 0;
     78 uint32_t efi_lba = 0, mac_lba = 0;
     79 uint16_t efi_count = 0, mac_count = 0;
     80 uint8_t efi_boot = 0, efi_media = 0, efi_sys = 0;
     81 
     82 int apm_parts = 3;
     83 
     84 uint8_t afp_header[] = { 0x45, 0x52, 0x08, 0x00, 0x00, 0x00, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
     85 
     86 uuid_t efi_system_partition = {0xC1, 0x2A, 0x73, 0x28, 0xF8, 0x1F, 0x11, 0xD2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B};
     87 uuid_t basic_partition = {0xEB,0xD0,0xA0,0xA2,0xB9,0xE5,0x44,0x33,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
     88 uuid_t hfs_partition = {0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xAA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
     89 
     90 uint32_t crc_tab[256] =
     91 {
     92     0, 0x77073096, 0xEE0E612C, 0x990951BA,
     93     0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
     94     0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
     95     0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
     96     0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
     97     0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
     98     0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
     99     0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
    100     0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
    101     0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
    102     0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
    103     0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    104     0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
    105     0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
    106     0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
    107     0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
    108     0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
    109     0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    110     0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
    111     0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
    112     0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
    113     0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
    114     0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
    115     0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    116     0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
    117     0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
    118     0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
    119     0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
    120     0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
    121     0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    122     0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
    123     0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
    124     0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
    125     0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
    126     0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
    127     0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    128     0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
    129     0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
    130     0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
    131     0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
    132     0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
    133     0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    134     0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
    135     0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
    136     0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
    137     0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
    138     0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
    139     0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    140     0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
    141     0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
    142     0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
    143     0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
    144     0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
    145     0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    146     0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
    147     0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
    148     0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
    149     0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
    150     0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
    151     0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    152     0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
    153     0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
    154     0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
    155     0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
    156 };
    157 
    158 struct iso_primary_descriptor {
    159     uint8_t ignore [80];
    160     uint32_t size;
    161     uint8_t ignore2 [44];
    162     uint16_t block_size;
    163 };
    164 
    165 struct gpt_header {
    166     uint64_t signature;
    167     uint32_t revision;
    168     uint32_t headerSize;
    169     uint32_t headerCRC;
    170     uint32_t reserved;
    171     uint64_t currentLBA;
    172     uint64_t backupLBA;
    173     uint64_t firstUsableLBA;
    174     uint64_t lastUsableLBA;
    175     uuid_t diskGUID;
    176     uint64_t partitionEntriesLBA;
    177     uint32_t numParts;
    178     uint32_t sizeOfPartitionEntries;
    179     uint32_t partitionEntriesCRC;
    180     uint8_t reserved2[420];
    181 };
    182 
    183 struct gpt_part_header {
    184     uuid_t partTypeGUID;
    185     uuid_t partGUID;
    186     uint64_t firstLBA;
    187     uint64_t lastLBA;
    188     uint64_t attributes;
    189     uint16_t name[36];
    190 };
    191 
    192 #define APM_OFFSET 2048
    193 
    194 struct apple_part_header {
    195     uint16_t        signature;      /* expected to be MAC_PARTITION_MAGIC */
    196     uint16_t        res1;
    197     uint32_t        map_count;      /* # blocks in partition map */
    198     uint32_t        start_block;    /* absolute starting block # of partition */
    199     uint32_t        block_count;    /* number of blocks in partition */
    200     char            name[32];       /* partition name */
    201     char            type[32];       /* string type description */
    202     uint32_t        data_start;     /* rel block # of first data block */
    203     uint32_t        data_count;     /* number of data blocks */
    204     uint32_t        status;         /* partition status bits */
    205     uint32_t        boot_start;
    206     uint32_t        boot_count;
    207     uint32_t        boot_load;
    208     uint32_t        boot_load2;
    209     uint32_t        boot_entry;
    210     uint32_t        boot_entry2;
    211     uint32_t        boot_cksum;
    212     char            processor[16];  /* Contains 680x0, x=0,2,3,4; or empty */
    213     uint32_t        driver_sig;
    214     char            _padding[372];
    215 };
    216 
    217 
    218 void
    219 usage(void)
    220 {
    221     printf("Usage: %s [OPTIONS] <boot.iso>\n", prog);
    222 }
    223 
    224 
    225 void
    226 printh(void)
    227 {
    228 #define FMT "%-20s %s\n"
    229 
    230     usage();
    231 
    232     printf("\n");
    233     printf("Options:\n");
    234     printf(FMT, "   -h <X>", "Number of geometry heads (default 64)");
    235     printf(FMT, "   -s <X>", "Number of geometry sectors (default 32)");
    236     printf(FMT, "   -e --entry", "Specify partition entry number (1-4)");
    237     printf(FMT, "   -o --offset", "Specify partition offset (default 0)");
    238     printf(FMT, "   -t --type", "Specify partition type (default 0x17)");
    239     printf(FMT, "   -i --id", "Specify MBR ID (default random)");
    240     printf(FMT, "   -u --uefi", "Build EFI bootable image");
    241     printf(FMT, "   -m --mac", "Add AFP table support");
    242     printf(FMT, "   -b --mbr <PATH>", "Load MBR from PATH");
    243 
    244     printf("\n");
    245     printf(FMT, "   --forcehd0", "Assume we are loaded as disk ID 0");
    246     printf(FMT, "   --ctrlhd0", "Assume disk ID 0 if the Ctrl key is pressed");
    247     printf(FMT, "   --partok", "Allow booting from within a partition");
    248 
    249     printf("\n");
    250     printf(FMT, "   -? --help", "Display this help");
    251     printf(FMT, "   -v --verbose", "Display verbose output");
    252     printf(FMT, "   -V --version", "Display version information");
    253 
    254     printf("\n");
    255     printf("Report bugs to <pj.pandit (at) yahoo.co.in>\n");
    256 }
    257 
    258 
    259 int
    260 check_option(int argc, char *argv[])
    261 {
    262     char *err = NULL;
    263     int n = 0, ind = 0;
    264 
    265     const char optstr[] = ":h:s:e:o:t:i:b:umfcp?vV";
    266     struct option lopt[] = \
    267     {
    268         { "entry", required_argument, NULL, 'e' },
    269         { "offset", required_argument, NULL, 'o' },
    270         { "type", required_argument, NULL, 't' },
    271         { "id", required_argument, NULL, 'i' },
    272 
    273         { "forcehd0", no_argument, NULL, 'f' },
    274         { "ctrlhd0", no_argument, NULL, 'c' },
    275         { "partok", no_argument, NULL, 'p'},
    276 	{ "uefi", no_argument, NULL, 'u'},
    277 	{ "mac", no_argument, NULL, 'm'},
    278         { "mbr", required_argument, NULL, 'b' },
    279 
    280         { "help", no_argument, NULL, '?' },
    281         { "verbose", no_argument, NULL, 'v' },
    282         { "version", no_argument, NULL, 'V' },
    283 
    284         { 0, 0, 0, 0 }
    285     };
    286 
    287     opterr = mode = 0;
    288     while ((n = getopt_long_only(argc, argv, optstr, lopt, &ind)) != -1)
    289     {
    290         switch (n)
    291         {
    292         case 'h':
    293             head = strtoul(optarg, &err, 0);
    294             if (head < 1 || head > 256)
    295                 errx(1, "invalid head: `%s', 1 <= head <= 256", optarg);
    296             break;
    297 
    298         case 's':
    299             sector = strtoul(optarg, &err, 0);
    300             if (sector < 1 || sector > 63)
    301                 errx(1, "invalid sector: `%s', 1 <= sector <= 63", optarg);
    302             break;
    303 
    304         case 'e':
    305             entry = strtoul(optarg, &err, 0);
    306             if (entry < 1 || entry > 4)
    307                 errx(1, "invalid entry: `%s', 1 <= entry <= 4", optarg);
    308 	    if (mode & MAC || mode & EFI)
    309 		errx(1, "setting an entry is unsupported with EFI or Mac");
    310             break;
    311 
    312         case 'o':
    313             offset = strtoul(optarg, &err, 0);
    314             if (*err || offset > 64)
    315                 errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg);
    316             break;
    317 
    318         case 't':
    319             type = strtoul(optarg, &err, 0);
    320             if (*err || type > 255)
    321                 errx(1, "invalid type: `%s', 0 <= type <= 255", optarg);
    322             break;
    323 
    324         case 'i':
    325             id = strtoul(optarg, &err, 0);
    326             if (*err)
    327                 errx(1, "invalid id: `%s'", optarg);
    328             break;
    329 
    330         case 'f':
    331             hd0 = 1;
    332             break;
    333 
    334         case 'c':
    335             hd0 = 2;
    336             break;
    337 
    338         case 'p':
    339             partok = 1;
    340             break;
    341 
    342 	case 'u':
    343 	    mode |= EFI;
    344 	    if (entry)
    345 		errx(1, "setting an entry is unsupported with EFI or Mac");
    346 	    break;
    347 
    348 	case 'm':
    349 	    mode |= MAC;
    350 	    if (entry)
    351 		errx(1, "setting an entry is unsupported with EFI or Mac");
    352 	    break;
    353 
    354 	case 'b':
    355             if (strlen(optarg) >= sizeof(mbr_template_path))
    356                 errx(1, "--mbr : Path too long");
    357             strcpy(mbr_template_path, optarg);
    358             break;
    359 
    360         case 'v':
    361             mode |= VERBOSE;
    362             break;
    363 
    364         case 'V':
    365             printf("%s version %s\n", prog, VERSION);
    366             exit(0);
    367 
    368         case ':':
    369             errx(1, "option `-%c' takes an argument", optopt);
    370 
    371         default:
    372         case '?':
    373             if (optopt)
    374                 errx(1, "invalid option `-%c', see --help", optopt);
    375 
    376             printh();
    377             exit(0);
    378         }
    379     }
    380 
    381     return optind;
    382 }
    383 
    384 uint16_t
    385 bendian_short(const uint16_t s)
    386 {
    387     uint16_t r = 1;
    388 
    389     if (!*(uint8_t *)&r)
    390         return s;
    391 
    392     r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
    393 
    394     return r;
    395 }
    396 
    397 
    398 uint32_t
    399 bendian_int(const uint32_t s)
    400 {
    401     uint32_t r = 1;
    402 
    403     if (!*(uint8_t *)&r)
    404         return s;
    405 
    406     r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
    407         | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
    408 
    409     return r;
    410 }
    411 
    412 uint16_t
    413 lendian_short(const uint16_t s)
    414 {
    415     uint16_t r = 1;
    416 
    417     if (*(uint8_t *)&r)
    418         return s;
    419 
    420     r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
    421 
    422     return r;
    423 }
    424 
    425 
    426 uint32_t
    427 lendian_int(const uint32_t s)
    428 {
    429     uint32_t r = 1;
    430 
    431     if (*(uint8_t *)&r)
    432         return s;
    433 
    434     r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
    435         | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
    436 
    437     return r;
    438 }
    439 
    440 uint64_t
    441 lendian_64(const uint64_t s)
    442 {
    443 	uint64_t r = 1;
    444 
    445 	if (*(uint8_t *)&r)
    446 		return s;
    447 
    448        r = (s & 0x00000000000000FFull) << 56 | (s & 0xFF00000000000000ull) >> 56
    449             | (s & 0x000000000000FF00ull) << 40 | (s & 0x00FF000000000000ull) >> 40
    450             | (s & 0x0000000000FF0000ull) << 24 | (s & 0x0000FF0000000000ull) >> 24
    451             | (s & 0x00000000FF000000ull) << 8 | (s & 0x000000FF00000000ull) >> 8;
    452 
    453 	return r;
    454 }
    455 
    456 
    457 int
    458 check_banner(const uint8_t *buf)
    459 {
    460     static const char banner[] = "\0CD001\1EL TORITO SPECIFICATION\0\0\0\0" \
    461         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
    462         "\0\0\0\0\0";
    463 
    464     if (!buf || memcmp(buf, banner, sizeof(banner) - 1))
    465         return 1;
    466 
    467     buf += sizeof(banner) - 1;
    468     memcpy(&catoffset, buf, sizeof(catoffset));
    469 
    470     catoffset = lendian_int(catoffset);
    471 
    472     return 0;
    473 }
    474 
    475 
    476 int
    477 check_catalogue(const uint8_t *buf)
    478 {
    479     int i = 0;
    480 
    481     for (i = 0, cs = 0; i < 16; i++)
    482     {
    483         ve[i] = 0;
    484         memcpy(&ve[i], buf, sizeof(ve[i]));
    485 
    486         ve[i] = lendian_short(ve[i]);
    487 
    488         buf += 2;
    489         cs += ve[i];
    490 
    491         if (mode & VERBOSE)
    492             printf("ve[%d]: %d, cs: %d\n", i, ve[i], cs);
    493     }
    494     if ((ve[0] != 0x0001) || (ve[15] != 0xAA55) || (cs & 0xFFFF))
    495         return 1;
    496 
    497     return 0;
    498 }
    499 
    500 
    501 int
    502 read_catalogue(const uint8_t *buf)
    503 {
    504     memcpy(&de_boot, buf++, 1);
    505     memcpy(&de_media, buf++, 1);
    506 
    507     memcpy(&de_seg, buf, 2);
    508     de_seg = lendian_short(de_seg);
    509     buf += 2;
    510 
    511     memcpy(&de_sys, buf++, 1);
    512     memcpy(&de_mbz1, buf++, 1);
    513 
    514     memcpy(&de_count, buf, 2);
    515     de_count = lendian_short(de_count);
    516     buf += 2;
    517 
    518     memcpy(&de_lba, buf, 4);
    519     de_lba = lendian_int(de_lba);
    520     buf += 4;
    521 
    522     memcpy(&de_mbz2, buf, 2);
    523     de_mbz2 = lendian_short(de_mbz2);
    524     buf += 2;
    525 
    526     if (de_boot != 0x88 || de_media != 0
    527         || (de_seg != 0 && de_seg != 0x7C0) || de_count != 4)
    528         return 1;
    529 
    530     return 0;
    531 }
    532 
    533 
    534 int
    535 read_efi_section(const uint8_t *buf)
    536 {
    537 	unsigned char header_indicator;
    538 	unsigned char platform_id;
    539 	short count;
    540 
    541 	memcpy(&header_indicator, buf++, 1);
    542 	memcpy(&platform_id, buf++, 1);
    543 
    544 	memcpy(&count, buf, 2);
    545 	count = lendian_short(count);
    546 	buf += 2;
    547 
    548 	if (platform_id == 0xef)
    549 		return 0;
    550 
    551 	return 1;
    552 }
    553 
    554 int
    555 read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
    556 {
    557     buf += 6;
    558 
    559     memcpy(count, buf, 2);
    560     *count = lendian_short(*count);
    561     buf += 2;
    562 
    563     memcpy(lba, buf, 4);
    564     *lba = lendian_int(*lba);
    565     buf += 6;
    566 
    567     return 0;
    568 }
    569 
    570 
    571 void
    572 display_catalogue(void)
    573 {
    574     printf("de_boot: %hhu\n", de_boot);
    575     printf("de_media: %hhu\n", de_media);
    576     printf("de_seg: %hu\n", de_seg);
    577     printf("de_sys: %hhu\n", de_sys);
    578     printf("de_mbz1: %hhu\n", de_mbz1);
    579     printf("de_count: %hu\n", de_count);
    580     printf("de_lba: %u\n", de_lba);
    581     printf("de_mbz2: %hu\n", de_mbz2);
    582 }
    583 
    584 
    585 void
    586 read_mbr_template(char *path, uint8_t *mbr)
    587 {
    588     FILE *fp;
    589     int ret;
    590 
    591     fp = fopen(path, "rb");
    592     if (fp == NULL)
    593         err(1, "could not open MBR template file `%s'", path);
    594     clearerr(fp);
    595     ret = fread(mbr, 1, MBRSIZE, fp);
    596     if (ferror(fp) || ret != MBRSIZE)
    597         err(1, "error while reading MBR template file `%s'", path);
    598     fclose(fp);
    599 }
    600 
    601 
    602 int
    603 initialise_mbr(uint8_t *mbr)
    604 {
    605     int i = 0;
    606     uint32_t tmp = 0;
    607     uint8_t ptype = 0, *rbm = mbr;
    608     uint8_t bhead = 0, bsect = 0, bcyle = 0;
    609     uint8_t ehead = 0, esect = 0, ecyle = 0;
    610 
    611 #ifndef ISOHYBRID_C_STANDALONE
    612     extern unsigned char isohdpfx[][MBRSIZE];
    613 #endif
    614 
    615     if (mbr_template_path[0]) {
    616         read_mbr_template(mbr_template_path, mbr);
    617     } else {
    618 
    619 #ifdef ISOHYBRID_C_STANDALONE
    620 
    621         err(1, "This is a standalone binary. You must specify --mbr. E.g with /usr/lib/syslinux/isohdpfx.bin");
    622 
    623 #else
    624 
    625         memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE);
    626 
    627 #endif /* ! ISOHYBRID_C_STANDALONE */
    628 
    629     }
    630 
    631     if (mode & MAC) {
    632 	memcpy(mbr, afp_header, sizeof(afp_header));
    633     }
    634 
    635     if (!entry)
    636 	entry = 1;
    637 
    638     if (mode & EFI)
    639 	type = 0;
    640 
    641     mbr += MBRSIZE;                                 /* offset 432 */
    642 
    643     tmp = lendian_int(de_lba * 4);
    644     memcpy(mbr, &tmp, sizeof(tmp));
    645     mbr += sizeof(tmp);                             /* offset 436 */
    646 
    647     tmp = 0;
    648     memcpy(mbr, &tmp, sizeof(tmp));
    649     mbr += sizeof(tmp);                             /* offset 440 */
    650 
    651     tmp = lendian_int(id);
    652     memcpy(mbr, &tmp, sizeof(tmp));
    653     mbr += sizeof(tmp);                             /* offset 444 */
    654 
    655     mbr[0] = '\0';
    656     mbr[1] = '\0';
    657     mbr += 2;                                       /* offset 446 */
    658 
    659     ptype = type;
    660     psize = c * head * sector - offset;
    661 
    662     bhead = (offset / sector) % head;
    663     bsect = (offset % sector) + 1;
    664     bcyle = offset / (head * sector);
    665 
    666     bsect += (bcyle & 0x300) >> 2;
    667     bcyle  &= 0xFF;
    668 
    669     ehead = head - 1;
    670     esect = sector + (((cc - 1) & 0x300) >> 2);
    671     ecyle = (cc - 1) & 0xFF;
    672 
    673     for (i = 1; i <= 4; i++)
    674     {
    675         memset(mbr, 0, 16);
    676         if (i == entry)
    677         {
    678             mbr[0] = 0x80;
    679             mbr[1] = bhead;
    680             mbr[2] = bsect;
    681             mbr[3] = bcyle;
    682             mbr[4] = ptype;
    683             mbr[5] = ehead;
    684             mbr[6] = esect;
    685             mbr[7] = ecyle;
    686 
    687             tmp = lendian_int(offset);
    688             memcpy(&mbr[8], &tmp, sizeof(tmp));
    689 
    690             tmp = lendian_int(psize);
    691             memcpy(&mbr[12], &tmp, sizeof(tmp));
    692         }
    693         if (i == 2 && (mode & EFI))
    694         {
    695             mbr[0] = 0x0;
    696             mbr[1] = 0xfe;
    697             mbr[2] = 0xff;
    698             mbr[3] = 0xff;
    699             mbr[4] = 0xef;
    700             mbr[5] = 0xfe;
    701             mbr[6] = 0xff;
    702             mbr[7] = 0xff;
    703 
    704             tmp = lendian_int(efi_lba * 4);
    705             memcpy(&mbr[8], &tmp, sizeof(tmp));
    706 
    707             tmp = lendian_int(efi_count);
    708             memcpy(&mbr[12], &tmp, sizeof(tmp));
    709         }
    710         if (i == 3 && (mode & MAC))
    711         {
    712             mbr[0] = 0x0;
    713             mbr[1] = 0xfe;
    714             mbr[2] = 0xff;
    715             mbr[3] = 0xff;
    716             mbr[4] = 0x0;
    717             mbr[5] = 0xfe;
    718             mbr[6] = 0xff;
    719             mbr[7] = 0xff;
    720 
    721             tmp = lendian_int(mac_lba * 4);
    722             memcpy(&mbr[8], &tmp, sizeof(tmp));
    723 
    724             tmp = lendian_int(mac_count);
    725             memcpy(&mbr[12], &tmp, sizeof(tmp));
    726         }
    727         mbr += 16;
    728     }
    729     mbr[0] = 0x55;
    730     mbr[1] = 0xAA;
    731     mbr += 2;
    732 
    733     return mbr - rbm;
    734 }
    735 
    736 void
    737 display_mbr(const uint8_t *mbr, size_t len)
    738 {
    739     unsigned char c = 0;
    740     unsigned int i = 0, j = 0;
    741 
    742     printf("sizeof(MBR): %zu bytes\n", len);
    743     for (i = 0; i < len; i++)
    744     {
    745         if (!(i % 16))
    746             printf("%04d ", i);
    747 
    748         if (!(i % 8))
    749             printf(" ");
    750 
    751         c = mbr[i];
    752         printf("%02x ", c);
    753 
    754         if (!((i + 1) % 16))
    755         {
    756             printf(" |");
    757             for (; j <= i; j++)
    758                 printf("%c", isprint(mbr[j]) ? mbr[j] : '.');
    759             printf("|\n");
    760         }
    761     }
    762 }
    763 
    764 
    765 uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
    766 {
    767 	register unsigned long crc;
    768 	unsigned long i;
    769 
    770 	crc = 0xFFFFFFFF;
    771 	for (i = 0; i < length; i++)
    772 	{
    773 		crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
    774 	}
    775 	return (crc ^ 0xFFFFFFFF);
    776 }
    777 
    778 void
    779 reverse_uuid(uuid_t uuid)
    780 {
    781 	uint8_t t, *p = (uint8_t *)uuid;
    782 
    783 	t = p[0]; p[0] = p[3]; p[3] = t;
    784 	t = p[1]; p[1] = p[2]; p[2] = t;
    785 	t = p[4]; p[4] = p[5]; p[5] = t;
    786 	t = p[6]; p[6] = p[7]; p[7] = t;
    787 }
    788 
    789 static uint16_t *
    790 ascii_to_utf16le(uint16_t *dst, const char *src)
    791 {
    792     uint8_t *p = (uint8_t *)dst;
    793     char c;
    794 
    795     do {
    796 	c = *src++;
    797 	*p++ = c;
    798 	*p++ = 0;
    799     } while (c);
    800 
    801     return (uint16_t *)p;
    802 }
    803 
    804 void
    805 initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary)
    806 {
    807     struct gpt_header *header = (struct gpt_header *)gpt;
    808     struct gpt_part_header *part;
    809     int hole = 0;
    810     int gptsize = 128 / 4 + 2;
    811 
    812     if (mac_lba) {
    813 	/* 2048 bytes per partition, plus round to 2048 boundary */
    814 	hole = (apm_parts * 4) + 2;
    815     }
    816 
    817     if (primary) {
    818 	uuid_generate(disk_uuid);
    819 	reverse_uuid(disk_uuid);
    820     }
    821 
    822     header->signature = lendian_64(0x5452415020494645ull);
    823     header->revision = lendian_int(0x010000);
    824     header->headerSize = lendian_int(0x5c);
    825     header->currentLBA = lendian_64(current);
    826     header->backupLBA = lendian_64(alternate);
    827     header->firstUsableLBA = lendian_64(gptsize + hole);
    828     header->lastUsableLBA = lendian_64((isostat.st_size + padding)/512 -
    829 				       gptsize);
    830     if (primary)
    831 	header->partitionEntriesLBA = lendian_64(0x02 + hole);
    832     else
    833 	header->partitionEntriesLBA = lendian_64(current - (128 / 4));
    834     header->numParts = lendian_int(0x80);
    835     header->sizeOfPartitionEntries = lendian_int(0x80);
    836     memcpy(header->diskGUID, disk_uuid, sizeof(uuid_t));
    837 
    838     if (primary)
    839 	gpt += sizeof(struct gpt_header) + hole * 512;
    840     else
    841 	gpt -= header->sizeOfPartitionEntries * header->numParts;
    842 
    843     part = (struct gpt_part_header *)gpt;
    844     if (primary) {
    845 	uuid_generate(part_uuid);
    846 	uuid_generate(iso_uuid);
    847 	reverse_uuid(part_uuid);
    848 	reverse_uuid(iso_uuid);
    849     }
    850 
    851     memcpy(part->partGUID, iso_uuid, sizeof(uuid_t));
    852     memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
    853     part->firstLBA = lendian_64(0);
    854     part->lastLBA = lendian_64(psize - 1);
    855     ascii_to_utf16le(part->name, "ISOHybrid ISO");
    856 
    857     gpt += sizeof(struct gpt_part_header);
    858     part++;
    859 
    860     memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
    861     memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
    862     part->firstLBA = lendian_64(efi_lba * 4);
    863     part->lastLBA = lendian_64(part->firstLBA + efi_count - 1);
    864     ascii_to_utf16le(part->name, "ISOHybrid");
    865 
    866     gpt += sizeof(struct gpt_part_header);
    867 
    868     if (mac_lba) {
    869 	gpt += sizeof(struct gpt_part_header);
    870 
    871 	part++;
    872 
    873 	memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
    874 	memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t));
    875 	part->firstLBA = lendian_64(mac_lba * 4);
    876 	part->lastLBA = lendian_64(part->firstLBA + mac_count - 1);
    877 	ascii_to_utf16le(part->name, "ISOHybrid");
    878 
    879 	part--;
    880     }
    881 
    882     part--;
    883 
    884     header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part,
    885 			   header->numParts * header->sizeOfPartitionEntries));
    886 
    887     header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header,
    888 						 header->headerSize));
    889 }
    890 
    891 void
    892 initialise_apm(uint8_t *gpt, uint32_t start)
    893 {
    894     struct apple_part_header *part = (struct apple_part_header *)gpt;
    895 
    896     part->signature = bendian_short(0x504d);
    897     part->map_count = bendian_int(apm_parts);
    898     part->start_block = bendian_int(1);
    899     part->block_count = bendian_int(4);
    900     strcpy(part->name, "Apple");
    901     strcpy(part->type, "Apple_partition_map");
    902     part->data_start = bendian_int(0);
    903     part->data_count = bendian_int(10);
    904     part->status = bendian_int(0x03);
    905 
    906     part = (struct apple_part_header *)(gpt + 2048);
    907 
    908     part->signature = bendian_short(0x504d);
    909     part->map_count = bendian_int(3);
    910     part->start_block = bendian_int(efi_lba);
    911     part->block_count = bendian_int(efi_count / 4);
    912     strcpy(part->name, "EFI");
    913     strcpy(part->type, "Apple_HFS");
    914     part->data_start = bendian_int(0);
    915     part->data_count = bendian_int(efi_count / 4);
    916     part->status = bendian_int(0x33);
    917 
    918     part = (struct apple_part_header *)(gpt + 4096);
    919 
    920     if (mac_lba)
    921     {
    922 	part->signature = bendian_short(0x504d);
    923 	part->map_count = bendian_int(3);
    924 	part->start_block = bendian_int(mac_lba);
    925 	part->block_count = bendian_int(mac_count / 4);
    926 	strcpy(part->name, "EFI");
    927 	strcpy(part->type, "Apple_HFS");
    928 	part->data_start = bendian_int(0);
    929 	part->data_count = bendian_int(mac_count / 4);
    930 	part->status = bendian_int(0x33);
    931     } else {
    932 	part->signature = bendian_short(0x504d);
    933 	part->map_count = bendian_int(3);
    934 	part->start_block = bendian_int((start/2048) + 10);
    935 	part->block_count = bendian_int(efi_lba - start/2048 - 10);
    936 	strcpy(part->name, "ISO");
    937 	strcpy(part->type, "Apple_Free");
    938 	part->data_start = bendian_int(0);
    939 	part->data_count = bendian_int(efi_lba - start/2048 - 10);
    940 	part->status = bendian_int(0x01);
    941     }
    942 }
    943 
    944 int
    945 main(int argc, char *argv[])
    946 {
    947     int i = 0;
    948     FILE *fp = NULL;
    949     uint8_t *buf = NULL, *bufz = NULL;
    950     int cylsize = 0, frac = 0;
    951     size_t orig_gpt_size, free_space, gpt_size;
    952     struct iso_primary_descriptor descriptor;
    953 
    954     prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
    955     i = check_option(argc, argv);
    956     argc -= i;
    957     argv += i;
    958 
    959     if (!argc)
    960     {
    961         usage();
    962         return 1;
    963     }
    964 
    965     if ((mode & EFI) && offset)
    966 	errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
    967 
    968     srand(time(NULL) << (getppid() << getpid()));
    969 
    970     if (!(fp = fopen(argv[0], "r+")))
    971         err(1, "could not open file `%s'", argv[0]);
    972 
    973     if (fseeko(fp, (off_t) (16 << 11), SEEK_SET))
    974         err(1, "%s: seek error - 0", argv[0]);
    975 
    976     if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
    977         err(1, "%s: read error - 0", argv[0]);
    978 
    979     if (fseeko(fp, (off_t) 17 * 2048, SEEK_SET))
    980         err(1, "%s: seek error - 1", argv[0]);
    981 
    982     bufz = buf = calloc(BUFSIZE, sizeof(char));
    983     if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
    984         err(1, "%s", argv[0]);
    985 
    986     if (check_banner(buf))
    987         errx(1, "%s: could not find boot record", argv[0]);
    988 
    989     if (mode & VERBOSE)
    990         printf("catalogue offset: %d\n", catoffset);
    991 
    992     if (fseeko(fp, ((off_t) catoffset) * 2048, SEEK_SET))
    993         err(1, "%s: seek error - 2", argv[0]);
    994 
    995     buf = bufz;
    996     memset(buf, 0, BUFSIZE);
    997     if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
    998         err(1, "%s", argv[0]);
    999 
   1000     if (check_catalogue(buf))
   1001         errx(1, "%s: invalid boot catalogue", argv[0]);
   1002 
   1003     buf += sizeof(ve);
   1004     if (read_catalogue(buf))
   1005         errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
   1006 
   1007     if (mode & VERBOSE)
   1008         display_catalogue();
   1009 
   1010     buf += 32;
   1011 
   1012     if (mode & EFI)
   1013     {
   1014 	if (!read_efi_section(buf)) {
   1015 	    buf += 32;
   1016 	    if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
   1017 		offset = 0;
   1018 	    } else {
   1019 		errx(1, "%s: invalid efi catalogue", argv[0]);
   1020 	    }
   1021 	} else {
   1022 	    errx(1, "%s: unable to find efi image", argv[0]);
   1023 	}
   1024     }
   1025 
   1026     buf += 32;
   1027 
   1028     if (mode & MAC)
   1029     {
   1030 	if (!read_efi_section(buf)) {
   1031 	    buf += 32;
   1032 	    if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
   1033 		offset = 0;
   1034 	    } else {
   1035 		errx(1, "%s: invalid efi catalogue", argv[0]);
   1036 	    }
   1037 	} else {
   1038 	    errx(1, "%s: unable to find mac efi image", argv[0]);
   1039 	}
   1040     }
   1041 
   1042     if (fseeko(fp, (((off_t) de_lba) * 2048 + 0x40), SEEK_SET))
   1043         err(1, "%s: seek error - 3", argv[0]);
   1044 
   1045     buf = bufz;
   1046     memset(buf, 0, BUFSIZE);
   1047     if (fread(buf, sizeof(char), 4, fp) != 4)
   1048         err(1, "%s", argv[0]);
   1049 
   1050     if (memcmp(buf, "\xFB\xC0\x78\x70", 4))
   1051         errx(1, "%s: boot loader does not have an isolinux.bin hybrid " \
   1052                  "signature. Note that isolinux-debug.bin does not support " \
   1053                  "hybrid booting", argv[0]);
   1054 
   1055     if (stat(argv[0], &isostat))
   1056         err(1, "%s", argv[0]);
   1057 
   1058     isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
   1059     free_space = isostat.st_size - isosize;
   1060 
   1061     cylsize = head * sector * 512;
   1062     frac = isostat.st_size % cylsize;
   1063     padding = (frac > 0) ? cylsize - frac : 0;
   1064 
   1065     if (mode & VERBOSE)
   1066         printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
   1067 
   1068     cc = c = ( isostat.st_size + padding) / cylsize;
   1069     if (c > 1024)
   1070     {
   1071         warnx("Warning: more than 1024 cylinders: %d", c);
   1072         warnx("Not all BIOSes will be able to boot this device");
   1073         cc = 1024;
   1074     }
   1075 
   1076     if (!id)
   1077     {
   1078         if (fseeko(fp, (off_t) 440, SEEK_SET))
   1079             err(1, "%s: seek error - 4", argv[0]);
   1080 
   1081 	if (fread(&id, 1, 4, fp) != 4)
   1082 	    err(1, "%s: read error", argv[0]);
   1083 
   1084         id = lendian_int(id);
   1085         if (!id)
   1086         {
   1087             if (mode & VERBOSE)
   1088                 printf("random ");
   1089             id = rand();
   1090         }
   1091     }
   1092     if (mode & VERBOSE)
   1093         printf("id: %u\n", id);
   1094 
   1095     buf = bufz;
   1096     memset(buf, 0, BUFSIZE);
   1097     i = initialise_mbr(buf);
   1098 
   1099     if (mode & VERBOSE)
   1100         display_mbr(buf, i);
   1101 
   1102     if (fseeko(fp, (off_t) 0, SEEK_SET))
   1103         err(1, "%s: seek error - 5", argv[0]);
   1104 
   1105     if (fwrite(buf, sizeof(char), i, fp) != (size_t)i)
   1106         err(1, "%s: write error - 1", argv[0]);
   1107 
   1108     if (efi_lba) {
   1109 	reverse_uuid(basic_partition);
   1110 	reverse_uuid(hfs_partition);
   1111 
   1112 	/* 512 byte header, 128 entries of 128 bytes */
   1113 	orig_gpt_size = gpt_size = 512 + (128 * 128);
   1114 
   1115 	/* Leave space for the APM if necessary */
   1116 	if (mac_lba)
   1117 	    gpt_size += (4 * 2048);
   1118 
   1119 	buf = calloc(gpt_size, sizeof(char));
   1120 	memset(buf, 0, gpt_size);
   1121 
   1122 	/*
   1123 	 * We need to ensure that we have enough space for the secondary GPT.
   1124 	 * Unlike the primary, this doesn't need a hole for the APM. We still
   1125 	 * want to be 1MB aligned so just bump the padding by a megabyte.
   1126 	 */
   1127 	if (free_space < orig_gpt_size && padding < orig_gpt_size) {
   1128 	    padding += 1024 * 1024;
   1129 	}
   1130 
   1131 	/*
   1132 	 * Determine the size of the ISO filesystem. This will define the size
   1133 	 * of the partition that covers it.
   1134 	 */
   1135 	psize = isosize / 512;
   1136 
   1137 	/*
   1138 	 * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
   1139 	 * before the end of the image
   1140 	 */
   1141 	initialise_gpt(buf, 1, (isostat.st_size + padding - 512) / 512, 1);
   1142 
   1143 	if (fseeko(fp, (off_t) 512, SEEK_SET))
   1144 	    err(1, "%s: seek error - 6", argv[0]);
   1145 
   1146 	if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size)
   1147 	    err(1, "%s: write error - 2", argv[0]);
   1148     }
   1149 
   1150     if (mac_lba)
   1151     {
   1152 	/* Apple partition entries filling 2048 bytes each */
   1153 	int apm_size = apm_parts * 2048;
   1154 
   1155 	buf = realloc(buf, apm_size);
   1156 	memset(buf, 0, apm_size);
   1157 
   1158 	initialise_apm(buf, APM_OFFSET);
   1159 
   1160 	fseeko(fp, (off_t) APM_OFFSET, SEEK_SET);
   1161 	fwrite(buf, sizeof(char), apm_size, fp);
   1162     }
   1163 
   1164     if (padding)
   1165     {
   1166         if (fsync(fileno(fp)))
   1167             err(1, "%s: could not synchronise", argv[0]);
   1168 
   1169         if (ftruncate(fileno(fp), isostat.st_size + padding))
   1170             err(1, "%s: could not add padding bytes", argv[0]);
   1171     }
   1172 
   1173     if (efi_lba) {
   1174 	buf = realloc(buf, orig_gpt_size);
   1175 	memset(buf, 0, orig_gpt_size);
   1176 
   1177 	buf += orig_gpt_size - sizeof(struct gpt_header);
   1178 
   1179 	initialise_gpt(buf, (isostat.st_size + padding - 512) / 512, 1, 0);
   1180 
   1181 	/* Shift back far enough to write the 128 GPT entries */
   1182 	buf -= 128 * sizeof(struct gpt_part_header);
   1183 
   1184 	/*
   1185 	 * Seek far enough back that the gpt header is 512 bytes before the
   1186 	 * end of the image
   1187 	 */
   1188 
   1189 	if (fseeko(fp, (isostat.st_size + padding) - orig_gpt_size, SEEK_SET))
   1190 	    err(1, "%s: seek error - 8", argv[0]);
   1191 
   1192 	if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
   1193 	    err(1, "%s: write error - 4", argv[0]);
   1194     }
   1195 
   1196     free(buf);
   1197     fclose(fp);
   1198 
   1199     return 0;
   1200 }
   1201