Ejemplo n.º 1
0
int main(int argc, char *argv[])
{
  static unsigned char sectbuf[512];
  int dev_fd;
  struct stat st;
  int status;
  char **argp, *opt;
  char mtools_conf[] = "/tmp/syslinux-mtools-XXXXXX";
  const char *subdir = NULL;
  int mtc_fd;
  FILE *mtc, *mtp;
  struct libfat_filesystem *fs;
  libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */
  int32_t ldlinux_cluster;
  int nsectors;
  const char *errmsg;

  int force = 0;              /* -f (force) option */
  int stupid = 0;             /* -s (stupid) option */
  int raid_mode = 0;          /* -r (RAID) option */

  (void)argc;			/* Unused */

  mypid = getpid();
  program = argv[0];

  device = NULL;

  for ( argp = argv+1 ; *argp ; argp++ ) {
    if ( **argp == '-' ) {
      opt = *argp + 1;
      if ( !*opt )
	usage();

      while ( *opt ) {
	if ( *opt == 's' ) {
	  stupid = 1;
	} else if ( *opt == 'r' ) {
	  raid_mode = 1;
	} else if ( *opt == 'f' ) {
	  force = 1;		/* Force install */
	} else if ( *opt == 'd' && argp[1] ) {
	  subdir = *++argp;
	} else if ( *opt == 'o' && argp[1] ) {
	  filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); /* Byte offset */
	} else {
	  usage();
	}
	opt++;
      }
    } else {
      if ( device )
	usage();
      device = *argp;
    }
  }

  if ( !device )
    usage();

  /*
   * First make sure we can open the device at all, and that we have
   * read/write permission.
   */
  dev_fd = open(device, O_RDWR);
  if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) {
    perror(device);
    exit(1);
  }

  if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) {
    fprintf(stderr, "%s: not a block device or regular file (use -f to override)\n", device);
    exit(1);
  }

  xpread(dev_fd, sectbuf, 512, filesystem_offset);

  /*
   * Check to see that what we got was indeed an MS-DOS boot sector/superblock
   */
  if( (errmsg = syslinux_check_bootsect(sectbuf)) ) {
    die(errmsg);
  }

  /*
   * Create an mtools configuration file
   */
  mtc_fd = mkstemp(mtools_conf);
  if ( mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")) ) {
    perror(program);
    exit(1);
  }
  fprintf(mtc,
	  /* "MTOOLS_NO_VFAT=1\n" */
	  "MTOOLS_SKIP_CHECK=1\n" /* Needed for some flash memories */
	  "drive s:\n"
	  "  file=\"/proc/%lu/fd/%d\"\n"
	  "  offset=%llu\n",
	  (unsigned long)mypid,
	  dev_fd,
	  (unsigned long long)filesystem_offset);
  fclose(mtc);

  /*
   * Run mtools to create the LDLINUX.SYS file
   */
  if ( setenv("MTOOLSRC", mtools_conf, 1) ) {
    perror(program);
    exit(1);
  }

  /* This command may fail legitimately */
  system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");

  mtp = popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
  if ( !mtp ||
       (fwrite(syslinux_ldlinux, 1, syslinux_ldlinux_len, mtp)
	!= syslinux_ldlinux_len) ||
       (status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status)) ) {
    die("failed to create ldlinux.sys");
  }

  /*
   * Now, use libfat to create a block map
   */
  fs = libfat_open(libfat_xpread, dev_fd);
  ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
  secp = sectors;
  nsectors = 0;
  s = libfat_clustertosector(fs, ldlinux_cluster);
  while ( s && nsectors < 65 ) {
    *secp++ = s;
    nsectors++;
    s = libfat_nextsector(fs, s);
  }
  libfat_close(fs);

  /* Patch ldlinux.sys and the boot sector */
  syslinux_patch(sectors, nsectors, stupid, raid_mode);

  /* Write the now-patched first sector of ldlinux.sys */
  xpwrite(dev_fd, syslinux_ldlinux, 512,
	  filesystem_offset + ((off_t)sectors[0] << 9));

  /* Move ldlinux.sys to the desired location */
  if (subdir) {
    char target_file[4096], command[5120];
    char *cp = target_file, *ep = target_file+sizeof target_file-16;
    const char *sd;
    int slash = 1;

    cp += sprintf(cp, "'s:/");
    for (sd = subdir; *sd; sd++) {
      if (*sd == '/' || *sd == '\\') {
	if (slash)
	  continue;		/* Remove duplicated slashes */
	slash = 1;
      } else if (*sd == '\'' || *sd == '!') {
	slash = 0;
	if (cp < ep) *cp++ = '\'';
	if (cp < ep) *cp++ = '\\';
	if (cp < ep) *cp++ = *sd;
	if (cp < ep) *cp++ = '\'';
	continue;
      } else {
	slash = 0;
      }

      if (cp < ep)
	*cp++ = *sd;
    }
    if (!slash)
      *cp++ = '/';
    strcpy(cp, "ldlinux.sys'");

    /* This command may fail legitimately */
    sprintf(command, "mattrib -h -r -s %s 2>/dev/null", target_file);
    system(command);

    sprintf(command, "mmove -D o -D O s:/ldlinux.sys %s", target_file);
    status = system(command);

    if ( !WIFEXITED(status) || WEXITSTATUS(status) ) {
      fprintf(stderr,
	      "%s: warning: unable to move ldlinux.sys\n",
	    program);

      status = system("mattrib +r +h +s s:/ldlinux.sys");
    } else {
      sprintf(command, "mattrib +r +h +s %s", target_file);
      status = system(command);
    }
  } else {
    status = system("mattrib +r +h +s s:/ldlinux.sys");
  }

  if ( !WIFEXITED(status) || WEXITSTATUS(status) ) {
    fprintf(stderr,
	    "%s: warning: failed to set system bit on ldlinux.sys\n",
	    program);
  }


  /*
   * Cleanup
   */
  unlink(mtools_conf);

  /*
   * To finish up, write the boot sector
   */

  /* Read the superblock again since it might have changed while mounted */
  xpread(dev_fd, sectbuf, 512, filesystem_offset);

  /* Copy the syslinux code into the boot sector */
  syslinux_make_bootsect(sectbuf);

  /* Write new boot sector */
  xpwrite(dev_fd, sectbuf, 512, filesystem_offset);

  close(dev_fd);
  sync();

  /* Done! */

  return 0;
}
Ejemplo n.º 2
0
int main(int argc, char *argv[])
{
    static unsigned char sectbuf[SECTOR_SIZE];
    int dev_fd, fd;
    struct stat st;
    int err = 0;
    char mntname[128];
    char *ldlinux_name;
    char *ldlinux_path;
    char *subdir;
    //sector_t *sectors = NULL;
    libfat_sector_t *sectors = NULL;
    int ldlinux_sectors = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    const char *errmsg;
    int mnt_cookie;
    int patch_sectors;
    int i;
    
    printf("syslinux for Mac OS X; created by Geza Kovacs for UNetbootin unetbootin.sf.net\n");

    mypid = getpid();
    umask(077);
    parse_options(argc, argv, MODE_SYSLINUX);

    /* Note: subdir is guaranteed to start and end in / */
    if (opt.directory && opt.directory[0]) {
	int len = strlen(opt.directory);
	int rv = asprintf(&subdir, "%s%s%s",
			  opt.directory[0] == '/' ? "" : "/",
			  opt.directory,
			  opt.directory[len-1] == '/' ? "" : "/");
	if (rv < 0 || !subdir) {
	    perror(program);
	    exit(1);
	}
    } else {
	subdir = "/";
    }

    if (!opt.device || opt.install_mbr || opt.activate_partition)
	usage(EX_USAGE, MODE_SYSLINUX);

    /*
     * First make sure we can open the device at all, and that we have
     * read/write permission.
     */

    if (geteuid()) {
	die("This program needs root privilege");
    }
    char umountCommand[4096];
    memset(umountCommand, 0, 4096);
    strcat(umountCommand, "hdiutil unmount ");
    strcat(umountCommand, opt.device);
    system(umountCommand);
    
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	perror("couldn't open device");
	exit(1);
    }

    if (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
	die("not a device or regular file");
    }

    if (opt.offset && S_ISBLK(st.st_mode)) {
	die("can't combine an offset with a block device");
    }

    fs_type = VFAT;
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
    fsync(dev_fd);
    close(dev_fd);

    /*
     * Check to see that what we got was indeed an MS-DOS boot sector/superblock
     */
    if ((errmsg = syslinux_check_bootsect(sectbuf))) {
	fprintf(stderr, "%s: %s\n", opt.device, errmsg);
	exit(1);
    }

    /*
     * Now mount the device.
     */
    if (geteuid()) {
	die("This program needs root privilege");
    }
