1 /* ----------------------------------------------------------------------- *
3 * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
14 * syslinux.c - Linux installer program for SYSLINUX
16 * This program now requires mtools. It turned out to be a lot
17 * easier to deal with than dealing with needing mount privileges.
18 * We need device write permission anyway.
21 #define _XOPEN_SOURCE 500 /* Required on glibc 2.x */
34 #include <sys/types.h>
41 char *program
; /* Name of program */
42 char *device
; /* Device to install to */
44 off_t filesystem_offset
= 0; /* Offset of filesystem */
46 void __attribute__((noreturn
)) usage(void)
48 fprintf(stderr
, "Usage: %s [-sfr][-d directory][-o offset] device\n", program
);
52 void __attribute__((noreturn
)) die(const char *msg
)
54 fprintf(stderr
, "%s: %s\n", program
, msg
);
59 * read/write wrapper functions
61 ssize_t
xpread(int fd
, void *buf
, size_t count
, off_t offset
)
63 char *bufp
= (char *)buf
;
68 rv
= pread(fd
, bufp
, count
, offset
);
71 } else if ( rv
== -1 ) {
72 if ( errno
== EINTR
) {
88 ssize_t
xpwrite(int fd
, const void *buf
, size_t count
, off_t offset
)
90 const char *bufp
= (const char *)buf
;
95 rv
= pwrite(fd
, bufp
, count
, offset
);
98 } else if ( rv
== -1 ) {
99 if ( errno
== EINTR
) {
102 die(strerror(errno
));
116 * Version of the read function suitable for libfat
118 int libfat_xpread(intptr_t pp
, void *buf
, size_t secsize
, libfat_sector_t sector
)
120 off_t offset
= (off_t
)sector
* secsize
+ filesystem_offset
;
121 return xpread(pp
, buf
, secsize
, offset
);
125 int main(int argc
, char *argv
[])
127 static unsigned char sectbuf
[512];
132 char mtools_conf
[] = "/tmp/syslinux-mtools-XXXXXX";
133 const char *subdir
= NULL
;
136 struct libfat_filesystem
*fs
;
137 libfat_sector_t s
, *secp
, sectors
[65]; /* 65 is maximum possible */
138 int32_t ldlinux_cluster
;
142 int force
= 0; /* -f (force) option */
143 int stupid
= 0; /* -s (stupid) option */
144 int raid_mode
= 0; /* -r (RAID) option */
146 (void)argc
; /* Unused */
153 for ( argp
= argv
+1 ; *argp
; argp
++ ) {
154 if ( **argp
== '-' ) {
162 } else if ( *opt
== 'r' ) {
164 } else if ( *opt
== 'f' ) {
165 force
= 1; /* Force install */
166 } else if ( *opt
== 'd' && argp
[1] ) {
168 } else if ( *opt
== 'o' && argp
[1] ) {
169 filesystem_offset
= (off_t
)strtoull(*++argp
, NULL
, 0); /* Byte offset */
186 * First make sure we can open the device at all, and that we have
187 * read/write permission.
189 dev_fd
= open(device
, O_RDWR
);
190 if ( dev_fd
< 0 || fstat(dev_fd
, &st
) < 0 ) {
195 if ( !force
&& !S_ISBLK(st
.st_mode
) && !S_ISREG(st
.st_mode
) ) {
196 fprintf(stderr
, "%s: not a block device or regular file (use -f to override)\n", device
);
200 xpread(dev_fd
, sectbuf
, 512, filesystem_offset
);
203 * Check to see that what we got was indeed an MS-DOS boot sector/superblock
205 if( (errmsg
= syslinux_check_bootsect(sectbuf
)) ) {
210 * Create an mtools configuration file
212 mtc_fd
= mkstemp(mtools_conf
);
213 if ( mtc_fd
< 0 || !(mtc
= fdopen(mtc_fd
, "w")) ) {
218 /* "MTOOLS_NO_VFAT=1\n" */
219 "MTOOLS_SKIP_CHECK=1\n" /* Needed for some flash memories */
221 " file=\"/proc/%lu/fd/%d\"\n"
223 (unsigned long)mypid
,
225 (unsigned long long)filesystem_offset
);
229 * Run mtools to create the LDLINUX.SYS file
231 if ( setenv("MTOOLSRC", mtools_conf
, 1) ) {
236 /* This command may fail legitimately */
237 system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
239 mtp
= popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
241 (fwrite(syslinux_ldlinux
, 1, syslinux_ldlinux_len
, mtp
)
242 != syslinux_ldlinux_len
) ||
243 (status
= pclose(mtp
), !WIFEXITED(status
) || WEXITSTATUS(status
)) ) {
244 die("failed to create ldlinux.sys");
248 * Now, use libfat to create a block map
250 fs
= libfat_open(libfat_xpread
, dev_fd
);
251 ldlinux_cluster
= libfat_searchdir(fs
, 0, "LDLINUX SYS", NULL
);
254 s
= libfat_clustertosector(fs
, ldlinux_cluster
);
255 while ( s
&& nsectors
< 65 ) {
258 s
= libfat_nextsector(fs
, s
);
262 /* Patch ldlinux.sys and the boot sector */
263 syslinux_patch(sectors
, nsectors
, stupid
, raid_mode
);
265 /* Write the now-patched first sector of ldlinux.sys */
266 xpwrite(dev_fd
, syslinux_ldlinux
, 512,
267 filesystem_offset
+ ((off_t
)sectors
[0] << 9));
269 /* Move ldlinux.sys to the desired location */
271 char target_file
[4096], command
[5120];
272 char *cp
= target_file
, *ep
= target_file
+sizeof target_file
-16;
276 cp
+= sprintf(cp
, "'s:/");
277 for (sd
= subdir
; *sd
; sd
++) {
278 if (*sd
== '/' || *sd
== '\\') {
280 continue; /* Remove duplicated slashes */
282 } else if (*sd
== '\'' || *sd
== '!') {
284 if (cp
< ep
) *cp
++ = '\'';
285 if (cp
< ep
) *cp
++ = '\\';
286 if (cp
< ep
) *cp
++ = *sd
;
287 if (cp
< ep
) *cp
++ = '\'';
298 strcpy(cp
, "ldlinux.sys'");
300 /* This command may fail legitimately */
301 sprintf(command
, "mattrib -h -r -s %s 2>/dev/null", target_file
);
304 sprintf(command
, "mmove -D o -D O s:/ldlinux.sys %s", target_file
);
305 status
= system(command
);
307 if ( !WIFEXITED(status
) || WEXITSTATUS(status
) ) {
309 "%s: warning: unable to move ldlinux.sys\n",
312 status
= system("mattrib +r +h +s s:/ldlinux.sys");
314 sprintf(command
, "mattrib +r +h +s %s", target_file
);
315 status
= system(command
);
318 status
= system("mattrib +r +h +s s:/ldlinux.sys");
321 if ( !WIFEXITED(status
) || WEXITSTATUS(status
) ) {
323 "%s: warning: failed to set system bit on ldlinux.sys\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
, 512, filesystem_offset
);
340 /* Copy the syslinux code into the boot sector */
341 syslinux_make_bootsect(sectbuf
);
343 /* Write new boot sector */
344 xpwrite(dev_fd
, sectbuf
, 512, filesystem_offset
);