return rc;
}
+/* attach a regular file to virtual block device.
+ * return vaule:
+ * -1: fatal error
+ * 1: error, it always means the command run failed
+ * 0: success
+ */
+static int jt_blockdev_run_process(const char *file, char *argv[])
+{
+ pid_t pid;
+ int rc;
+
+ pid = vfork();
+ if (pid == 0) { /* child process */
+ /* don't print error messages */
+ close(1), close(2);
+ (void)execvp(file, argv);
+ exit(-1);
+ } else if (pid > 0) {
+ int status;
+
+ rc = waitpid(pid, &status, 0);
+ if (rc < 0 || !WIFEXITED(status))
+ return -1;
+
+ return WEXITSTATUS(status);
+ }
+
+ return -1;
+}
+
+static int jt_blockdev_find_module(const char *module)
+{
+ FILE *fp;
+ int found = 0;
+ char modname[256];
+
+ fp = fopen("/proc/modules", "r");
+ if (fp == NULL)
+ return -1;
+
+ while (fscanf(fp, "%s %*s %*s %*s %*s %*s", modname) == 1) {
+ if (strcmp(module, modname) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ fclose(fp);
+
+ return found;
+}
+
+static int jt_blockdev_probe_module(const char *module)
+{
+ char buf[1024];
+ char *argv[10];
+ int c, rc;
+
+ if (jt_blockdev_find_module(module) == 1)
+ return 0;
+
+ /* run modprobe first */
+ c = 0;
+ argv[c++] = "/sbin/modprobe";
+ argv[c++] = "-q";
+ argv[c++] = (char *)module;
+ argv[c++] = NULL;
+ rc = jt_blockdev_run_process("modprobe", argv);
+ if (rc != 1)
+ return rc;
+
+ /* cannot find the module in default directory ... */
+ sprintf(buf, "../llite/%s.ko", module);
+ c = 0;
+ argv[c++] = "/sbin/insmod";
+ argv[c++] = buf;
+ argv[c++] = NULL;
+ rc = jt_blockdev_run_process("insmod", argv);
+ return rc ? -1 : 0;
+}
+
+int jt_blockdev_attach(int argc, char **argv)
+{
+ int rc, fd;
+ struct stat st;
+ char *filename, *devname;
+ unsigned long dev;
+
+ if (argc != 3)
+ return CMD_HELP;
+
+ if (jt_blockdev_probe_module("llite_lloop") < 0) {
+ fprintf(stderr, "error: cannot find module llite_lloop.(k)o\n");
+ return ENOENT;
+ }
+
+ filename = argv[1];
+ devname = argv[2];
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "file %s can't be opened(%s)\n\n",
+ filename, strerror(errno));
+ return CMD_HELP;
+ }
+
+ rc = ioctl(fd, LL_IOC_LLOOP_ATTACH, &dev);
+ if (rc < 0) {
+ rc = errno;
+ fprintf(stderr, "attach error(%s)\n", strerror(rc));
+ goto out;
+ }
+
+ rc = stat(devname, &st);
+ if (rc == 0 && (!S_ISBLK(st.st_mode) || st.st_rdev != dev)) {
+ rc = EEXIST;
+ } else if (rc < 0) {
+ if (errno == ENOENT &&
+ !mknod(devname, S_IFBLK|S_IRUSR|S_IWUSR, dev))
+ rc = 0;
+ else
+ rc = errno;
+ }
+
+ if (rc) {
+ fprintf(stderr, "error: the file %s could be attached to block "
+ "device %X but creating %s failed: %s\n"
+ "now detaching the block device..",
+ filename, (int)dev, devname, strerror(rc));
+
+ (void)ioctl(fd, LL_IOC_LLOOP_DETACH_BYDEV, dev);
+ fprintf(stderr, "%s\n", strerror(errno));
+ }
+out:
+ close(fd);
+ return -rc;
+}
+
+int jt_blockdev_detach(int argc, char **argv)
+{
+ char *filename;
+ int rc, fd;
+
+ if (argc != 2)
+ return CMD_HELP;
+
+ filename = argv[1];
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "cannot open file %s error %s\n",
+ filename, strerror(errno));
+ return CMD_HELP;
+ }
+
+ rc = ioctl(fd, LL_IOC_LLOOP_DETACH, 0);
+ if (rc < 0) {
+ rc = errno;
+ fprintf(stderr, "detach error(%s)\n", strerror(rc));
+ } else {
+ (void)unlink(filename);
+ }
+
+ close(fd);
+ return -rc;
+}
+
+int jt_blockdev_info(int argc, char **argv)
+{
+ char *filename;
+ int rc, fd;
+ __u64 ino;
+
+ if (argc != 2)
+ return CMD_HELP;
+
+ filename = argv[1];
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "cannot open file %s error: %s\n",
+ filename, strerror(errno));
+ return CMD_HELP;
+ }
+
+ rc = ioctl(fd, LL_IOC_LLOOP_INFO, &ino);
+ if (rc < 0) {
+ rc = errno;
+ fprintf(stderr, "error: %s\n", strerror(errno));
+ goto out;
+ }
+ fprintf(stdout, "lloop device info: ");
+ if (ino == 0ULL)
+ fprintf(stdout, "Not attached\n");
+ else
+ fprintf(stdout, "attached to inode %llu\n", ino);
+out:
+ close(fd);
+ return -rc;
+}
+
static void signal_server(int sig)
{
if (sig == SIGINT) {