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>
45 char *program
; /* Name of program */
48 void __attribute__ ((noreturn
)) die(const char *msg
)
50 fprintf(stderr
, "%s: %s\n", program
, msg
);
54 void __attribute__ ((noreturn
)) die_err(const char *msg
)
56 fprintf(stderr
, "%s: %s: %s\n", program
, msg
, strerror(errno
));
61 * read/write wrapper functions
63 ssize_t
xpread(int fd
, void *buf
, size_t count
, off_t offset
)
65 char *bufp
= (char *)buf
;
70 rv
= pread(fd
, bufp
, count
, offset
);
73 } else if (rv
== -1) {
90 ssize_t
xpwrite(int fd
, const void *buf
, size_t count
, off_t offset
)
92 const char *bufp
= (const char *)buf
;
97 rv
= pwrite(fd
, bufp
, count
, offset
);
100 } else if (rv
== -1) {
101 if (errno
== EINTR
) {
104 die(strerror(errno
));
118 * Version of the read function suitable for libfat
120 int libfat_xpread(intptr_t pp
, void *buf
, size_t secsize
,
121 libfat_sector_t sector
)
123 off_t offset
= (off_t
) sector
* secsize
+ opt
.offset
;
124 return xpread(pp
, buf
, secsize
, offset
);
127 int main(int argc
, char *argv
[])
129 static unsigned char sectbuf
[SECTOR_SIZE
];
137 struct libfat_filesystem
*fs
;
138 libfat_sector_t s
, *secp
;
139 libfat_sector_t
*sectors
;
140 int32_t ldlinux_cluster
;
143 int ldlinux_sectors
, patch_sectors
;
146 (void)argc
; /* Unused */
151 parse_options(argc
, argv
, MODE_SYSLINUX
);
154 usage(EX_USAGE
, MODE_SYSLINUX
);
156 if (opt
.sectors
|| opt
.heads
|| opt
.reset_adv
|| opt
.set_once
157 || (opt
.update_only
> 0) || opt
.menu_save
) {
159 "At least one specified option not yet implemented"
160 " for this installer.\n");
165 * Temp directory of choice...
167 tmpdir
= getenv("TMPDIR");
171 #elif defined(_PATH_TMP)
179 * First make sure we can open the device at all, and that we have
180 * read/write permission.
182 dev_fd
= open(opt
.device
, O_RDWR
);
183 if (dev_fd
< 0 || fstat(dev_fd
, &st
) < 0) {
188 if (!opt
.force
&& !S_ISBLK(st
.st_mode
) && !S_ISREG(st
.st_mode
)) {
190 "%s: not a block device or regular file (use -f to override)\n",
195 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
198 * Check to see that what we got was indeed an MS-DOS boot sector/superblock
200 if ((errmsg
= syslinux_check_bootsect(sectbuf
))) {
205 * Create an mtools configuration file
207 if (asprintf(&mtools_conf
, "%s//syslinux-mtools-XXXXXX", tmpdir
) < 0 ||
211 mtc_fd
= mkstemp(mtools_conf
);
212 if (mtc_fd
< 0 || !(mtc
= fdopen(mtc_fd
, "w")))
213 die_err(mtools_conf
);
216 /* These are needed for some flash memories */
217 "MTOOLS_SKIP_CHECK=1\n"
218 "MTOOLS_FAT_COMPATIBILITY=1\n"
220 " file=\"/proc/%lu/fd/%d\"\n"
222 (unsigned long)mypid
,
223 dev_fd
, (unsigned long long)opt
.offset
);
225 if (ferror(mtc
) || fclose(mtc
))
226 die_err(mtools_conf
);
229 * Run mtools to create the LDLINUX.SYS file
231 if (setenv("MTOOLSRC", mtools_conf
, 1)) {
237 * Create a vacuous ADV in memory. This should be smarter.
239 syslinux_reset_adv(syslinux_adv
);
241 /* This command may fail legitimately */
242 status
= system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
243 (void)status
; /* Keep _FORTIFY_SOURCE happy */
245 mtp
= popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
247 fwrite(syslinux_ldlinux
, 1, syslinux_ldlinux_len
, mtp
)
248 != syslinux_ldlinux_len
||
249 fwrite(syslinux_adv
, 1, 2 * ADV_SIZE
, mtp
)
251 (status
= pclose(mtp
), !WIFEXITED(status
) || WEXITSTATUS(status
))) {
252 die("failed to create ldlinux.sys");
256 * Now, use libfat to create a block map
258 ldlinux_sectors
= (syslinux_ldlinux_len
+ 2 * ADV_SIZE
259 + SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
260 sectors
= calloc(ldlinux_sectors
, sizeof *sectors
);
261 fs
= libfat_open(libfat_xpread
, dev_fd
);
262 ldlinux_cluster
= libfat_searchdir(fs
, 0, "LDLINUX SYS", NULL
);
265 s
= libfat_clustertosector(fs
, ldlinux_cluster
);
266 while (s
&& nsectors
< ldlinux_sectors
) {
269 s
= libfat_nextsector(fs
, s
);
273 /* Patch ldlinux.sys and the boot sector */
274 i
= syslinux_patch(sectors
, nsectors
, opt
.stupid_mode
, opt
.raid_mode
,
275 opt
.directory
, NULL
);
276 patch_sectors
= (i
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
278 /* Write the now-patched first sectors of ldlinux.sys */
279 for (i
= 0; i
< patch_sectors
; i
++) {
280 xpwrite(dev_fd
, syslinux_ldlinux
+ i
* SECTOR_SIZE
, SECTOR_SIZE
,
281 opt
.offset
+ ((off_t
) sectors
[i
] << SECTOR_SHIFT
));
284 /* Move ldlinux.sys to the desired location */
286 char target_file
[4096], command
[5120];
287 char *cp
= target_file
, *ep
= target_file
+ sizeof target_file
- 16;
291 cp
+= sprintf(cp
, "'s:/");
292 for (sd
= opt
.directory
; *sd
; sd
++) {
293 if (*sd
== '/' || *sd
== '\\') {
295 continue; /* Remove duplicated slashes */
297 } else if (*sd
== '\'' || *sd
== '!') {
317 strcpy(cp
, "ldlinux.sys'");
319 /* This command may fail legitimately */
320 sprintf(command
, "mattrib -h -r -s %s 2>/dev/null", target_file
);
321 status
= system(command
);
322 (void)status
; /* Keep _FORTIFY_SOURCE happy */
324 sprintf(command
, "mmove -D o -D O s:/ldlinux.sys %s", target_file
);
325 status
= system(command
);
327 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
329 "%s: warning: unable to move ldlinux.sys\n", program
);
331 status
= system("mattrib +r +h +s s:/ldlinux.sys");
333 sprintf(command
, "mattrib +r +h +s %s", target_file
);
334 status
= system(command
);
337 status
= system("mattrib +r +h +s s:/ldlinux.sys");
340 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
342 "%s: warning: failed to set system bit on ldlinux.sys\n",
352 * To finish up, write the boot sector
355 /* Read the superblock again since it might have changed while mounted */
356 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
358 /* Copy the syslinux code into the boot sector */
359 syslinux_make_bootsect(sectbuf
);
361 /* Write new boot sector */
362 xpwrite(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);