comparison toys/pending/mount.c @ 1385:ffc015bddb26 draft 0.4.9

Autodetect --bind and --loop mounts in a way that doesn't interfere with network filesystems or -t newtype mounts that trigger a module load.
author Rob Landley <rob@landley.net>
date Sun, 06 Jul 2014 23:43:29 -0500
parents 9fd2bcedbeb5
children 487716951287
comparison
equal deleted inserted replaced
1384:4a7438307429 1385:ffc015bddb26
64 {"loud", ~MS_SILENT}, 64 {"loud", ~MS_SILENT},
65 {"shared", MS_SHARED}, {"rshared", MS_SHARED|MS_REC}, 65 {"shared", MS_SHARED}, {"rshared", MS_SHARED|MS_REC},
66 {"slave", MS_SLAVE}, {"rslave", MS_SLAVE|MS_REC}, 66 {"slave", MS_SLAVE}, {"rslave", MS_SLAVE|MS_REC},
67 {"private", MS_PRIVATE}, {"rprivate", MS_SLAVE|MS_REC}, 67 {"private", MS_PRIVATE}, {"rprivate", MS_SLAVE|MS_REC},
68 {"unbindable", MS_UNBINDABLE}, {"runbindable", MS_UNBINDABLE|MS_REC}, 68 {"unbindable", MS_UNBINDABLE}, {"runbindable", MS_UNBINDABLE|MS_REC},
69 {"remount", MS_REMOUNT}, {"bind", MS_BIND}, {"move", MS_MOVE}, 69 {"remount", MS_REMOUNT}, {"move", MS_MOVE},
70 // mand dirsync rec iversion strictatime 70 // mand dirsync rec iversion strictatime
71 }; 71 };
72 72
73 for (;;) { 73 for (;;) {
74 char *comma = strchr(new, ','); 74 char *comma = strchr(new, ',');
108 FILE *fp = 0; 108 FILE *fp = 0;
109 int rc = EINVAL; 109 int rc = EINVAL;
110 110
111 if (toys.optflags & FLAG_f) return; 111 if (toys.optflags & FLAG_f) return;
112 112
113 // Autodetect bind mount or filesystem type
113 if (!type) { 114 if (!type) {
114 struct stat stdev, stdir; 115 struct stat stdev, stdir;
115 116
116 if (!stat(dev, &stdev) && !stat(dir, &stdir)) { 117 if (!stat(dev, &stdev) && !stat(dir, &stdir)
117 if (S_ISREG(stdev.st_mode)) { 118 && ((S_ISREG(stdev.st_mode) && S_ISREG(stdir.st_mode))
118 // Loopback mount? 119 || (S_ISDIR(stdev.st_mode) && S_ISDIR(stdir.st_mode))))
119 if (S_ISDIR(stdir.st_mode)) { 120 {
120 char *losetup[] = {"losetup", "-fs", dev, 0}; 121 flags |= MS_BIND;
121 int pipes[2], len; 122 } else fp = xfopen("/proc/filesystems", "r");
122 pid_t pid;
123
124 if (flags & MS_RDONLY) losetup[1] = "-fsr";
125 pid = xpopen(losetup, pipes);
126 len = readall(pipes[1], toybuf, sizeof(toybuf)-1);
127 if (!xpclose(pid, pipes) && len > 1) {
128 if (toybuf[len-1] == '\n') --len;
129 toybuf[len] = 0;
130 dev = toybuf;
131 } else error_msg("losetup failed %d", len);
132 } else if (S_ISREG(stdir.st_mode)) flags |= MS_BIND;
133 } else if (S_ISDIR(stdev.st_mode) && S_ISDIR(stdir.st_mode))
134 flags |= MS_BIND;
135 }
136
137 if (!(flags & MS_BIND)) fp = xfopen("/proc/filesystems", "r");
138 } 123 }
139 124
140 for (;;) { 125 for (;;) {
141 char *buf = 0; 126 char *buf = 0;
142 127
157 if (i) type[i-1] = 0; 142 if (i) type[i-1] = 0;
158 } 143 }
159 if (toys.optflags & FLAG_v) 144 if (toys.optflags & FLAG_v)
160 printf("try '%s' type '%s' on '%s'\n", dev, type, dir); 145 printf("try '%s' type '%s' on '%s'\n", dev, type, dir);
161 rc = mount(dev, dir, type, flags, opts); 146 rc = mount(dev, dir, type, flags, opts);
147
148 // Looking for bind mounts in autodetect above isn't good enough because
149 // "mount -t ext2 fs.img dir" is valid, but if you _do_ accept bind mounts
150 // with -t how do you tell "-t cifs" isn't looking for a block device if
151 // it's not in /proc/filesystems yet because the module that won't be
152 // loaded until you try the mount, and if you can't then DEVICE
153 // existing as a file would cause a false positive loopback mount.
154 //
155 // Solution: try mount, let the kernel tell us it wanted a block device,
156 // do the loopback setup and retry the mount.
157 if (rc && errno == ENOTBLK) {
158 char *losetup[] = {"losetup", "-fs", dev, 0};
159 int pipes[2], len;
160 pid_t pid;
161
162 if (flags & MS_RDONLY) losetup[1] = "-fsr";
163 pid = xpopen(losetup, pipes);
164 len = readall(pipes[1], toybuf, sizeof(toybuf)-1);
165 if (!xpclose(pid, pipes) && len > 1) {
166 if (toybuf[len-1] == '\n') --len;
167 toybuf[len] = 0;
168 dev = toybuf;
169
170 continue;
171 } else error_msg("losetup failed %d", len);
172 }
173
162 if (!fp || (rc && errno != EINVAL)) break; 174 if (!fp || (rc && errno != EINVAL)) break;
163 free(buf); 175 free(buf);
164 } 176 }
165 if (fp) fclose(fp); 177 if (fp) fclose(fp);
166 178