#if 0
    else {
	int i = 0;
	struct stat dst;
	int rv;

	/* We're root or at least setuid.
	   Make a temp dir and pass all the gunky options to mount. */

	if (chdir(_PATH_TMP)) {
	    fprintf(stderr, "%s: Cannot access the %s directory.\n",
		    program, _PATH_TMP);
	    exit(1);
	}
#define TMP_MODE (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH|S_ISVTX)

	if (stat(".", &dst) || !S_ISDIR(dst.st_mode) ||
	    (dst.st_mode & TMP_MODE) != TMP_MODE) {
	    die("possibly unsafe " _PATH_TMP " permissions");
	}

	for (i = 0;; i++) {
	    snprintf(mntname, sizeof mntname, "syslinux.mnt.%lu.%d",
		     (unsigned long)mypid, i);

	    if (lstat(mntname, &dst) != -1 || errno != ENOENT)
		continue;

	    rv = mkdir(mntname, 0000);

	    if (rv == -1) {
		if (errno == EEXIST || errno == EINTR)
		    continue;
		perror(program);
		exit(1);
	    }

	    if (lstat(mntname, &dst) || dst.st_mode != (S_IFDIR | 0000) ||
		dst.st_uid != 0) {
		die("someone is trying to symlink race us!");
	    }
	    break;		/* OK, got something... */
	}

	mntpath = mntname;
    }

    if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") &&
	do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) {
	rmdir(mntpath);
	die("mount failed");
    }

