// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem // type detection. Returns 0 for success, nonzero for failure. // NB: mp->xxx fields may be trashed on exit static int singlemount(struct mntent *mp, int ignore_busy) { int rc = -1, vfsflags; char *loopFile = 0, *filteropts = 0; llist_t *fl = 0; struct stat st; vfsflags = parse_mount_options(mp->mnt_opts, &filteropts); // Treat fstype "auto" as unspecified. if (mp->mnt_type && strcmp(mp->mnt_type,"auto") == 0) mp->mnt_type = 0; // Might this be an CIFS filesystem? if (ENABLE_FEATURE_MOUNT_CIFS && (!mp->mnt_type || strcmp(mp->mnt_type,"cifs") == 0) && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\') && mp->mnt_fsname[0]==mp->mnt_fsname[1] ) { len_and_sockaddr *lsa; char *ip, *dotted; char *s; rc = 1; // Replace '/' with '\' and verify that unc points to "//server/share". for (s = mp->mnt_fsname; *s; ++s) if (*s == '/') *s = '\\'; // get server IP s = strrchr(mp->mnt_fsname, '\\'); if (s <= mp->mnt_fsname+1) goto report_error; *s = '\0'; lsa = host2sockaddr(mp->mnt_fsname+2, 0); *s = '\\'; if (!lsa) goto report_error; // insert ip=... option into string flags. dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); ip = xasprintf("ip=%s", dotted); parse_mount_options(ip, &filteropts); // compose new unc '\\server-ip\share' // (s => slash after hostname) mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s); // lock is required vfsflags |= MS_MANDLOCK; mp->mnt_type = (char*)"cifs"; rc = mount_it_now(mp, vfsflags, filteropts); if (ENABLE_FEATURE_CLEAN_UP) { free(mp->mnt_fsname); free(ip); free(dotted); free(lsa); } goto report_error; } // Might this be an NFS filesystem? if (ENABLE_FEATURE_MOUNT_NFS && (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && strchr(mp->mnt_fsname, ':') != NULL ) { rc = nfsmount(mp, vfsflags, filteropts); goto report_error; } // Look at the file. (Not found isn't a failure for remount, or for // a synthetic filesystem like proc or sysfs.) // (We use stat, not lstat, in order to allow // mount symlink_to_file_or_blkdev dir) if (!stat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)) ) { // Do we need to allocate a loopback device for it? if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { loopFile = bb_simplify_path(mp->mnt_fsname); mp->mnt_fsname = 0; switch (set_loop(&(mp->mnt_fsname), loopFile, 0)) { case 0: case 1: break; default: bb_error_msg( errno == EPERM || errno == EACCES ? bb_msg_perm_denied_are_you_root : "cannot setup loop device"); return errno; } // Autodetect bind mounts } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) vfsflags |= MS_BIND; } /* If we know the fstype (or don't need to), jump straight * to the actual mount. */ if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) rc = mount_it_now(mp, vfsflags, filteropts); else { // Loop through filesystem types until mount succeeds // or we run out /* Initialize list of block backed filesystems. This has to be * done here so that during "mount -a", mounts after /proc shows up * can autodetect. */ if (!fslist) { fslist = get_block_backed_filesystems(); if (ENABLE_FEATURE_CLEAN_UP && fslist) atexit(delete_block_backed_filesystems); } for (fl = fslist; fl; fl = fl->link) { mp->mnt_type = fl->data; rc = mount_it_now(mp, vfsflags, filteropts); if (!rc) break; } } // If mount failed, clean up loop file (if any). if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) { del_loop(mp->mnt_fsname); if (ENABLE_FEATURE_CLEAN_UP) { free(loopFile); free(mp->mnt_fsname); } } report_error: if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); if (rc && errno == EBUSY && ignore_busy) rc = 0; if (rc < 0) /* perror here sometimes says "mounting ... on ... failed: Success" */ bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); return rc; }
static int singlemount(struct mntent *mp, int ignore_busy) { int rc = -1, vfsflags; char *loopFile = 0, *filteropts = 0; llist_t *fl = 0; struct stat st; vfsflags = parse_mount_options(mp->mnt_opts, &filteropts); // Treat fstype "auto" as unspecified. if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0; // Might this be an NFS filesystem? if (ENABLE_FEATURE_MOUNT_NFS && (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && strchr(mp->mnt_fsname, ':') != NULL) { if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &filteropts, 1)) { bb_perror_msg("nfsmount failed"); goto report_error; } else { // Strangely enough, nfsmount() doesn't actually mount() anything. mp->mnt_type = "nfs"; rc = mount_it_now(mp, vfsflags, filteropts); if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); goto report_error; } } // Look at the file. (Not found isn't a failure for remount, or for // a synthetic filesystem like proc or sysfs.) if (stat(mp->mnt_fsname, &st)); else if (!(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { // Do we need to allocate a loopback device for it? if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { loopFile = bb_simplify_path(mp->mnt_fsname); mp->mnt_fsname = 0; switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) { case 0: case 1: break; default: bb_error_msg( errno == EPERM || errno == EACCES ? bb_msg_perm_denied_are_you_root : "Couldn't setup loop device"); return errno; } // Autodetect bind mounts } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) vfsflags |= MS_BIND; } /* If we know the fstype (or don't need to), jump straight * to the actual mount. */ if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) rc = mount_it_now(mp, vfsflags, filteropts); // Loop through filesystem types until mount succeeds or we run out else { /* Initialize list of block backed filesystems. This has to be * done here so that during "mount -a", mounts after /proc shows up * can autodetect. */ if (!fslist) { fslist = get_block_backed_filesystems(); if (ENABLE_FEATURE_CLEAN_UP && fslist) atexit(delete_block_backed_filesystems); } for (fl = fslist; fl; fl = fl->link) { mp->mnt_type = fl->data; if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break; mp->mnt_type = 0; } } if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); // If mount failed, clean up loop file (if any). if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) { del_loop(mp->mnt_fsname); if (ENABLE_FEATURE_CLEAN_UP) { free(loopFile); free(mp->mnt_fsname); } } report_error: if (rc && errno == EBUSY && ignore_busy) rc = 0; if (rc < 0) bb_perror_msg("Mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); return rc; }