blob: 09740bd75a1a8587c80d3b8cd2f1ddd03324d148 [file] [log] [blame]
Greg Hartman76d05dc2016-11-23 15:51:27 -08001/* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin
5 *
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.
11 *
12 * ----------------------------------------------------------------------- */
13
14/*
15 * extlinux.c
16 *
17 * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs, xfs,
18 * and ufs1/2 filesystem.
19 */
20
21#define _GNU_SOURCE /* Enable everything */
22#include <inttypes.h>
23/* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
24#include <alloca.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <dirent.h>
30#ifndef __KLIBC__
31#include <mntent.h>
32#endif
33#include <stdbool.h>
34#include <stddef.h>
35#include <stdlib.h>
36#include <string.h>
37#include <getopt.h>
38#include <sysexits.h>
39#include <sys/ioctl.h>
40#include <sys/stat.h>
41#include <sys/types.h>
42#include <sys/mount.h>
43#include <sys/vfs.h>
44
45#include "linuxioctl.h"
46
47#include "btrfs.h"
48#include "fat.h"
49#include "ntfs.h"
50#include "xfs.h"
51#include "xfs_types.h"
52#include "xfs_sb.h"
53#include "ufs.h"
54#include "ufs_fs.h"
55#include "misc.h"
56#include "version.h"
57#include "syslxint.h"
58#include "syslxcom.h" /* common functions shared with extlinux and syslinux */
59#include "syslxfs.h"
60#include "setadv.h"
61#include "syslxopt.h" /* unified options */
62#include "mountinfo.h"
63
64#ifdef DEBUG
65# define dprintf printf
66#else
67# define dprintf(...) ((void)0)
68#endif
69
70#ifndef EXT2_SUPER_OFFSET
71#define EXT2_SUPER_OFFSET 1024
72#endif
73
74/* Since we have unused 2048 bytes in the primary AG of an XFS partition,
75 * we will use the first 0~512 bytes starting from 2048 for the Syslinux
76 * boot sector.
77 */
78#define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
79#define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
80
81/*
82 * btrfs has two discontiguous areas reserved for the boot loader.
83 * Use the first one (Boot Area A) for the boot sector and the ADV,
84 * and the second one for "ldlinux.sys".
85 */
86#define BTRFS_EXTLINUX_OFFSET BTRFS_BOOT_AREA_B_OFFSET
87#define BTRFS_EXTLINUX_SIZE BTRFS_BOOT_AREA_B_SIZE
88#define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
89static char subvol[BTRFS_SUBVOL_MAX];
90
91#define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \
92 - 2*ADV_SIZE)
93
94/*
95 * Get the size of a block device
96 */
97static uint64_t get_size(int devfd)
98{
99 uint64_t bytes;
100 uint32_t sects;
101 struct stat st;
102
103#ifdef BLKGETSIZE64
104 if (!ioctl(devfd, BLKGETSIZE64, &bytes))
105 return bytes;
106#endif
107 if (!ioctl(devfd, BLKGETSIZE, &sects))
108 return (uint64_t) sects << 9;
109 else if (!fstat(devfd, &st) && st.st_size)
110 return st.st_size;
111 else
112 return 0;
113}
114
115/*
116 * Get device geometry and partition offset
117 */
118struct geometry_table {
119 uint64_t bytes;
120 struct hd_geometry g;
121};
122
123static int sysfs_get_offset(int devfd, unsigned long *start)
124{
125 struct stat st;
126 char sysfs_name[128];
127 FILE *f;
128 int rv;
129
130 if (fstat(devfd, &st))
131 return -1;
132
133 if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
134 "/sys/dev/block/%u:%u/start",
135 major(st.st_rdev), minor(st.st_rdev))
136 >= sizeof sysfs_name)
137 return -1;
138
139 f = fopen(sysfs_name, "r");
140 if (!f)
141 return -1;
142
143 rv = fscanf(f, "%lu", start);
144 fclose(f);
145
146 return (rv == 1) ? 0 : -1;
147}
148
149/* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
150 (x/64/32) is the final fallback. I don't know what LS-240 has
151 as its geometry, since I don't have one and don't know anyone that does,
152 and Google wasn't helpful... */
153static const struct geometry_table standard_geometries[] = {
154 {360 * 1024, {2, 9, 40, 0}},
155 {720 * 1024, {2, 9, 80, 0}},
156 {1200 * 1024, {2, 15, 80, 0}},
157 {1440 * 1024, {2, 18, 80, 0}},
158 {1680 * 1024, {2, 21, 80, 0}},
159 {1722 * 1024, {2, 21, 80, 0}},
160 {2880 * 1024, {2, 36, 80, 0}},
161 {3840 * 1024, {2, 48, 80, 0}},
162 {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */
163 {0, {0, 0, 0, 0}}
164};
165
166int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
167{
168 struct floppy_struct fd_str;
169 struct loop_info li;
170 struct loop_info64 li64;
171 const struct geometry_table *gp;
172 int rv = 0;
173
174 memset(geo, 0, sizeof *geo);
175
176 if (!ioctl(devfd, HDIO_GETGEO, geo)) {
177 goto ok;
178 } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
179 geo->heads = fd_str.head;
180 geo->sectors = fd_str.sect;
181 geo->cylinders = fd_str.track;
182 geo->start = 0;
183 goto ok;
184 }
185
186 /* Didn't work. Let's see if this is one of the standard geometries */
187 for (gp = standard_geometries; gp->bytes; gp++) {
188 if (gp->bytes == totalbytes) {
189 memcpy(geo, &gp->g, sizeof *geo);
190 goto ok;
191 }
192 }
193
194 /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
195 what zipdisks use, so this would help if someone has a USB key that
196 they're booting in USB-ZIP mode. */
197
198 geo->heads = opt.heads ? : 64;
199 geo->sectors = opt.sectors ? : 32;
200 geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
201 geo->start = 0;
202
203 if (!opt.sectors && !opt.heads) {
204 fprintf(stderr,
205 "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
206 " (on hard disks, this is usually harmless.)\n",
207 geo->heads, geo->sectors);
208 rv = 1; /* Suboptimal result */
209 }
210
211ok:
212 /* If this is a loopback device, try to set the start */
213 if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
214 geo->start = li64.lo_offset >> SECTOR_SHIFT;
215 else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
216 geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
217 else if (!sysfs_get_offset(devfd, &geo->start)) {
218 /* OK */
219 }
220
221 return rv;
222}
223
224/*
225 * Query the device geometry and put it into the boot sector.
226 * Map the file and put the map in the boot sector and file.
227 * Stick the "current directory" inode number into the file.
228 *
229 * Returns the number of modified bytes in the boot file.
230 */
231static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
232{
233 struct stat dirst, xdst;
234 struct hd_geometry geo;
235 sector_t *sectp;
236 uint64_t totalbytes, totalsectors;
237 int nsect;
238 struct fat_boot_sector *sbs;
239 char *dirpath, *subpath, *xdirpath;
240 int rv;
241
242 dirpath = realpath(dir, NULL);
243 if (!dirpath || stat(dir, &dirst)) {
244 perror("accessing install directory");
245 exit(255); /* This should never happen */
246 }
247
248 if (lstat(dirpath, &xdst) ||
249 dirst.st_ino != xdst.st_ino ||
250 dirst.st_dev != xdst.st_dev) {
251 perror("realpath returned nonsense");
252 exit(255);
253 }
254
255 subpath = strchr(dirpath, '\0');
256 for (;;) {
257 if (*subpath == '/') {
258 if (subpath > dirpath) {
259 *subpath = '\0';
260 xdirpath = dirpath;
261 } else {
262 xdirpath = "/";
263 }
264 if (lstat(xdirpath, &xdst) || dirst.st_dev != xdst.st_dev) {
265 subpath = strchr(subpath+1, '/');
266 if (!subpath)
267 subpath = "/"; /* It's the root of the filesystem */
268 break;
269 }
270 *subpath = '/';
271 }
272
273 if (subpath == dirpath)
274 break;
275
276 subpath--;
277 }
278
279 /* Now subpath should contain the path relative to the fs base */
280 dprintf("subpath = %s\n", subpath);
281
282 totalbytes = get_size(devfd);
283 get_geometry(devfd, totalbytes, &geo);
284
285 if (opt.heads)
286 geo.heads = opt.heads;
287 if (opt.sectors)
288 geo.sectors = opt.sectors;
289
290 /* Patch this into a fake FAT superblock. This isn't because
291 FAT is a good format in any way, it's because it lets the
292 early bootstrap share code with the FAT version. */
293 dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
294
295 sbs = (struct fat_boot_sector *)syslinux_bootsect;
296
297 totalsectors = totalbytes >> SECTOR_SHIFT;
298 if (totalsectors >= 65536) {
299 set_16(&sbs->bsSectors, 0);
300 } else {
301 set_16(&sbs->bsSectors, totalsectors);
302 }
303 set_32(&sbs->bsHugeSectors, totalsectors);
304
305 set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
306 set_16(&sbs->bsSecPerTrack, geo.sectors);
307 set_16(&sbs->bsHeads, geo.heads);
308 set_32(&sbs->bsHiddenSecs, geo.start);
309
310 /* Construct the boot file map */
311
312 dprintf("directory inode = %lu\n", (unsigned long)dirst.st_ino);
313 nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
314 nsect += 2; /* Two sectors for the ADV */
315 sectp = alloca(sizeof(sector_t) * nsect);
316 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
317 fs_type == XFS || fs_type == UFS1 || fs_type == UFS2) {
318 if (sectmap(fd, sectp, nsect)) {
319 perror("bmap");
320 exit(1);
321 }
322 } else if (fs_type == BTRFS) {
323 int i;
324 sector_t *sp = sectp;
325
326 for (i = 0; i < nsect - 2; i++)
327 *sp++ = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
328 for (i = 0; i < 2; i++)
329 *sp++ = BTRFS_ADV_OFFSET/SECTOR_SIZE + i;
330 }
331
332 /* Create the modified image in memory */
333 rv = syslinux_patch(sectp, nsect, opt.stupid_mode,
334 opt.raid_mode, subpath, subvol);
335
336 free(dirpath);
337 return rv;
338}
339
340/*
341 * Install the boot block on the specified device.
342 * Must be run AFTER install_file()!
343 */
344int install_bootblock(int fd, const char *device)
345{
346 struct ext2_super_block sb;
347 struct btrfs_super_block sb2;
348 struct fat_boot_sector sb3;
349 struct ntfs_boot_sector sb4;
350 xfs_sb_t sb5;
351 struct ufs_super_block sb6;
352 bool ok = false;
353
354 if (fs_type == EXT2) {
355 if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb) {
356 perror("reading superblock");
357 return 1;
358 }
359
360 if (sb.s_magic == EXT2_SUPER_MAGIC)
361 ok = true;
362 } else if (fs_type == BTRFS) {
363 if (xpread(fd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET)
364 != sizeof sb2) {
365 perror("reading superblock");
366 return 1;
367 }
368 if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
369 ok = true;
370 } else if (fs_type == VFAT) {
371 if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
372 perror("reading fat superblock");
373 return 1;
374 }
375
376 if (fat_check_sb_fields(&sb3))
377 ok = true;
378 } else if (fs_type == NTFS) {
379 if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) {
380 perror("reading ntfs superblock");
381 return 1;
382 }
383
384 if (ntfs_check_sb_fields(&sb4))
385 ok = true;
386 } else if (fs_type == XFS) {
387 if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
388 perror("reading xfs superblock");
389 return 1;
390 }
391
392 if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
393 if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
394 fprintf(stderr,
395 "You need to have 4 KiB filesystem block size for "
396 " being able to install Syslinux in your XFS "
397 "partition (because there is no enough space in MBR to "
398 "determine where Syslinux bootsector can be installed "
399 "regardless the filesystem block size)\n");
400 return 1;
401 }
402
403 ok = true;
404 }
405 } else if (fs_type == UFS1 || fs_type == UFS2) {
406 uint32_t sblock_off = (fs_type == UFS1) ?
407 SBLOCK_UFS1 : SBLOCK_UFS2;
408 uint32_t ufs_smagic = (fs_type == UFS1) ?
409 UFS1_SUPER_MAGIC : UFS2_SUPER_MAGIC;
410
411 if (xpread(fd, &sb6, sizeof sb6, sblock_off) != sizeof sb6) {
412 perror("reading superblock");
413 return 1;
414 }
415
416 if (sb6.fs_magic == ufs_smagic)
417 ok = true;
418 }
419
420 if (!ok) {
421 fprintf(stderr,
422 "no fat, ntfs, ext2/3/4, btrfs, xfs "
423 "or ufs1/2 superblock found on %s\n",
424 device);
425 return 1;
426 }
427
428 if (fs_type == VFAT) {
429 struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
430 if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
431 xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen,
432 offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) {
433 perror("writing fat bootblock");
434 return 1;
435 }
436 } else if (fs_type == NTFS) {
437 struct ntfs_boot_sector *sbs =
438 (struct ntfs_boot_sector *)syslinux_bootsect;
439 if (xpwrite(fd, &sbs->NTFS_bsHead,
440 NTFS_bsHeadLen, 0) != NTFS_bsHeadLen ||
441 xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen,
442 offsetof(struct ntfs_boot_sector,
443 NTFS_bsCode)) != NTFS_bsCodeLen) {
444 perror("writing ntfs bootblock");
445 return 1;
446 }
447 } else if (fs_type == XFS) {
448 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
449 XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
450 perror("writing xfs bootblock");
451 return 1;
452 }
453 } else {
454 if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
455 != syslinux_bootsect_len) {
456 perror("writing bootblock");
457 return 1;
458 }
459 }
460
461 return 0;
462}
463
464static int rewrite_boot_image(int devfd, const char *path, const char *filename)
465{
466 int fd;
467 int ret;
468 int modbytes;
469
470 /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
471 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
472 S_IRUSR | S_IRGRP | S_IROTH);
473 if (fd < 0) {
474 perror(filename);
475 return -1;
476 }
477
478 /* Write boot image data into LDLINUX.SYS file */
479 ret = xpwrite(fd, (const char _force *)boot_image, boot_image_len, 0);
480 if (ret != boot_image_len) {
481 perror("writing bootblock");
482 goto error;
483 }
484
485 /* Write ADV */
486 ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
487 if (ret != 2 * ADV_SIZE) {
488 fprintf(stderr, "%s: write failure on %s\n", program, filename);
489 goto error;
490 }
491
492 /* Map the file, and patch the initial sector accordingly */
493 modbytes = patch_file_and_bootblock(fd, path, devfd);
494
495 /* Write the patch area again - this relies on the file being overwritten
496 * in place! */
497 ret = xpwrite(fd, (const char _force *)boot_image, modbytes, 0);
498 if (ret != modbytes) {
499 fprintf(stderr, "%s: write failure on %s\n", program, filename);
500 goto error;
501 }
502
503 return fd;
504
505error:
506 close(fd);
507
508 return -1;
509}
510
511int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
512{
513 char *file, *oldfile, *c32file;
514 int fd = -1, dirfd = -1;
515 int r1, r2, r3;
516
517 r1 = asprintf(&file, "%s%sldlinux.sys",
518 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
519 r2 = asprintf(&oldfile, "%s%sextlinux.sys",
520 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
521 r3 = asprintf(&c32file, "%s%sldlinux.c32",
522 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
523 if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) {
524 perror(program);
525 return 1;
526 }
527
528 dirfd = open(path, O_RDONLY | O_DIRECTORY);
529 if (dirfd < 0) {
530 perror(path);
531 goto bail;
532 }
533
534 fd = open(file, O_RDONLY);
535 if (fd < 0) {
536 if (errno != ENOENT) {
537 perror(file);
538 goto bail;
539 }
540 } else {
541 clear_attributes(fd);
542 }
543 close(fd);
544
545 fd = rewrite_boot_image(devfd, path, file);
546 if (fd < 0)
547 goto bail;
548
549 /* Attempt to set immutable flag and remove all write access */
550 /* Only set immutable flag if file is owned by root */
551 set_attributes(fd);
552
553 if (fstat(fd, rst)) {
554 perror(file);
555 goto bail;
556 }
557
558 close(dirfd);
559 close(fd);
560
561 /* Look if we have the old filename */
562 fd = open(oldfile, O_RDONLY);
563 if (fd >= 0) {
564 clear_attributes(fd);
565 close(fd);
566 unlink(oldfile);
567 }
568
569 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
570 S_IRUSR | S_IRGRP | S_IROTH);
571 if (fd < 0) {
572 perror(c32file);
573 goto bail;
574 }
575
576 r3 = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
577 syslinux_ldlinuxc32_len, 0);
578 if (r3 != syslinux_ldlinuxc32_len) {
579 fprintf(stderr, "%s: write failure on %s\n", program, c32file);
580 goto bail;
581 }
582
583 free(file);
584 free(oldfile);
585 free(c32file);
586 return 0;
587
588bail:
589 if (dirfd >= 0)
590 close(dirfd);
591 if (fd >= 0)
592 close(fd);
593
594 free(file);
595 free(oldfile);
596 free(c32file);
597 return 1;
598}
599
600/* btrfs has to install the ldlinux.sys in the first 64K blank area, which
601 is not managered by btrfs tree, so actually this is not installed as files.
602 since the cow feature of btrfs will move the ldlinux.sys every where */
603int btrfs_install_file(const char *path, int devfd, struct stat *rst)
604{
605 char *file;
606 int fd, rv;
607
608 patch_file_and_bootblock(-1, path, devfd);
609 if (xpwrite(devfd, (const char _force *)boot_image,
610 boot_image_len, BTRFS_EXTLINUX_OFFSET)
611 != boot_image_len) {
612 perror("writing bootblock");
613 return 1;
614 }
615 dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET);
616 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
617 != 2 * ADV_SIZE) {
618 perror("writing adv");
619 return 1;
620 }
621 dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET);
622 if (stat(path, rst)) {
623 perror(path);
624 return 1;
625 }
626
627 /*
628 * Note that we *can* install ldinux.c32 as a regular file because
629 * it doesn't need to be within the first 64K. The Syslinux core
630 * has enough smarts to search the btrfs dirs and find this file.
631 */
632 rv = asprintf(&file, "%s%sldlinux.c32",
633 path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
634 if (rv < 0 || !file) {
635 perror(program);
636 return 1;
637 }
638
639 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
640 S_IRUSR | S_IRGRP | S_IROTH);
641 if (fd < 0) {
642 perror(file);
643 free(file);
644 return 1;
645 }
646
647 rv = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
648 syslinux_ldlinuxc32_len, 0);
649 if (rv != (int)syslinux_ldlinuxc32_len) {
650 fprintf(stderr, "%s: write failure on %s\n", program, file);
651 rv = 1;
652 } else
653 rv = 0;
654
655 close(fd);
656 free(file);
657 return rv;
658}
659
660/*
661 * Due to historical reasons (SGI IRIX's design of disk layouts), the first
662 * sector in the primary AG on XFS filesystems contains the superblock, which is
663 * a problem with bootloaders that rely on BIOSes (that load VBRs which are
664 * (located in the first sector of the partition).
665 *
666 * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
667 * superblock.
668 */
669static int xfs_install_file(const char *path, int devfd, struct stat *rst)
670{
671 static char file[PATH_MAX + 1];
672 static char c32file[PATH_MAX + 1];
673 int dirfd = -1;
674 int fd = -1;
675 int retval;
676
677 snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path,
678 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
679 snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path,
680 path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
681
682 dirfd = open(path, O_RDONLY | O_DIRECTORY);
683 if (dirfd < 0) {
684 perror(path);
685 goto bail;
686 }
687
688 fd = open(file, O_RDONLY);
689 if (fd < 0) {
690 if (errno != ENOENT) {
691 perror(file);
692 goto bail;
693 }
694 } else {
695 clear_attributes(fd);
696 }
697
698 close(fd);
699
700 fd = rewrite_boot_image(devfd, path, file);
701 if (fd < 0)
702 goto bail;
703
704 /* Attempt to set immutable flag and remove all write access */
705 /* Only set immutable flag if file is owned by root */
706 set_attributes(fd);
707
708 if (fstat(fd, rst)) {
709 perror(file);
710 goto bail;
711 }
712
713 close(dirfd);
714 close(fd);
715
716 dirfd = -1;
717 fd = -1;
718
719 fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
720 S_IRUSR | S_IRGRP | S_IROTH);
721 if (fd < 0) {
722 perror(c32file);
723 goto bail;
724 }
725
726 retval = xpwrite(fd, (const char _force *)syslinux_ldlinuxc32,
727 syslinux_ldlinuxc32_len, 0);
728 if (retval != (int)syslinux_ldlinuxc32_len) {
729 fprintf(stderr, "%s: write failure on %s\n", program, file);
730 goto bail;
731 }
732
733 close(fd);
734
735 sync();
736
737 return 0;
738
739bail:
740 if (dirfd >= 0)
741 close(dirfd);
742
743 if (fd >= 0)
744 close(fd);
745
746 return 1;
747}
748
749/*
750 * * test if path is a subvolume:
751 * * this function return
752 * * 0-> path exists but it is not a subvolume
753 * * 1-> path exists and it is a subvolume
754 * * -1 -> path is unaccessible
755 * */
756static int test_issubvolume(char *path)
757{
758
759 struct stat st;
760 int res;
761
762 res = stat(path, &st);
763 if(res < 0 )
764 return -1;
765
766 return (st.st_ino == 256) && S_ISDIR(st.st_mode);
767
768}
769
770/*
771 * Get the default subvolume of a btrfs filesystem
772 * rootdir: btrfs root dir
773 * subvol: this function will save the default subvolume name here
774 */
775static char * get_default_subvol(char * rootdir, char * subvol)
776{
777 struct btrfs_ioctl_search_args args;
778 struct btrfs_ioctl_search_key *sk = &args.key;
779 struct btrfs_ioctl_search_header *sh;
780 int ret, i;
781 int fd;
782 struct btrfs_root_ref *ref;
783 struct btrfs_dir_item *dir_item;
784 unsigned long off = 0;
785 int name_len;
786 char *name;
787 char dirname[4096];
788 u64 defaultsubvolid = 0;
789
790 ret = test_issubvolume(rootdir);
791 if (ret == 1) {
792 fd = open(rootdir, O_RDONLY);
793 if (fd < 0) {
794 fprintf(stderr, "ERROR: failed to open %s\n", rootdir);
795 }
796 ret = fd;
797 }
798 if (ret <= 0) {
799 subvol[0] = '\0';
800 return NULL;
801 }
802
803 memset(&args, 0, sizeof(args));
804
805 /* search in the tree of tree roots */
806 sk->tree_id = 1;
807
808 /*
809 * set the min and max to backref keys. The search will
810 * only send back this type of key now.
811 */
812 sk->max_type = BTRFS_DIR_ITEM_KEY;
813 sk->min_type = BTRFS_DIR_ITEM_KEY;
814
815 /*
816 * set all the other params to the max, we'll take any objectid
817 * and any trans
818 */
819 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
820 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
821
822 sk->max_offset = (u64)-1;
823 sk->min_offset = 0;
824 sk->max_transid = (u64)-1;
825
826 /* just a big number, doesn't matter much */
827 sk->nr_items = 4096;
828
829 while(1) {
830 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
831 if (ret < 0) {
832 fprintf(stderr, "ERROR: can't perform the search\n");
833 subvol[0] = '\0';
834 return NULL;
835 }
836 /* the ioctl returns the number of item it found in nr_items */
837 if (sk->nr_items == 0) {
838 break;
839 }
840
841 off = 0;
842
843 /*
844 * for each item, pull the key out of the header and then
845 * read the root_ref item it contains
846 */
847 for (i = 0; i < sk->nr_items; i++) {
848 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
849 off += sizeof(*sh);
850 if (sh->type == BTRFS_DIR_ITEM_KEY) {
851 dir_item = (struct btrfs_dir_item *)(args.buf + off);
852 name_len = dir_item->name_len;
853 name = (char *)(dir_item + 1);
854
855
856 /*add_root(&root_lookup, sh->objectid, sh->offset,
857 dir_id, name, name_len);*/
858 strncpy(dirname, name, name_len);
859 dirname[name_len] = '\0';
860 if (strcmp(dirname, "default") == 0) {
861 defaultsubvolid = dir_item->location.objectid;
862 break;
863 }
864 }
865 off += sh->len;
866
867 /*
868 * record the mins in sk so we can make sure the
869 * next search doesn't repeat this root
870 */
871 sk->min_objectid = sh->objectid;
872 sk->min_type = sh->type;
873 sk->max_type = sh->type;
874 sk->min_offset = sh->offset;
875 }
876 if (defaultsubvolid != 0)
877 break;
878 sk->nr_items = 4096;
879 /* this iteration is done, step forward one root for the next
880 * ioctl
881 */
882 if (sk->min_objectid < (u64)-1) {
883 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
884 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
885 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
886 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
887 sk->min_offset = 0;
888 } else
889 break;
890 }
891
892 if (defaultsubvolid == 0) {
893 subvol[0] = '\0';
894 return NULL;
895 }
896
897 memset(&args, 0, sizeof(args));
898
899 /* search in the tree of tree roots */
900 sk->tree_id = 1;
901
902 /*
903 * set the min and max to backref keys. The search will
904 * only send back this type of key now.
905 */
906 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
907 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
908
909 /*
910 * set all the other params to the max, we'll take any objectid
911 * and any trans
912 */
913 sk->max_objectid = (u64)-1;
914 sk->max_offset = (u64)-1;
915 sk->max_transid = (u64)-1;
916
917 /* just a big number, doesn't matter much */
918 sk->nr_items = 4096;
919
920 while(1) {
921 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
922 if (ret < 0) {
923 fprintf(stderr, "ERROR: can't perform the search\n");
924 subvol[0] = '\0';
925 return NULL;
926 }
927 /* the ioctl returns the number of item it found in nr_items */
928 if (sk->nr_items == 0)
929 break;
930
931 off = 0;
932
933 /*
934 * for each item, pull the key out of the header and then
935 * read the root_ref item it contains
936 */
937 for (i = 0; i < sk->nr_items; i++) {
938 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
939 off += sizeof(*sh);
940 if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
941 ref = (struct btrfs_root_ref *)(args.buf + off);
942 name_len = ref->name_len;
943 name = (char *)(ref + 1);
944
945 if (sh->objectid == defaultsubvolid) {
946 strncpy(subvol, name, name_len);
947 subvol[name_len] = '\0';
948 dprintf("The default subvolume: %s, ID: %llu\n",
949 subvol, sh->objectid);
950 break;
951 }
952
953 }
954
955 off += sh->len;
956
957 /*
958 * record the mins in sk so we can make sure the
959 * next search doesn't repeat this root
960 */
961 sk->min_objectid = sh->objectid;
962 sk->min_type = sh->type;
963 sk->min_offset = sh->offset;
964 }
965 if (subvol[0] != '\0')
966 break;
967 sk->nr_items = 4096;
968 /* this iteration is done, step forward one root for the next
969 * ioctl
970 */
971 if (sk->min_objectid < (u64)-1) {
972 sk->min_objectid++;
973 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
974 sk->min_offset = 0;
975 } else
976 break;
977 }
978 return subvol;
979}
980
981static int install_file(const char *path, int devfd, struct stat *rst)
982{
983 if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS
984 || fs_type == UFS1 || fs_type == UFS2)
985 return ext2_fat_install_file(path, devfd, rst);
986 else if (fs_type == BTRFS)
987 return btrfs_install_file(path, devfd, rst);
988 else if (fs_type == XFS)
989 return xfs_install_file(path, devfd, rst);
990
991 return 1;
992}
993
994#ifdef __KLIBC__
995static char devname_buf[64];
996
997static void device_cleanup(void)
998{
999 unlink(devname_buf);
1000}
1001#endif
1002
1003/* Verify that a device fd and a pathname agree.
1004 Return 0 on valid, -1 on error. */
1005static int validate_device_btrfs(int pathfd, int devfd);
1006static int validate_device(const char *path, int devfd)
1007{
1008 struct stat pst, dst;
1009 struct statfs sfs;
1010 int pfd;
1011 int rv = -1;
1012
1013 pfd = open(path, O_RDONLY|O_DIRECTORY);
1014 if (pfd < 0)
1015 goto err;
1016
1017 if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
1018 goto err;
1019
1020 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1021 if (fs_type == BTRFS) {
1022 if (sfs.f_type == BTRFS_SUPER_MAGIC)
1023 rv = validate_device_btrfs(pfd, devfd);
1024 } else {
1025 rv = (pst.st_dev == dst.st_rdev) ? 0 : -1;
1026 }
1027
1028err:
1029 if (pfd >= 0)
1030 close(pfd);
1031 return rv;
1032}
1033
1034#ifndef __KLIBC__
1035static const char *find_device(const char *mtab_file, dev_t dev)
1036{
1037 struct mntent *mnt;
1038 struct stat dst;
1039 FILE *mtab;
1040 const char *devname = NULL;
1041 bool done;
1042
1043 mtab = setmntent(mtab_file, "r");
1044 if (!mtab)
1045 return NULL;
1046
1047 done = false;
1048 while ((mnt = getmntent(mtab))) {
1049 /* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
1050 switch (fs_type) {
1051 case BTRFS:
1052 if (!strcmp(mnt->mnt_type, "btrfs") &&
1053 !stat(mnt->mnt_dir, &dst) &&
1054 dst.st_dev == dev) {
1055 if (!subvol[0])
1056 get_default_subvol(mnt->mnt_dir, subvol);
1057 done = true;
1058 }
1059 break;
1060 case EXT2:
1061 if ((!strcmp(mnt->mnt_type, "ext2") ||
1062 !strcmp(mnt->mnt_type, "ext3") ||
1063 !strcmp(mnt->mnt_type, "ext4")) &&
1064 !stat(mnt->mnt_fsname, &dst) &&
1065 dst.st_rdev == dev) {
1066 done = true;
1067 break;
1068 }
1069 case VFAT:
1070 if ((!strcmp(mnt->mnt_type, "vfat")) &&
1071 !stat(mnt->mnt_fsname, &dst) &&
1072 dst.st_rdev == dev) {
1073 done = true;
1074 break;
1075 }
1076 case NTFS:
1077 if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
1078 !strcmp(mnt->mnt_type, "ntfs")) &&
1079 !stat(mnt->mnt_fsname, &dst) &&
1080 dst.st_rdev == dev) {
1081 done = true;
1082 break;
1083 }
1084
1085 break;
1086 case XFS:
1087 if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
1088 dst.st_rdev == dev) {
1089 done = true;
1090 break;
1091 }
1092
1093 break;
1094 case UFS1:
1095 case UFS2:
1096 if (!strcmp(mnt->mnt_type, "ufs") && !stat(mnt->mnt_fsname, &dst) &&
1097 dst.st_rdev == dev) {
1098 done = true;
1099 }
1100
1101 break;
1102 case NONE:
1103 break;
1104 }
1105
1106 if (done) {
1107 devname = strdup(mnt->mnt_fsname);
1108 break;
1109 }
1110 }
1111
1112 endmntent(mtab);
1113
1114 return devname;
1115}
1116#endif
1117
1118/*
1119 * On newer Linux kernels we can use sysfs to get a backwards mapping
1120 * from device names to standard filenames
1121 */
1122static const char *find_device_sysfs(dev_t dev)
1123{
1124 char sysname[64];
1125 char linkname[PATH_MAX];
1126 ssize_t llen;
1127 char *p, *q;
1128 char *buf = NULL;
1129 struct stat st;
1130
1131 snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
1132 major(dev), minor(dev));
1133
1134 llen = readlink(sysname, linkname, sizeof linkname);
1135 if (llen < 0 || llen >= sizeof linkname)
1136 goto err;
1137
1138 linkname[llen] = '\0';
1139
1140 p = strrchr(linkname, '/');
1141 p = p ? p+1 : linkname; /* Leave basename */
1142
1143 buf = q = malloc(strlen(p) + 6);
1144 if (!buf)
1145 goto err;
1146
1147 memcpy(q, "/dev/", 5);
1148 q += 5;
1149
1150 while (*p) {
1151 *q++ = (*p == '!') ? '/' : *p;
1152 p++;
1153 }
1154
1155 *q = '\0';
1156
1157 if (!stat(buf, &st) && st.st_dev == dev)
1158 return buf; /* Found it! */
1159
1160err:
1161 if (buf)
1162 free(buf);
1163 return NULL;
1164}
1165
1166static const char *find_device_mountinfo(const char *path, dev_t dev)
1167{
1168 const struct mountinfo *m;
1169 struct stat st;
1170
1171 m = find_mount(path, NULL);
1172 if (!m)
1173 return NULL;
1174
1175 if (m->devpath[0] == '/' && m->dev == dev &&
1176 !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
1177 return m->devpath;
1178 else
1179 return NULL;
1180}
1181
1182static int validate_device_btrfs(int pfd, int dfd)
1183{
1184 struct btrfs_ioctl_fs_info_args fsinfo;
1185 static struct btrfs_ioctl_dev_info_args devinfo;
1186 struct btrfs_super_block sb2;
1187
1188 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1189 return -1;
1190
1191 /* We do not support multi-device btrfs yet */
1192 if (fsinfo.num_devices != 1)
1193 return -1;
1194
1195 /* The one device will have the max devid */
1196 memset(&devinfo, 0, sizeof devinfo);
1197 devinfo.devid = fsinfo.max_id;
1198 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1199 return -1;
1200
1201 if (devinfo.path[0] != '/')
1202 return -1;
1203
1204 if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2)
1205 return -1;
1206
1207 if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
1208 return -1;
1209
1210 if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1211 return -1;
1212
1213 if (sb2.num_devices != 1)
1214 return -1;
1215
1216 if (sb2.dev_item.devid != devinfo.devid)
1217 return -1;
1218
1219 if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid))
1220 return -1;
1221
1222 if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
1223 return -1;
1224
1225 return 0; /* It's good! */
1226}
1227
1228static const char *find_device_btrfs(const char *path)
1229{
1230 int pfd, dfd;
1231 struct btrfs_ioctl_fs_info_args fsinfo;
1232 static struct btrfs_ioctl_dev_info_args devinfo;
1233 const char *rv = NULL;
1234
1235 pfd = dfd = -1;
1236
1237 pfd = open(path, O_RDONLY);
1238 if (pfd < 0)
1239 goto err;
1240
1241 if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
1242 goto err;
1243
1244 /* We do not support multi-device btrfs yet */
1245 if (fsinfo.num_devices != 1)
1246 goto err;
1247
1248 /* The one device will have the max devid */
1249 memset(&devinfo, 0, sizeof devinfo);
1250 devinfo.devid = fsinfo.max_id;
1251 if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
1252 goto err;
1253
1254 if (devinfo.path[0] != '/')
1255 goto err;
1256
1257 dfd = open((const char *)devinfo.path, O_RDONLY);
1258 if (dfd < 0)
1259 goto err;
1260
1261 if (!validate_device_btrfs(pfd, dfd))
1262 rv = (const char *)devinfo.path; /* It's good! */
1263
1264err:
1265 if (pfd >= 0)
1266 close(pfd);
1267 if (dfd >= 0)
1268 close(dfd);
1269 return rv;
1270}
1271
1272static const char *get_devname(const char *path)
1273{
1274 const char *devname = NULL;
1275 struct stat st;
1276 struct statfs sfs;
1277
1278 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
1279 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1280 return devname;
1281 }
1282 if (statfs(path, &sfs)) {
1283 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1284 return devname;
1285 }
1286
1287 if (opt.device)
1288 devname = opt.device;
1289
1290 if (!devname){
1291 if (fs_type == BTRFS) {
1292 /* For btrfs try to get the device name from btrfs itself */
1293 devname = find_device_btrfs(path);
1294 }
1295 }
1296
1297 if (!devname) {
1298 devname = find_device_mountinfo(path, st.st_dev);
1299 }
1300
1301#ifdef __KLIBC__
1302 if (!devname) {
1303 devname = find_device_sysfs(st.st_dev);
1304 }
1305 if (!devname) {
1306 /* klibc doesn't have getmntent and friends; instead, just create
1307 a new device with the appropriate device type */
1308 snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
1309 major(st.st_dev), minor(st.st_dev));
1310
1311 if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
1312 fprintf(stderr, "%s: cannot create device %s\n", program, devname);
1313 return devname;
1314 }
1315
1316 atexit(device_cleanup); /* unlink the device node on exit */
1317 devname = devname_buf;
1318 }
1319
1320#else
1321 if (!devname) {
1322 devname = find_device("/proc/mounts", st.st_dev);
1323 }
1324 if (!devname) {
1325 /* Didn't find it in /proc/mounts, try /etc/mtab */
1326 devname = find_device("/etc/mtab", st.st_dev);
1327 }
1328 if (!devname) {
1329 devname = find_device_sysfs(st.st_dev);
1330
1331 fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
1332 return devname;
1333 }
1334
1335 fprintf(stderr, "%s is device %s\n", path, devname);
1336
1337#endif
1338 return devname;
1339}
1340
1341static int open_device(const char *path, struct stat *st, const char **_devname)
1342{
1343 int devfd;
1344 const char *devname = NULL;
1345 struct statfs sfs;
1346
1347 if (st)
1348 if (stat(path, st) || !S_ISDIR(st->st_mode)) {
1349 fprintf(stderr, "%s: Not a directory: %s\n", program, path);
1350 return -1;
1351 }
1352
1353 if (statfs(path, &sfs)) {
1354 fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
1355 return -1;
1356 }
1357
1358 if (sfs.f_type == EXT2_SUPER_MAGIC)
1359 fs_type = EXT2;
1360 else if (sfs.f_type == BTRFS_SUPER_MAGIC)
1361 fs_type = BTRFS;
1362 else if (sfs.f_type == MSDOS_SUPER_MAGIC)
1363 fs_type = VFAT;
1364 else if (sfs.f_type == NTFS_SB_MAGIC ||
1365 sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
1366 fs_type = NTFS;
1367 else if (sfs.f_type == XFS_SUPER_MAGIC)
1368 fs_type = XFS;
1369 else if (sfs.f_type == UFS1_SUPER_MAGIC)
1370 fs_type = UFS1;
1371 else if (sfs.f_type == UFS2_SUPER_MAGIC)
1372 fs_type = UFS2;
1373
1374 if (!fs_type) {
1375 fprintf(stderr,
1376 "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or"
1377 "ufs1/2 filesystem: %s\n",
1378 program, path);
1379 return -1;
1380 }
1381
1382 devfd = -1;
1383 devname = get_devname(path);
1384 if (_devname)
1385 *_devname = devname;
1386
1387 if ((devfd = open(devname, O_RDWR | O_SYNC)) < 0) {
1388 fprintf(stderr, "%s: cannot open device %s\n", program, devname);
1389 return -1;
1390 }
1391
1392 /* Verify that the device we opened is the device intended */
1393 if (validate_device(path, devfd)) {
1394 fprintf(stderr, "%s: path %s doesn't match device %s\n",
1395 program, path, devname);
1396 close(devfd);
1397 return -1;
1398 }
1399 return devfd;
1400}
1401
1402static int btrfs_read_adv(int devfd)
1403{
1404 if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET)
1405 != 2 * ADV_SIZE)
1406 return -1;
1407
1408 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1409}
1410
1411static inline int xfs_read_adv(int devfd)
1412{
1413 const size_t adv_size = 2 * ADV_SIZE;
1414
1415 if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
1416 return -1;
1417
1418 return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
1419}
1420
1421static int ext_read_adv(const char *path, int devfd, const char **namep)
1422{
1423 int err;
1424 const char *name;
1425
1426 if (fs_type == BTRFS) {
1427 /* btrfs "ldlinux.sys" is in 64k blank area */
1428 return btrfs_read_adv(devfd);
1429 } else if (fs_type == XFS) {
1430 /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
1431 return xfs_read_adv(devfd);
1432 } else {
1433 err = read_adv(path, name = "ldlinux.sys");
1434 if (err == 2) /* ldlinux.sys does not exist */
1435 err = read_adv(path, name = "extlinux.sys");
1436 if (namep)
1437 *namep = name;
1438 return err;
1439 }
1440}
1441
1442static int ext_write_adv(const char *path, const char *cfg, int devfd)
1443{
1444 if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */
1445 if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE,
1446 BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) {
1447 perror("writing adv");
1448 return 1;
1449 }
1450 return 0;
1451 }
1452 return write_adv(path, cfg);
1453}
1454
1455static int install_loader(const char *path, int update_only)
1456{
1457 struct stat st, fst;
1458 int devfd, rv;
1459 const char *devname;
1460
1461 devfd = open_device(path, &st, &devname);
1462 if (devfd < 0)
1463 return 1;
1464
1465 if (update_only && !syslinux_already_installed(devfd)) {
1466 fprintf(stderr, "%s: no previous syslinux boot sector found\n",
1467 program);
1468 close(devfd);
1469 return 1;
1470 }
1471
1472 /* Read a pre-existing ADV, if already installed */
1473 if (opt.reset_adv) {
1474 syslinux_reset_adv(syslinux_adv);
1475 } else if (ext_read_adv(path, devfd, NULL) < 0) {
1476 close(devfd);
1477 return 1;
1478 }
1479
1480 if (modify_adv() < 0) {
1481 close(devfd);
1482 return 1;
1483 }
1484
1485 /* Install ldlinux.sys */
1486 if (install_file(path, devfd, &fst)) {
1487 close(devfd);
1488 return 1;
1489 }
1490 if (fst.st_dev != st.st_dev) {
1491 fprintf(stderr, "%s: file system changed under us - aborting!\n",
1492 program);
1493 close(devfd);
1494 return 1;
1495 }
1496
1497 sync();
1498 rv = install_bootblock(devfd, devname);
1499 close(devfd);
1500 sync();
1501
1502 return rv;
1503}
1504
1505/*
1506 * Modify the ADV of an existing installation
1507 */
1508int modify_existing_adv(const char *path)
1509{
1510 const char *filename;
1511 int devfd;
1512
1513 devfd = open_device(path, NULL, NULL);
1514 if (devfd < 0)
1515 return 1;
1516
1517 if (ext_read_adv(path, devfd, &filename) < 0) {
1518 close(devfd);
1519 return 1;
1520 }
1521 if (modify_adv() < 0) {
1522 close(devfd);
1523 return 1;
1524 }
1525 if (ext_write_adv(path, filename, devfd) < 0) {
1526 close(devfd);
1527 return 1;
1528 }
1529 close(devfd);
1530 return 0;
1531}
1532
1533int main(int argc, char *argv[])
1534{
1535 parse_options(argc, argv, MODE_EXTLINUX);
1536
1537 if (!opt.directory || opt.install_mbr || opt.activate_partition)
1538 usage(EX_USAGE, 0);
1539
1540 if (opt.update_only == -1) {
1541 if (opt.reset_adv || opt.set_once || opt.menu_save)
1542 return modify_existing_adv(opt.directory);
1543 else
1544 usage(EX_USAGE, MODE_EXTLINUX);
1545 }
1546
1547 return install_loader(opt.directory, opt.update_only);
1548}