#endif

    char mountCmd[4096];
    memset(mountCmd, 0, 4096);
    strcat(mountCmd, "hdiutil mount ");
    strcat(mountCmd, opt.device);
    system(mountCmd);
    
    char mountGrepCmd[4096];
    memset(mountGrepCmd, 0, 4096);
    strcat(mountGrepCmd, "echo `mount | grep ");
    strcat(mountGrepCmd, opt.device);
    strcat(mountGrepCmd, " | sed 's/ on /$/' | tr '$' '\n' | head -n 2 | tail -n 1 | tr '(' '\n' | head -n 1`");
    char mountPoint[4096];
    memset(mountPoint, 0, 4096);
    FILE *mountCmdOutput = popen(mountGrepCmd, "r");
    fgets(mountPoint, 4096, mountCmdOutput);
    mountPoint[strlen(mountPoint)-1] = 0; // removes trailing newline
    printf("mountpoint is %s\n", mountPoint);
    
    mntpath = mountPoint;
    ldlinux_path = alloca(strlen(mntpath) + strlen(subdir) + 1);
    sprintf(ldlinux_path, "%s%s", mntpath, subdir);

    ldlinux_name = alloca(strlen(ldlinux_path) + 14);
    if (!ldlinux_name) {
	perror(program);
	err = 1;
	goto umount;
    }
    sprintf(ldlinux_name, "%sldlinux.sys", ldlinux_path);

    /* update ADV only ? */
    if (opt.update_only == -1) {
	if (opt.reset_adv || opt.set_once) {
	    modify_existing_adv(ldlinux_path);
	    //do_umount(mntpath, mnt_cookie);
	    sync();
	    //rmdir(mntpath);
	    exit(0);
	} else {
	    fprintf(stderr, "%s: please specify --install or --update for the future\n", argv[0]);
	    opt.update_only = 0;
	}
    }

    printf("checkpoint1\n");

    /* Read a pre-existing ADV, if already installed */
    if (opt.reset_adv)
	syslinux_reset_adv(syslinux_adv);
    else if (read_adv(ldlinux_path, "ldlinux.sys") < 0)
	syslinux_reset_adv(syslinux_adv);
    if (modify_adv() < 0)
	exit(1);
	
	printf("checkpoint1.5\n");

    if ((fd = open(ldlinux_name, O_RDONLY)) >= 0) {
	uint32_t zero_attr = 0;
	//ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &zero_attr);
	printf("checkpoint1.55bad\n");
	close(fd);
    }
    
    printf("checkpoint1.6\n");

    unlink(ldlinux_name);
    printf(ldlinux_name);
    printf(" ldlinuxname\n");
    fd = open(ldlinux_name, O_WRONLY | O_CREAT | O_TRUNC, 0444);
    if (fd < 0) {
	perror(opt.device);
	err = 1;
	goto umount;
    }
    
    printf("checkpoint2\n");

    /* Write it the first time */
    if (xpwrite(fd, boot_image, boot_image_len, 0) != (int)boot_image_len ||
	xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
		boot_image_len) != 2 * ADV_SIZE) {
	fprintf(stderr, "%s: write failure on %s\n", program, ldlinux_name);
	exit(1);
    }

    fsync(fd);
    /*
     * Set the attributes
     */
    {
	uint32_t attr = 0x07;	/* Hidden+System+Readonly */
	//ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
    }
    
    printf("checkpoint3\n");

    /*
     * Create a block map.
     */
    
    ldlinux_sectors += 2; /* 2 ADV sectors */
    
    close(fd);
    sync();
    /*
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    if (sectmap(fd, sectors, ldlinux_sectors)) {
	perror("bmap");
	exit(1);
    }
    close(fd);
    sync();
    printf("checkpoint4\n");
    */
    
    /* Map the file (is there a better way to do this?) */
    //ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    struct libfat_filesystem *fs;
    libfat_sector_t s;
    libfat_sector_t *secp;
    //libfat_sector_t *sectors;
    uint32_t ldlinux_cluster;
    
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    //fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
    system(umountCommand);
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	perror("couldn't open device");
	exit(1);
    }
    fs = libfat_open(libfat_readfile, dev_fd);
    if (fs == NULL) printf("null fs struct\n");
    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
    
    printf("checkpoint4\n");
    
    secp = sectors;
    int nsectors;
    nsectors  = 0;
    s = libfat_clustertosector(fs, ldlinux_cluster);
    while (s && nsectors < ldlinux_sectors) {
	*secp++ = s;
	nsectors++;
	s = libfat_nextsector(fs, s);
    }
    libfat_close(fs);
    printf("checkpoint5\n");

