source: bootcd/isolinux/syslinux-6.03/extlinux/main.c @ e16e8f2

Last change on this file since e16e8f2 was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 37.9 KB
RevLine 
[e16e8f2]1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin
5 *
6 *   This program is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 *   Boston MA 02111-1307, USA; either version 2 of the License, or
10 *   (at your option) any later version; incorporated herein by reference.
11 *
12 * ----------------------------------------------------------------------- */
13
14/*
15 * extlinux.c
16 *
17 * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs, xfs,
18 * and ufs1/2 filesystem.
19 */
20
21#define  _GNU_SOURCE            /* Enable everything */
22#include <inttypes.h>
23/* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
24#include <alloca.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <dirent.h>
30#ifndef __KLIBC__
31#include <mntent.h>
32#endif
33#include <stdbool.h>
34#include <stddef.h>
35#include <stdlib.h>
36#include <string.h>
37#include <getopt.h>
38#include <sysexits.h>
39#include <sys/ioctl.h>
40#include <sys/stat.h>
41#include <sys/types.h>
42#include <sys/mount.h>
43#include <sys/vfs.h>
44
45#include "linuxioctl.h"
46
47#include "btrfs.h"
48#include "fat.h"
49#include "ntfs.h"
50#include "xfs.h"
51#include "xfs_types.h"
52#include "xfs_sb.h"
53#include "ufs.h"
54#include "ufs_fs.h"
55#include "misc.h"
56#include "version.h"
57#include "syslxint.h"
58#include "syslxcom.h" /* common functions shared with extlinux and syslinux */
59#include "syslxfs.h"
60#include "setadv.h"
61#include "syslxopt.h" /* unified options */
62#include "mountinfo.h"
63
64#ifdef DEBUG
65# define dprintf printf
66#else
67# define dprintf(...) ((void)0)
68#endif
69
70#ifndef EXT2_SUPER_OFFSET
71#define EXT2_SUPER_OFFSET 1024
72#endif
73
74/* Since we have unused 2048 bytes in the primary AG of an XFS partition,
75 * we will use the first 0~512 bytes starting from 2048 for the Syslinux
76 * boot sector.
77 */
78#define XFS_BOOTSECT_OFFSET     (4 << SECTOR_SHIFT)
79#define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
80
81/*
82 * btrfs has two discontiguous areas reserved for the boot loader.
83 * Use the first one (Boot Area A) for the boot sector and the ADV,
84 * and the second one for "ldlinux.sys".
85 */
86#define BTRFS_EXTLINUX_OFFSET   BTRFS_BOOT_AREA_B_OFFSET
87#define BTRFS_EXTLINUX_SIZE     BTRFS_BOOT_AREA_B_SIZE
88#define BTRFS_SUBVOL_MAX 256    /* By btrfs specification */
89static char subvol[BTRFS_SUBVOL_MAX];
90
91#define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \
92                          - 2*ADV_SIZE)
93
94/*
95 * Get the size of a block device
96 */
97static uint64_t get_size(int devfd)
98{
99    uint64_t bytes;
100    uint32_t sects;
101    struct stat st;
102
103#ifdef BLKGETSIZE64
104    if (!ioctl(devfd, BLKGETSIZE64, &bytes))
105        return bytes;
106#endif
107    if (!ioctl(devfd, BLKGETSIZE, &sects))
108        return (uint64_t) sects << 9;
109    else if (!fstat(devfd, &st) && st.st_size)
110        return st.st_size;
111    else
112        return 0;
113}
114
115/*
116 * Get device geometry and partition offset
117 */
118struct geometry_table {
119    uint64_t bytes;
120    struct hd_geometry g;
121};
122
123static int sysfs_get_offset(int devfd, unsigned long *start)
124{
125    struct stat st;
126    char sysfs_name[128];
127    FILE *f;
128    int rv;
129
130    if (fstat(devfd, &st))
131        return -1;
132
133    if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
134                         "/sys/dev/block/%u:%u/start",
135                         major(st.st_rdev), minor(st.st_rdev))
136        >= sizeof sysfs_name)
137        return -1;
138
139    f = fopen(sysfs_name, "r");
140    if (!f)
141        return -1;
142
143    rv = fscanf(f, "%lu", start);
144    fclose(f);
145
146    return (rv == 1) ? 0 : -1;
147}
148
149/* Standard floppy disk geometries, plus LS-120.  Zipdisk geometry
150   (x/64/32) is the final fallback.  I don't know what LS-240 has
151   as its geometry, since I don't have one and don't know anyone that does,
152   and Google wasn't helpful... */
153static const struct geometry_table standard_geometries[] = {
154    {360 * 1024, {2, 9, 40, 0}},
155    {720 * 1024, {2, 9, 80, 0}},
156    {1200 * 1024, {2, 15, 80, 0}},
157    {1440 * 1024, {2, 18, 80, 0}},
158    {1680 * 1024, {2, 21, 80, 0}},
159    {1722 * 1024, {2, 21, 80, 0}},
160    {2880 * 1024, {2, 36, 80, 0}},
161    {3840 * 1024, {2, 48, 80, 0}},
162    {123264 * 1024, {8, 32, 963, 0}},   /* LS120 */
163    {0, {0, 0, 0, 0}}
164};
165
166int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
167{
168    struct floppy_struct fd_str;
169    struct loop_info li;
170    struct loop_info64 li64;
171    const struct geometry_table *gp;
172    int rv = 0;
173
174    memset(geo, 0, sizeof *geo);
175
176    if (!ioctl(devfd, HDIO_GETGEO, geo)) {
177        goto ok;
178    } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
179        geo->heads = fd_str.head;
180        geo->sectors = fd_str.sect;
181        geo->cylinders = fd_str.track;
182        geo->start = 0;
183        goto ok;
184    }
185
186    /* Didn't work.  Let's see if this is one of the standard geometries */
187    for (gp = standard_geometries; gp->bytes; gp++) {
188        if (gp->bytes == totalbytes) {
189            memcpy(geo, &gp->g, sizeof *geo);
190            goto ok;
191        }
192    }
193
194    /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
195       what zipdisks use, so this would help if someone has a USB key that
196       they're booting in USB-ZIP mode. */
197
198    geo->heads = opt.heads ? : 64;
199    geo->sectors = opt.sectors ? : 32;
200    geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
201    geo->start = 0;
202
203    if (!opt.sectors && !opt.heads) {
204        fprintf(stderr,
205                "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
206                "         (on hard disks, this is usually harmless.)\n",
207                geo->heads, geo->sectors);
208        rv = 1;                 /* Suboptimal result */
209    }
210
211ok:
212    /* If this is a loopback device, try to set the start */
213    if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
214        geo->start = li64.lo_offset >> SECTOR_SHIFT;
215    else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
216        geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
217    else if (!sysfs_get_offset(devfd, &geo->start)) {
218        /* OK */
219    }
220
221    return rv;
222}
223
224/*
225 * Query the device geometry and put it into the boot sector.
226 * Map the file and put the map in the boot sector and file.
227 * Stick the "current directory" inode number into the file.
228 *
229 * Returns the number of modified bytes in the boot file.
230 */
231static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
232{
233    struct stat dirst, xdst;
234    struct hd_geometry geo;
235    sector_t *sectp;
236    uint64_t totalbytes, totalsectors;
237    int nsect;
238    struct fat_boot_sector *sbs;
239    char *dirpath, *subpath, *xdirpath;
240    int rv;
241
242    dirpath = realpath(dir, NULL);
243    if (!dirpath || stat(dir, &dirst)) {
244        perror("accessing install directory");
245        exit(255);              /* This should never happen */
246    }
247
248    if (lstat(dirpath, &xdst) ||
249        dirst.st_ino != xdst.st_ino ||
250        dirst.st_dev != xdst.st_dev) {
251        perror("realpath returned nonsense");
252        exit(255);
253    }
254
255    subpath = strchr(dirpath, '\0');
256    for (;;) {
257        if (*subpath == '/') {
258            if (subpath > dirpath) {
259                *subpath = '\0';
260                xdirpath = dirpath;
261            } else {
262                xdirpath = "/";
263            }
264            if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
265                subpath = strchr(subpath+1, '/');
266                if (!subpath)
267                    subpath = "/"; /* It's the root of the filesystem */
268                break;
269            }
270            *subpath = '/';
271        }
272
273        if (subpath == dirpath)
274            break;
275
276        subpath--;
277    }
278
279    /* Now subpath should contain the path relative to the fs base */
280    dprintf("subpath = %s\n", subpath);
281
282    totalbytes = get_size(devfd);
283    get_geometry(devfd, totalbytes, &geo);
284
285    if (opt.heads)
286        geo.heads = opt.heads;
287    if (opt.sectors)
288        geo.sectors = opt.sectors;
289
290    /* Patch this into a fake FAT superblock.  This isn't because
291       FAT is a good format in any way, it's because it lets the
292       early bootstrap share code with the FAT version. */
293    dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
294
295    sbs = (struct fat_boot_sector *)syslinux_bootsect;
296
297    totalsectors = totalbytes >> SECTOR_SHIFT;
298    if (totalsectors >= 65536) {
299        set_16(&sbs->bsSectors, 0);
300    } else {
301        set_16(&sbs->bsSectors, totalsectors);
302    }
303    set_32(&sbs->bsHugeSectors, totalsectors);
304
305    set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
306    set_16(&sbs->bsSecPerTrack, geo.sectors);
307    set_16(&sbs->bsHeads, geo.heads);
308    set_32(&sbs->bsHiddenSecs, geo.start);
309
310    /* Construct the boot file map */
311
312    dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
313    nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
314    nsect += 2;                 /* Two sectors for the ADV */
315    sectp = alloca(sizeof(sector_t) * nsect);
316    if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
317        fs_type == XFS || fs_type == UFS1 || fs_type == UFS2) {
318        if (sectmap(fd, sectp, nsect)) {
319                perror("bmap");
320                exit(1);
321        }
322    } else if (fs_type == BTRFS) {
323        int i;
324        sector_t *sp = sectp;
325
326        for (i = 0; i < nsect - 2; i++)
327            *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
328        for (i = 0; i < 2; i++)
329            *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
330    }
331
332    /* Create the modified image in memory */
333    rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
334                        opt.raid_mode, subpath, subvol);
335
336    free(dirpath);
337    return rv;
338}
339
340/*
341 * Install the boot block on the specified device.
342 * Must be run AFTER install_file()!
343 */
344int install_bootblock(int fd, const char *device)
345{
346    struct ext2_super_block sb;
347    struct btrfs_super_block sb2;
348    struct fat_boot_sector sb3;
349    struct ntfs_boot_sector sb4;
350    xfs_sb_t sb5;
351    struct ufs_super_block sb6;
352    bool ok = false;
353
354    if (fs_type == EXT2) {
355        if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
356                perror("reading superblock");
357                return 1;
358        }
359
360        if (sb.s_magic == EXT2_SUPER_MAGIC)
361                ok = true;
362    } else if (fs_type == BTRFS) {
363        if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
364                        != sizeof sb2) {
365                perror("reading superblock");
366                return 1;
367        }
368        if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
369                ok = true;
370    } else if (fs_type == VFAT) {
371        if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
372                perror("reading fat superblock");
373                return 1;
374        }
375
376        if (fat_check_sb_fields(&sb3))
377                ok = true;
378    } else if (fs_type == NTFS) {
379        if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) {
380            perror("reading ntfs superblock");
381            return 1;
382        }
383
384        if (ntfs_check_sb_fields(&sb4))
385             ok = true;
386    } else if (fs_type == XFS) {
387        if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
388            perror("reading xfs superblock");
389            return 1;
390        }
391
392        if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
393            if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
394                fprintf(stderr,
395                        "You need to have 4 KiB filesystem block size for "
396                        " being able to install Syslinux in your XFS "
397                        "partition (because there is no enough space in MBR to "
398                        "determine where Syslinux bootsector can be installed "
399                        "regardless the filesystem block size)\n");
400                return 1;
401            }
402
403            ok = true;
404        }
405    } else if (fs_type == UFS1 || fs_type == UFS2) {
406        uint32_t sblock_off = (fs_type == UFS1) ?
407            SBLOCK_UFS1 : SBLOCK_UFS2;
408        uint32_t ufs_smagic = (fs_type == UFS1) ?
409            UFS1_SUPER_MAGIC : UFS2_SUPER_MAGIC;
410
411        if (xpread(fd, &sb6, sizeof sb6, sblock_off) != sizeof sb6) {
412                perror("reading superblock");
413                return 1;
414        }
415
416        if (sb6.fs_magic == ufs_smagic)
417                ok = true;
418    }
419
420    if (!ok) {
421        fprintf(stderr,
422                "no fat, ntfs, ext2/3/4, btrfs, xfs "
423                "or ufs1/2 superblock found on %s\n",
424                device);
425        return 1;
426    }
427
428    if (fs_type == VFAT) {
429        struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
430        if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
431            xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen,
432                    offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) {
433            perror("writing fat bootblock");
434            return 1;
435        }
436    } else if (fs_type == NTFS) {
437        struct ntfs_boot_sector *sbs =
438                (struct ntfs_boot_sector *)syslinux_bootsect;
439        if (xpwrite(fd, &sbs->NTFS_bsHead,
440                    NTFS_bsHeadLen, 0) != NTFS_bsHeadLen ||
441                    xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen,
442                    offsetof(struct ntfs_boot_sector,
443                    NTFS_bsCode)) != NTFS_bsCodeLen) {
444            perror("writing ntfs bootblock");
445            return 1;
446        }
447    } else if (fs_type == XFS) {
448        if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
449                    XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
450            perror("writing xfs bootblock");
451            return 1;
452        }
453    } else {
454        if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
455            != syslinux_bootsect_len) {
456            perror("writing bootblock");
457            return 1;
458        }
459    }
460
461    return 0;
462}
463
464static int rewrite_boot_image(int devfd, const char *path, const char *filename)
465{
466    int fd;
467    int ret;
468    int modbytes;
469
470    /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
471    fd = open(filename,  O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
472              S_IRUSR | S_IRGRP | S_IROTH);
473    if (fd < 0) {
474        perror(filename);
475        return -1;
476    }
477
478    /* Write boot image data into LDLINUX.SYS file */
479    ret = xpwrite(fd, (const char _force *)boot_image, boot_image_len, 0);
480    if (ret != boot_image_len) {
481        perror("writing bootblock");
482        goto error;
483    }
484
485    /* Write ADV */
486    ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
487    if (ret != 2 * ADV_SIZE) {
488        fprintf(stderr, "%s: write failure on %s\n", program, filename);
489        goto error;
490    }
491
492    /* Map the file, and patch the initial sector accordingly */
493    modbytes = patch_file_and_bootblock(fd, path, devfd);
494
495    /* Write the patch area again - this relies on the file being overwritten
496     * in place! */
497    ret = xpwrite(fd, (const char _force *)boot_image, modbytes, 0);
498    if (ret != modbytes) {
499        fprintf(stderr, "%s: write failure on %s\n", program, filename);
500        goto error;
501    }
502
503    return fd;
504
505error:
506    close(fd);
507
508    return -1;
509}
510
511int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
512{
513    char *file, *oldfile, *c32file;
514    int fd = -1, dirfd = -1;
515    int r1, r2, r3;
516
517    r1 = asprintf(&file, "%s%sldlinux.sys",
518                  path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
519    r2 = asprintf(&oldfile, "%s%sextlinux.sys",
520                  path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
521    r3 = asprintf(&c32file, "%s%sldlinux.c32",
522                  path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
523    if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) {
524        perror(program);
525        return 1;
526    }
527
528    dirfd = open(path, O_RDONLY | O_DIRECTORY);
529    if (dirfd < 0) {
530        perror(path);
531        goto bail;
532    }
533
534    fd = open(file, O_RDONLY);
535    if (fd < 0) {
536        if (errno != ENOENT) {
537            perror(file);
538            goto bail;
539        }
540    } else {
541        clear_attributes(fd);
542    }
543    close(fd);
544
545    fd = rewrite_boot_image(devfd, path, file);
546    if (fd < 0)
547        goto bail;
548
549    /* Attempt to set immutable flag and remove all write access */
550    /* Only set immutable flag if file is owned by root */
551    set_attributes(fd);
552
553    if (fstat(fd, rst)) {
554        perror(file);
555        goto bail;
556    }
557
558    close(dirfd);
559    close(fd);
560
561    /* Look if we have the old filename */
562    fd = open(oldfile, O_RDONLY);
563    if (fd >= 0) {
564        clear_attributes(fd);
565        close(fd);
566        unlink(oldfile);
567    }
568
569    fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
570              S_IRUSR | S_IRGRP | S_IROTH);
571    if (fd < 0) {
572        perror(c32file);
573        goto bail;
574    }
575
576    r3 = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
577                 syslinux_ldlinuxc32_len, 0);
578    if (r3 != syslinux_ldlinuxc32_len) {
579        fprintf(stderr, "%s: write failure on %s\n", program, c32file);
580        goto bail;
581    }
582
583    free(file);
584    free(oldfile);
585    free(c32file);
586    return 0;
587
588bail:
589    if (dirfd >= 0)
590        close(dirfd);
591    if (fd >= 0)
592        close(fd);
593
594    free(file);
595    free(oldfile);
596    free(c32file);
597    return 1;
598}
599
600/* btrfs has to install the ldlinux.sys in the first 64K blank area, which
601   is not managered by btrfs tree, so actually this is not installed as files.
602   since the cow feature of btrfs will move the ldlinux.sys every where */
603int btrfs_install_file(const char *path, int devfd, struct stat *rst)
604{
605    char *file;
606    int fd, rv;
607
608    patch_file_and_bootblock(-1, path, devfd);
609    if (xpwrite(devfd, (const char _force *)boot_image,
610                boot_image_len, BTRFS_EXTLINUX_OFFSET)
611                != boot_image_len) {
612        perror("writing bootblock");
613        return 1;
614    }
615    dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
616    if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
617        != 2 * ADV_SIZE) {
618        perror("writing adv");
619        return 1;
620    }
621    dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
622    if (stat(path, rst)) {
623        perror(path);
624        return 1;
625    }
626
627    /*
628     * Note that we *can* install ldinux.c32 as a regular file because
629     * it doesn't need to be within the first 64K. The Syslinux core
630     * has enough smarts to search the btrfs dirs and find this file.
631     */
632    rv = asprintf(&file, "%s%sldlinux.c32",
633                  path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
634    if (rv < 0 || !file) {
635        perror(program);
636        return 1;
637    }
638
639    fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
640              S_IRUSR | S_IRGRP | S_IROTH);
641    if (fd < 0) {
642        perror(file);
643        free(file);
644        return 1;
645    }
646
647    rv = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
648                 syslinux_ldlinuxc32_len, 0);
649    if (rv != (int)syslinux_ldlinuxc32_len) {
650        fprintf(stderr, "%s: write failure on %s\n", program, file);
651        rv = 1;
652    } else
653        rv = 0;
654
655    close(fd);
656    free(file);
657    return rv;
658}
659
660/*
661 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
662 * sector in the primary AG on XFS filesystems contains the superblock, which is
663 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
664 * (located in the first sector of the partition).
665 *
666 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
667 * superblock.
668 */
669static int xfs_install_file(const char *path, int devfd, struct stat *rst)
670{
671    static char file[PATH_MAX + 1];
672    static char c32file[PATH_MAX + 1];
673    int dirfd = -1;
674    int fd = -1;
675    int retval;
676
677    snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path,
678             path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
679    snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path,
680             path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
681
682    dirfd = open(path, O_RDONLY | O_DIRECTORY);
683    if (dirfd < 0) {
684        perror(path);
685        goto bail;
686    }
687
688    fd = open(file, O_RDONLY);
689    if (fd < 0) {
690        if (errno != ENOENT) {
691            perror(file);
692            goto bail;
693        }
694    } else {
695        clear_attributes(fd);
696    }
697
698    close(fd);
699
700    fd = rewrite_boot_image(devfd, path, file);
701    if (fd < 0)
702        goto bail;
703
704    /* Attempt to set immutable flag and remove all write access */
705    /* Only set immutable flag if file is owned by root */
706    set_attributes(fd);
707
708    if (fstat(fd, rst)) {
709        perror(file);
710        goto bail;
711    }
712
713    close(dirfd);
714    close(fd);
715
716    dirfd = -1;
717    fd = -1;
718
719    fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
720              S_IRUSR | S_IRGRP | S_IROTH);
721    if (fd < 0) {
722        perror(c32file);
723        goto bail;
724    }
725
726    retval = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
727                     syslinux_ldlinuxc32_len, 0);
728    if (retval != (int)syslinux_ldlinuxc32_len) {
729        fprintf(stderr, "%s: write failure on %s\n", program, file);
730        goto bail;
731    }
732
733    close(fd);
734
735    sync();
736
737    return 0;
738
739bail:
740    if (dirfd >= 0)
741        close(dirfd);
742
743    if (fd >= 0)
744        close(fd);
745
746    return 1;
747}
748
749/*
750 *  * test if path is a subvolume:
751 *   * this function return
752 *    * 0-> path exists but it is not a subvolume
753 *     * 1-> path exists and it is  a subvolume
754 *      * -1 -> path is unaccessible
755 *       */
756static int test_issubvolume(char *path)
757{
758
759        struct stat     st;
760        int             res;
761
762        res = stat(path, &st);
763        if(res < 0 )
764                return -1;
765
766        return (st.st_ino == 256) && S_ISDIR(st.st_mode);
767
768}
769
770/*
771 * Get the default subvolume of a btrfs filesystem
772 *   rootdir: btrfs root dir
773 *   subvol:  this function will save the default subvolume name here
774 */
775static char * get_default_subvol(char * rootdir, char * subvol)
776{
777    struct btrfs_ioctl_search_args args;
778    struct btrfs_ioctl_search_key *sk = &args.key;
779    struct btrfs_ioctl_search_header *sh;
780    int ret, i;
781    int fd;
782    struct btrfs_root_ref *ref;
783    struct btrfs_dir_item *dir_item;
784    unsigned long off = 0;
785    int name_len;
786    char *name;
787    char dirname[4096];
788    u64 defaultsubvolid = 0;
789
790    ret = test_issubvolume(rootdir);
791    if (ret == 1) {
792        fd = open(rootdir, O_RDONLY);
793        if (fd < 0) {
794            fprintf(stderr, "ERROR: failed to open %s\n", rootdir);
795        }
796        ret = fd;
797    }
798    if (ret <= 0) {
799        subvol[0] = '\0';
800        return NULL;
801    }
802
803    memset(&args, 0, sizeof(args));
804
805   /* search in the tree of tree roots */
806   sk->tree_id = 1;
807
808   /*
809    * set the min and max to backref keys.  The search will
810    * only send back this type of key now.
811    */
812   sk->max_type = BTRFS_DIR_ITEM_KEY;
813   sk->min_type = BTRFS_DIR_ITEM_KEY;
814
815   /*
816    * set all the other params to the max, we'll take any objectid
817    * and any trans
818    */
819   sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
820   sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
821
822   sk->max_offset = (u64)-1;
823   sk->min_offset = 0;
824   sk->max_transid = (u64)-1;
825
826   /* just a big number, doesn't matter much */
827   sk->nr_items = 4096;
828
829   while(1) {
830       ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
831       if (ret < 0) {
832           fprintf(stderr, "ERROR: can't perform the search\n");
833           subvol[0] = '\0';
834           return NULL;
835       }
836       /* the ioctl returns the number of item it found in nr_items */
837       if (sk->nr_items == 0) {
838           break;
839       }
840
841       off = 0;
842
843       /*
844        * for each item, pull the key out of the header and then
845        * read the root_ref item it contains
846        */
847       for (i = 0; i < sk->nr_items; i++) {
848           sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
849           off += sizeof(*sh);
850           if (sh->type == BTRFS_DIR_ITEM_KEY) {
851               dir_item = (struct btrfs_dir_item *)(args.buf + off);
852               name_len = dir_item->name_len;
853               name = (char *)(dir_item + 1);
854
855
856               /*add_root(&root_lookup, sh->objectid, sh->offset,
857                        dir_id, name, name_len);*/
858               strncpy(dirname, name, name_len);
859               dirname[name_len] = '\0';
860               if (strcmp(dirname, "default") == 0) {
861                   defaultsubvolid = dir_item->location.objectid;
862                   break;
863               }
864           }
865           off += sh->len;
866
867           /*
868            * record the mins in sk so we can make sure the
869            * next search doesn't repeat this root
870            */
871           sk->min_objectid = sh->objectid;
872           sk->min_type = sh->type;
873           sk->max_type = sh->type;
874           sk->min_offset = sh->offset;
875       }
876       if (defaultsubvolid != 0)
877           break;
878       sk->nr_items = 4096;
879       /* this iteration is done, step forward one root for the next
880        * ioctl
881        */
882       if (sk->min_objectid < (u64)-1) {
883           sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
884           sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
885           sk->max_type = BTRFS_ROOT_BACKREF_KEY;
886           sk->min_type = BTRFS_ROOT_BACKREF_KEY;
887           sk->min_offset = 0;
888       } else
889           break;
890   }
891
892   if (defaultsubvolid == 0) {
893       subvol[0] = '\0';
894       return NULL;
895   }
896
897   memset(&args, 0, sizeof(args));
898
899   /* search in the tree of tree roots */
900   sk->tree_id = 1;
901
902   /*
903    * set the min and max to backref keys.  The search will
904    * only send back this type of key now.
905    */
906   sk->max_type = BTRFS_ROOT_BACKREF_KEY;
907   sk->min_type = BTRFS_ROOT_BACKREF_KEY;
908
909   /*
910    * set all the other params to the max, we'll take any objectid
911    * and any trans
912    */
913   sk->max_objectid = (u64)-1;
914   sk->max_offset = (u64)-1;
915   sk->max_transid = (u64)-1;
916
917   /* just a big number, doesn't matter much */
918   sk->nr_items = 4096;
919
920   while(1) {
921       ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
922       if (ret < 0) {
923           fprintf(stderr, "ERROR: can't perform the search\n");
924           subvol[0] = '\0';
925           return NULL;
926       }
927       /* the ioctl returns the number of item it found in nr_items */
928       if (sk->nr_items == 0)
929           break;
930
931       off = 0;
932
933       /*
934        * for each item, pull the key out of the header and then
935        * read the root_ref item it contains
936        */
937       for (i = 0; i < sk->nr_items; i++) {
938           sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
939           off += sizeof(*sh);
940           if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
941               ref = (struct btrfs_root_ref *)(args.buf + off);
942               name_len = ref->name_len;
943               name = (char *)(ref + 1);
944
945               if (sh->objectid == defaultsubvolid) {
946                   strncpy(subvol, name, name_len);
947                   subvol[name_len] = '\0';
948                   dprintf("The default subvolume: %s, ID: %llu\n",
949                           subvol, sh->objectid);
950                   break;
951               }
952
953           }
954
955           off += sh->len;
956
957           /*
958            * record the mins in sk so we can make sure the
959            * next search doesn't repeat this root
960            */
961           sk->min_objectid = sh->objectid;
962           sk->min_type = sh->type;
963           sk->min_offset = sh->offset;
964       }
965       if (subvol[0] != '\0')
966           break;
967       sk->nr_items = 4096;
968       /* this iteration is done, step forward one root for the next
969        * ioctl
970        */
971       if (sk->min_objectid < (u64)-1) {
972           sk->min_objectid++;
973           sk->min_type = BTRFS_ROOT_BACKREF_KEY;
974           sk->min_offset = 0;
975       } else
976           break;
977   }
978   return subvol;
979}
980
981static int install_file(const char *path, int devfd, struct stat *rst)
982{
983    if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS
984        || fs_type == UFS1 || fs_type == UFS2)
985        return ext2_fat_install_file(path, devfd, rst);
986    else if (fs_type == BTRFS)
987        return btrfs_install_file(path, devfd, rst);
988    else if (fs_type == XFS)
989        return xfs_install_file(path, devfd, rst);
990
991    return 1;
992}
993
994#ifdef __KLIBC__
995static char devname_buf[64];
996
997static void device_cleanup(void)
998{
999    unlink(devname_buf);
1000}
1001#endif
1002
1003/* Verify that a device fd and a pathname agree.
1004   Return 0 on valid, -1 on error. */
1005static int validate_device_btrfs(int pathfd, int devfd);
1006static int validate_device(const char *path, int devfd)
1007{
1008    struct stat pst, dst;
1009    struct statfs sfs;
1010    int pfd;
1011    int rv = -1;
1012
1013    pfd = open(path, O_RDONLY|O_DIRECTORY);
1014    if (pfd < 0)
1015        goto err;
1016
1017    if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
1018        goto err;
1019
1020    /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1021    if (fs_type == BTRFS) {
1022        if (sfs.f_type == BTRFS_SUPER_MAGIC)
1023            rv = validate_device_btrfs(pfd, devfd);
1024    } else {
1025        rv = (pst.st_dev == dst.st_rdev) ? 0 : -1;
1026    }
1027
1028err:
1029    if (pfd >= 0)
1030        close(pfd);
1031    return rv;
1032}
1033
1034#ifndef __KLIBC__
1035static const char *find_device(const char *mtab_file, dev_t dev)
1036{
1037    struct mntent *mnt;
1038    struct stat dst;
1039    FILE *mtab;
1040    const char *devname = NULL;
1041    bool done;
1042
1043    mtab = setmntent(mtab_file, "r");
1044    if (!mtab)
1045        return NULL;
1046
1047    done = false;
1048    while ((mnt = getmntent(mtab))) {
1049        /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1050        switch (fs_type) {
1051        case BTRFS:
1052            if (!strcmp(mnt->mnt_type, "btrfs") &&
1053                !stat(mnt->mnt_dir, &dst) &&
1054                dst.st_dev == dev) {
1055                if (!subvol[0])
1056                    get_default_subvol(mnt->mnt_dir, subvol);
1057                done = true;
1058            }
1059            break;
1060        case EXT2:
1061            if ((!strcmp(mnt->mnt_type, "ext2") ||
1062                 !strcmp(mnt->mnt_type, "ext3") ||
1063                 !strcmp(mnt->mnt_type, "ext4")) &&
1064                !stat(mnt->mnt_fsname, &dst) &&
1065                dst.st_rdev == dev) {
1066                done = true;
1067                break;
1068            }
1069        case VFAT:
1070            if ((!strcmp(mnt->mnt_type, "vfat")) &&
1071                !stat(mnt->mnt_fsname, &dst) &&
1072                dst.st_rdev == dev) {
1073                done = true;
1074                break;
1075            }
1076        case NTFS:
1077            if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
1078                 !strcmp(mnt->mnt_type, "ntfs")) &&
1079                !stat(mnt->mnt_fsname, &dst) &&
1080                dst.st_rdev == dev) {
1081                done = true;
1082                break;
1083            }
1084
1085            break;
1086        case XFS:
1087            if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
1088                dst.st_rdev == dev) {
1089                done = true;
1090                break;
1091            }
1092
1093            break;
1094        case UFS1:
1095        case UFS2:
1096            if (!strcmp(mnt->mnt_type, "ufs") && !stat(mnt->mnt_fsname, &dst) &&
1097                dst.st_rdev == dev) {
1098                done = true;
1099            }
1100
1101            break;
1102        case NONE:
1103            break;
1104        }
1105
1106        if (done) {
1107            devname = strdup(mnt->mnt_fsname);
1108            break;
1109        }
1110    }
1111
1112    endmntent(mtab);
1113
1114    return devname;
1115}
1116#endif
1117
1118/*
1119 * On newer Linux kernels we can use sysfs to get a backwards mapping
1120 * from device names to standard filenames
1121 */
1122static const char *find_device_sysfs(dev_t dev)
1123{
1124    char sysname[64];
1125    char linkname[PATH_MAX];
1126    ssize_t llen;
1127    char *p, *q;
1128    char *buf = NULL;
1129    struct stat st;
1130
1131    snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
1132             major(dev), minor(dev));
1133
1134    llen = readlink(sysname, linkname, sizeof linkname);
1135    if (llen < 0 || llen >= sizeof linkname)
1136        goto err;
1137
1138    linkname[llen] = '\0';
1139
1140    p = strrchr(linkname, '/');
1141    p = p ? p+1 : linkname;     /* Leave basename */
1142
1143    buf = q = malloc(strlen(p) + 6);
1144    if (!buf)
1145        goto err;
1146
1147    memcpy(q, "/dev/", 5);
1148    q += 5;
1149
1150    while (*p) {
1151        *q++ = (*p == '!') ? '/' : *p;
1152        p++;
1153    }
1154
1155    *q = '\0';
1156
1157    if (!stat(buf, &st) && st.st_dev == dev)
1158        return buf;             /* Found it! */
1159
1160err:
1161    if (buf)
1162        free(buf);
1163    return NULL;
1164}
1165
1166static const char *find_device_mountinfo(const char *path, dev_t dev)
1167{
1168    const struct mountinfo *m;
1169    struct stat st;
1170
1171    m = find_mount(path, NULL);
1172    if (!m)
1173        return NULL;
1174
1175    if (m->devpath[0] == '/' && m->dev == dev &&
1176        !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
1177        return m->devpath;
1178    else
1179        return NULL;
1180}
1181
1182static int validate_device_btrfs(int pfd, int dfd)
1183{
1184    struct btrfs_ioctl_fs_info_args fsinfo;
1185    static struct btrfs_ioctl_dev_info_args devinfo;
1186    struct btrfs_super_block sb2;
1187
1188    if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1189        return -1;
1190
1191    /* We do not support multi-device btrfs yet */
1192    if (fsinfo.num_devices != 1)
1193        return -1;
1194
1195    /* The one device will have the max devid */
1196    memset(&devinfo, 0, sizeof devinfo);
1197    devinfo.devid = fsinfo.max_id;
1198    if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1199        return -1;
1200
1201    if (devinfo.path[0] != '/')
1202        return -1;
1203
1204    if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2)
1205        return -1;
1206
1207    if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
1208        return -1;
1209
1210    if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1211        return -1;
1212
1213    if (sb2.num_devices != 1)
1214        return -1;
1215
1216    if (sb2.dev_item.devid != devinfo.devid)
1217        return -1;
1218
1219    if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid))
1220        return -1;
1221
1222    if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1223        return -1;
1224
1225    return 0;                   /* It's good! */
1226}
1227
1228static const char *find_device_btrfs(const char *path)
1229{
1230    int pfd, dfd;
1231    struct btrfs_ioctl_fs_info_args fsinfo;
1232    static struct btrfs_ioctl_dev_info_args devinfo;
1233    const char *rv = NULL;
1234
1235    pfd = dfd = -1;
1236
1237    pfd = open(path, O_RDONLY);
1238    if (pfd < 0)
1239        goto err;
1240
1241    if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1242        goto err;
1243
1244    /* We do not support multi-device btrfs yet */
1245    if (fsinfo.num_devices != 1)
1246        goto err;
1247
1248    /* The one device will have the max devid */
1249    memset(&devinfo, 0, sizeof devinfo);
1250    devinfo.devid = fsinfo.max_id;
1251    if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1252        goto err;
1253
1254    if (devinfo.path[0] != '/')
1255        goto err;
1256
1257    dfd = open((const char *)devinfo.path, O_RDONLY);
1258    if (dfd < 0)
1259        goto err;
1260
1261    if (!validate_device_btrfs(pfd, dfd))
1262        rv = (const char *)devinfo.path; /* It's good! */
1263
1264err:
1265    if (pfd >= 0)
1266        close(pfd);
1267    if (dfd >= 0)
1268        close(dfd);
1269    return rv;
1270}
1271
1272static const char *get_devname(const char *path)
1273{
1274    const char *devname = NULL;
1275    struct stat st;
1276    struct statfs sfs;
1277
1278    if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
1279        fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1280        return devname;
1281    }
1282    if (statfs(path, &sfs)) {
1283        fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1284        return devname;
1285    }
1286
1287    if (opt.device)
1288        devname = opt.device;
1289
1290    if (!devname){
1291        if (fs_type == BTRFS) {
1292            /* For btrfs try to get the device name from btrfs itself */
1293            devname = find_device_btrfs(path);
1294        }
1295    }
1296
1297    if (!devname) {
1298        devname = find_device_mountinfo(path, st.st_dev);
1299    }
1300
1301#ifdef __KLIBC__
1302    if (!devname) {
1303        devname = find_device_sysfs(st.st_dev);
1304    }
1305    if (!devname) {
1306        /* klibc doesn't have getmntent and friends; instead, just create
1307           a new device with the appropriate device type */
1308        snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
1309                 major(st.st_dev), minor(st.st_dev));
1310
1311        if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
1312            fprintf(stderr, "%s: cannot create device %s\n", program, devname);
1313            return devname;
1314        }
1315
1316        atexit(device_cleanup); /* unlink the device node on exit */
1317        devname = devname_buf;
1318    }
1319
1320#else
1321    if (!devname) {
1322        devname = find_device("/proc/mounts", st.st_dev);
1323    }
1324    if (!devname) {
1325        /* Didn't find it in /proc/mounts, try /etc/mtab */
1326        devname = find_device("/etc/mtab", st.st_dev);
1327    }
1328    if (!devname) {
1329        devname = find_device_sysfs(st.st_dev);
1330
1331        fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
1332        return devname;
1333    }
1334
1335    fprintf(stderr, "%s is device %s\n", path, devname);
1336
1337#endif
1338    return devname;
1339}
1340
1341static int open_device(const char *path, struct stat *st, const char **_devname)
1342{
1343    int devfd;
1344    const char *devname = NULL;
1345    struct statfs sfs;
1346
1347    if (st)
1348        if (stat(path, st) || !S_ISDIR(st->st_mode)) {
1349                fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1350                return -1;
1351        }
1352
1353    if (statfs(path, &sfs)) {
1354        fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1355        return -1;
1356    }
1357
1358    if (sfs.f_type == EXT2_SUPER_MAGIC)
1359        fs_type = EXT2;
1360    else if (sfs.f_type == BTRFS_SUPER_MAGIC)
1361        fs_type = BTRFS;
1362    else if (sfs.f_type == MSDOS_SUPER_MAGIC)
1363        fs_type = VFAT;
1364    else if (sfs.f_type == NTFS_SB_MAGIC ||
1365                sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
1366        fs_type = NTFS;
1367    else if (sfs.f_type == XFS_SUPER_MAGIC)
1368        fs_type = XFS;
1369    else if (sfs.f_type == UFS1_SUPER_MAGIC)
1370        fs_type = UFS1;
1371    else if (sfs.f_type == UFS2_SUPER_MAGIC)
1372        fs_type = UFS2;
1373
1374    if (!fs_type) {
1375        fprintf(stderr,
1376                "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1377                "ufs1/2 filesystem: %s\n",
1378                program, path);
1379        return -1;
1380    }
1381
1382    devfd = -1;
1383    devname = get_devname(path);
1384    if (_devname)
1385        *_devname = devname;
1386
1387    if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
1388        fprintf(stderr, "%s: cannot open device %s\n", program, devname);
1389        return -1;
1390    }
1391
1392    /* Verify that the device we opened is the device intended */
1393    if (validate_device(path, devfd)) {
1394        fprintf(stderr, "%s: path %s doesn't match device %s\n",
1395                program, path, devname);
1396        close(devfd);
1397        return -1;
1398    }
1399    return devfd;
1400}
1401
1402static int btrfs_read_adv(int devfd)
1403{
1404    if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
1405        != 2 * ADV_SIZE)
1406        return -1;
1407
1408    return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1409}
1410
1411static inline int xfs_read_adv(int devfd)
1412{
1413    const size_t adv_size = 2 * ADV_SIZE;
1414
1415    if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
1416        return -1;
1417
1418    return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1419}
1420
1421static int ext_read_adv(const char *path, int devfd, const char **namep)
1422{
1423    int err;
1424    const char *name;
1425
1426    if (fs_type == BTRFS) {
1427        /* btrfs "ldlinux.sys" is in 64k blank area */
1428        return btrfs_read_adv(devfd);
1429    } else if (fs_type == XFS) {
1430        /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1431        return xfs_read_adv(devfd);
1432    } else {
1433        err = read_adv(path, name = "ldlinux.sys");
1434        if (err == 2)           /* ldlinux.sys does not exist */
1435            err = read_adv(path, name = "extlinux.sys");
1436        if (namep)
1437            *namep = name;
1438        return err;
1439    }
1440}
1441
1442static int ext_write_adv(const char *path, const char *cfg, int devfd)
1443{
1444    if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
1445        if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
1446                BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
1447                perror("writing adv");
1448                return 1;
1449        }
1450        return 0;
1451    }
1452    return write_adv(path, cfg);
1453}
1454
1455static int install_loader(const char *path, int update_only)
1456{
1457    struct stat st, fst;
1458    int devfd, rv;
1459    const char *devname;
1460
1461    devfd = open_device(path, &st, &devname);
1462    if (devfd < 0)
1463        return 1;
1464
1465    if (update_only && !syslinux_already_installed(devfd)) {
1466        fprintf(stderr, "%s: no previous syslinux boot sector found\n",
1467                program);
1468        close(devfd);
1469        return 1;
1470    }
1471
1472    /* Read a pre-existing ADV, if already installed */
1473    if (opt.reset_adv) {
1474        syslinux_reset_adv(syslinux_adv);
1475    } else if (ext_read_adv(path, devfd, NULL) < 0) {
1476        close(devfd);
1477        return 1;
1478    }
1479
1480    if (modify_adv() < 0) {
1481        close(devfd);
1482        return 1;
1483    }
1484
1485    /* Install ldlinux.sys */
1486    if (install_file(path, devfd, &fst)) {
1487        close(devfd);
1488        return 1;
1489    }
1490    if (fst.st_dev != st.st_dev) {
1491        fprintf(stderr, "%s: file system changed under us - aborting!\n",
1492                program);
1493        close(devfd);
1494        return 1;
1495    }
1496
1497    sync();
1498    rv = install_bootblock(devfd, devname);
1499    close(devfd);
1500    sync();
1501
1502    return rv;
1503}
1504
1505/*
1506 * Modify the ADV of an existing installation
1507 */
1508int modify_existing_adv(const char *path)
1509{
1510    const char *filename;
1511    int devfd;
1512
1513    devfd = open_device(path, NULL, NULL);
1514    if (devfd < 0)
1515        return 1;
1516
1517    if (ext_read_adv(path, devfd, &filename) < 0) {
1518        close(devfd);
1519        return 1;
1520    }
1521    if (modify_adv() < 0) {
1522        close(devfd);
1523        return 1;
1524    }
1525    if (ext_write_adv(path, filename, devfd) < 0) {
1526        close(devfd);
1527        return 1;
1528    }
1529    close(devfd);
1530    return 0;
1531}
1532
1533int main(int argc, char *argv[])
1534{
1535    parse_options(argc, argv, MODE_EXTLINUX);
1536
1537    if (!opt.directory || opt.install_mbr || opt.activate_partition)
1538        usage(EX_USAGE, 0);
1539
1540    if (opt.update_only == -1) {
1541        if (opt.reset_adv || opt.set_once || opt.menu_save)
1542            return modify_existing_adv(opt.directory);
1543        else
1544            usage(EX_USAGE, MODE_EXTLINUX);
1545    }
1546
1547    return install_loader(opt.directory, opt.update_only);
1548}
Note: See TracBrowser for help on using the repository browser.