Adding upstream version 4.01+dfsg.
[syslinux-debian/hramrach.git] / extlinux / main.c
blobdaebc101f942af3dd7360c68ae621594d0b5ecf0
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2010 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 * ----------------------------------------------------------------------- */
15 * extlinux.c
17 * Install the syslinux boot block on an fat, ext2/3/4 and btrfs filesystem
20 #define _GNU_SOURCE /* Enable everything */
21 #include <inttypes.h>
22 /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
23 typedef uint64_t u64;
24 #include <alloca.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #ifndef __KLIBC__
30 #include <mntent.h>
31 #endif
32 #include <stdbool.h>
33 #include <stddef.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <getopt.h>
37 #include <sysexits.h>
38 #include <sys/ioctl.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/mount.h>
42 #include <sys/vfs.h>
44 #include "linuxioctl.h"
46 #include "btrfs.h"
47 #include "fat.h"
48 #include "../version.h"
49 #include "syslxint.h"
50 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
51 #include "setadv.h"
52 #include "syslxopt.h" /* unified options */
54 #ifdef DEBUG
55 # define dprintf printf
56 #else
57 # define dprintf(...) ((void)0)
58 #endif
60 #ifndef EXT2_SUPER_OFFSET
61 #define EXT2_SUPER_OFFSET 1024
62 #endif
64 /* the btrfs partition first 64K blank area is used to store boot sector and
65 boot image, the boot sector is from 0~512, the boot image starts after */
66 #define BTRFS_BOOTSECT_AREA 65536
67 #define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE
68 #define BTRFS_SUBVOL_OPT "subvol="
69 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
70 static char subvol[BTRFS_SUBVOL_MAX];
72 #define BTRFS_ADV_OFFSET (BTRFS_BOOTSECT_AREA - 2 * ADV_SIZE)
75 * Get the size of a block device
77 uint64_t get_size(int devfd)
79 uint64_t bytes;
80 uint32_t sects;
81 struct stat st;
83 #ifdef BLKGETSIZE64
84 if (!ioctl(devfd, BLKGETSIZE64, &bytes))
85 return bytes;
86 #endif
87 if (!ioctl(devfd, BLKGETSIZE, &sects))
88 return (uint64_t) sects << 9;
89 else if (!fstat(devfd, &st) && st.st_size)
90 return st.st_size;
91 else
92 return 0;
96 * Get device geometry and partition offset
98 struct geometry_table {
99 uint64_t bytes;
100 struct hd_geometry g;
103 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
104 (x/64/32) is the final fallback. I don't know what LS-240 has
105 as its geometry, since I don't have one and don't know anyone that does,
106 and Google wasn't helpful... */
107 static const struct geometry_table standard_geometries[] = {
108 {360 * 1024, {2, 9, 40, 0}},
109 {720 * 1024, {2, 9, 80, 0}},
110 {1200 * 1024, {2, 15, 80, 0}},
111 {1440 * 1024, {2, 18, 80, 0}},
112 {1680 * 1024, {2, 21, 80, 0}},
113 {1722 * 1024, {2, 21, 80, 0}},
114 {2880 * 1024, {2, 36, 80, 0}},
115 {3840 * 1024, {2, 48, 80, 0}},
116 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
117 {0, {0, 0, 0, 0}}
120 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
122 struct floppy_struct fd_str;
123 struct loop_info li;
124 struct loop_info64 li64;
125 const struct geometry_table *gp;
127 memset(geo, 0, sizeof *geo);
129 if (!ioctl(devfd, HDIO_GETGEO, &geo)) {
130 return 0;
131 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
132 geo->heads = fd_str.head;
133 geo->sectors = fd_str.sect;
134 geo->cylinders = fd_str.track;
135 geo->start = 0;
136 return 0;
139 /* Didn't work. Let's see if this is one of the standard geometries */
140 for (gp = standard_geometries; gp->bytes; gp++) {
141 if (gp->bytes == totalbytes) {
142 memcpy(geo, &gp->g, sizeof *geo);
143 return 0;
147 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
148 what zipdisks use, so this would help if someone has a USB key that
149 they're booting in USB-ZIP mode. */
151 geo->heads = opt.heads ? : 64;
152 geo->sectors = opt.sectors ? : 32;
153 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
154 geo->start = 0;
156 if (!opt.sectors && !opt.heads)
157 fprintf(stderr,
158 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
159 " (on hard disks, this is usually harmless.)\n",
160 geo->heads, geo->sectors);
162 /* If this is a loopback device, try to set the start */
163 if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
164 geo->start = li64.lo_offset >> SECTOR_SHIFT;
165 else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
166 geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
168 return 1;
172 * Query the device geometry and put it into the boot sector.
173 * Map the file and put the map in the boot sector and file.
174 * Stick the "current directory" inode number into the file.
176 * Returns the number of modified bytes in the boot file.
178 int patch_file_and_bootblock(int fd, const char *dir, int devfd)
180 struct stat dirst, xdst;
181 struct hd_geometry geo;
182 sector_t *sectp;
183 uint64_t totalbytes, totalsectors;
184 int nsect;
185 struct boot_sector *sbs;
186 char *dirpath, *subpath, *xdirpath, *xsubpath;
187 int rv;
189 dirpath = realpath(dir, NULL);
190 if (!dirpath || stat(dir, &dirst)) {
191 perror("accessing install directory");
192 exit(255); /* This should never happen */
195 if (lstat(dirpath, &xdst) ||
196 dirst.st_ino != xdst.st_ino ||
197 dirst.st_dev != xdst.st_dev) {
198 perror("realpath returned nonsense");
199 exit(255);
202 subpath = strchr(dirpath, '\0');
203 for (;;) {
204 if (*subpath == '/') {
205 if (subpath > dirpath) {
206 *subpath = '\0';
207 xsubpath = subpath+1;
208 xdirpath = dirpath;
209 } else {
210 xsubpath = subpath;
211 xdirpath = "/";
213 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
214 subpath = strchr(subpath+1, '/');
215 if (!subpath)
216 subpath = "/"; /* It's the root of the filesystem */
217 break;
219 *subpath = '/';
222 if (subpath == dirpath)
223 break;
225 subpath--;
228 /* Now subpath should contain the path relative to the fs base */
229 dprintf("subpath = %s\n", subpath);
231 totalbytes = get_size(devfd);
232 get_geometry(devfd, totalbytes, &geo);
234 if (opt.heads)
235 geo.heads = opt.heads;
236 if (opt.sectors)
237 geo.sectors = opt.sectors;
239 /* Patch this into a fake FAT superblock. This isn't because
240 FAT is a good format in any way, it's because it lets the
241 early bootstrap share code with the FAT version. */
242 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
244 sbs = (struct boot_sector *)syslinux_bootsect;
246 totalsectors = totalbytes >> SECTOR_SHIFT;
247 if (totalsectors >= 65536) {
248 set_16(&sbs->bsSectors, 0);
249 } else {
250 set_16(&sbs->bsSectors, totalsectors);
252 set_32(&sbs->bsHugeSectors, totalsectors);
254 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
255 set_16(&sbs->bsSecPerTrack, geo.sectors);
256 set_16(&sbs->bsHeads, geo.heads);
257 set_32(&sbs->bsHiddenSecs, geo.start);
259 /* Construct the boot file map */
261 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
262 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
263 nsect += 2; /* Two sectors for the ADV */
264 sectp = alloca(sizeof(sector_t) * nsect);
265 if (fs_type == EXT2 || fs_type == VFAT) {
266 if (sectmap(fd, sectp, nsect)) {
267 perror("bmap");
268 exit(1);
270 } else if (fs_type == BTRFS) {
271 int i;
272 sector_t *sp = sectp;
274 for (i = 0; i < nsect - 2; i++)
275 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
276 for (i = 0; i < 2; i++)
277 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
280 /* Create the modified image in memory */
281 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
282 opt.raid_mode, subpath, subvol);
284 free(dirpath);
285 return rv;
289 * Install the boot block on the specified device.
290 * Must be run AFTER install_file()!
292 int install_bootblock(int fd, const char *device)
294 struct ext2_super_block sb;
295 struct btrfs_super_block sb2;
296 struct boot_sector sb3;
297 bool ok = false;
299 if (fs_type == EXT2) {
300 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
301 perror("reading superblock");
302 return 1;
304 if (sb.s_magic == EXT2_SUPER_MAGIC)
305 ok = true;
306 } else if (fs_type == BTRFS) {
307 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
308 != sizeof sb2) {
309 perror("reading superblock");
310 return 1;
312 if (sb2.magic == *(u64 *)BTRFS_MAGIC)
313 ok = true;
314 } else if (fs_type == VFAT) {
315 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
316 perror("reading fat superblock");
317 return 1;
319 if (sb3.bsResSectors && sb3.bsFATs &&
320 (strstr(sb3.bs16.FileSysType, "FAT") ||
321 strstr(sb3.bs32.FileSysType, "FAT")))
322 ok = true;
324 if (!ok) {
325 fprintf(stderr, "no fat, ext2/3/4 or btrfs superblock found on %s\n",
326 device);
327 return 1;
329 if (fs_type == VFAT) {
330 struct boot_sector *sbs = (struct boot_sector *)syslinux_bootsect;
331 if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
332 xpwrite(fd, &sbs->bsCode, bsCodeLen,
333 offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
334 perror("writing fat bootblock");
335 return 1;
337 } else {
338 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
339 != syslinux_bootsect_len) {
340 perror("writing bootblock");
341 return 1;
345 return 0;
348 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
350 char *file, *oldfile;
351 int fd = -1, dirfd = -1;
352 int modbytes;
353 int r1, r2;
355 r1 = asprintf(&file, "%s%sldlinux.sys",
356 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
357 r2 = asprintf(&oldfile, "%s%sextlinux.sys",
358 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
359 if (r1 < 0 || !file || r2 < 0 || !oldfile) {
360 perror(program);
361 return 1;
364 dirfd = open(path, O_RDONLY | O_DIRECTORY);
365 if (dirfd < 0) {
366 perror(path);
367 goto bail;
370 fd = open(file, O_RDONLY);
371 if (fd < 0) {
372 if (errno != ENOENT) {
373 perror(file);
374 goto bail;
376 } else {
377 clear_attributes(fd);
379 close(fd);
381 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
382 S_IRUSR | S_IRGRP | S_IROTH);
383 if (fd < 0) {
384 perror(file);
385 goto bail;
388 /* Write it the first time */
389 if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
390 xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
391 boot_image_len) != 2 * ADV_SIZE) {
392 fprintf(stderr, "%s: write failure on %s\n", program, file);
393 goto bail;
396 /* Map the file, and patch the initial sector accordingly */
397 modbytes = patch_file_and_bootblock(fd, path, devfd);
399 /* Write the patch area again - this relies on the file being
400 overwritten in place! */
401 if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
402 fprintf(stderr, "%s: write failure on %s\n", program, file);
403 goto bail;
406 /* Attempt to set immutable flag and remove all write access */
407 /* Only set immutable flag if file is owned by root */
408 set_attributes(fd);
410 if (fstat(fd, rst)) {
411 perror(file);
412 goto bail;
415 close(dirfd);
416 close(fd);
418 /* Look if we have the old filename */
419 fd = open(oldfile, O_RDONLY);
420 if (fd >= 0) {
421 clear_attributes(fd);
422 close(fd);
423 unlink(oldfile);
426 free(file);
427 free(oldfile);
428 return 0;
430 bail:
431 if (dirfd >= 0)
432 close(dirfd);
433 if (fd >= 0)
434 close(fd);
436 free(file);
437 free(oldfile);
438 return 1;
441 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
442 is not managered by btrfs tree, so actually this is not installed as files.
443 since the cow feature of btrfs will move the ldlinux.sys every where */
444 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
446 patch_file_and_bootblock(-1, path, devfd);
447 if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET)
448 != boot_image_len) {
449 perror("writing bootblock");
450 return 1;
452 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
453 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
454 != 2 * ADV_SIZE) {
455 perror("writing adv");
456 return 1;
458 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
459 if (stat(path, rst)) {
460 perror(path);
461 return 1;
463 return 0;
466 int install_file(const char *path, int devfd, struct stat *rst)
468 if (fs_type == EXT2 || fs_type == VFAT)
469 return ext2_fat_install_file(path, devfd, rst);
470 else if (fs_type == BTRFS)
471 return btrfs_install_file(path, devfd, rst);
472 return 1;
476 * SYSLINUX installs the string 'SYSLINUX' at offset 3 in the boot
477 * sector; this is consistent with FAT filesystems. Earlier versions
478 * would install the string "EXTLINUX" instead, handle both.
480 int already_installed(int devfd)
482 char buffer[8];
484 xpread(devfd, buffer, 8, 3);
485 return !memcmp(buffer, "SYSLINUX", 8) || !memcmp(buffer, "EXTLINUX", 8);
488 #ifdef __KLIBC__
489 static char devname_buf[64];
491 static void device_cleanup(void)
493 unlink(devname_buf);
495 #endif
497 /* Verify that a device fd and a pathname agree.
498 Return 0 on valid, -1 on error. */
499 static int validate_device(const char *path, int devfd)
501 struct stat pst, dst;
502 struct statfs sfs;
504 if (stat(path, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
505 return -1;
506 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
507 if (fs_type == BTRFS && sfs.f_type == BTRFS_SUPER_MAGIC)
508 return 0;
509 return (pst.st_dev == dst.st_rdev) ? 0 : -1;
512 #ifndef __KLIBC__
513 static const char *find_device(const char *mtab_file, dev_t dev)
515 struct mntent *mnt;
516 struct stat dst;
517 FILE *mtab;
518 const char *devname = NULL;
519 bool done;
521 mtab = setmntent(mtab_file, "r");
522 if (!mtab)
523 return NULL;
525 done = false;
526 while ((mnt = getmntent(mtab))) {
527 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
528 switch (fs_type) {
529 case BTRFS:
530 if (!strcmp(mnt->mnt_type, "btrfs") &&
531 !stat(mnt->mnt_dir, &dst) &&
532 dst.st_dev == dev) {
533 char *opt = strstr(mnt->mnt_opts, BTRFS_SUBVOL_OPT);
535 if (opt) {
536 if (!subvol[0]) {
537 char *tmp;
539 strcpy(subvol, opt + sizeof(BTRFS_SUBVOL_OPT) - 1);
540 tmp = strchr(subvol, 32);
541 if (tmp)
542 *tmp = '\0';
544 break; /* should break and let upper layer try again */
545 } else
546 done = true;
548 break;
549 case EXT2:
550 if ((!strcmp(mnt->mnt_type, "ext2") ||
551 !strcmp(mnt->mnt_type, "ext3") ||
552 !strcmp(mnt->mnt_type, "ext4")) &&
553 !stat(mnt->mnt_fsname, &dst) &&
554 dst.st_rdev == dev) {
555 done = true;
556 break;
558 case VFAT:
559 if ((!strcmp(mnt->mnt_type, "vfat")) &&
560 !stat(mnt->mnt_fsname, &dst) &&
561 dst.st_rdev == dev) {
562 done = true;
563 break;
565 case NONE:
566 break;
568 if (done) {
569 devname = strdup(mnt->mnt_fsname);
570 break;
573 endmntent(mtab);
575 return devname;
577 #endif
579 static const char *get_devname(const char *path)
581 const char *devname = NULL;
582 struct stat st;
583 struct statfs sfs;
585 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
586 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
587 return devname;
589 if (statfs(path, &sfs)) {
590 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
591 return devname;
593 #ifdef __KLIBC__
595 /* klibc doesn't have getmntent and friends; instead, just create
596 a new device with the appropriate device type */
597 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
598 major(st.st_dev), minor(st.st_dev));
600 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
601 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
602 return devname;
605 atexit(device_cleanup); /* unlink the device node on exit */
606 devname = devname_buf;
608 #else
610 /* check /etc/mtab first, since btrfs subvol info is only in here */
611 devname = find_device("/etc/mtab", st.st_dev);
612 if (subvol[0] && !devname) { /* we just find it is a btrfs subvol */
613 char parent[256];
614 char *tmp;
616 strcpy(parent, path);
617 tmp = strrchr(parent, '/');
618 if (tmp) {
619 *tmp = '\0';
620 fprintf(stderr, "%s is subvol, try its parent dir %s\n", path, parent);
621 devname = get_devname(parent);
622 } else
623 devname = NULL;
625 if (!devname) {
626 /* Didn't find it in /etc/mtab, try /proc/mounts */
627 devname = find_device("/proc/mounts", st.st_dev);
629 if (!devname) {
630 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
631 return devname;
634 fprintf(stderr, "%s is device %s\n", path, devname);
635 #endif
636 return devname;
639 static int open_device(const char *path, struct stat *st, const char **_devname)
641 int devfd;
642 const char *devname = NULL;
643 struct statfs sfs;
645 if (st)
646 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
647 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
648 return -1;
651 if (statfs(path, &sfs)) {
652 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
653 return -1;
655 if (sfs.f_type == EXT2_SUPER_MAGIC)
656 fs_type = EXT2;
657 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
658 fs_type = BTRFS;
659 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
660 fs_type = VFAT;
662 if (!fs_type) {
663 fprintf(stderr, "%s: not a fat, ext2/3/4 or btrfs filesystem: %s\n",
664 program, path);
665 return -1;
668 devfd = -1;
669 devname = get_devname(path);
670 if (_devname)
671 *_devname = devname;
673 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
674 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
675 return -1;
678 /* Verify that the device we opened is the device intended */
679 if (validate_device(path, devfd)) {
680 fprintf(stderr, "%s: path %s doesn't match device %s\n",
681 program, path, devname);
682 close(devfd);
683 return -1;
685 return devfd;
688 static int btrfs_read_adv(int devfd)
690 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
691 != 2 * ADV_SIZE)
692 return -1;
694 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
697 static int ext_read_adv(const char *path, int devfd, const char **namep)
699 int err;
700 const char *name;
702 if (fs_type == BTRFS) {
703 /* btrfs "ldlinux.sys" is in 64k blank area */
704 return btrfs_read_adv(devfd);
705 } else {
706 err = read_adv(path, name = "ldlinux.sys");
707 if (err == 2) /* ldlinux.sys does not exist */
708 err = read_adv(path, name = "extlinux.sys");
709 if (namep)
710 *namep = name;
711 return err;
715 static int ext_write_adv(const char *path, const char *cfg, int devfd)
717 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
718 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
719 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
720 perror("writing adv");
721 return 1;
723 return 0;
725 return write_adv(path, cfg);
728 int install_loader(const char *path, int update_only)
730 struct stat st, fst;
731 int devfd, rv;
732 const char *devname;
734 devfd = open_device(path, &st, &devname);
735 if (devfd < 0)
736 return 1;
738 if (update_only && !already_installed(devfd)) {
739 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
740 program);
741 close(devfd);
742 return 1;
745 /* Read a pre-existing ADV, if already installed */
746 if (opt.reset_adv) {
747 syslinux_reset_adv(syslinux_adv);
748 } else if (ext_read_adv(path, devfd, NULL) < 0) {
749 close(devfd);
750 return 1;
753 if (modify_adv() < 0) {
754 close(devfd);
755 return 1;
758 /* Install ldlinux.sys */
759 if (install_file(path, devfd, &fst)) {
760 close(devfd);
761 return 1;
763 if (fst.st_dev != st.st_dev) {
764 fprintf(stderr, "%s: file system changed under us - aborting!\n",
765 program);
766 close(devfd);
767 return 1;
770 sync();
771 rv = install_bootblock(devfd, devname);
772 close(devfd);
773 sync();
775 return rv;
779 * Modify the ADV of an existing installation
781 int modify_existing_adv(const char *path)
783 const char *filename;
784 int devfd;
786 devfd = open_device(path, NULL, NULL);
787 if (devfd < 0)
788 return 1;
790 if (opt.reset_adv)
791 syslinux_reset_adv(syslinux_adv);
792 else if (ext_read_adv(path, devfd, &filename) < 0) {
793 close(devfd);
794 return 1;
796 if (modify_adv() < 0) {
797 close(devfd);
798 return 1;
800 if (ext_write_adv(path, filename, devfd) < 0) {
801 close(devfd);
802 return 1;
804 close(devfd);
805 return 0;
808 int main(int argc, char *argv[])
810 parse_options(argc, argv, MODE_EXTLINUX);
812 if (!opt.directory)
813 usage(EX_USAGE, 0);
815 if (opt.update_only == -1) {
816 if (opt.reset_adv || opt.set_once || opt.menu_save)
817 return modify_existing_adv(opt.directory);
818 else
819 usage(EX_USAGE, MODE_EXTLINUX);
822 return install_loader(opt.directory, opt.update_only);