1 /* ----------------------------------------------------------------------- *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
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.
12 * ----------------------------------------------------------------------- */
17 * Install the extlinux boot block on an ext2/3/4 and btrfs filesystem
20 #define _GNU_SOURCE /* Enable everything */
22 /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
37 #include <sys/ioctl.h>
39 #include <sys/types.h>
40 #include <sys/mount.h>
43 #include <linux/fd.h> /* Floppy geometry */
44 #include <linux/hdreg.h> /* Hard disk geometry */
45 #define statfs _kernel_statfs /* HACK to deal with broken 2.4 distros */
46 #include <linux/fs.h> /* FIGETBSZ, FIBMAP */
51 #include "../version.h"
55 # define dprintf printf
57 # define dprintf(...) ((void)0)
60 /* Global option handling */
61 /* Global fs_type for handling ext2/3/4 vs btrfs */
68 /* These are the options we can set and their values */
77 .sectors = 0,.heads = 0,.raid_mode = 0,.stupid_mode = 0,.reset_adv =
80 static void __attribute__ ((noreturn)) usage(int rv)
83 "Usage: %s [options] directory\n"
84 " --install -i Install over the current bootsector\n"
85 " --update -U Update a previous EXTLINUX installation\n"
86 " --zip -z Force zipdrive geometry (-H 64 -S 32)\n"
87 " --sectors=# -S Force the number of sectors per track\n"
88 " --heads=# -H Force number of heads\n"
89 " --stupid -s Slow, safe and stupid mode\n"
90 " --raid -r Fall back to the next device on boot failure\n"
91 " --once=... -o Execute a command once upon boot\n"
92 " --clear-once -O Clear the boot-once command\n"
93 " --reset-adv Reset auxilliary data\n"
95 " Note: geometry is determined at boot time for devices which\n"
96 " are considered hard disks by the BIOS. Unfortunately, this is\n"
97 " not possible for devices which are considered floppy disks,\n"
98 " which includes zipdisks and LS-120 superfloppies.\n"
100 " The -z option is useful for USB devices which are considered\n"
101 " hard disks by some BIOSes and zipdrives by other BIOSes.\n",
112 static const struct option long_options[] = {
113 {"install", 0, NULL, 'i'},
114 {"update", 0, NULL, 'U'},
115 {"zipdrive", 0, NULL, 'z'},
116 {"sectors", 1, NULL, 'S'},
117 {"stupid", 0, NULL, 's'},
118 {"heads", 1, NULL, 'H'},
119 {"raid-mode", 0, NULL, 'r'},
120 {"version", 0, NULL, 'v'},
121 {"help", 0, NULL, 'h'},
122 {"once", 1, NULL, 'o'},
123 {"clear-once", 0, NULL, 'O'},
124 {"reset-adv", 0, NULL, OPT_RESET_ADV},
128 static const char short_options[] = "iUuzS:H:rvho:O";
130 #if defined(__linux__) && !defined(BLKGETSIZE64)
131 /* This takes a u64, but the size field says size_t. Someone screwed big. */
132 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
135 #ifndef EXT2_SUPER_OFFSET
136 #define EXT2_SUPER_OFFSET 1024
139 /* the btrfs partition first 64K blank area is used to store boot sector and
140 boot image, the boot sector is from 0~512, the boot image starts at 2K */
141 #define BTRFS_EXTLINUX_OFFSET (2*1024)
145 extern unsigned char extlinux_bootsect[];
146 extern unsigned int extlinux_bootsect_len;
147 #define boot_block extlinux_bootsect
148 #define boot_block_len extlinux_bootsect_len
153 extern unsigned char extlinux_image[];
154 extern unsigned int extlinux_image_len;
155 #define boot_image extlinux_image
156 #define boot_image_len extlinux_image_len
159 * Common abort function
161 void __attribute__ ((noreturn)) die(const char *msg)
168 * read/write wrapper functions
170 ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
172 char *bufp = (char *)buf;
177 rv = pread(fd, bufp, count, offset);
180 } else if (rv == -1) {
181 if (errno == EINTR) {
184 die(strerror(errno));
197 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
199 const char *bufp = (const char *)buf;
204 rv = pwrite(fd, bufp, count, offset);
207 } else if (rv == -1) {
208 if (errno == EINTR) {
211 die(strerror(errno));
227 int sectmap(int fd, uint32_t * sectors, int nsectors)
229 unsigned int blksize, blk, nblk;
233 if (ioctl(fd, FIGETBSZ, &blksize))
236 /* Number of sectors per block */
237 blksize >>= SECTOR_SHIFT;
243 dprintf("querying block %u\n", blk);
244 if (ioctl(fd, FIBMAP, &blk))
248 for (i = 0; i < blksize; i++) {
252 dprintf("Sector: %10u\n", blk);
262 * Get the size of a block device
264 uint64_t get_size(int devfd)
271 if (!ioctl(devfd, BLKGETSIZE64, &bytes))
274 if (!ioctl(devfd, BLKGETSIZE, §s))
275 return (uint64_t) sects << 9;
276 else if (!fstat(devfd, &st) && st.st_size)
283 * Get device geometry and partition offset
285 struct geometry_table {
287 struct hd_geometry g;
290 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
291 (x/64/32) is the final fallback. I don't know what LS-240 has
292 as its geometry, since I don't have one and don't know anyone that does,
293 and Google wasn't helpful... */
294 static const struct geometry_table standard_geometries[] = {
295 {360 * 1024, {2, 9, 40, 0}},
296 {720 * 1024, {2, 9, 80, 0}},
297 {1200 * 1024, {2, 15, 80, 0}},
298 {1440 * 1024, {2, 18, 80, 0}},
299 {1680 * 1024, {2, 21, 80, 0}},
300 {1722 * 1024, {2, 21, 80, 0}},
301 {2880 * 1024, {2, 36, 80, 0}},
302 {3840 * 1024, {2, 48, 80, 0}},
303 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
307 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
309 struct floppy_struct fd_str;
310 const struct geometry_table *gp;
312 memset(geo, 0, sizeof *geo);
314 if (!ioctl(devfd, HDIO_GETGEO, &geo)) {
316 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
317 geo->heads = fd_str.head;
318 geo->sectors = fd_str.sect;
319 geo->cylinders = fd_str.track;
324 /* Didn't work. Let's see if this is one of the standard geometries */
325 for (gp = standard_geometries; gp->bytes; gp++) {
326 if (gp->bytes == totalbytes) {
327 memcpy(geo, &gp->g, sizeof *geo);
332 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
333 what zipdisks use, so this would help if someone has a USB key that
334 they're booting in USB-ZIP mode. */
336 geo->heads = opt.heads ? : 64;
337 geo->sectors = opt.sectors ? : 32;
338 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
341 if (!opt.sectors && !opt.heads)
343 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
344 " (on hard disks, this is usually harmless.)\n",
345 geo->heads, geo->sectors);
351 * Query the device geometry and put it into the boot sector.
352 * Map the file and put the map in the boot sector and file.
353 * Stick the "current directory" inode number into the file.
355 * Returns the number of modified bytes in the boot file.
357 int patch_file_and_bootblock(int fd, const char *dir, int devfd)
359 struct stat dirst, xdst;
360 struct hd_geometry geo;
362 uint64_t totalbytes, totalsectors;
365 struct boot_sector *bs;
366 struct patch_area *patcharea;
369 int secptroffset, diroffset, dirlen;
370 char *dirpath, *subpath;
372 dirpath = realpath(dir, NULL);
373 if (!dirpath || stat(dir, &dirst)) {
374 perror("accessing install directory");
375 exit(255); /* This should never happen */
378 if (lstat(dirpath, &xdst) ||
379 dirst.st_ino != xdst.st_ino ||
380 dirst.st_dev != xdst.st_dev) {
381 perror("realpath returned nonsense");
385 subpath = strchr(dirpath, '\0');
386 while (--subpath > dirpath) {
387 if (*subpath == '/') {
389 if (lstat(dirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
390 subpath = strchr(subpath+1, '/');
392 subpath = "/"; /* It's the root of the filesystem */
399 /* Now subpath should contain the path relative to the fs base */
400 dprintf("subpath = %s\n", subpath);
402 totalbytes = get_size(devfd);
403 get_geometry(devfd, totalbytes, &geo);
406 geo.heads = opt.heads;
408 geo.sectors = opt.sectors;
410 /* Patch this into a fake FAT superblock. This isn't because
411 FAT is a good format in any way, it's because it lets the
412 early bootstrap share code with the FAT version. */
413 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
415 bs = (struct boot_sector *)boot_block;
417 totalsectors = totalbytes >> SECTOR_SHIFT;
418 if (totalsectors >= 65536) {
419 set_16(&bs->bsSectors, 0);
421 set_16(&bs->bsSectors, totalsectors);
423 set_32(&bs->bsHugeSectors, totalsectors);
425 set_16(&bs->bsBytesPerSec, SECTOR_SIZE);
426 set_16(&bs->bsSecPerTrack, geo.sectors);
427 set_16(&bs->bsHeads, geo.heads);
428 set_32(&bs->bsHiddenSecs, geo.start);
430 /* If we're in RAID mode then patch the appropriate instruction;
431 either way write the proper boot signature */
432 i = get_16(&bs->bsSignature);
434 set_16((uint16_t *) (boot_block + i), 0x18CD); /* INT 18h */
436 set_16(&bs->bsSignature, 0xAA55);
438 /* Construct the boot file */
440 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
441 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
442 nsect += 2; /* Two sectors for the ADV */
443 sectp = alloca(sizeof(uint32_t) * nsect);
444 if (fs_type == EXT2) {
445 if (sectmap(fd, sectp, nsect)) {
449 } else if (fs_type == BTRFS) {
452 for (i = 0; i < nsect; i++)
453 *(sectp + i) = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
456 /* First sector need pointer in boot sector */
457 set_32(&bs->NextSector, *sectp++);
460 set_16(&bs->MaxTransfer, 1);
462 /* Search for LDLINUX_MAGIC to find the patch area */
463 for (wp = (uint32_t *) boot_image; get_32(wp) != LDLINUX_MAGIC; wp++) ;
464 patcharea = (struct patch_area *)wp;
466 /* Set up the totals */
467 dw = boot_image_len >> 2; /* COMPLETE dwords, excluding ADV */
468 set_16(&patcharea->data_sectors, nsect - 2); /* -2 for the ADVs */
469 set_16(&patcharea->adv_sectors, 2);
470 set_32(&patcharea->dwords, dw);
472 /* Set the sector pointers */
473 secptroffset = get_16(&patcharea->secptroffset);
474 wp = (uint32_t *) ((char *)boot_image + secptroffset);
475 nptrs = get_16(&patcharea->secptrcnt);
477 memset(wp, 0, nptrs * 4);
479 set_32(wp++, *sectp++);
481 /* Poke in the base directory path */
482 diroffset = get_16(&patcharea->diroffset);
483 dirlen = get_16(&patcharea->dirlen);
484 if (dirlen <= strlen(subpath)) {
485 fprintf(stderr, "Subdirectory path too long... aborting install!\n");
488 strncpy((char *)boot_image + diroffset, subpath, dirlen);
491 /* Now produce a checksum */
492 set_32(&patcharea->checksum, 0);
494 csum = LDLINUX_MAGIC;
495 for (i = 0, wp = (uint32_t *) boot_image; i < dw; i++, wp++)
496 csum -= get_32(wp); /* Negative checksum */
498 set_32(&patcharea->checksum, csum);
500 return secptroffset + nptrs*4;
504 * Read the ADV from an existing instance, or initialize if invalid.
505 * Returns -1 on fatal errors, 0 if ADV is okay, and 1 if no valid
508 int read_adv(const char *path, int devfd)
515 if (fs_type == BTRFS) { /* btrfs "extlinux.sys" is in 64k blank area */
516 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE,
517 BTRFS_EXTLINUX_OFFSET + boot_image_len) != 2 * ADV_SIZE) {
518 perror("writing adv");
523 asprintf(&file, "%s%sextlinux.sys",
524 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
531 fd = open(file, O_RDONLY);
533 if (errno != ENOENT) {
536 syslinux_reset_adv(syslinux_adv);
538 } else if (fstat(fd, &st)) {
540 } else if (st.st_size < 2 * ADV_SIZE) {
541 /* Too small to be useful */
542 syslinux_reset_adv(syslinux_adv);
543 err = 0; /* Nothing to read... */
544 } else if (xpread(fd, syslinux_adv, 2 * ADV_SIZE,
545 st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
548 /* We got it... maybe? */
549 err = syslinux_validate_adv(syslinux_adv) ? 1 : 0;
564 * Update the ADV in an existing installation.
566 int write_adv(const char *path, int devfd)
568 unsigned char advtmp[2 * ADV_SIZE];
575 if (fs_type == BTRFS) { /* btrfs "extlinux.sys" is in 64k blank area */
576 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
577 BTRFS_EXTLINUX_OFFSET + boot_image_len) != 2 * ADV_SIZE) {
578 perror("writing adv");
583 asprintf(&file, "%s%sextlinux.sys",
584 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
591 fd = open(file, O_RDONLY);
594 } else if (fstat(fd, &st)) {
596 } else if (st.st_size < 2 * ADV_SIZE) {
597 /* Too small to be useful */
599 } else if (xpread(fd, advtmp, 2 * ADV_SIZE,
600 st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
603 /* We got it... maybe? */
604 err = syslinux_validate_adv(advtmp) ? -2 : 0;
606 /* Got a good one, write our own ADV here */
607 if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
608 nflags = flags & ~EXT2_IMMUTABLE_FL;
610 ioctl(fd, EXT2_IOC_SETFLAGS, &nflags);
612 if (!(st.st_mode & S_IWUSR))
613 fchmod(fd, st.st_mode | S_IWUSR);
615 /* Need to re-open read-write */
617 fd = open(file, O_RDWR | O_SYNC);
620 } else if (fstat(fd, &xst) || xst.st_ino != st.st_ino ||
621 xst.st_dev != st.st_dev || xst.st_size != st.st_size) {
622 fprintf(stderr, "%s: race condition on write\n", file);
625 /* Write our own version ... */
626 if (xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
627 st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
633 if (!(st.st_mode & S_IWUSR))
634 fchmod(fd, st.st_mode);
637 ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
642 fprintf(stderr, "%s: cannot write auxilliary data (need --update)?\n",
656 * Make any user-specified ADV modifications
663 if (syslinux_setadv(ADV_BOOTONCE, strlen(opt.set_once), opt.set_once)) {
664 fprintf(stderr, "%s: not enough space for boot-once command\n",
674 * Install the boot block on the specified device.
675 * Must be run AFTER install_file()!
677 int install_bootblock(int fd, const char *device)
679 struct ext2_super_block sb;
680 struct btrfs_super_block sb2;
683 if (fs_type == EXT2) {
684 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
685 perror("reading superblock");
688 if (sb.s_magic == EXT2_SUPER_MAGIC)
690 } else if (fs_type == BTRFS) {
691 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
693 perror("reading superblock");
696 if (sb2.magic == *(u64 *)BTRFS_MAGIC)
700 fprintf(stderr, "no ext2/3/4 or btrfs superblock found on %s\n",
704 if (xpwrite(fd, boot_block, boot_block_len, 0) != boot_block_len) {
705 perror("writing bootblock");
712 int ext2_install_file(const char *path, int devfd, struct stat *rst)
715 int fd = -1, dirfd = -1, flags;
719 asprintf(&file, "%s%sextlinux.sys",
720 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
726 dirfd = open(path, O_RDONLY | O_DIRECTORY);
732 fd = open(file, O_RDONLY);
734 if (errno != ENOENT) {
739 /* If file exist, remove the immutable flag and set u+w mode */
740 if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
741 flags &= ~EXT2_IMMUTABLE_FL;
742 ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
744 if (!fstat(fd, &st)) {
745 fchmod(fd, st.st_mode | S_IWUSR);
750 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
751 S_IRUSR | S_IRGRP | S_IROTH);
757 /* Write it the first time */
758 if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
759 xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
760 boot_image_len) != 2 * ADV_SIZE) {
761 fprintf(stderr, "%s: write failure on %s\n", program, file);
765 /* Map the file, and patch the initial sector accordingly */
766 modbytes = patch_file_and_bootblock(fd, path, devfd);
768 /* Write the patch area again - this relies on the file being
769 overwritten in place! */
770 if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
771 fprintf(stderr, "%s: write failure on %s\n", program, file);
775 /* Attempt to set immutable flag and remove all write access */
776 /* Only set immutable flag if file is owned by root */
777 if (!fstat(fd, &st)) {
778 fchmod(fd, st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH));
779 if (st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
780 flags |= EXT2_IMMUTABLE_FL;
781 ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
785 if (fstat(fd, rst)) {
803 /* btrfs has to install the extlinux.sys in the first 64K blank area, which
804 is not managered by btrfs tree, so actually this is not installed as files.
805 since the cow feature of btrfs will move the extlinux.sys every where */
806 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
808 patch_file_and_bootblock(-1, path, devfd);
809 if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET)
811 perror("writing bootblock");
814 printf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
815 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
816 BTRFS_EXTLINUX_OFFSET + boot_image_len) != 2 * ADV_SIZE) {
817 perror("writing adv");
820 printf("write adv to 0x%x\n", BTRFS_EXTLINUX_OFFSET + boot_image_len);
821 if (stat(path, rst)) {
828 int install_file(const char *path, int devfd, struct stat *rst)
831 return ext2_install_file(path, devfd, rst);
832 else if (fs_type == BTRFS)
833 return btrfs_install_file(path, devfd, rst);
837 /* EXTLINUX installs the string 'EXTLINUX' at offset 3 in the boot
838 sector; this is consistent with FAT filesystems. */
839 int already_installed(int devfd)
843 xpread(devfd, buffer, 8, 3);
844 return !memcmp(buffer, "EXTLINUX", 8);
848 static char devname_buf[64];
850 static void device_cleanup(void)
856 /* Verify that a device fd and a pathname agree.
857 Return 0 on valid, -1 on error. */
858 static int validate_device(const char *path, int devfd)
860 struct stat pst, dst;
863 if (stat(path, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
865 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
866 if (fs_type == BTRFS && sfs.f_type == BTRFS_SUPER_MAGIC)
868 return (pst.st_dev == dst.st_rdev) ? 0 : -1;
872 static const char *find_device(const char *mtab_file, dev_t dev)
877 const char *devname = NULL;
880 mtab = setmntent(mtab_file, "r");
885 while ((mnt = getmntent(mtab))) {
886 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
889 if (!strcmp(mnt->mnt_type, "btrfs") &&
890 !stat(mnt->mnt_dir, &dst) &&
895 if ((!strcmp(mnt->mnt_type, "ext2") ||
896 !strcmp(mnt->mnt_type, "ext3") ||
897 !strcmp(mnt->mnt_type, "ext4")) &&
898 !stat(mnt->mnt_fsname, &dst) &&
899 dst.st_rdev == dev) {
905 devname = strdup(mnt->mnt_fsname);
915 static const char *get_devname(const char *path)
917 const char *devname = NULL;
921 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
922 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
925 if (statfs(path, &sfs)) {
926 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
931 /* klibc doesn't have getmntent and friends; instead, just create
932 a new device with the appropriate device type */
933 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
934 major(st.st_dev), minor(st.st_dev));
936 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
937 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
941 atexit(device_cleanup); /* unlink the device node on exit */
942 devname = devname_buf;
946 devname = find_device("/proc/mounts", st.st_dev);
948 /* Didn't find it in /proc/mounts, try /etc/mtab */
949 devname = find_device("/etc/mtab", st.st_dev);
952 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
956 fprintf(stderr, "%s is device %s\n", path, devname);
961 static int open_device(const char *path, struct stat *st, const char **_devname)
964 const char *devname = NULL;
968 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
969 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
973 if (statfs(path, &sfs)) {
974 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
977 if (sfs.f_type == EXT2_SUPER_MAGIC)
979 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
983 fprintf(stderr, "%s: not an ext2/3/4 or btrfs filesystem: %s\n",
989 devname = get_devname(path);
993 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
994 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
998 /* Verify that the device we opened is the device intended */
999 if (validate_device(path, devfd)) {
1000 fprintf(stderr, "%s: path %s doesn't match device %s\n",
1001 program, path, devname);
1008 int install_loader(const char *path, int update_only)
1010 struct stat st, fst;
1012 const char *devname;
1014 devfd = open_device(path, &st, &devname);
1018 if (update_only && !already_installed(devfd)) {
1019 fprintf(stderr, "%s: no previous extlinux boot sector found\n",
1025 /* Read a pre-existing ADV, if already installed */
1027 syslinux_reset_adv(syslinux_adv);
1028 else if (read_adv(path, devfd) < 0) {
1032 if (modify_adv() < 0) {
1037 /* Install extlinux.sys */
1038 if (install_file(path, devfd, &fst)) {
1042 if (fst.st_dev != st.st_dev) {
1043 fprintf(stderr, "%s: file system changed under us - aborting!\n",
1050 rv = install_bootblock(devfd, devname);
1058 * Modify the ADV of an existing installation
1060 int modify_existing_adv(const char *path)
1064 devfd = open_device(path, NULL, NULL);
1069 syslinux_reset_adv(syslinux_adv);
1070 else if (read_adv(path, devfd) < 0) {
1074 if (modify_adv() < 0) {
1078 if (write_adv(path, devfd) < 0) {
1086 int main(int argc, char *argv[])
1089 const char *directory;
1090 int update_only = -1;
1094 while ((o = getopt_long(argc, argv, short_options,
1095 long_options, NULL)) != EOF) {
1102 opt.sectors = strtoul(optarg, NULL, 0);
1103 if (opt.sectors < 1 || opt.sectors > 63) {
1105 "%s: invalid number of sectors: %u (must be 1-63)\n",
1106 program, opt.sectors);
1111 opt.heads = strtoul(optarg, NULL, 0);
1112 if (opt.heads < 1 || opt.heads > 256) {
1114 "%s: invalid number of heads: %u (must be 1-256)\n",
1115 program, opt.heads);
1123 opt.stupid_mode = 1;
1136 opt.set_once = optarg;
1145 fputs("extlinux " VERSION_STR
1146 " Copyright 1994-" YEAR_STR " H. Peter Anvin \n", stderr);
1153 directory = argv[optind];
1158 if (update_only == -1) {
1159 if (opt.reset_adv || opt.set_once) {
1160 return modify_existing_adv(directory);
1166 return install_loader(directory, update_only);