1 /* ----------------------------------------------------------------------- *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 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 * syslinux.c - Linux installer program for SYSLINUX
17 * This program now requires mtools. It turned out to be a lot
18 * easier to deal with than dealing with needing mount privileges.
19 * We need device write permission anyway.
36 #include <sys/types.h>
46 char *program
; /* Name of program */
49 void __attribute__ ((noreturn
)) die(const char *msg
)
51 fprintf(stderr
, "%s: %s\n", program
, msg
);
55 void __attribute__ ((noreturn
)) die_err(const char *msg
)
57 fprintf(stderr
, "%s: %s: %s\n", program
, msg
, strerror(errno
));
62 * read/write wrapper functions
64 ssize_t
xpread(int fd
, void *buf
, size_t count
, off_t offset
)
66 char *bufp
= (char *)buf
;
71 rv
= pread(fd
, bufp
, count
, offset
);
74 } else if (rv
== -1) {
91 ssize_t
xpwrite(int fd
, const void *buf
, size_t count
, off_t offset
)
93 const char *bufp
= (const char *)buf
;
98 rv
= pwrite(fd
, bufp
, count
, offset
);
101 } else if (rv
== -1) {
102 if (errno
== EINTR
) {
105 die(strerror(errno
));
119 * Version of the read function suitable for libfat
121 int libfat_xpread(intptr_t pp
, void *buf
, size_t secsize
,
122 libfat_sector_t sector
)
124 off_t offset
= (off_t
) sector
* secsize
+ opt
.offset
;
125 return xpread(pp
, buf
, secsize
, offset
);
128 static int move_file(char *filename
)
130 char target_file
[4096], command
[5120];
131 char *cp
= target_file
, *ep
= target_file
+ sizeof target_file
- 16;
136 cp
+= sprintf(cp
, "'s:/");
137 for (sd
= opt
.directory
; *sd
; sd
++) {
138 if (*sd
== '/' || *sd
== '\\') {
140 continue; /* Remove duplicated slashes */
142 } else if (*sd
== '\'' || *sd
== '!') {
162 sprintf(cp
, "%s'", filename
);
164 /* This command may fail legitimately */
165 sprintf(command
, "mattrib -h -r -s %s 2>/dev/null", target_file
);
166 status
= system(command
);
167 (void)status
; /* Keep _FORTIFY_SOURCE happy */
169 sprintf(command
, "mmove -D o -D O s:/%s %s", filename
, target_file
);
170 status
= system(command
);
172 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
174 "%s: warning: unable to move %s\n", program
, filename
);
176 sprintf(command
, "mattrib +r +h +s s:/%s", filename
);
177 status
= system(command
);
179 sprintf(command
, "mattrib +r +h +s %s", target_file
);
180 status
= system(command
);
186 int main(int argc
, char *argv
[])
188 static unsigned char sectbuf
[SECTOR_SIZE
];
196 struct libfat_filesystem
*fs
;
197 libfat_sector_t s
, *secp
;
198 libfat_sector_t
*sectors
;
199 int32_t ldlinux_cluster
;
202 int ldlinux_sectors
, patch_sectors
;
205 (void)argc
; /* Unused */
210 parse_options(argc
, argv
, MODE_SYSLINUX
);
213 usage(EX_USAGE
, MODE_SYSLINUX
);
215 if (opt
.sectors
|| opt
.heads
|| opt
.reset_adv
|| opt
.set_once
216 || (opt
.update_only
> 0) || opt
.menu_save
) {
218 "At least one specified option not yet implemented"
219 " for this installer.\n");
224 * Temp directory of choice...
226 tmpdir
= getenv("TMPDIR");
230 #elif defined(_PATH_TMP)
238 * First make sure we can open the device at all, and that we have
239 * read/write permission.
241 dev_fd
= open(opt
.device
, O_RDWR
);
242 if (dev_fd
< 0 || fstat(dev_fd
, &st
) < 0) {
247 if (!opt
.force
&& !S_ISBLK(st
.st_mode
) && !S_ISREG(st
.st_mode
)) {
249 "%s: not a block device or regular file (use -f to override)\n",
254 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
257 * Check to see that what we got was indeed an MS-DOS boot sector/superblock
259 if ((errmsg
= syslinux_check_bootsect(sectbuf
, NULL
))) {
264 * Create an mtools configuration file
266 if (asprintf(&mtools_conf
, "%s//syslinux-mtools-XXXXXX", tmpdir
) < 0 ||
270 mtc_fd
= mkstemp(mtools_conf
);
271 if (mtc_fd
< 0 || !(mtc
= fdopen(mtc_fd
, "w")))
272 die_err(mtools_conf
);
275 /* These are needed for some flash memories */
276 "MTOOLS_SKIP_CHECK=1\n"
277 "MTOOLS_FAT_COMPATIBILITY=1\n"
279 " file=\"/proc/%lu/fd/%d\"\n"
281 (unsigned long)mypid
,
282 dev_fd
, (unsigned long long)opt
.offset
);
284 if (ferror(mtc
) || fclose(mtc
))
285 die_err(mtools_conf
);
288 * Run mtools to create the LDLINUX.SYS file
290 if (setenv("MTOOLSRC", mtools_conf
, 1)) {
296 * Create a vacuous ADV in memory. This should be smarter.
298 syslinux_reset_adv(syslinux_adv
);
300 /* This command may fail legitimately */
301 status
= system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
302 (void)status
; /* Keep _FORTIFY_SOURCE happy */
304 mtp
= popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
306 fwrite(syslinux_ldlinux
, 1, syslinux_ldlinux_len
, mtp
)
307 != syslinux_ldlinux_len
||
308 fwrite(syslinux_adv
, 1, 2 * ADV_SIZE
, mtp
)
310 (status
= pclose(mtp
), !WIFEXITED(status
) || WEXITSTATUS(status
))) {
311 die("failed to create ldlinux.sys");
315 * Now, use libfat to create a block map
317 ldlinux_sectors
= (syslinux_ldlinux_len
+ 2 * ADV_SIZE
318 + SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
319 sectors
= calloc(ldlinux_sectors
, sizeof *sectors
);
320 fs
= libfat_open(libfat_xpread
, dev_fd
);
321 ldlinux_cluster
= libfat_searchdir(fs
, 0, "LDLINUX SYS", NULL
);
324 s
= libfat_clustertosector(fs
, ldlinux_cluster
);
325 while (s
&& nsectors
< ldlinux_sectors
) {
328 s
= libfat_nextsector(fs
, s
);
332 /* Patch ldlinux.sys and the boot sector */
333 i
= syslinux_patch(sectors
, nsectors
, opt
.stupid_mode
, opt
.raid_mode
,
334 opt
.directory
, NULL
);
335 patch_sectors
= (i
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
337 /* Write the now-patched first sectors of ldlinux.sys */
338 for (i
= 0; i
< patch_sectors
; i
++) {
339 xpwrite(dev_fd
, syslinux_ldlinux
+ i
* SECTOR_SIZE
, SECTOR_SIZE
,
340 opt
.offset
+ ((off_t
) sectors
[i
] << SECTOR_SHIFT
));
343 /* Move ldlinux.sys to the desired location */
345 status
= move_file("ldlinux.sys");
347 status
= system("mattrib +r +h +s s:/ldlinux.sys");
350 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
352 "%s: warning: failed to set system bit on ldlinux.sys\n",
356 /* This command may fail legitimately */
357 status
= system("mattrib -h -r -s s:/ldlinux.c32 2>/dev/null");
358 (void)status
; /* Keep _FORTIFY_SOURCE happy */
360 mtp
= popen("mcopy -D o -D O -o - s:/ldlinux.c32", "w");
361 if (!mtp
|| fwrite(syslinux_ldlinuxc32
, 1, syslinux_ldlinuxc32_len
, mtp
)
362 != syslinux_ldlinuxc32_len
||
363 (status
= pclose(mtp
), !WIFEXITED(status
) || WEXITSTATUS(status
))) {
364 die("failed to create ldlinux.c32");
367 /* Move ldlinux.c32 to the desired location */
369 status
= move_file("ldlinux.c32");
371 status
= system("mattrib +r +h +s s:/ldlinux.c32");
374 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
376 "%s: warning: failed to set system bit on ldlinux.c32\n",
386 * To finish up, write the boot sector
389 /* Read the superblock again since it might have changed while mounted */
390 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
392 /* Copy the syslinux code into the boot sector */
393 syslinux_make_bootsect(sectbuf
, VFAT
);
395 /* Write new boot sector */
396 xpwrite(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);