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 int main(int argc
, char *argv
[])
130 static unsigned char sectbuf
[SECTOR_SIZE
];
138 struct libfat_filesystem
*fs
;
139 libfat_sector_t s
, *secp
;
140 libfat_sector_t
*sectors
;
141 int32_t ldlinux_cluster
;
144 int ldlinux_sectors
, patch_sectors
;
147 (void)argc
; /* Unused */
152 parse_options(argc
, argv
, MODE_SYSLINUX
);
155 usage(EX_USAGE
, MODE_SYSLINUX
);
157 if (opt
.sectors
|| opt
.heads
|| opt
.reset_adv
|| opt
.set_once
158 || (opt
.update_only
> 0) || opt
.menu_save
) {
160 "At least one specified option not yet implemented"
161 " for this installer.\n");
166 * Temp directory of choice...
168 tmpdir
= getenv("TMPDIR");
172 #elif defined(_PATH_TMP)
180 * First make sure we can open the device at all, and that we have
181 * read/write permission.
183 dev_fd
= open(opt
.device
, O_RDWR
);
184 if (dev_fd
< 0 || fstat(dev_fd
, &st
) < 0) {
189 if (!opt
.force
&& !S_ISBLK(st
.st_mode
) && !S_ISREG(st
.st_mode
)) {
191 "%s: not a block device or regular file (use -f to override)\n",
196 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
199 * Check to see that what we got was indeed an MS-DOS boot sector/superblock
201 if ((errmsg
= syslinux_check_bootsect(sectbuf
, NULL
))) {
206 * Create an mtools configuration file
208 if (asprintf(&mtools_conf
, "%s//syslinux-mtools-XXXXXX", tmpdir
) < 0 ||
212 mtc_fd
= mkstemp(mtools_conf
);
213 if (mtc_fd
< 0 || !(mtc
= fdopen(mtc_fd
, "w")))
214 die_err(mtools_conf
);
217 /* These are needed for some flash memories */
218 "MTOOLS_SKIP_CHECK=1\n"
219 "MTOOLS_FAT_COMPATIBILITY=1\n"
221 " file=\"/proc/%lu/fd/%d\"\n"
223 (unsigned long)mypid
,
224 dev_fd
, (unsigned long long)opt
.offset
);
226 if (ferror(mtc
) || fclose(mtc
))
227 die_err(mtools_conf
);
230 * Run mtools to create the LDLINUX.SYS file
232 if (setenv("MTOOLSRC", mtools_conf
, 1)) {
238 * Create a vacuous ADV in memory. This should be smarter.
240 syslinux_reset_adv(syslinux_adv
);
242 /* This command may fail legitimately */
243 status
= system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
244 (void)status
; /* Keep _FORTIFY_SOURCE happy */
246 mtp
= popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
248 fwrite(syslinux_ldlinux
, 1, syslinux_ldlinux_len
, mtp
)
249 != syslinux_ldlinux_len
||
250 fwrite(syslinux_adv
, 1, 2 * ADV_SIZE
, mtp
)
252 (status
= pclose(mtp
), !WIFEXITED(status
) || WEXITSTATUS(status
))) {
253 die("failed to create ldlinux.sys");
257 * Now, use libfat to create a block map
259 ldlinux_sectors
= (syslinux_ldlinux_len
+ 2 * ADV_SIZE
260 + SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
261 sectors
= calloc(ldlinux_sectors
, sizeof *sectors
);
262 fs
= libfat_open(libfat_xpread
, dev_fd
);
263 ldlinux_cluster
= libfat_searchdir(fs
, 0, "LDLINUX SYS", NULL
);
266 s
= libfat_clustertosector(fs
, ldlinux_cluster
);
267 while (s
&& nsectors
< ldlinux_sectors
) {
270 s
= libfat_nextsector(fs
, s
);
274 /* Patch ldlinux.sys and the boot sector */
275 i
= syslinux_patch(sectors
, nsectors
, opt
.stupid_mode
, opt
.raid_mode
,
276 opt
.directory
, NULL
);
277 patch_sectors
= (i
+ SECTOR_SIZE
- 1) >> SECTOR_SHIFT
;
279 /* Write the now-patched first sectors of ldlinux.sys */
280 for (i
= 0; i
< patch_sectors
; i
++) {
281 xpwrite(dev_fd
, syslinux_ldlinux
+ i
* SECTOR_SIZE
, SECTOR_SIZE
,
282 opt
.offset
+ ((off_t
) sectors
[i
] << SECTOR_SHIFT
));
285 /* Move ldlinux.sys to the desired location */
287 char target_file
[4096], command
[5120];
288 char *cp
= target_file
, *ep
= target_file
+ sizeof target_file
- 16;
292 cp
+= sprintf(cp
, "'s:/");
293 for (sd
= opt
.directory
; *sd
; sd
++) {
294 if (*sd
== '/' || *sd
== '\\') {
296 continue; /* Remove duplicated slashes */
298 } else if (*sd
== '\'' || *sd
== '!') {
318 strcpy(cp
, "ldlinux.sys'");
320 /* This command may fail legitimately */
321 sprintf(command
, "mattrib -h -r -s %s 2>/dev/null", target_file
);
322 status
= system(command
);
323 (void)status
; /* Keep _FORTIFY_SOURCE happy */
325 sprintf(command
, "mmove -D o -D O s:/ldlinux.sys %s", target_file
);
326 status
= system(command
);
328 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
330 "%s: warning: unable to move ldlinux.sys\n", program
);
332 status
= system("mattrib +r +h +s s:/ldlinux.sys");
334 sprintf(command
, "mattrib +r +h +s %s", target_file
);
335 status
= system(command
);
338 status
= system("mattrib +r +h +s s:/ldlinux.sys");
341 if (!WIFEXITED(status
) || WEXITSTATUS(status
)) {
343 "%s: warning: failed to set system bit on ldlinux.sys\n",
353 * To finish up, write the boot sector
356 /* Read the superblock again since it might have changed while mounted */
357 xpread(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);
359 /* Copy the syslinux code into the boot sector */
360 syslinux_make_bootsect(sectbuf
, VFAT
);
362 /* Write new boot sector */
363 xpwrite(dev_fd
, sectbuf
, SECTOR_SIZE
, opt
.offset
);