syslinux-3.08-2 sources from FC4
[bootcd.git] / syslinux / extlinux / extlinux.c
1 #ident "$Id: extlinux.c,v 1.15 2005/04/03 00:00:36 hpa Exp $"
2 /* ----------------------------------------------------------------------- *
3  *   
4  *   Copyright 1998-2005 H. Peter Anvin - All Rights Reserved
5  *
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.
11  *
12  * ----------------------------------------------------------------------- */
13
14 /*
15  * extlinux.c
16  *
17  * Install the extlinux boot block on an ext2/3 filesystem
18  */
19
20 #define  _GNU_SOURCE            /* Enable everything */
21 #include <inttypes.h>
22 /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
23 typedef uint64_t u64;
24 #include <alloca.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <mntent.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <getopt.h>
33 #include <sysexits.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/mount.h>
38
39 #include <linux/fd.h>           /* Floppy geometry */
40 #include <linux/hdreg.h>        /* Hard disk geometry */
41 #include <linux/fs.h>           /* FIGETBSZ, FIBMAP */
42
43 #include "ext2_fs.h"
44 #include "../version.h"
45
46 #ifdef DEBUG
47 # define dprintf printf
48 #else
49 # define dprintf(...) ((void)0)
50 #endif
51
52 /* Global option handling */
53
54 const char *program;
55
56 /* These are the options we can set and their values */
57 struct my_options {
58   unsigned int sectors;
59   unsigned int heads;
60 } opt = {
61   .sectors = 0,
62   .heads = 0,
63 };
64
65 static void __attribute__((noreturn)) usage(int rv)
66 {
67   fprintf(stderr,
68           "Usage: %s [options] directory\n"
69           "  --zip        -z  Force zipdrive geometry (-H 64 -S 32)\n"
70           "  --sectors=#  -S  Force the number of sectors per track\n"
71           "  --heads=#    -H  Force number of heads\n"
72           "\n"
73           "  Note: geometry is determined at boot time for devices which\n"
74           "  are considered hard disks by the BIOS.  Unfortunately, this is\n"
75           "  not possible for devices which are considered floppy disks,\n"
76           "  which includes zipdisks and LS-120 superfloppies.\n"
77           "\n"
78           "  The -z option is useful for USB devices which are considered\n"
79           "  hard disks by some BIOSes and zipdrives by other BIOSes.\n",
80           program);
81
82   exit(rv);
83 }
84
85 static const struct option long_options[] = {
86   { "zipdrive", 0, NULL, 'z' },
87   { "sectors",  1, NULL, 'S' },
88   { "heads",    1, NULL, 'H' },
89   { "version",  0, NULL, 'v' },
90   { "help",     0, NULL, 'h' },
91   { 0, 0, 0, 0 }
92 };
93     
94 static const char short_options[] = "zS:H:vh";
95
96
97
98 #if defined(__linux__) && !defined(BLKGETSIZE64)
99 /* This takes a u64, but the size field says size_t.  Someone screwed big. */
100 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
101 #endif
102
103 #define LDLINUX_MAGIC   0x3eb202fe
104
105 enum bs_offsets {
106   bsJump            = 0x00,
107   bsOemName         = 0x03,
108   bsBytesPerSec     = 0x0b,
109   bsSecPerClust     = 0x0d,
110   bsResSectors      = 0x0e,
111   bsFATs            = 0x10,
112   bsRootDirEnts     = 0x11,
113   bsSectors         = 0x13,
114   bsMedia           = 0x15,
115   bsFATsecs         = 0x16,
116   bsSecPerTrack     = 0x18,
117   bsHeads           = 0x1a,
118   bsHiddenSecs      = 0x1c,
119   bsHugeSectors     = 0x20,
120
121   /* FAT12/16 only */
122   bs16DriveNumber   = 0x24,
123   bs16Reserved1     = 0x25,
124   bs16BootSignature = 0x26,
125   bs16VolumeID      = 0x27,
126   bs16VolumeLabel   = 0x2b,
127   bs16FileSysType   = 0x36,
128   bs16Code          = 0x3e,
129
130   /* FAT32 only */
131   bs32FATSz32       = 36,
132   bs32ExtFlags      = 40,
133   bs32FSVer         = 42,
134   bs32RootClus      = 44,
135   bs32FSInfo        = 48,
136   bs32BkBootSec     = 50,
137   bs32Reserved      = 52,
138   bs32DriveNumber   = 64,
139   bs32Reserved1     = 65,
140   bs32BootSignature = 66,
141   bs32VolumeID      = 67,
142   bs32VolumeLabel   = 71,
143   bs32FileSysType   = 82,
144   bs32Code          = 90,
145   
146   bsSignature     = 0x1fe
147 };
148
149 #define bsHead      bsJump
150 #define bsHeadLen   (bsOemName-bsHead)
151 #define bsCode      bs32Code    /* The common safe choice */
152 #define bsCodeLen   (bsSignature-bs32Code)
153
154 /*
155  * Access functions for littleendian numbers, possibly misaligned.
156  */
157 static inline uint8_t get_8(const unsigned char *p)
158 {
159   return *(const uint8_t *)p;
160 }
161
162 static inline uint16_t get_16(const unsigned char *p)
163 {
164 #if defined(__i386__) || defined(__x86_64__)
165   /* Littleendian and unaligned-capable */
166   return *(const uint16_t *)p;
167 #else
168   return (uint16_t)p[0] + ((uint16_t)p[1] << 8);
169 #endif
170 }
171
172 static inline uint32_t get_32(const unsigned char *p)
173 {
174 #if defined(__i386__) || defined(__x86_64__)
175   /* Littleendian and unaligned-capable */
176   return *(const uint32_t *)p;
177 #else
178   return (uint32_t)p[0] + ((uint32_t)p[1] << 8) +
179     ((uint32_t)p[2] << 16) + ((uint32_t)p[3] << 24);
180 #endif
181 }
182
183 static inline void set_16(unsigned char *p, uint16_t v)
184 {
185 #if defined(__i386__) || defined(__x86_64__)
186   /* Littleendian and unaligned-capable */
187   *(uint16_t *)p = v;
188 #else
189   p[0] = (v & 0xff);
190   p[1] = ((v >> 8) & 0xff);
191 #endif
192 }
193
194 static inline void set_32(unsigned char *p, uint32_t v)
195 {
196 #if defined(__i386__) || defined(__x86_64__)
197   /* Littleendian and unaligned-capable */
198   *(uint32_t *)p = v;
199 #else
200   p[0] = (v & 0xff);
201   p[1] = ((v >> 8) & 0xff);
202   p[2] = ((v >> 16) & 0xff);
203   p[3] = ((v >> 24) & 0xff);
204 #endif
205 }
206
207 #ifndef EXT2_SUPER_OFFSET
208 #define EXT2_SUPER_OFFSET 1024
209 #endif
210
211 #define SECTOR_SHIFT    9       /* 512-byte sectors */
212 #define SECTOR_SIZE     (1 << SECTOR_SHIFT)
213
214 const char *program;
215
216 /*
217  * Boot block
218  */
219 extern unsigned char extlinux_bootsect[];
220 extern unsigned int  extlinux_bootsect_len;
221 #define boot_block      extlinux_bootsect
222 #define boot_block_len  extlinux_bootsect_len
223
224 /*
225  * Image file
226  */
227 extern unsigned char extlinux_image[];
228 extern unsigned int  extlinux_image_len;
229 #define boot_image      extlinux_image
230 #define boot_image_len  extlinux_image_len
231
232 /*
233  * Common abort function
234  */
235 void __attribute__((noreturn)) die(const char *msg)
236 {
237   fputs(msg, stderr);
238   exit(1);
239 }
240
241 /*
242  * read/write wrapper functions
243  */
244 ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
245 {
246   char *bufp = (char *)buf;
247   ssize_t rv;
248   ssize_t done = 0;
249
250   while ( count ) {
251     rv = pread(fd, bufp, count, offset);
252     if ( rv == 0 ) {
253       die("short read");
254     } else if ( rv == -1 ) {
255       if ( errno == EINTR ) {
256         continue;
257       } else {
258         die(strerror(errno));
259       }
260     } else {
261       bufp += rv;
262       offset += rv;
263       done += rv;
264       count -= rv;
265     }
266   }
267
268   return done;
269 }
270
271 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
272 {
273   const char *bufp = (const char *)buf;
274   ssize_t rv;
275   ssize_t done = 0;
276
277   while ( count ) {
278     rv = pwrite(fd, bufp, count, offset);
279     if ( rv == 0 ) {
280       die("short write");
281     } else if ( rv == -1 ) {
282       if ( errno == EINTR ) {
283         continue;
284       } else {
285         die(strerror(errno));
286       }
287     } else {
288       bufp += rv;
289       offset += rv;
290       done += rv;
291       count -= rv;
292     }
293   }
294
295   return done;
296 }
297
298 /*
299  * Produce file map
300  */
301 int
302 sectmap(int fd, uint32_t *sectors, int nsectors)
303 {
304   unsigned int blksize, blk, nblk;
305   unsigned int i;
306
307   /* Get block size */
308   if ( ioctl(fd, FIGETBSZ, &blksize) )
309     return -1;
310
311   /* Number of sectors per block */
312   blksize >>= SECTOR_SHIFT;
313
314   nblk = 0;
315   while ( nsectors ) {
316     
317     blk = nblk++;
318     dprintf("querying block %u\n", blk);
319     if ( ioctl(fd, FIBMAP, &blk) )
320       return -1;
321
322     blk *= blksize;
323     for ( i = 0 ; i < blksize ; i++ ) {
324       if ( !nsectors )
325         return 0;
326
327       dprintf("Sector: %10u\n", blk);
328       *sectors++ = blk++;
329       nsectors--;
330     }
331   }
332
333   return 0;
334 }
335
336 /*
337  * Get the size of a block device
338  */
339 uint64_t get_size(int devfd)
340 {
341   uint64_t bytes;
342   uint32_t sects;
343   struct stat st;
344
345 #ifdef BLKGETSIZE64
346   if ( !ioctl(devfd, BLKGETSIZE64, &bytes) )
347     return bytes;
348 #endif
349   if ( !ioctl(devfd, BLKGETSIZE, &sects) )
350     return (uint64_t)sects << 9;
351   else if ( !fstat(devfd, &st) && st.st_size )
352     return st.st_size;
353   else
354     return 0;
355 }
356
357
358 /*
359  * Get device geometry and partition offset
360  */
361 struct geometry_table {
362   uint64_t bytes;
363   struct hd_geometry g;
364 };
365
366 /* Standard floppy disk geometries, plus LS-120.  Zipdisk geometry
367    (x/64/32) is the final fallback.  I don't know what LS-240 has
368    as its geometry, since I don't have one and don't know anyone that does,
369    and Google wasn't helpful... */
370 static const struct geometry_table standard_geometries[] = {
371   {    360*1024, {  2,  9,  40, 0 } },
372   {    720*1024, {  2,  9,  80, 0 } },
373   {   1200*1024, {  2, 15,  80, 0 } },
374   {   1440*1024, {  2, 18,  80, 0 } },
375   {   1680*1024, {  2, 21,  80, 0 } },
376   {   1722*1024, {  2, 21,  80, 0 } },
377   {   2880*1024, {  2, 36,  80, 0 } },
378   {   3840*1024, {  2, 48,  80, 0 } },
379   { 123264*1024, {  8, 32, 963, 0 } }, /* LS120 */
380   { 0, {0,0,0,0} }
381 };
382
383 int
384 get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
385 {
386   struct floppy_struct fd_str;
387   const struct geometry_table *gp;
388
389   memset(geo, 0, sizeof *geo);
390
391   if ( !ioctl(devfd, HDIO_GETGEO, &geo) ) {
392     return 0;
393   } else if ( !ioctl(devfd, FDGETPRM, &fd_str) ) {
394     geo->heads     = fd_str.head;
395     geo->sectors   = fd_str.sect;
396     geo->cylinders = fd_str.track;
397     geo->start     = 0;
398     return 0;
399   } 
400
401   /* Didn't work.  Let's see if this is one of the standard geometries */
402   for ( gp = standard_geometries ; gp->bytes ; gp++ ) {
403     if ( gp->bytes == totalbytes ) {
404       memcpy(geo, &gp->g, sizeof *geo);
405       return 0;
406     }
407   }
408
409   /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
410      what zipdisks use, so this would help if someone has a USB key that
411      they're booting in USB-ZIP mode. */
412
413   geo->heads     = opt.heads ?: 64;
414   geo->sectors   = opt.sectors ?: 32;
415   geo->cylinders = totalbytes/(geo->heads*geo->sectors << SECTOR_SHIFT);
416   geo->start     = 0;
417
418   if ( !opt.sectors && !opt.heads )
419     fprintf(stderr, "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
420             "         (on hard disks, this is usually harmless.)\n",
421             geo->heads, geo->sectors);
422
423   return 1;
424 }
425
426 /*
427  * Query the device geometry and put it into the boot sector.
428  * Map the file and put the map in the boot sector and file.
429  * Stick the "current directory" inode number into the file.
430  */
431 void
432 patch_file_and_bootblock(int fd, int dirfd, int devfd)
433 {
434   struct stat dirst;
435   struct hd_geometry geo;
436   uint32_t *sectp;
437   uint64_t totalbytes, totalsectors;
438   int nsect;
439   unsigned char *p, *patcharea;
440   int i, dw;
441   uint32_t csum;
442
443   if ( fstat(dirfd, &dirst) ) {
444     perror("fstat dirfd");
445     exit(255);                  /* This should never happen */
446   }
447
448   totalbytes = get_size(devfd);
449   get_geometry(devfd, totalbytes, &geo);
450
451   if ( opt.heads )
452     geo.heads = opt.heads;
453   if ( opt.sectors )
454     geo.sectors = opt.sectors;
455
456   /* Patch this into a fake FAT superblock.  This isn't because
457      FAT is a good format in any way, it's because it lets the
458      early bootstrap share code with the FAT version. */
459   dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
460
461   totalsectors = totalbytes >> SECTOR_SHIFT;
462   if ( totalsectors >= 65536 ) {
463     set_16(boot_block+bsSectors, 0);
464   } else {
465     set_16(boot_block+bsSectors, totalsectors);
466   }
467   set_32(boot_block+bsHugeSectors, totalsectors);
468
469   set_16(boot_block+bsBytesPerSec, SECTOR_SIZE);
470   set_16(boot_block+bsSecPerTrack, geo.sectors);
471   set_16(boot_block+bsHeads, geo.heads);
472   set_32(boot_block+bsHiddenSecs, geo.start);
473
474   /* Construct the boot file */
475
476   dprintf("directory inode = %lu\n", (unsigned long) dirst.st_ino);
477   nsect = (boot_image_len+SECTOR_SIZE-1) >> SECTOR_SHIFT;
478   sectp = alloca(sizeof(uint32_t)*nsect);
479   if ( sectmap(fd, sectp, nsect) ) {
480     perror("bmap");
481     exit(1);
482   }
483
484   /* First sector need pointer in boot sector */
485   set_32(boot_block+0x1F8, *sectp++);
486   nsect--;
487   
488   /* Search for LDLINUX_MAGIC to find the patch area */
489   for ( p = boot_image ; get_32(p) != LDLINUX_MAGIC ; p += 4 );
490   patcharea = p+8;
491   
492   /* Set up the totals */
493   dw = boot_image_len >> 2; /* COMPLETE dwords! */
494   set_16(patcharea, dw);
495   set_16(patcharea+2, nsect);   /* Does not include the first sector! */
496   set_32(patcharea+8, dirst.st_ino); /* "Current" directory */
497   
498   /* Set the sector pointers */
499   p = patcharea+12;
500   
501   memset(p, 0, 64*4);
502   while ( nsect-- ) {
503     set_32(p, *sectp++);
504     p += 4;
505   }
506   
507   /* Now produce a checksum */
508   set_32(patcharea+4, 0);
509
510   csum = LDLINUX_MAGIC;
511   for ( i = 0, p = boot_image ; i < dw ; i++, p += 4 )
512     csum -= get_32(p);          /* Negative checksum */
513   
514   set_32(patcharea+4, csum);
515 }
516
517 /*
518  * Install the boot block on the specified device.
519  * Must be run AFTER install_file()!
520  */
521 int
522 install_bootblock(int fd, const char *device)
523 {
524   struct ext2_super_block sb;
525
526   if ( xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET) != sizeof sb ) {
527     perror("reading superblock");
528     return 1;
529   }
530
531   if ( sb.s_magic != EXT2_SUPER_MAGIC ) {
532     fprintf(stderr, "no ext2/ext3 superblock found on %s\n", device);
533     return 1;
534   }
535   
536   if ( xpwrite(fd, boot_block, boot_block_len, 0) != boot_block_len ) {
537     perror("writing bootblock");
538     return 1;
539   }
540
541   return 0;
542 }
543
544 int
545 install_file(const char *path, int devfd, struct stat *rst)
546 {
547   char *file;
548   int fd = -1, dirfd = -1, flags;
549   struct stat st;
550
551   asprintf(&file, "%s%sextlinux.sys",
552            path,
553            path[0] && path[strlen(path)-1] == '/' ? "" : "/");
554   if ( !file ) {
555     perror(program);
556     return 1;
557   }
558
559   dirfd = open(path, O_RDONLY|O_DIRECTORY);
560   if ( dirfd < 0 ) {
561     perror(path);
562     goto bail;
563   }
564     
565   fd = open(file, O_RDONLY);
566   if ( fd < 0 ) {
567     if ( errno != ENOENT ) {
568       perror(file);
569       goto bail;
570     }
571   } else {
572     /* If file exist, remove the immutable flag and set u+w mode */
573     if ( !ioctl(fd, EXT2_IOC_GETFLAGS, &flags) ) {
574       flags &= ~EXT2_IMMUTABLE_FL;
575       ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
576     }
577     if ( !fstat(fd, &st) ) {
578       fchmod(fd, st.st_mode | S_IWUSR);
579     }
580   }
581   close(fd);
582
583   fd = open(file, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IRGRP|S_IROTH);
584   if ( fd < 0 ) {
585     perror(file);
586     goto bail;
587   }
588   
589   /* Write it the first time */
590   if ( xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ) {
591     fprintf(stderr, "%s: write failure on %s\n", program, file);
592     goto bail;
593   }
594
595   /* Map the file, and patch the initial sector accordingly */
596   patch_file_and_bootblock(fd, dirfd, devfd);
597
598   /* Write it again - this relies on the file being overwritten in place! */
599   if ( xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ) {
600     fprintf(stderr, "%s: write failure on %s\n", program, file);
601     goto bail;
602   }
603
604   /* Attempt to set immutable flag and remove all write access */
605   /* Only set immutable flag if file is owned by root */
606   if ( !fstat(fd, &st) ) {
607     fchmod(fd, st.st_mode & (S_IRUSR|S_IRGRP|S_IROTH));
608     if ( st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags) ) {
609       flags |= EXT2_IMMUTABLE_FL;
610       ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
611     }
612   }
613
614   if ( fstat(fd, rst) ) {
615     perror(file);
616     goto bail;
617   }
618
619   close(dirfd);
620   close(fd);
621   return 0;
622
623  bail:
624   if ( dirfd >= 0 )
625     close(dirfd);
626   if ( fd >= 0 )
627     close(fd);
628
629   return 1;
630 }
631
632 int
633 install_loader(const char *path)
634 {
635   struct stat st, dst, fst;
636   struct mntent *mnt = NULL;
637   int devfd, rv;
638   FILE *mtab;
639
640   if ( stat(path, &st) || !S_ISDIR(st.st_mode) ) {
641     fprintf(stderr, "%s: Not a directory: %s\n", program, path);
642     return 1;
643   }
644   
645   devfd = -1;
646
647   if ( (mtab = setmntent("/proc/mounts", "r")) ) {
648     while ( (mnt = getmntent(mtab)) ) {
649       if ( (!strcmp(mnt->mnt_type, "ext2") ||
650             !strcmp(mnt->mnt_type, "ext3")) &&
651            !stat(mnt->mnt_fsname, &dst) &&
652            dst.st_rdev == st.st_dev ) {
653         fprintf(stderr, "%s is device %s\n", path, mnt->mnt_fsname);
654         if ( (devfd = open(mnt->mnt_fsname, O_RDWR|O_SYNC)) < 0 ) {
655           fprintf(stderr, "%s: cannot open device %s\n", program, mnt->mnt_fsname);
656           return 1;
657         }
658         break;
659       }
660     }
661   }
662
663   if ( devfd < 0 ) {
664     /* Didn't find it in /proc/mounts, try /etc/mtab */
665     if ( (mtab = setmntent("/etc/mtab", "r")) ) {
666       while ( (mnt = getmntent(mtab)) ) {
667         if ( (!strcmp(mnt->mnt_type, "ext2") ||
668               !strcmp(mnt->mnt_type, "ext3")) &&
669              !stat(mnt->mnt_fsname, &dst) &&
670              dst.st_rdev == st.st_dev ) {
671           fprintf(stderr, "%s is device %s\n", path, mnt->mnt_fsname);
672           if ( (devfd = open(mnt->mnt_fsname, O_RDWR|O_SYNC)) < 0 ) {
673             fprintf(stderr, "%s: cannot open device %s\n", program, mnt->mnt_fsname);
674             return 1;
675           }
676           break;
677         }
678       }
679     }
680   }
681
682   if ( devfd < 0 ) {
683     fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
684     return 1;
685   }
686
687   install_file(path, devfd, &fst);
688
689   if ( fst.st_dev != st.st_dev ) {
690     fprintf(stderr, "%s: file system changed under us - aborting!\n",
691             program);
692     return 1;
693   }
694
695   sync();
696   rv = install_bootblock(devfd, mnt->mnt_fsname);
697   close(devfd);
698   sync();
699
700   endmntent(mtab);
701
702   if ( rv ) return rv;
703
704   return 0;
705 }
706
707 int
708 main(int argc, char *argv[])
709 {
710   int o;
711   const char *directory;
712
713   program = argv[0];
714
715   while ( (o = getopt_long(argc, argv, short_options,
716                              long_options, NULL)) != EOF ) {
717     switch ( o ) {
718     case 'z':
719       opt.heads = 64;
720       opt.sectors = 32;
721       break;
722     case 'S':
723       opt.sectors = strtoul(optarg, NULL, 0);
724       if ( opt.sectors < 1 || opt.sectors > 63 ) {
725         fprintf(stderr, "%s: invalid number of sectors: %u (must be 1-63)\n",
726                 program, opt.sectors);
727         exit(EX_USAGE);
728       }
729       break;
730     case 'H':
731       opt.heads = strtoul(optarg, NULL, 0);
732       if ( opt.heads < 1 || opt.heads > 256 ) {
733         fprintf(stderr, "%s: invalid number of heads: %u (must be 1-256)\n",
734                 program, opt.heads);
735         exit(EX_USAGE);
736       }
737       break;
738     case 'h':
739       usage(0);
740       break;
741     case 'v':
742       fputs("extlinux " VERSION "\n", stderr);
743       exit(0);
744     default:
745       fprintf(stderr, "%s: Unknown option: %c\n", program, optopt);
746       exit(EX_USAGE);
747     }
748   }
749
750   directory = argv[optind];
751
752   if ( !directory )
753     usage(EX_USAGE);
754
755   return install_loader(directory);
756 }