1 #ident "$Id: syslinux.c,v 1.6 2005/01/04 03:27:43 hpa Exp $"
2 /* ----------------------------------------------------------------------- *
4 * Copyright 1998-2004 H. Peter Anvin - All Rights Reserved
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.
22 #define _XOPEN_SOURCE 500 /* Required on glibc 2.x */
35 #include <sys/types.h>
42 char *program; /* Name of program */
43 char *device; /* Device to install to */
45 off_t filesystem_offset = 0; /* Offset of filesystem */
47 void __attribute__((noreturn)) usage(void)
49 fprintf(stderr, "Usage: %s [-sf] [-o offset] device\n", program);
53 void __attribute__((noreturn)) die(const char *msg)
55 fprintf(stderr, "%s: %s\n", program, msg);
60 * read/write wrapper functions
62 ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
64 char *bufp = (char *)buf;
69 rv = pread(fd, bufp, count, offset);
72 } else if ( rv == -1 ) {
73 if ( errno == EINTR ) {
89 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
91 const char *bufp = (const char *)buf;
96 rv = pwrite(fd, bufp, count, offset);
99 } else if ( rv == -1 ) {
100 if ( errno == EINTR ) {
103 die(strerror(errno));
117 * Version of the read function suitable for libfat
119 int libfat_xpread(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sector)
121 off_t offset = (off_t)sector * secsize + filesystem_offset;
122 return xpread(pp, buf, secsize, offset);
126 int main(int argc, char *argv[])
128 static unsigned char sectbuf[512];
133 int force = 0; /* -f (force) option */
134 char mtools_conf[] = "/tmp/syslinux-mtools-XXXXXX";
137 struct libfat_filesystem *fs;
138 libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */
139 int32_t ldlinux_cluster;
143 (void)argc; /* Unused */
150 for ( argp = argv+1 ; *argp ; argp++ ) {
151 if ( **argp == '-' ) {
158 syslinux_make_stupid(); /* Use "safe, slow and stupid" code */
159 } else if ( *opt == 'f' ) {
160 force = 1; /* Force install */
161 } else if ( *opt == 'o' && argp[1] ) {
162 filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); /* Byte offset */
179 * First make sure we can open the device at all, and that we have
180 * read/write permission.
182 dev_fd = open(device, O_RDWR);
183 if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) {
188 if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) {
189 fprintf(stderr, "%s: not a block device or regular file (use -f to override)\n", device);
193 xpread(dev_fd, sectbuf, 512, filesystem_offset);
196 * Check to see that what we got was indeed an MS-DOS boot sector/superblock
198 if( (errmsg = syslinux_check_bootsect(sectbuf)) ) {
203 * Create an mtools configuration file
205 mtc_fd = mkstemp(mtools_conf);
206 if ( mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")) ) {
212 "MTOOLS_SKIP_CHECK=1\n" /* Needed for some flash memories */
214 " file=\"/proc/%lu/fd/%d\"\n"
216 (unsigned long)mypid,
218 (unsigned long long)filesystem_offset);
222 * Run mtools to create the LDLINUX.SYS file
224 if ( setenv("MTOOLSRC", mtools_conf, 1) ) {
229 /* This command may fail legitimately */
230 system("mattrib -h -r -s s:ldlinux.sys 2>/dev/null");
232 mtp = popen("mcopy -D o -D O -o - s:ldlinux.sys", "w");
234 (fwrite(syslinux_ldlinux, 1, syslinux_ldlinux_len, mtp)
235 != syslinux_ldlinux_len) ||
236 (status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status)) ) {
237 die("failed to create ldlinux.sys");
240 status = system("mattrib +r +h +s s:ldlinux.sys");
242 if ( !WIFEXITED(status) || WEXITSTATUS(status) ) {
244 "%s: warning: failed to set system bit on ldlinux.sys\n",
251 * Now, use libfat to create a block map
253 fs = libfat_open(libfat_xpread, dev_fd);
254 ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
257 s = libfat_clustertosector(fs, ldlinux_cluster);
258 while ( s && nsectors < 65 ) {
261 s = libfat_nextsector(fs, s);
266 * Patch ldlinux.sys and the boot sector
268 syslinux_patch(sectors, nsectors);
271 * Write the now-patched first sector of ldlinux.sys
273 xpwrite(dev_fd, syslinux_ldlinux, 512, filesystem_offset + ((off_t)sectors[0] << 9));
276 * To finish up, write the boot sector
279 /* Read the superblock again since it might have changed while mounted */
280 xpread(dev_fd, sectbuf, 512, filesystem_offset);
282 /* Copy the syslinux code into the boot sector */
283 syslinux_make_bootsect(sectbuf);
285 /* Write new boot sector */
286 xpwrite(dev_fd, sectbuf, 512, filesystem_offset);