umount:
    //do_umount(mntpath, mnt_cookie);
    sync();
    //rmdir(mntpath);

    if (err)
	exit(err);
	
	printf("checkpoint6\n");

    /*
     * Patch ldlinux.sys and the boot sector
     */
    i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode,
		       opt.raid_mode, subdir, NULL);
    patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT;

    /*
     * Write the now-patched first sectors of ldlinux.sys
     */
    for (i = 0; i < patch_sectors; i++) {
	xpwrite(dev_fd, boot_image + i * SECTOR_SIZE, SECTOR_SIZE,
		opt.offset + ((off_t) sectors[i] << SECTOR_SHIFT));
    }
    
    printf("checkpoint7\n");

    /*
     * To finish up, write the boot sector
     */

    /* Read the superblock again since it might have changed while mounted */
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /* Copy the syslinux code into the boot sector */
    syslinux_make_bootsect(sectbuf);

    /* Write new boot sector */
    xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
    
    printf("checkpoint8\n");

    close(dev_fd);
    sync();
    system(mountCmd);

    /* Done! */

    return 0;
}
Ejemplo n.º 3
0
int main(int argc, char *argv[])
{
  static unsigned char sectbuf[512];
  unsigned char *dp;
  const unsigned char *cdp;
  int dev_fd, fd;
  struct stat st;
  int nb, left;
  int err = 0;
  pid_t f, w;
  int status;
  char mntname[64], devfdname[64];
  char *ldlinux_name, **argp, *opt;
  int my_umask;
  int force = 0;		/* -f (force) option */
  int offset = 0;		/* -o (offset) option */

  program = argv[0];
  mypid = getpid();
  
  device = NULL;

  umask(077);

  for ( argp = argv+1 ; *argp ; argp++ ) {
    if ( **argp == '-' ) {
      opt = *argp + 1;
      if ( !*opt )
	usage();

      while ( *opt ) {
	if ( *opt == 's' ) {
	  syslinux_make_stupid();	/* Use "safe, slow and stupid" code */
	} else if ( *opt == 'f' ) {
	  force = 1;		/* Force install */
	} else if ( *opt == 'o' && argp[1] ) {
	  offset = strtoul(*++argp, NULL, 0); /* Byte offset */
	} else {
	  usage();
	}
	opt++;
      }
    } else {
      if ( device )
	usage();
      device = *argp;
    }
  }

  if ( !device )
    usage();

  /*
   * First make sure we can open the device at all, and that we have
   * read/write permission.
   */
  dev_fd = open(device, O_RDWR|O_LARGEFILE);
  if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) {
    perror(device);
    exit(1);
  }

  if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) {
    die("not a block device or regular file (use -f to override)");
  }

  if ( !force && offset != 0 && !S_ISREG(st.st_mode) ) {
    die("not a regular file and an offset specified (use -f to override)");
  }

  xpread(dev_fd, sectbuf, 512, offset);
  fsync(dev_fd);

  /*
   * Check to see that what we got was indeed an MS-DOS boot sector/superblock
   */
  if(!syslinux_check_bootsect(sectbuf,device)) {
    exit(1);
  }

  /*
   * Now mount the device.
   */
  if ( geteuid() ) {
    die("This program needs root privilege");
  } else {
    int i = 0;
    struct stat dst;
    int rv;

    /* We're root or at least setuid.
       Make a temp dir and pass all the gunky options to mount. */

    if ( chdir("/tmp") ) {
      perror(program);
      exit(1);
    }

#define TMP_MODE (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH|S_ISVTX)

    if ( stat(".", &dst) || !S_ISDIR(dst.st_mode) ||
	 (dst.st_mode & TMP_MODE) != TMP_MODE ) {
      die("possibly unsafe /tmp permissions");
    }

    for ( i = 0 ; ; i++ ) {
      snprintf(mntname, sizeof mntname, "syslinux.mnt.%lu.%d",
	       (unsigned long)mypid, i);

      if ( lstat(mntname, &dst) != -1 || errno != ENOENT )
	continue;

      rv = mkdir(mntname, 0000);

      if ( rv == -1 ) {
	if ( errno == EEXIST || errno == EINTR )
	  continue;
	perror(program);
	exit(1);
      }

      if ( lstat(mntname, &dst) || dst.st_mode != (S_IFDIR|0000) ||
	   dst.st_uid != 0 ) {
	die("someone is trying to symlink race us!");
      }
      break;			/* OK, got something... */
    }

    mntpath = mntname;

#if DO_DIRECT_MOUNT
    if ( S_ISREG(st.st_mode) ) {
      /* It's file, need to mount it loopback */
      unsigned int n = 0;
      struct loop_info64 loopinfo;

      for ( n = 0 ; loop_fd < 0 ; n++ ) {
	snprintf(devfdname, sizeof devfdname, "/dev/loop%u", n);
	loop_fd = open(devfdname, O_RDWR);
	if ( loop_fd < 0 && errno == ENOENT ) {
	  die("no available loopback device!");
	}
	if ( ioctl(loop_fd, LOOP_SET_FD, (void *)dev_fd) ) {
	  close(loop_fd); loop_fd = -1;
	  if ( errno != EBUSY )
	    die("cannot set up loopback device");
	  else
	    continue;
	}
	
	if ( ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo) ||
	     (loopinfo.lo_offset = offset,
	      ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo)) )
	  die("cannot set up loopback device");
      }
    } else {
      snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d",
	       (unsigned long)mypid, dev_fd);
    }

    if ( mount(devfdname, mntpath, "msdos",
	       MS_NOEXEC|MS_NOSUID, "umask=077,quiet") )
      die("could not mount filesystem");

