loop_check(const char **spec, const char **type, int *flags,
	   int *loop, const char **loopdev, const char **loopfile,
	   const char *node) {
  int looptype;
  uintmax_t offset = 0, sizelimit = 0;

  /*
   * In the case of a loop mount, either type is of the form lo@/dev/loop5
   * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
   * mount just has to figure things out for itself from the fact that
   * spec is not a block device. We do not test for a block device
   * immediately: maybe later other types of mountable objects will occur.
   */

  *loopdev = opt_loopdev;

  looptype = (*type && strncmp("lo@", *type, 3) == 0);
  if (looptype) {
    if (*loopdev)
      error(_("mount: loop device specified twice"));
    *loopdev = *type + 3;
    *type = opt_vfstype;
  } else if (opt_vfstype) {
    if (*type)
      error(_("mount: type specified twice"));
    else
      *type = opt_vfstype;
  }

  *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_sizelimit || opt_encryption);
  *loopfile = *spec;

  /* Automatically create a loop device from a regular file if a filesystem
   * is not specified or the filesystem is known for libblkid (these
   * filesystems work with block devices only).
   *
   * Note that there is not a restriction (on kernel side) that prevents regular
   * file as a mount(2) source argument. A filesystem that is able to mount
   * regular files could be implemented.
   */
  if (!*loop && !(*flags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) &&
      (!*type || strcmp(*type, "auto") == 0 || fsprobe_known_fstype(*type))) {

    struct stat st;
    if (stat(*loopfile, &st) == 0)
      *loop = S_ISREG(st.st_mode);
  }

  if (*loop) {
    *flags |= MS_LOOP;
    if (fake) {
      if (verbose)
	printf(_("mount: skipping the setup of a loop device\n"));
    } else {
      int loop_opts = 0;
      int res;

      /* since 2.6.37 we don't have to store backing filename to mtab
       * because kernel provides the name in /sys
       */
      if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
	  mtab_is_writable() == 0) {

	if (verbose)
	  printf(_("mount: enabling autoclear loopdev flag\n"));
	loop_opts = SETLOOP_AUTOCLEAR;
      }

      if (*flags & MS_RDONLY)
        loop_opts |= SETLOOP_RDONLY;

      if (opt_offset && parse_offset(&opt_offset, &offset)) {
        error(_("mount: invalid offset '%s' specified"), opt_offset);
        return EX_FAIL;
      }
      if (opt_sizelimit && parse_offset(&opt_sizelimit, &sizelimit)) {
        error(_("mount: invalid sizelimit '%s' specified"), opt_sizelimit);
        return EX_FAIL;
      }

      if (is_mounted_same_loopfile(node, *loopfile, offset)) {
        error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile, node);
        return EX_FAIL;
      }

      do {
        if (!*loopdev || !**loopdev)
	  *loopdev = find_unused_loop_device();
	if (!*loopdev)
	  return EX_SYSERR;	/* no more loop devices */
	if (verbose)
	  printf(_("mount: going to use the loop device %s\n"), *loopdev);

	if ((res = set_loop(*loopdev, *loopfile, offset, sizelimit,
			    opt_encryption, pfd, &loop_opts))) {
	  if (res == 2) {
	     /* loop dev has been grabbed by some other process,
	        try again, if not given explicitly */
	     if (!opt_loopdev) {
	       if (verbose)
	         printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev);
	       my_free(*loopdev);
	       *loopdev = NULL;
	       continue;
	     }
	     error(_("mount: stolen loop=%s"), *loopdev);
	     return EX_FAIL;

	  } else {
	     if (verbose)
	       printf(_("mount: failed setting up loop device\n"));
	     if (!opt_loopdev) {
	       my_free(*loopdev);
	       *loopdev = NULL;
	     }
	     return EX_FAIL;
	  }
	}
      } while (!*loopdev);

      if (verbose > 1)
	printf(_("mount: setup loop device successfully\n"));
      *spec = *loopdev;

      if (loop_opts & SETLOOP_RDONLY)
        *flags |= MS_RDONLY;

      if (loop_opts & SETLOOP_AUTOCLEAR)
        /* Prevent recording loop dev in mtab for cleanup on umount */
        *loop = 0;
    }
  }

  return 0;
}
loop_check(const char **spec, const char **type, int *flags,
	   int *loop, const char **loopdev, const char **loopfile,
	   const char *node) {
  int looptype;
  uintmax_t offset = 0, sizelimit = 0;

   

  *loopdev = opt_loopdev;

  looptype = (*type && strncmp("lo@", *type, 3) == 0);
  if (looptype) {
    if (*loopdev)
      error(_("mount: loop device specified twice"));
    *loopdev = *type + 3;
    *type = opt_vfstype;
  } else if (opt_vfstype) {
    if (*type)
      error(_("mount: type specified twice"));
    else
      *type = opt_vfstype;
  }

  *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_sizelimit || opt_encryption);
  *loopfile = *spec;

   
  if (!*loop && !(*flags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) &&
      (!*type || strcmp(*type, "auto") == 0 || fsprobe_known_fstype(*type))) {

    struct stat st;
    if (stat(*loopfile, &st) == 0)
      *loop = S_ISREG(st.st_mode);
  }

  if (*loop) {
    *flags |= MS_LOOP;
    if (fake) {
      if (verbose)
	printf(_("mount: skipping the setup of a loop device\n"));
    } else {
      int loop_opts = 0;
      int res;

       
      if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
	  mtab_is_writable() == 0) {

	if (verbose)
	  printf(_("mount: enabling autoclear loopdev flag\n"));
	loop_opts = SETLOOP_AUTOCLEAR;
      }

      if (*flags & MS_RDONLY)
        loop_opts |= SETLOOP_RDONLY;

      if (opt_offset && parse_offset(&opt_offset, &offset)) {
        error(_("mount: invalid offset '%s' specified"), opt_offset);
        return EX_FAIL;
      }
      if (opt_sizelimit && parse_offset(&opt_sizelimit, &sizelimit)) {
        error(_("mount: invalid sizelimit '%s' specified"), opt_sizelimit);
        return EX_FAIL;
      }

      if (is_mounted_same_loopfile(node, *loopfile, offset)) {
        error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile, node);
        return EX_FAIL;
      }

      do {
        if (!*loopdev || !**loopdev)
	  *loopdev = find_unused_loop_device();
	if (!*loopdev)
	  return EX_SYSERR;	 
	if (verbose)
	  printf(_("mount: going to use the loop device %s\n"), *loopdev);

	if ((res = set_loop(*loopdev, *loopfile, offset, sizelimit,
			    opt_encryption, pfd, &loop_opts))) {
	  if (res == 2) {
	      
	     if (!opt_loopdev) {
	       if (verbose)
	         printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev);
	       my_free(*loopdev);
	       *loopdev = NULL;
	       continue;
	     }
	     error(_("mount: stolen loop=%s"), *loopdev);
	     return EX_FAIL;

	  } else {
	     if (verbose)
	       printf(_("mount: failed setting up loop device\n"));
	     if (!opt_loopdev) {
	       my_free(*loopdev);
	       *loopdev = NULL;
	     }
	     return EX_FAIL;
	  }
	}
      } while (!*loopdev);

      if (verbose > 1)
	printf(_("mount: setup loop device successfully\n"));
      *spec = *loopdev;

      if (loop_opts & SETLOOP_RDONLY)
        *flags |= MS_RDONLY;

      if (loop_opts & SETLOOP_AUTOCLEAR)
         
        *loop = 0;
    }
  }

  return 0;
}