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>
50 void __attribute__ ((noreturn
)) die(const char *msg
)
52 fprintf(stderr
, "%s: %s\n", program
, msg
);
56 void __attribute__ ((noreturn
)) die_err(const char *msg
)
58 fprintf(stderr
, "%s: %s: %s\n", program
, msg
, strerror(errno
));
63 * Version of the read function suitable for libfat
65 int libfat_xpread(intptr_t pp
, void *buf
, size_t secsize
,
66 libfat_sector_t sector
)
68 off_t offset
= (off_t
) sector
* secsize
+ opt
.offset
;
69 return xpread(pp
, buf
, secsize
, offset
);
72 static int move_file(char *filename
)
74 char target_file
[4096], command
[5120];
75 char *cp
= target_file
, *ep
= target_file
+ sizeof target_file
- 16;
80 cp
+= sprintf(cp
, "'s:/");
81 for (sd
= opt
.directory
; *sd
; sd
++) {
82 if (*sd
== '/' || *sd
== '\\') {
84 continue; /* Remove duplicated slashes */
86 } else if (*sd
== '\'' || *sd
== '!') {
106 sprintf(cp
, "%s'", filename
);
108 /* This command may fail legitimately */
109 sprintf(command
, "mattrib -h -r -s %s 2>/dev/null", target_file
);
110 status
= system(command
);
111 (void)status
; /* Keep _FORTIFY_SOURCE happy */
113 sprintf(command
, "mmove -D o -D O s:/%s %s", filename
, target_file
);
114 status
= system(command
);
116 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
118 "%s: warning: unable to move %s\n", program
, filename
);
120 sprintf(command
, "mattrib +r +h +s s:/%s", filename
);
121 status
= system(command
);
123 sprintf(command
, "mattrib +r +h +s %s", target_file
);
124 status
= system(command
);
130 int main(int argc
, char *argv
[])
132 static unsigned char sectbuf
[SECTOR_SIZE
];
140 struct libfat_filesystem
*fs
;
141 libfat_sector_t s
, *secp
;
142 libfat_sector_t
*sectors
;
143 int32_t ldlinux_cluster
;
146 int ldlinux_sectors
, patch_sectors
;
149 (void)argc
; /* Unused */
154 parse_options(argc
, argv
, MODE_SYSLINUX
);
157 usage(EX_USAGE
, MODE_SYSLINUX
);
159 if (opt
.sectors
|| opt
.heads
|| opt
.reset_adv
|| opt
.set_once
160 || (opt
.update_only
> 0) || opt
.menu_save
) {
162 "At least one specified option not yet implemented"
163 " for this installer.\n");
168 * Temp directory of choice...
170 tmpdir
= getenv("TMPDIR");
174 #elif defined(_PATH_TMP)
182 * First make sure we can open the device at all, and that we have
183 * read/write permission.
185 dev_fd
= open(opt
.device
, O_RDWR
);
186 if (dev_fd
< 0 || fstat(dev_fd
, &st
) < 0) {
191 if (!opt
.force
&& !S_ISBLK(st
.st_mode
) && !S_ISREG(st
.st_mode
)) {
193 "%s: not a block device or regular file (use -f to override)\n",
198 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
201 * Check to see that what we got was indeed an MS-DOS boot sector/superblock
203 if ((errmsg
= syslinux_check_bootsect(sectbuf
, NULL
))) {
208 * Create an mtools configuration file
210 if (asprintf(&mtools_conf
, "%s//syslinux-mtools-XXXXXX", tmpdir
) < 0 ||
214 mtc_fd
= mkstemp(mtools_conf
);
215 if (mtc_fd
< 0 || !(mtc
= fdopen(mtc_fd
, "w")))
216 die_err(mtools_conf
);
219 /* These are needed for some flash memories */
220 "MTOOLS_SKIP_CHECK=1\n"
221 "MTOOLS_FAT_COMPATIBILITY=1\n"
223 " file=\"/proc/%lu/fd/%d\"\n"
225 (unsigned long)mypid
,
226 dev_fd
, (unsigned long long)opt
.offset
);
228 if (ferror(mtc
) || fclose(mtc
))
229 die_err(mtools_conf
);
232 * Run mtools to create the LDLINUX.SYS file
234 if (setenv("MTOOLSRC", mtools_conf
, 1)) {
240 * Create a vacuous ADV in memory. This should be smarter.
242 syslinux_reset_adv(syslinux_adv
);
244 /* This command may fail legitimately */
245 status
= system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
246 (void)status
; /* Keep _FORTIFY_SOURCE happy */
248 mtp
= popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
250 fwrite((const void _force
*)syslinux_ldlinux
,
251 1, syslinux_ldlinux_len
, mtp
)
252 != syslinux_ldlinux_len
||
253 fwrite((const void _force
*)syslinux_adv
,
254 1, 2 * ADV_SIZE
, mtp
)
256 (status
= pclose(mtp
), !WIFEXITED(status
) || WEXITSTATUS(status
))) {
257 die("failed to create ldlinux.sys");
261 * Now, use libfat to create a block map
263 ldlinux_sectors
= (syslinux_ldlinux_len
+ 2 * ADV_SIZE
264 + SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
265 sectors
= calloc(ldlinux_sectors
, sizeof *sectors
);
266 fs
= libfat_open(libfat_xpread
, dev_fd
);
267 ldlinux_cluster
= libfat_searchdir(fs
, 0, "LDLINUX SYS", NULL
);
270 s
= libfat_clustertosector(fs
, ldlinux_cluster
);
271 while (s
&& nsectors
< ldlinux_sectors
) {
274 s
= libfat_nextsector(fs
, s
);
278 /* Patch ldlinux.sys and the boot sector */
279 i
= syslinux_patch(sectors
, nsectors
, opt
.stupid_mode
, opt
.raid_mode
,
280 opt
.directory
, NULL
);
281 patch_sectors
= (i
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
283 /* Write the now-patched first sectors of ldlinux.sys */
284 for (i
= 0; i
< patch_sectors
; i
++) {
285 xpwrite(dev_fd
, (const char _force
*)syslinux_ldlinux
286 + i
* SECTOR_SIZE
, SECTOR_SIZE
,
287 opt
.offset
+ ((off_t
) sectors
[i
] << SECTOR_SHIFT
));
290 /* Move ldlinux.sys to the desired location */
292 status
= move_file("ldlinux.sys");
294 status
= system("mattrib +r +h +s s:/ldlinux.sys");
297 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
299 "%s: warning: failed to set system bit on ldlinux.sys\n",
303 /* This command may fail legitimately */
304 status
= system("mattrib -h -r -s s:/ldlinux.c32 2>/dev/null");
305 (void)status
; /* Keep _FORTIFY_SOURCE happy */
307 mtp
= popen("mcopy -D o -D O -o - s:/ldlinux.c32", "w");
308 if (!mtp
|| fwrite((const char _force
*)syslinux_ldlinuxc32
,
309 1, syslinux_ldlinuxc32_len
, mtp
)
310 != syslinux_ldlinuxc32_len
||
311 (status
= pclose(mtp
), !WIFEXITED(status
) || WEXITSTATUS(status
))) {
312 die("failed to create ldlinux.c32");
315 /* Move ldlinux.c32 to the desired location */
317 status
= move_file("ldlinux.c32");
319 status
= system("mattrib +r +h +s s:/ldlinux.c32");
322 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
324 "%s: warning: failed to set system bit on ldlinux.c32\n",
334 * To finish up, write the boot sector
337 /* Read the superblock again since it might have changed while mounted */
338 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
340 /* Copy the syslinux code into the boot sector */
341 syslinux_make_bootsect(sectbuf
, VFAT
);
343 /* Write new boot sector */
344 xpwrite(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);