Adding upstream version 4.00~pre61+dfsg.
[syslinux-debian/hramrach.git] / extlinux / main.c
blobad17351655011c4c7c0eb04f30849674443f2b58
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 #if defined(__linux__) && !defined(BLKGETSIZE64)
61 /* This takes a u64, but the size field says size_t. Someone screwed big. */
62 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
63 #endif
65 #ifndef EXT2_SUPER_OFFSET
66 #define EXT2_SUPER_OFFSET 1024
67 #endif
69 /* the btrfs partition first 64K blank area is used to store boot sector and
70 boot image, the boot sector is from 0~512, the boot image starts at 2K */
71 #define BTRFS_EXTLINUX_OFFSET (2*1024)
72 #define BTRFS_SUBVOL_OPT "subvol="
73 #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
74 static char subvol[BTRFS_SUBVOL_MAX];
76 #define BTRFS_ADV_OFFSET (BTRFS_EXTLINUX_OFFSET + boot_image_len)
79 * Get the size of a block device
81 uint64_t get_size(int devfd)
83 uint64_t bytes;
84 uint32_t sects;
85 struct stat st;
87 #ifdef BLKGETSIZE64
88 if (!ioctl(devfd, BLKGETSIZE64, &bytes))
89 return bytes;
90 #endif
91 if (!ioctl(devfd, BLKGETSIZE, &sects))
92 return (uint64_t) sects << 9;
93 else if (!fstat(devfd, &st) && st.st_size)
94 return st.st_size;
95 else
96 return 0;
100 * Get device geometry and partition offset
102 struct geometry_table {
103 uint64_t bytes;
104 struct hd_geometry g;
107 /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
108 (x/64/32) is the final fallback. I don't know what LS-240 has
109 as its geometry, since I don't have one and don't know anyone that does,
110 and Google wasn't helpful... */
111 static const struct geometry_table standard_geometries[] = {
112 {360 * 1024, {2, 9, 40, 0}},
113 {720 * 1024, {2, 9, 80, 0}},
114 {1200 * 1024, {2, 15, 80, 0}},
115 {1440 * 1024, {2, 18, 80, 0}},
116 {1680 * 1024, {2, 21, 80, 0}},
117 {1722 * 1024, {2, 21, 80, 0}},
118 {2880 * 1024, {2, 36, 80, 0}},
119 {3840 * 1024, {2, 48, 80, 0}},
120 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
121 {0, {0, 0, 0, 0}}
124 int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
126 struct floppy_struct fd_str;
127 const struct geometry_table *gp;
129 memset(geo, 0, sizeof *geo);
131 if (!ioctl(devfd, HDIO_GETGEO, &geo)) {
132 return 0;
133 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
134 geo->heads = fd_str.head;
135 geo->sectors = fd_str.sect;
136 geo->cylinders = fd_str.track;
137 geo->start = 0;
138 return 0;
141 /* Didn't work. Let's see if this is one of the standard geometries */
142 for (gp = standard_geometries; gp->bytes; gp++) {
143 if (gp->bytes == totalbytes) {
144 memcpy(geo, &gp->g, sizeof *geo);
145 return 0;
149 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
150 what zipdisks use, so this would help if someone has a USB key that
151 they're booting in USB-ZIP mode. */
153 geo->heads = opt.heads ? : 64;
154 geo->sectors = opt.sectors ? : 32;
155 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
156 geo->start = 0;
158 if (!opt.sectors && !opt.heads)
159 fprintf(stderr,
160 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
161 " (on hard disks, this is usually harmless.)\n",
162 geo->heads, geo->sectors);
164 return 1;
168 * Query the device geometry and put it into the boot sector.
169 * Map the file and put the map in the boot sector and file.
170 * Stick the "current directory" inode number into the file.
172 * Returns the number of modified bytes in the boot file.
174 int patch_file_and_bootblock(int fd, const char *dir, int devfd)
176 struct stat dirst, xdst;
177 struct hd_geometry geo;
178 sector_t *sectp;
179 uint64_t totalbytes, totalsectors;
180 int nsect;
181 struct boot_sector *sbs;
182 char *dirpath, *subpath, *xdirpath, *xsubpath;
183 int rv;
185 dirpath = realpath(dir, NULL);
186 if (!dirpath || stat(dir, &dirst)) {
187 perror("accessing install directory");
188 exit(255); /* This should never happen */
191 if (lstat(dirpath, &xdst) ||
192 dirst.st_ino != xdst.st_ino ||
193 dirst.st_dev != xdst.st_dev) {
194 perror("realpath returned nonsense");
195 exit(255);
198 subpath = strchr(dirpath, '\0');
199 for (;;) {
200 if (*subpath == '/') {
201 if (subpath > dirpath) {
202 *subpath = '\0';
203 xsubpath = subpath+1;
204 xdirpath = dirpath;
205 } else {
206 xsubpath = subpath;
207 xdirpath = "/";
209 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
210 subpath = strchr(subpath+1, '/');
211 if (!subpath)
212 subpath = "/"; /* It's the root of the filesystem */
213 break;
215 *subpath = '/';
218 if (subpath == dirpath)
219 break;
221 subpath--;
224 /* Now subpath should contain the path relative to the fs base */
225 dprintf("subpath = %s\n", subpath);
227 totalbytes = get_size(devfd);
228 get_geometry(devfd, totalbytes, &geo);
230 if (opt.heads)
231 geo.heads = opt.heads;
232 if (opt.sectors)
233 geo.sectors = opt.sectors;
235 /* Patch this into a fake FAT superblock. This isn't because
236 FAT is a good format in any way, it's because it lets the
237 early bootstrap share code with the FAT version. */
238 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
240 sbs = (struct boot_sector *)syslinux_bootsect;
242 totalsectors = totalbytes >> SECTOR_SHIFT;
243 if (totalsectors >= 65536) {
244 set_16(&sbs->bsSectors, 0);
245 } else {
246 set_16(&sbs->bsSectors, totalsectors);
248 set_32(&sbs->bsHugeSectors, totalsectors);
250 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
251 set_16(&sbs->bsSecPerTrack, geo.sectors);
252 set_16(&sbs->bsHeads, geo.heads);
253 set_32(&sbs->bsHiddenSecs, geo.start);
255 /* Construct the boot file map */
257 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
258 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
259 nsect += 2; /* Two sectors for the ADV */
260 sectp = alloca(sizeof(sector_t) * nsect);
261 if (fs_type == EXT2 || fs_type == VFAT) {
262 if (sectmap(fd, sectp, nsect)) {
263 perror("bmap");
264 exit(1);
266 } else if (fs_type == BTRFS) {
267 int i;
269 for (i = 0; i < nsect; i++)
270 sectp[i] = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
273 /* Create the modified image in memory */
274 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
275 opt.raid_mode, subpath, subvol);
277 free(dirpath);
278 return rv;
282 * Install the boot block on the specified device.
283 * Must be run AFTER install_file()!
285 int install_bootblock(int fd, const char *device)
287 struct ext2_super_block sb;
288 struct btrfs_super_block sb2;
289 struct boot_sector sb3;
290 bool ok = false;
292 if (fs_type == EXT2) {
293 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
294 perror("reading superblock");
295 return 1;
297 if (sb.s_magic == EXT2_SUPER_MAGIC)
298 ok = true;
299 } else if (fs_type == BTRFS) {
300 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
301 != sizeof sb2) {
302 perror("reading superblock");
303 return 1;
305 if (sb2.magic == *(u64 *)BTRFS_MAGIC)
306 ok = true;
307 } else if (fs_type == VFAT) {
308 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
309 perror("reading fat superblock");
310 return 1;
312 if (sb3.bsResSectors && sb3.bsFATs &&
313 (strstr(sb3.bs16.FileSysType, "FAT") ||
314 strstr(sb3.bs32.FileSysType, "FAT")))
315 ok = true;
317 if (!ok) {
318 fprintf(stderr, "no fat, ext2/3/4 or btrfs superblock found on %s\n",
319 device);
320 return 1;
322 if (fs_type == VFAT) {
323 struct boot_sector *sbs = (struct boot_sector *)syslinux_bootsect;
324 if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
325 xpwrite(fd, &sbs->bsCode, bsCodeLen,
326 offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
327 perror("writing fat bootblock");
328 return 1;
330 } else {
331 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
332 != syslinux_bootsect_len) {
333 perror("writing bootblock");
334 return 1;
338 return 0;
341 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
343 char *file, *oldfile;
344 int fd = -1, dirfd = -1;
345 int modbytes;
347 asprintf(&file, "%s%sldlinux.sys",
348 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
349 asprintf(&oldfile, "%s%sextlinux.sys",
350 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
351 if (!file || !oldfile) {
352 perror(program);
353 return 1;
356 dirfd = open(path, O_RDONLY | O_DIRECTORY);
357 if (dirfd < 0) {
358 perror(path);
359 goto bail;
362 fd = open(file, O_RDONLY);
363 if (fd < 0) {
364 if (errno != ENOENT) {
365 perror(file);
366 goto bail;
368 } else {
369 clear_attributes(fd);
371 close(fd);
373 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
374 S_IRUSR | S_IRGRP | S_IROTH);
375 if (fd < 0) {
376 perror(file);
377 goto bail;
380 /* Write it the first time */
381 if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
382 xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
383 boot_image_len) != 2 * ADV_SIZE) {
384 fprintf(stderr, "%s: write failure on %s\n", program, file);
385 goto bail;
388 /* Map the file, and patch the initial sector accordingly */
389 modbytes = patch_file_and_bootblock(fd, path, devfd);
391 /* Write the patch area again - this relies on the file being
392 overwritten in place! */
393 if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
394 fprintf(stderr, "%s: write failure on %s\n", program, file);
395 goto bail;
398 /* Attempt to set immutable flag and remove all write access */
399 /* Only set immutable flag if file is owned by root */
400 set_attributes(fd);
402 if (fstat(fd, rst)) {
403 perror(file);
404 goto bail;
407 close(dirfd);
408 close(fd);
410 /* Look if we have the old filename */
411 fd = open(oldfile, O_RDONLY);
412 if (fd >= 0) {
413 clear_attributes(fd);
414 close(fd);
415 unlink(oldfile);
418 free(file);
419 free(oldfile);
420 return 0;
422 bail:
423 if (dirfd >= 0)
424 close(dirfd);
425 if (fd >= 0)
426 close(fd);
428 free(file);
429 free(oldfile);
430 return 1;
433 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
434 is not managered by btrfs tree, so actually this is not installed as files.
435 since the cow feature of btrfs will move the ldlinux.sys every where */
436 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
438 patch_file_and_bootblock(-1, path, devfd);
439 if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET)
440 != boot_image_len) {
441 perror("writing bootblock");
442 return 1;
444 printf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
445 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
446 BTRFS_EXTLINUX_OFFSET + boot_image_len) != 2 * ADV_SIZE) {
447 perror("writing adv");
448 return 1;
450 printf("write adv to 0x%x\n", BTRFS_EXTLINUX_OFFSET + boot_image_len);
451 if (stat(path, rst)) {
452 perror(path);
453 return 1;
455 return 0;
458 int install_file(const char *path, int devfd, struct stat *rst)
460 if (fs_type == EXT2 || fs_type == VFAT)
461 return ext2_fat_install_file(path, devfd, rst);
462 else if (fs_type == BTRFS)
463 return btrfs_install_file(path, devfd, rst);
464 return 1;
468 * SYSLINUX installs the string 'SYSLINUX' at offset 3 in the boot
469 * sector; this is consistent with FAT filesystems. Earlier versions
470 * would install the string "EXTLINUX" instead, handle both.
472 int already_installed(int devfd)
474 char buffer[8];
476 xpread(devfd, buffer, 8, 3);
477 return !memcmp(buffer, "SYSLINUX", 8) || !memcmp(buffer, "EXTLINUX", 8);
480 #ifdef __KLIBC__
481 static char devname_buf[64];
483 static void device_cleanup(void)
485 unlink(devname_buf);
487 #endif
489 /* Verify that a device fd and a pathname agree.
490 Return 0 on valid, -1 on error. */
491 static int validate_device(const char *path, int devfd)
493 struct stat pst, dst;
494 struct statfs sfs;
496 if (stat(path, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
497 return -1;
498 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
499 if (fs_type == BTRFS && sfs.f_type == BTRFS_SUPER_MAGIC)
500 return 0;
501 return (pst.st_dev == dst.st_rdev) ? 0 : -1;
504 #ifndef __KLIBC__
505 static const char *find_device(const char *mtab_file, dev_t dev)
507 struct mntent *mnt;
508 struct stat dst;
509 FILE *mtab;
510 const char *devname = NULL;
511 bool done;
513 mtab = setmntent(mtab_file, "r");
514 if (!mtab)
515 return NULL;
517 done = false;
518 while ((mnt = getmntent(mtab))) {
519 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
520 switch (fs_type) {
521 case BTRFS:
522 if (!strcmp(mnt->mnt_type, "btrfs") &&
523 !stat(mnt->mnt_dir, &dst) &&
524 dst.st_dev == dev) {
525 char *opt = strstr(mnt->mnt_opts, BTRFS_SUBVOL_OPT);
527 if (opt) {
528 if (!subvol[0]) {
529 char *tmp;
531 strcpy(subvol, opt + sizeof(BTRFS_SUBVOL_OPT) - 1);
532 tmp = strchr(subvol, 32);
533 if (tmp)
534 *tmp = '\0';
536 break; /* should break and let upper layer try again */
537 } else
538 done = true;
540 break;
541 case EXT2:
542 if ((!strcmp(mnt->mnt_type, "ext2") ||
543 !strcmp(mnt->mnt_type, "ext3") ||
544 !strcmp(mnt->mnt_type, "ext4")) &&
545 !stat(mnt->mnt_fsname, &dst) &&
546 dst.st_rdev == dev) {
547 done = true;
548 break;
550 case VFAT:
551 if ((!strcmp(mnt->mnt_type, "vfat")) &&
552 !stat(mnt->mnt_fsname, &dst) &&
553 dst.st_rdev == dev) {
554 done = true;
555 break;
557 case NONE:
558 break;
560 if (done) {
561 devname = strdup(mnt->mnt_fsname);
562 break;
565 endmntent(mtab);
567 return devname;
569 #endif
571 static const char *get_devname(const char *path)
573 const char *devname = NULL;
574 struct stat st;
575 struct statfs sfs;
577 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
578 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
579 return devname;
581 if (statfs(path, &sfs)) {
582 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
583 return devname;
585 #ifdef __KLIBC__
587 /* klibc doesn't have getmntent and friends; instead, just create
588 a new device with the appropriate device type */
589 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
590 major(st.st_dev), minor(st.st_dev));
592 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
593 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
594 return devname;
597 atexit(device_cleanup); /* unlink the device node on exit */
598 devname = devname_buf;
600 #else
602 /* check /etc/mtab first, since btrfs subvol info is only in here */
603 devname = find_device("/etc/mtab", st.st_dev);
604 if (subvol[0] && !devname) { /* we just find it is a btrfs subvol */
605 char parent[256];
606 char *tmp;
608 strcpy(parent, path);
609 tmp = strrchr(parent, '/');
610 if (tmp) {
611 *tmp = '\0';
612 fprintf(stderr, "%s is subvol, try its parent dir %s\n", path, parent);
613 devname = get_devname(parent);
614 } else
615 devname = NULL;
617 if (!devname) {
618 /* Didn't find it in /etc/mtab, try /proc/mounts */
619 devname = find_device("/proc/mounts", st.st_dev);
621 if (!devname) {
622 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
623 return devname;
626 fprintf(stderr, "%s is device %s\n", path, devname);
627 #endif
628 return devname;
631 static int open_device(const char *path, struct stat *st, const char **_devname)
633 int devfd;
634 const char *devname = NULL;
635 struct statfs sfs;
637 if (st)
638 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
639 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
640 return -1;
643 if (statfs(path, &sfs)) {
644 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
645 return -1;
647 if (sfs.f_type == EXT2_SUPER_MAGIC)
648 fs_type = EXT2;
649 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
650 fs_type = BTRFS;
651 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
652 fs_type = VFAT;
654 if (!fs_type) {
655 fprintf(stderr, "%s: not a fat, ext2/3/4 or btrfs filesystem: %s\n",
656 program, path);
657 return -1;
660 devfd = -1;
661 devname = get_devname(path);
662 if (_devname)
663 *_devname = devname;
665 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
666 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
667 return -1;
670 /* Verify that the device we opened is the device intended */
671 if (validate_device(path, devfd)) {
672 fprintf(stderr, "%s: path %s doesn't match device %s\n",
673 program, path, devname);
674 close(devfd);
675 return -1;
677 return devfd;
680 static int btrfs_read_adv(int devfd)
682 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
683 != 2 * ADV_SIZE)
684 return -1;
686 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
689 static int ext_read_adv(const char *path, int devfd, const char **namep)
691 int err;
692 const char *name;
694 if (fs_type == BTRFS) {
695 /* btrfs "ldlinux.sys" is in 64k blank area */
696 return btrfs_read_adv(devfd);
697 } else {
698 err = read_adv(path, name = "ldlinux.sys");
699 if (err == 2) /* ldlinux.sys does not exist */
700 err = read_adv(path, name = "extlinux.sys");
701 if (namep)
702 *namep = name;
703 return err;
707 static int ext_write_adv(const char *path, const char *cfg, int devfd)
709 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
710 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
711 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
712 perror("writing adv");
713 return 1;
715 return 0;
717 return write_adv(path, cfg);
720 int install_loader(const char *path, int update_only)
722 struct stat st, fst;
723 int devfd, rv;
724 const char *devname;
726 devfd = open_device(path, &st, &devname);
727 if (devfd < 0)
728 return 1;
730 if (update_only && !already_installed(devfd)) {
731 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
732 program);
733 close(devfd);
734 return 1;
737 /* Read a pre-existing ADV, if already installed */
738 if (opt.reset_adv) {
739 syslinux_reset_adv(syslinux_adv);
740 } else if (ext_read_adv(path, devfd, NULL) < 0) {
741 close(devfd);
742 return 1;
745 if (modify_adv() < 0) {
746 close(devfd);
747 return 1;
750 /* Install ldlinux.sys */
751 if (install_file(path, devfd, &fst)) {
752 close(devfd);
753 return 1;
755 if (fst.st_dev != st.st_dev) {
756 fprintf(stderr, "%s: file system changed under us - aborting!\n",
757 program);
758 close(devfd);
759 return 1;
762 sync();
763 rv = install_bootblock(devfd, devname);
764 close(devfd);
765 sync();
767 return rv;
771 * Modify the ADV of an existing installation
773 int modify_existing_adv(const char *path)
775 const char *filename;
776 int devfd;
778 devfd = open_device(path, NULL, NULL);
779 if (devfd < 0)
780 return 1;
782 if (opt.reset_adv)
783 syslinux_reset_adv(syslinux_adv);
784 else if (ext_read_adv(path, devfd, &filename) < 0) {
785 close(devfd);
786 return 1;
788 if (modify_adv() < 0) {
789 close(devfd);
790 return 1;
792 if (ext_write_adv(path, filename, devfd) < 0) {
793 close(devfd);
794 return 1;
796 close(devfd);
797 return 0;
800 int main(int argc, char *argv[])
802 parse_options(argc, argv, MODE_EXTLINUX);
804 if (!opt.directory)
805 usage(EX_USAGE, 0);
807 if (opt.update_only == -1) {
808 if (opt.reset_adv || opt.set_once || opt.menu_save)
809 return modify_existing_adv(opt.directory);
810 else
811 usage(EX_USAGE, MODE_EXTLINUX);
814 return install_loader(opt.directory, opt.update_only);