com32/chain/partiter: make iterators not autofree after fin/err
[syslinux/sherbszt.git] / extlinux / main.c
blob30422c2dc7b4e0e16592465b873de800fa7652db
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, *xsubpath;
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 xsubpath = subpath+1;
241 xdirpath = dirpath;
242 } else {
243 xsubpath = subpath;
244 xdirpath = "/";
246 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
247 subpath = strchr(subpath+1, '/');
248 if (!subpath)
249 subpath = "/"; /* It's the root of the filesystem */
250 break;
252 *subpath = '/';
255 if (subpath == dirpath)
256 break;
258 subpath--;
261 /* Now subpath should contain the path relative to the fs base */
262 dprintf("subpath = %s\n", subpath);
264 totalbytes = get_size(devfd);
265 get_geometry(devfd, totalbytes, &geo);
267 if (opt.heads)
268 geo.heads = opt.heads;
269 if (opt.sectors)
270 geo.sectors = opt.sectors;
272 /* Patch this into a fake FAT superblock. This isn't because
273 FAT is a good format in any way, it's because it lets the
274 early bootstrap share code with the FAT version. */
275 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
277 sbs = (struct boot_sector *)syslinux_bootsect;
279 totalsectors = totalbytes >> SECTOR_SHIFT;
280 if (totalsectors >= 65536) {
281 set_16(&sbs->bsSectors, 0);
282 } else {
283 set_16(&sbs->bsSectors, totalsectors);
285 set_32(&sbs->bsHugeSectors, totalsectors);
287 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
288 set_16(&sbs->bsSecPerTrack, geo.sectors);
289 set_16(&sbs->bsHeads, geo.heads);
290 set_32(&sbs->bsHiddenSecs, geo.start);
292 /* Construct the boot file map */
294 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
295 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
296 nsect += 2; /* Two sectors for the ADV */
297 sectp = alloca(sizeof(sector_t) * nsect);
298 if (fs_type == EXT2 || fs_type == VFAT) {
299 if (sectmap(fd, sectp, nsect)) {
300 perror("bmap");
301 exit(1);
303 } else if (fs_type == BTRFS) {
304 int i;
305 sector_t *sp = sectp;
307 for (i = 0; i < nsect - 2; i++)
308 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
309 for (i = 0; i < 2; i++)
310 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
313 /* Create the modified image in memory */
314 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
315 opt.raid_mode, subpath, subvol);
317 free(dirpath);
318 return rv;
322 * Install the boot block on the specified device.
323 * Must be run AFTER install_file()!
325 int install_bootblock(int fd, const char *device)
327 struct ext2_super_block sb;
328 struct btrfs_super_block sb2;
329 struct boot_sector sb3;
330 bool ok = false;
332 if (fs_type == EXT2) {
333 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
334 perror("reading superblock");
335 return 1;
337 if (sb.s_magic == EXT2_SUPER_MAGIC)
338 ok = true;
339 } else if (fs_type == BTRFS) {
340 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
341 != sizeof sb2) {
342 perror("reading superblock");
343 return 1;
345 if (sb2.magic == *(u64 *)BTRFS_MAGIC)
346 ok = true;
347 } else if (fs_type == VFAT) {
348 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
349 perror("reading fat superblock");
350 return 1;
352 if (sb3.bsResSectors && sb3.bsFATs &&
353 (strstr(sb3.bs16.FileSysType, "FAT") ||
354 strstr(sb3.bs32.FileSysType, "FAT")))
355 ok = true;
357 if (!ok) {
358 fprintf(stderr, "no fat, ext2/3/4 or btrfs superblock found on %s\n",
359 device);
360 return 1;
362 if (fs_type == VFAT) {
363 struct boot_sector *sbs = (struct boot_sector *)syslinux_bootsect;
364 if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
365 xpwrite(fd, &sbs->bsCode, bsCodeLen,
366 offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
367 perror("writing fat bootblock");
368 return 1;
370 } else {
371 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
372 != syslinux_bootsect_len) {
373 perror("writing bootblock");
374 return 1;
378 return 0;
381 int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
383 char *file, *oldfile;
384 int fd = -1, dirfd = -1;
385 int modbytes;
386 int r1, r2;
388 r1 = asprintf(&file, "%s%sldlinux.sys",
389 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
390 r2 = asprintf(&oldfile, "%s%sextlinux.sys",
391 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
392 if (r1 < 0 || !file || r2 < 0 || !oldfile) {
393 perror(program);
394 return 1;
397 dirfd = open(path, O_RDONLY | O_DIRECTORY);
398 if (dirfd < 0) {
399 perror(path);
400 goto bail;
403 fd = open(file, O_RDONLY);
404 if (fd < 0) {
405 if (errno != ENOENT) {
406 perror(file);
407 goto bail;
409 } else {
410 clear_attributes(fd);
412 close(fd);
414 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
415 S_IRUSR | S_IRGRP | S_IROTH);
416 if (fd < 0) {
417 perror(file);
418 goto bail;
421 /* Write it the first time */
422 if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
423 xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
424 boot_image_len) != 2 * ADV_SIZE) {
425 fprintf(stderr, "%s: write failure on %s\n", program, file);
426 goto bail;
429 /* Map the file, and patch the initial sector accordingly */
430 modbytes = patch_file_and_bootblock(fd, path, devfd);
432 /* Write the patch area again - this relies on the file being
433 overwritten in place! */
434 if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
435 fprintf(stderr, "%s: write failure on %s\n", program, file);
436 goto bail;
439 /* Attempt to set immutable flag and remove all write access */
440 /* Only set immutable flag if file is owned by root */
441 set_attributes(fd);
443 if (fstat(fd, rst)) {
444 perror(file);
445 goto bail;
448 close(dirfd);
449 close(fd);
451 /* Look if we have the old filename */
452 fd = open(oldfile, O_RDONLY);
453 if (fd >= 0) {
454 clear_attributes(fd);
455 close(fd);
456 unlink(oldfile);
459 free(file);
460 free(oldfile);
461 return 0;
463 bail:
464 if (dirfd >= 0)
465 close(dirfd);
466 if (fd >= 0)
467 close(fd);
469 free(file);
470 free(oldfile);
471 return 1;
474 /* btrfs has to install the ldlinux.sys in the first 64K blank area, which
475 is not managered by btrfs tree, so actually this is not installed as files.
476 since the cow feature of btrfs will move the ldlinux.sys every where */
477 int btrfs_install_file(const char *path, int devfd, struct stat *rst)
479 patch_file_and_bootblock(-1, path, devfd);
480 if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET)
481 != boot_image_len) {
482 perror("writing bootblock");
483 return 1;
485 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
486 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
487 != 2 * ADV_SIZE) {
488 perror("writing adv");
489 return 1;
491 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
492 if (stat(path, rst)) {
493 perror(path);
494 return 1;
496 return 0;
499 int install_file(const char *path, int devfd, struct stat *rst)
501 if (fs_type == EXT2 || fs_type == VFAT)
502 return ext2_fat_install_file(path, devfd, rst);
503 else if (fs_type == BTRFS)
504 return btrfs_install_file(path, devfd, rst);
505 return 1;
509 * SYSLINUX installs the string 'SYSLINUX' at offset 3 in the boot
510 * sector; this is consistent with FAT filesystems. Earlier versions
511 * would install the string "EXTLINUX" instead, handle both.
513 int already_installed(int devfd)
515 char buffer[8];
517 xpread(devfd, buffer, 8, 3);
518 return !memcmp(buffer, "SYSLINUX", 8) || !memcmp(buffer, "EXTLINUX", 8);
521 #ifdef __KLIBC__
522 static char devname_buf[64];
524 static void device_cleanup(void)
526 unlink(devname_buf);
528 #endif
530 /* Verify that a device fd and a pathname agree.
531 Return 0 on valid, -1 on error. */
532 static int validate_device(const char *path, int devfd)
534 struct stat pst, dst;
535 struct statfs sfs;
537 if (stat(path, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
538 return -1;
539 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
540 if (fs_type == BTRFS && sfs.f_type == BTRFS_SUPER_MAGIC)
541 return 0;
542 return (pst.st_dev == dst.st_rdev) ? 0 : -1;
545 #ifndef __KLIBC__
546 static const char *find_device(const char *mtab_file, dev_t dev)
548 struct mntent *mnt;
549 struct stat dst;
550 FILE *mtab;
551 const char *devname = NULL;
552 bool done;
554 mtab = setmntent(mtab_file, "r");
555 if (!mtab)
556 return NULL;
558 done = false;
559 while ((mnt = getmntent(mtab))) {
560 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
561 switch (fs_type) {
562 case BTRFS:
563 if (!strcmp(mnt->mnt_type, "btrfs") &&
564 !stat(mnt->mnt_dir, &dst) &&
565 dst.st_dev == dev) {
566 char *opt = strstr(mnt->mnt_opts, BTRFS_SUBVOL_OPT);
568 if (opt) {
569 if (!subvol[0]) {
570 char *tmp;
572 strcpy(subvol, opt + sizeof(BTRFS_SUBVOL_OPT) - 1);
573 tmp = strchr(subvol, 32);
574 if (tmp)
575 *tmp = '\0';
577 break; /* should break and let upper layer try again */
578 } else
579 done = true;
581 break;
582 case EXT2:
583 if ((!strcmp(mnt->mnt_type, "ext2") ||
584 !strcmp(mnt->mnt_type, "ext3") ||
585 !strcmp(mnt->mnt_type, "ext4")) &&
586 !stat(mnt->mnt_fsname, &dst) &&
587 dst.st_rdev == dev) {
588 done = true;
589 break;
591 case VFAT:
592 if ((!strcmp(mnt->mnt_type, "vfat")) &&
593 !stat(mnt->mnt_fsname, &dst) &&
594 dst.st_rdev == dev) {
595 done = true;
596 break;
598 case NONE:
599 break;
601 if (done) {
602 devname = strdup(mnt->mnt_fsname);
603 break;
606 endmntent(mtab);
608 return devname;
610 #endif
612 static const char *get_devname(const char *path)
614 const char *devname = NULL;
615 struct stat st;
616 struct statfs sfs;
618 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
619 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
620 return devname;
622 if (statfs(path, &sfs)) {
623 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
624 return devname;
626 #ifdef __KLIBC__
628 /* klibc doesn't have getmntent and friends; instead, just create
629 a new device with the appropriate device type */
630 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
631 major(st.st_dev), minor(st.st_dev));
633 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
634 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
635 return devname;
638 atexit(device_cleanup); /* unlink the device node on exit */
639 devname = devname_buf;
641 #else
643 /* check /etc/mtab first, since btrfs subvol info is only in here */
644 devname = find_device("/etc/mtab", st.st_dev);
645 if (subvol[0] && !devname) { /* we just find it is a btrfs subvol */
646 char parent[256];
647 char *tmp;
649 strcpy(parent, path);
650 tmp = strrchr(parent, '/');
651 if (tmp) {
652 *tmp = '\0';
653 fprintf(stderr, "%s is subvol, try its parent dir %s\n", path, parent);
654 devname = get_devname(parent);
655 } else
656 devname = NULL;
658 if (!devname) {
659 /* Didn't find it in /etc/mtab, try /proc/mounts */
660 devname = find_device("/proc/mounts", st.st_dev);
662 if (!devname) {
663 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
664 return devname;
667 fprintf(stderr, "%s is device %s\n", path, devname);
668 #endif
669 return devname;
672 static int open_device(const char *path, struct stat *st, const char **_devname)
674 int devfd;
675 const char *devname = NULL;
676 struct statfs sfs;
678 if (st)
679 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
680 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
681 return -1;
684 if (statfs(path, &sfs)) {
685 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
686 return -1;
688 if (sfs.f_type == EXT2_SUPER_MAGIC)
689 fs_type = EXT2;
690 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
691 fs_type = BTRFS;
692 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
693 fs_type = VFAT;
695 if (!fs_type) {
696 fprintf(stderr, "%s: not a fat, ext2/3/4 or btrfs filesystem: %s\n",
697 program, path);
698 return -1;
701 devfd = -1;
702 devname = get_devname(path);
703 if (_devname)
704 *_devname = devname;
706 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
707 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
708 return -1;
711 /* Verify that the device we opened is the device intended */
712 if (validate_device(path, devfd)) {
713 fprintf(stderr, "%s: path %s doesn't match device %s\n",
714 program, path, devname);
715 close(devfd);
716 return -1;
718 return devfd;
721 static int btrfs_read_adv(int devfd)
723 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
724 != 2 * ADV_SIZE)
725 return -1;
727 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
730 static int ext_read_adv(const char *path, int devfd, const char **namep)
732 int err;
733 const char *name;
735 if (fs_type == BTRFS) {
736 /* btrfs "ldlinux.sys" is in 64k blank area */
737 return btrfs_read_adv(devfd);
738 } else {
739 err = read_adv(path, name = "ldlinux.sys");
740 if (err == 2) /* ldlinux.sys does not exist */
741 err = read_adv(path, name = "extlinux.sys");
742 if (namep)
743 *namep = name;
744 return err;
748 static int ext_write_adv(const char *path, const char *cfg, int devfd)
750 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
751 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
752 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
753 perror("writing adv");
754 return 1;
756 return 0;
758 return write_adv(path, cfg);
761 int install_loader(const char *path, int update_only)
763 struct stat st, fst;
764 int devfd, rv;
765 const char *devname;
767 devfd = open_device(path, &st, &devname);
768 if (devfd < 0)
769 return 1;
771 if (update_only && !already_installed(devfd)) {
772 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
773 program);
774 close(devfd);
775 return 1;
778 /* Read a pre-existing ADV, if already installed */
779 if (opt.reset_adv) {
780 syslinux_reset_adv(syslinux_adv);
781 } else if (ext_read_adv(path, devfd, NULL) < 0) {
782 close(devfd);
783 return 1;
786 if (modify_adv() < 0) {
787 close(devfd);
788 return 1;
791 /* Install ldlinux.sys */
792 if (install_file(path, devfd, &fst)) {
793 close(devfd);
794 return 1;
796 if (fst.st_dev != st.st_dev) {
797 fprintf(stderr, "%s: file system changed under us - aborting!\n",
798 program);
799 close(devfd);
800 return 1;
803 sync();
804 rv = install_bootblock(devfd, devname);
805 close(devfd);
806 sync();
808 return rv;
812 * Modify the ADV of an existing installation
814 int modify_existing_adv(const char *path)
816 const char *filename;
817 int devfd;
819 devfd = open_device(path, NULL, NULL);
820 if (devfd < 0)
821 return 1;
823 if (opt.reset_adv)
824 syslinux_reset_adv(syslinux_adv);
825 else if (ext_read_adv(path, devfd, &filename) < 0) {
826 close(devfd);
827 return 1;
829 if (modify_adv() < 0) {
830 close(devfd);
831 return 1;
833 if (ext_write_adv(path, filename, devfd) < 0) {
834 close(devfd);
835 return 1;
837 close(devfd);
838 return 0;
841 int main(int argc, char *argv[])
843 parse_options(argc, argv, MODE_EXTLINUX);
845 if (!opt.directory || opt.install_mbr || opt.activate_partition)
846 usage(EX_USAGE, 0);
848 if (opt.update_only == -1) {
849 if (opt.reset_adv || opt.set_once || opt.menu_save)
850 return modify_existing_adv(opt.directory);
851 else
852 usage(EX_USAGE, MODE_EXTLINUX);
855 return install_loader(opt.directory, opt.update_only);