#else

    snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d",
	     (unsigned long)mypid, dev_fd);

    f = fork();
    if ( f < 0 ) {
      perror(program);
      rmdir(mntpath);
      exit(1);
    } else if ( f == 0 ) {
      char mnt_opts[128];
      if ( S_ISREG(st.st_mode) ) {
	snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,loop,offset=%llu,umask=077,quiet",
		 (unsigned long long)offset);
      } else {
	snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,umask=077,quiet");
      }
      execl(_PATH_MOUNT, _PATH_MOUNT, "-t", "msdos", "-o", mnt_opts,\
	    devfdname, mntpath, NULL);
      _exit(255);		/* execl failed */
    }

    w = waitpid(f, &status, 0);
    if ( w != f || status ) {
      rmdir(mntpath);
      exit(1);			/* Mount failed */
    }
    
#endif
  }
  
  ldlinux_name = alloca(strlen(mntpath)+13);
  if ( !ldlinux_name ) {
    perror(program);
    err = 1;
    goto umount;
  }
  sprintf(ldlinux_name, "%s/ldlinux.sys", mntpath);

  unlink(ldlinux_name);
  fd = open(ldlinux_name, O_WRONLY|O_CREAT|O_TRUNC, 0444);
  if ( fd < 0 ) {
    perror(device);
    err = 1;
    goto umount;
  }

  cdp = syslinux_ldlinux;
  left = syslinux_ldlinux_len;
  while ( left ) {
    nb = write(fd, cdp, left);
    if ( nb == -1 && errno == EINTR )
      continue;
    else if ( nb <= 0 ) {
      perror(device);
      err = 1;
      goto umount;
    }

    dp += nb;
    left -= nb;
  }

  /*
   * I don't understand why I need this.  Does the DOS filesystems
   * not honour the mode passed to open()?
   */
  fchmod(fd, 0400);

  close(fd);

