CLI: don't highlight the prompt
[syslinux/sherbszt.git] / extlinux / main.c
blobe5212a95068291f025f6c1254f96afe324b50ea0
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 static int sysfs_get_offset(int devfd, unsigned long *start)
105 struct stat st;
106 char sysfs_name[128];
107 FILE *f;
108 int rv;
110 if (fstat(devfd, &st))
111 return -1;
113 if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
114 "/sys/dev/block/%u:%u/start",
115 major(st.st_dev), minor(st.st_dev))
116 >= sizeof sysfs_name)
117 return -1;
119 f = fopen(sysfs_name, "r");
120 if (!f)
121 return -1;
123 rv = fscanf(f, "%lu", start);
124 fclose(f);
126 return (rv == 1) ? 0 : -1;
129 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
130 (x/64/32) is the final fallback. I don't know what LS-240 has
131 as its geometry, since I don't have one and don't know anyone that does,
132 and Google wasn't helpful... */
133 static const struct geometry_table standard_geometries[] = {
134 {360 * 1024, {2, 9, 40, 0}},
135 {720 * 1024, {2, 9, 80, 0}},
136 {1200 * 1024, {2, 15, 80, 0}},
137 {1440 * 1024, {2, 18, 80, 0}},
138 {1680 * 1024, {2, 21, 80, 0}},
139 {1722 * 1024, {2, 21, 80, 0}},
140 {2880 * 1024, {2, 36, 80, 0}},
141 {3840 * 1024, {2, 48, 80, 0}},
142 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
143 {0, {0, 0, 0, 0}}
146 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
148 struct floppy_struct fd_str;
149 struct loop_info li;
150 struct loop_info64 li64;
151 const struct geometry_table *gp;
152 int rv = 0;
154 memset(geo, 0, sizeof *geo);
156 if (!ioctl(devfd, HDIO_GETGEO, &geo)) {
157 goto ok;
158 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
159 geo->heads = fd_str.head;
160 geo->sectors = fd_str.sect;
161 geo->cylinders = fd_str.track;
162 geo->start = 0;
163 goto ok;
166 /* Didn't work. Let's see if this is one of the standard geometries */
167 for (gp = standard_geometries; gp->bytes; gp++) {
168 if (gp->bytes == totalbytes) {
169 memcpy(geo, &gp->g, sizeof *geo);
170 goto ok;
174 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
175 what zipdisks use, so this would help if someone has a USB key that
176 they're booting in USB-ZIP mode. */
178 geo->heads = opt.heads ? : 64;
179 geo->sectors = opt.sectors ? : 32;
180 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
181 geo->start = 0;
183 if (!opt.sectors && !opt.heads) {
184 fprintf(stderr,
185 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
186 " (on hard disks, this is usually harmless.)\n",
187 geo->heads, geo->sectors);
188 rv = 1; /* Suboptimal result */
192 /* If this is a loopback device, try to set the start */
193 if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
194 geo->start = li64.lo_offset >> SECTOR_SHIFT;
195 else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
196 geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
197 else if (!sysfs_get_offset(devfd, &geo->start)) {
198 /* OK */
201 return rv;
205 * Query the device geometry and put it into the boot sector.
206 * Map the file and put the map in the boot sector and file.
207 * Stick the "current directory" inode number into the file.
209 * Returns the number of modified bytes in the boot file.
211 int patch_file_and_bootblock(int fd, const char *dir, int devfd)
213 struct stat dirst, xdst;
214 struct hd_geometry geo;
215 sector_t *sectp;
216 uint64_t totalbytes, totalsectors;
217 int nsect;
218 struct boot_sector *sbs;
219 char *dirpath, *subpath, *xdirpath;
220 int rv;
222 dirpath = realpath(dir, NULL);
223 if (!dirpath || stat(dir, &dirst)) {
224 perror("accessing install directory");
225 exit(255); /* This should never happen */
228 if (lstat(dirpath, &xdst) ||
229 dirst.st_ino != xdst.st_ino ||
230 dirst.st_dev != xdst.st_dev) {
231 perror("realpath returned nonsense");
232 exit(255);
235 subpath = strchr(dirpath, '\0');
236 for (;;) {
237 if (*subpath == '/') {
238 if (subpath > dirpath) {
239 *subpath = '\0';
240 xdirpath = dirpath;
241 } else {
242 xdirpath = "/";
244 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
245 subpath = strchr(subpath+1, '/');
246 if (!subpath)
247 subpath = "/"; /* It's the root of the filesystem */
248 break;
250 *subpath = '/';
253 if (subpath == dirpath)
254 break;
256 subpath--;
259 /* Now subpath should contain the path relative to the fs base */
260 dprintf("subpath = %s\n", subpath);
262 totalbytes = get_size(devfd);
263 get_geometry(devfd, totalbytes, &geo);
265 if (opt.heads)
266 geo.heads = opt.heads;
267 if (opt.sectors)
268 geo.sectors = opt.sectors;
270 /* Patch this into a fake FAT superblock. This isn't because
271 FAT is a good format in any way, it's because it lets the
272 early bootstrap share code with the FAT version. */
273 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
275 sbs = (struct boot_sector *)syslinux_bootsect;
277 totalsectors = totalbytes >> SECTOR_SHIFT;
278 if (totalsectors >= 65536) {
279 set_16(&sbs->bsSectors, 0);
280 } else {
281 set_16(&sbs->bsSectors, totalsectors);
283 set_32(&sbs->bsHugeSectors, totalsectors);
285 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
286 set_16(&sbs->bsSecPerTrack, geo.sectors);
287 set_16(&sbs->bsHeads, geo.heads);
288 set_32(&sbs->bsHiddenSecs, geo.start);
290 /* Construct the boot file map */
292 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
293 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
294 nsect += 2; /* Two sectors for the ADV */
295 sectp = alloca(sizeof(sector_t) * nsect);
296 if (fs_type == EXT2 || fs_type == VFAT) {
297 if (sectmap(fd, sectp, nsect)) {
298 perror("bmap");
299 exit(1);
301 } else if (fs_type == BTRFS) {
302 int i;
303 sector_t *sp = sectp;
305 for (i = 0; i < nsect - 2; i++)
306 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
307 for (i = 0; i < 2; i++)
308 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
311 /* Create the modified image in memory */
312 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
313 opt.raid_mode, subpath, subvol);
315 free(dirpath);
316 return rv;
320 * Install the boot block on the specified device.
321 * Must be run AFTER install_file()!
323 int install_bootblock(int fd, const char *device)
325 struct ext2_super_block sb;
326 struct btrfs_super_block sb2;
327 struct boot_sector sb3;
328 bool ok = false;
330 if (fs_type == EXT2) {
331 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
332 perror("reading superblock");
333 return 1;
335 if (sb.s_magic == EXT2_SUPER_MAGIC)
336 ok = true;
337 } else if (fs_type == BTRFS) {
338 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
339 != sizeof sb2) {
340 perror("reading superblock");
341 return 1;
343 if (sb2.magic == *(u64 *)BTRFS_MAGIC)
344 ok = true;
345 } else if (fs_type == VFAT) {
346 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
347 perror("reading fat superblock");
348 return 1;
350 if (sb3.bsResSectors && sb3.bsFATs &&
351 (strstr(sb3.bs16.FileSysType, "FAT") ||
352 strstr(sb3.bs32.FileSysType, "FAT")))
353 ok = true;
355 if (!ok) {
356 fprintf(stderr, "no fat, ext2/3/4 or btrfs superblock found on %s\n",
357 device);
358 return 1;
360 if (fs_type == VFAT) {
361 struct boot_sector *sbs = (struct boot_sector *)syslinux_bootsect;
362 if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
363 xpwrite(fd, &sbs->bsCode, bsCodeLen,
364 offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
365 perror("writing fat bootblock");
366 return 1;
368 } else {
369 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
370 != syslinux_bootsect_len) {
371 perror("writing bootblock");
372 return 1;
376 return 0;
379 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
381 char *file, *oldfile;
382 int fd = -1, dirfd = -1;
383 int modbytes;
384 int r1, r2;
386 r1 = asprintf(&file, "%s%sldlinux.sys",
387 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
388 r2 = asprintf(&oldfile, "%s%sextlinux.sys",
389 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
390 if (r1 < 0 || !file || r2 < 0 || !oldfile) {
391 perror(program);
392 return 1;
395 dirfd = open(path, O_RDONLY | O_DIRECTORY);
396 if (dirfd < 0) {
397 perror(path);
398 goto bail;
401 fd = open(file, O_RDONLY);
402 if (fd < 0) {
403 if (errno != ENOENT) {
404 perror(file);
405 goto bail;
407 } else {
408 clear_attributes(fd);
410 close(fd);
412 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
413 S_IRUSR | S_IRGRP | S_IROTH);
414 if (fd < 0) {
415 perror(file);
416 goto bail;
419 /* Write it the first time */
420 if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
421 xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
422 boot_image_len) != 2 * ADV_SIZE) {
423 fprintf(stderr, "%s: write failure on %s\n", program, file);
424 goto bail;
427 /* Map the file, and patch the initial sector accordingly */
428 modbytes = patch_file_and_bootblock(fd, path, devfd);
430 /* Write the patch area again - this relies on the file being
431 overwritten in place! */
432 if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
433 fprintf(stderr, "%s: write failure on %s\n", program, file);
434 goto bail;
437 /* Attempt to set immutable flag and remove all write access */
438 /* Only set immutable flag if file is owned by root */
439 set_attributes(fd);
441 if (fstat(fd, rst)) {
442 perror(file);
443 goto bail;
446 close(dirfd);
447 close(fd);
449 /* Look if we have the old filename */
450 fd = open(oldfile, O_RDONLY);
451 if (fd >= 0) {
452 clear_attributes(fd);
453 close(fd);
454 unlink(oldfile);
457 free(file);
458 free(oldfile);
459 return 0;
461 bail:
462 if (dirfd >= 0)
463 close(dirfd);
464 if (fd >= 0)
465 close(fd);
467 free(file);
468 free(oldfile);
469 return 1;
472 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
473 is not managered by btrfs tree, so actually this is not installed as files.
474 since the cow feature of btrfs will move the ldlinux.sys every where */
475 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
477 patch_file_and_bootblock(-1, path, devfd);
478 if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET)
479 != boot_image_len) {
480 perror("writing bootblock");
481 return 1;
483 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
484 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
485 != 2 * ADV_SIZE) {
486 perror("writing adv");
487 return 1;
489 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
490 if (stat(path, rst)) {
491 perror(path);
492 return 1;
494 return 0;
497 int install_file(const char *path, int devfd, struct stat *rst)
499 if (fs_type == EXT2 || fs_type == VFAT)
500 return ext2_fat_install_file(path, devfd, rst);
501 else if (fs_type == BTRFS)
502 return btrfs_install_file(path, devfd, rst);
503 return 1;
506 #ifdef __KLIBC__
507 static char devname_buf[64];
509 static void device_cleanup(void)
511 unlink(devname_buf);
513 #endif
515 /* Verify that a device fd and a pathname agree.
516 Return 0 on valid, -1 on error. */
517 static int validate_device(const char *path, int devfd)
519 struct stat pst, dst;
520 struct statfs sfs;
522 if (stat(path, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
523 return -1;
524 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
525 if (fs_type == BTRFS && sfs.f_type == BTRFS_SUPER_MAGIC)
526 return 0;
527 return (pst.st_dev == dst.st_rdev) ? 0 : -1;
530 #ifndef __KLIBC__
531 static const char *find_device(const char *mtab_file, dev_t dev)
533 struct mntent *mnt;
534 struct stat dst;
535 FILE *mtab;
536 const char *devname = NULL;
537 bool done;
539 mtab = setmntent(mtab_file, "r");
540 if (!mtab)
541 return NULL;
543 done = false;
544 while ((mnt = getmntent(mtab))) {
545 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
546 switch (fs_type) {
547 case BTRFS:
548 if (!strcmp(mnt->mnt_type, "btrfs") &&
549 !stat(mnt->mnt_dir, &dst) &&
550 dst.st_dev == dev) {
551 char *opt = strstr(mnt->mnt_opts, BTRFS_SUBVOL_OPT);
553 if (opt) {
554 if (!subvol[0]) {
555 char *tmp;
557 strcpy(subvol, opt + sizeof(BTRFS_SUBVOL_OPT) - 1);
558 tmp = strchr(subvol, 32);
559 if (tmp)
560 *tmp = '\0';
562 break; /* should break and let upper layer try again */
563 } else
564 done = true;
566 break;
567 case EXT2:
568 if ((!strcmp(mnt->mnt_type, "ext2") ||
569 !strcmp(mnt->mnt_type, "ext3") ||
570 !strcmp(mnt->mnt_type, "ext4")) &&
571 !stat(mnt->mnt_fsname, &dst) &&
572 dst.st_rdev == dev) {
573 done = true;
574 break;
576 case VFAT:
577 if ((!strcmp(mnt->mnt_type, "vfat")) &&
578 !stat(mnt->mnt_fsname, &dst) &&
579 dst.st_rdev == dev) {
580 done = true;
581 break;
583 case NONE:
584 break;
586 if (done) {
587 devname = strdup(mnt->mnt_fsname);
588 break;
591 endmntent(mtab);
593 return devname;
595 #endif
597 static const char *get_devname(const char *path)
599 const char *devname = NULL;
600 struct stat st;
601 struct statfs sfs;
603 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
604 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
605 return devname;
607 if (statfs(path, &sfs)) {
608 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
609 return devname;
611 #ifdef __KLIBC__
613 /* klibc doesn't have getmntent and friends; instead, just create
614 a new device with the appropriate device type */
615 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
616 major(st.st_dev), minor(st.st_dev));
618 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
619 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
620 return devname;
623 atexit(device_cleanup); /* unlink the device node on exit */
624 devname = devname_buf;
626 #else
628 /* check /etc/mtab first, since btrfs subvol info is only in here */
629 devname = find_device("/etc/mtab", st.st_dev);
630 if (subvol[0] && !devname) { /* we just find it is a btrfs subvol */
631 char parent[256];
632 char *tmp;
634 strcpy(parent, path);
635 tmp = strrchr(parent, '/');
636 if (tmp) {
637 *tmp = '\0';
638 fprintf(stderr, "%s is subvol, try its parent dir %s\n", path, parent);
639 devname = get_devname(parent);
640 } else
641 devname = NULL;
643 if (!devname) {
644 /* Didn't find it in /etc/mtab, try /proc/mounts */
645 devname = find_device("/proc/mounts", st.st_dev);
647 if (!devname) {
648 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
649 return devname;
652 fprintf(stderr, "%s is device %s\n", path, devname);
653 #endif
654 return devname;
657 static int open_device(const char *path, struct stat *st, const char **_devname)
659 int devfd;
660 const char *devname = NULL;
661 struct statfs sfs;
663 if (st)
664 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
665 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
666 return -1;
669 if (statfs(path, &sfs)) {
670 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
671 return -1;
673 if (sfs.f_type == EXT2_SUPER_MAGIC)
674 fs_type = EXT2;
675 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
676 fs_type = BTRFS;
677 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
678 fs_type = VFAT;
680 if (!fs_type) {
681 fprintf(stderr, "%s: not a fat, ext2/3/4 or btrfs filesystem: %s\n",
682 program, path);
683 return -1;
686 devfd = -1;
687 devname = get_devname(path);
688 if (_devname)
689 *_devname = devname;
691 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
692 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
693 return -1;
696 /* Verify that the device we opened is the device intended */
697 if (validate_device(path, devfd)) {
698 fprintf(stderr, "%s: path %s doesn't match device %s\n",
699 program, path, devname);
700 close(devfd);
701 return -1;
703 return devfd;
706 static int btrfs_read_adv(int devfd)
708 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
709 != 2 * ADV_SIZE)
710 return -1;
712 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
715 static int ext_read_adv(const char *path, int devfd, const char **namep)
717 int err;
718 const char *name;
720 if (fs_type == BTRFS) {
721 /* btrfs "ldlinux.sys" is in 64k blank area */
722 return btrfs_read_adv(devfd);
723 } else {
724 err = read_adv(path, name = "ldlinux.sys");
725 if (err == 2) /* ldlinux.sys does not exist */
726 err = read_adv(path, name = "extlinux.sys");
727 if (namep)
728 *namep = name;
729 return err;
733 static int ext_write_adv(const char *path, const char *cfg, int devfd)
735 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
736 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
737 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
738 perror("writing adv");
739 return 1;
741 return 0;
743 return write_adv(path, cfg);
746 int install_loader(const char *path, int update_only)
748 struct stat st, fst;
749 int devfd, rv;
750 const char *devname;
752 devfd = open_device(path, &st, &devname);
753 if (devfd < 0)
754 return 1;
756 if (update_only && !syslinux_already_installed(devfd)) {
757 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
758 program);
759 close(devfd);
760 return 1;
763 /* Read a pre-existing ADV, if already installed */
764 if (opt.reset_adv) {
765 syslinux_reset_adv(syslinux_adv);
766 } else if (ext_read_adv(path, devfd, NULL) < 0) {
767 close(devfd);
768 return 1;
771 if (modify_adv() < 0) {
772 close(devfd);
773 return 1;
776 /* Install ldlinux.sys */
777 if (install_file(path, devfd, &fst)) {
778 close(devfd);
779 return 1;
781 if (fst.st_dev != st.st_dev) {
782 fprintf(stderr, "%s: file system changed under us - aborting!\n",
783 program);
784 close(devfd);
785 return 1;
788 sync();
789 rv = install_bootblock(devfd, devname);
790 close(devfd);
791 sync();
793 return rv;
797 * Modify the ADV of an existing installation
799 int modify_existing_adv(const char *path)
801 const char *filename;
802 int devfd;
804 devfd = open_device(path, NULL, NULL);
805 if (devfd < 0)
806 return 1;
808 if (opt.reset_adv)
809 syslinux_reset_adv(syslinux_adv);
810 else if (ext_read_adv(path, devfd, &filename) < 0) {
811 close(devfd);
812 return 1;
814 if (modify_adv() < 0) {
815 close(devfd);
816 return 1;
818 if (ext_write_adv(path, filename, devfd) < 0) {
819 close(devfd);
820 return 1;
822 close(devfd);
823 return 0;
826 int main(int argc, char *argv[])
828 parse_options(argc, argv, MODE_EXTLINUX);
830 if (!opt.directory || opt.install_mbr || opt.activate_partition)
831 usage(EX_USAGE, 0);
833 if (opt.update_only == -1) {
834 if (opt.reset_adv || opt.set_once || opt.menu_save)
835 return modify_existing_adv(opt.directory);
836 else
837 usage(EX_USAGE, MODE_EXTLINUX);
840 return install_loader(opt.directory, opt.update_only);