1 /* ----------------------------------------------------------------------- *
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 */
89 static 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  */
get_size(int devfd)97 static 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  */
118 struct geometry_table {
119     uint64_t bytes;
120     struct hd_geometry g;
121 };
122 
sysfs_get_offset(int devfd,unsigned long * start)123 static 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... */
153 static 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 
get_geometry(int devfd,uint64_t totalbytes,struct hd_geometry * geo)166 int 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 
211 ok:
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  */
patch_file_and_bootblock(int fd,const char * dir,int devfd)231 static 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  */
install_bootblock(int fd,const char * device)344 int 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 
rewrite_boot_image(int devfd,const char * path,const char * filename)464 static 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 
505 error:
506     close(fd);
507 
508     return -1;
509 }
510 
ext2_fat_install_file(const char * path,int devfd,struct stat * rst)511 int 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 
588 bail:
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 */
btrfs_install_file(const char * path,int devfd,struct stat * rst)603 int 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  */
xfs_install_file(const char * path,int devfd,struct stat * rst)669 static 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 
739 bail:
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  *       */
test_issubvolume(char * path)756 static 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  */
get_default_subvol(char * rootdir,char * subvol)775 static 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 
install_file(const char * path,int devfd,struct stat * rst)981 static 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__
995 static char devname_buf[64];
996 
device_cleanup(void)997 static 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. */
1005 static int validate_device_btrfs(int pathfd, int devfd);
validate_device(const char * path,int devfd)1006 static 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 
1028 err:
1029     if (pfd >= 0)
1030 	close(pfd);
1031     return rv;
1032 }
1033 
1034 #ifndef __KLIBC__
find_device(const char * mtab_file,dev_t dev)1035 static 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  */
find_device_sysfs(dev_t dev)1122 static 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 
1160 err:
1161     if (buf)
1162 	free(buf);
1163     return NULL;
1164 }
1165 
find_device_mountinfo(const char * path,dev_t dev)1166 static 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 
validate_device_btrfs(int pfd,int dfd)1182 static 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 
find_device_btrfs(const char * path)1228 static 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 
1264 err:
1265     if (pfd >= 0)
1266 	close(pfd);
1267     if (dfd >= 0)
1268 	close(dfd);
1269     return rv;
1270 }
1271 
get_devname(const char * path)1272 static 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 
open_device(const char * path,struct stat * st,const char ** _devname)1341 static 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 
btrfs_read_adv(int devfd)1402 static 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 
xfs_read_adv(int devfd)1411 static 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 
ext_read_adv(const char * path,int devfd,const char ** namep)1421 static 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 
ext_write_adv(const char * path,const char * cfg,int devfd)1442 static 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 
install_loader(const char * path,int update_only)1455 static 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  */
modify_existing_adv(const char * path)1508 int 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 
main(int argc,char * argv[])1533 int 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 }
1549