umount:
#if DO_DIRECT_MOUNT

  if ( umount2(mntpath, 0) )
    die("could not umount path");

  if ( loop_fd != -1 ) {
    ioctl(loop_fd, LOOP_CLR_FD, 0); /* Free loop device */
    close(loop_fd);
    loop_fd = -1;
  }

#else

  f = fork();
  if ( f < 0 ) {
    perror("fork");
    exit(1);
  } else if ( f == 0 ) {
    execl(_PATH_UMOUNT, _PATH_UMOUNT, mntpath, NULL);
  }

  w = waitpid(f, &status, 0);
  if ( w != f || status ) {
    exit(1);
  }

#endif

  sync();
  rmdir(mntpath);

  if ( err )
    exit(err);

  /*
   * To finish up, write the boot sector
   */

  /* Read the superblock again since it might have changed while mounted */
  xpread(dev_fd, sectbuf, 512, offset);

  /* Copy the syslinux code into the boot sector */
  syslinux_make_bootsect(sectbuf);

  /* Write new boot sector */
  xpwrite(dev_fd, sectbuf, 512, offset);

  close(dev_fd);
  sync();

  /* Done! */

  return 0;
}
Ejemplo n.º 4
0
int main(int argc, char *argv[])
{
    static unsigned char sectbuf[SECTOR_SIZE];
    int dev_fd;
    struct stat st;
    int status;
    const char *tmpdir;
    char *mtools_conf;
    int mtc_fd;
    FILE *mtc, *mtp;
    struct libfat_filesystem *fs;
    libfat_sector_t s, *secp;
    libfat_sector_t *sectors;
    int32_t ldlinux_cluster;
    int nsectors;
    const char *errmsg;
    int ldlinux_sectors, patch_sectors;
    int i;

    (void)argc;			/* Unused */

    mypid = getpid();
    program = argv[0];

    parse_options(argc, argv, MODE_SYSLINUX);

    if (!opt.device)
	usage(EX_USAGE, MODE_SYSLINUX);

    if (opt.sectors || opt.heads || opt.reset_adv || opt.set_once
	|| (opt.update_only > 0) || opt.menu_save) {
	fprintf(stderr,
		"At least one specified option not yet implemented"
		" for this installer.\n");
	exit(1);
    }

    /*
     * Temp directory of choice...
     */
    tmpdir = getenv("TMPDIR");
    if (!tmpdir) {
#ifdef P_tmpdir
	tmpdir = P_tmpdir;
#elif defined(_PATH_TMP)
	tmpdir = _PATH_TMP;
#else
	tmpdir = "/tmp";
#endif
    }

    /*
     * First make sure we can open the device at all, and that we have
     * read/write permission.
     */
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	die_err(opt.device);
	exit(1);
    }

    if (!opt.force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode)) {
	fprintf(stderr,
		"%s: not a block device or regular file (use -f to override)\n",
		opt.device);
	exit(1);
    }

    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /*
     * Check to see that what we got was indeed an MS-DOS boot sector/superblock
     */
    if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
	die(errmsg);
    }

    /*
     * Create an mtools configuration file
     */
    if (asprintf(&mtools_conf, "%s//syslinux-mtools-XXXXXX", tmpdir) < 0 ||
	!mtools_conf)
	die_err(tmpdir);

    mtc_fd = mkstemp(mtools_conf);
    if (mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")))
	die_err(mtools_conf);

    fprintf(mtc,
	    /* These are needed for some flash memories */
	    "MTOOLS_SKIP_CHECK=1\n"
	    "MTOOLS_FAT_COMPATIBILITY=1\n"
	    "drive s:\n"
	    "  file=\"/proc/%lu/fd/%d\"\n"
	    "  offset=%llu\n",
	    (unsigned long)mypid,
	    dev_fd, (unsigned long long)opt.offset);

    if (ferror(mtc) || fclose(mtc))
	die_err(mtools_conf);

    /*
     * Run mtools to create the LDLINUX.SYS file
     */
    if (setenv("MTOOLSRC", mtools_conf, 1)) {
	perror(program);
	exit(1);
    }

    /*
     * Create a vacuous ADV in memory.  This should be smarter.
     */
    syslinux_reset_adv(syslinux_adv);

    /* This command may fail legitimately */
    status = system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
    (void)status;		/* Keep _FORTIFY_SOURCE happy */

    mtp = popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
    if (!mtp ||
	fwrite((const void _force *)syslinux_ldlinux,
	       1, syslinux_ldlinux_len, mtp)
		!= syslinux_ldlinux_len ||
	fwrite((const void _force *)syslinux_adv,
	       1, 2 * ADV_SIZE, mtp)
		!= 2 * ADV_SIZE ||
	(status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status))) {
	die("failed to create ldlinux.sys");
    }

    /*
     * Now, use libfat to create a block map
     */
    ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE
		       + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    fs = libfat_open(libfat_xpread, dev_fd);
    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
    secp = sectors;
    nsectors = 0;
    s = libfat_clustertosector(fs, ldlinux_cluster);
    while (s && nsectors < ldlinux_sectors) {
	*secp++ = s;
	nsectors++;
	s = libfat_nextsector(fs, s);
    }
    libfat_close(fs);

    /* Patch ldlinux.sys and the boot sector */
    i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode,
		       opt.directory, NULL);
    patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT;

    /* Write the now-patched first sectors of ldlinux.sys */
    for (i = 0; i < patch_sectors; i++) {
	xpwrite(dev_fd, (const char _force *)syslinux_ldlinux
		+ i * SECTOR_SIZE, SECTOR_SIZE,
		opt.offset + ((off_t) sectors[i] << SECTOR_SHIFT));
    }

    /* Move ldlinux.sys to the desired location */
    if (opt.directory) {
	status = move_file("ldlinux.sys");
    } else {
	status = system("mattrib +r +h +s s:/ldlinux.sys");
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
	fprintf(stderr,
		"%s: warning: failed to set system bit on ldlinux.sys\n",
		program);
    }

    /* This command may fail legitimately */
    status = system("mattrib -h -r -s s:/ldlinux.c32 2>/dev/null");
    (void)status;		/* Keep _FORTIFY_SOURCE happy */

    mtp = popen("mcopy -D o -D O -o - s:/ldlinux.c32", "w");
    if (!mtp ||	fwrite((const char _force *)syslinux_ldlinuxc32,
		       1, syslinux_ldlinuxc32_len, mtp)
	!= syslinux_ldlinuxc32_len ||
	(status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status))) {
	die("failed to create ldlinux.c32");
    }

    /* Move ldlinux.c32 to the desired location */
    if (opt.directory) {
	status = move_file("ldlinux.c32");
    } else {
	status = system("mattrib +r +h +s s:/ldlinux.c32");
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
	fprintf(stderr,
		"%s: warning: failed to set system bit on ldlinux.c32\n",
		program);
    }

    /*
     * Cleanup
     */
    unlink(mtools_conf);

    /*
     * To finish up, write the boot sector
     */

    /* Read the superblock again since it might have changed while mounted */
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /* Copy the syslinux code into the boot sector */
    syslinux_make_bootsect(sectbuf, VFAT);

    /* Write new boot sector */
    xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    close(dev_fd);
    sync();

    /* Done! */

    return 0;
}