void update_mtab(const char *dir, struct mntent *instead) { struct mntent *mnt; struct mntent *next; struct mntent remnt; int added = 0; mntFILE *mfp, *mftmp; if (mtab_does_not_exist() || mtab_is_a_symlink()) return; lock_mtab(); mfp = my_setmntent(MOUNTED, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { error("cannot open %s (%s) - mtab not updated", MOUNTED, strerror(errno)); goto leave; } mftmp = my_setmntent(MOUNTED_TEMP, "w"); if (mftmp == NULL || mftmp->mntent_fp == NULL) { error("can't open %s (%s) - mtab not updated", MOUNTED_TEMP, strerror(errno)); goto leave; } while ((mnt = my_getmntent(mfp))) { if (streq(mnt->mnt_dir, dir)) { added++; if (instead) { /* a remount */ remnt = *instead; next = &remnt; remnt.mnt_fsname = mnt->mnt_fsname; remnt.mnt_type = mnt->mnt_type; if (instead->mnt_fsname && !streq(mnt->mnt_fsname, instead->mnt_fsname)) printf("mount: warning: cannot change " "mounted device with a remount\n"); else if (instead->mnt_type && !streq(instead->mnt_type, "unknown") && !streq(mnt->mnt_type, instead->mnt_type)) printf("mount: warning: cannot change " "filesystem type with a remount\n"); } else next = NULL; } else next = mnt; if (next && my_addmntent(mftmp, next) == 1) die(EX_FILEIO, "error writing %s: %s", MOUNTED_TEMP, strerror(errno)); } if (instead && !added && my_addmntent(mftmp, instead) == 1) die(EX_FILEIO, "error writing %s: %s", MOUNTED_TEMP, strerror(errno)); my_endmntent(mfp); if (fchmod(fileno(mftmp->mntent_fp), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) fprintf(stderr, "error changing mode of %s: %s\n", MOUNTED_TEMP, strerror(errno)); my_endmntent(mftmp); if (rename(MOUNTED_TEMP, MOUNTED) < 0) fprintf(stderr, "can't rename %s to %s: %s\n", MOUNTED_TEMP, MOUNTED, strerror(errno)); leave: unlock_mtab(); }
/* Fatal error. Print message and exit. */ void die (int err, const char *fmt, ...) { va_list args; va_start (args, fmt); vfprintf (stderr, fmt, args); fprintf (stderr, "\n"); va_end (args); unlock_mtab (); exit (err); }
/* * based on similar function in util-linux-2.12r/mount/mount.c */ static void update_mtab_entry(const char *spec, const char *node, const char *type, const char *opts, int freq, int pass, int addnew) { struct my_mntent mnt; mnt.mnt_fsname = canonicalize (spec); mnt.mnt_dir = canonicalize (node); mnt.mnt_type = xstrdup(type); mnt.mnt_opts = xstrdup(opts); mnt.mnt_freq = freq; mnt.mnt_passno = pass; /* We get chatty now rather than after the update to mtab since the mount succeeded, even if the write to /etc/mtab should fail. */ if (verbose) print_one (&mnt); if (!addnew) update_mtab (mnt.mnt_dir, &mnt); else { mntFILE *mfp; lock_mtab(); mfp = my_setmntent(MOUNTED, "a+"); if (mfp == NULL || mfp->mntent_fp == NULL) { int errsv = errno; error(_("%s: can't open %s, %s"), progname, MOUNTED, strerror(errsv)); } else { if ((my_addmntent (mfp, &mnt)) == 1) { int errsv = errno; error(_("%s: error writing %s, %s"), progname, MOUNTED, strerror(errsv)); } } my_endmntent(mfp); unlock_mtab(); } my_free(mnt.mnt_fsname); my_free(mnt.mnt_dir); my_free(mnt.mnt_type); my_free(mnt.mnt_opts); }
/* * Code based on similar function in util-linux-2.12p/mount/mount.c * */ static void update_mtab_entry(char *spec, char *node, char *type, char *opts, int flags, int freq, int pass) { struct my_mntent mnt; mnt.mnt_fsname = canonicalize (spec); mnt.mnt_dir = canonicalize (node); mnt.mnt_type = type; mnt.mnt_opts = opts; mnt.mnt_freq = freq; mnt.mnt_passno = pass; /* We get chatty now rather than after the update to mtab since the mount succeeded, even if the write to /etc/mtab should fail. */ if (verbose) print_one (&mnt); if (!nomtab && mtab_is_writable()) { if (flags & MS_REMOUNT) update_mtab (mnt.mnt_dir, &mnt); else { mntFILE *mfp; lock_mtab(); mfp = my_setmntent(MOUNTED, "a+"); if (mfp == NULL || mfp->mntent_fp == NULL) { com_err(progname, OCFS2_ET_IO, "%s, %s", MOUNTED, strerror(errno)); } else { if ((my_addmntent (mfp, &mnt)) == 1) { com_err(progname, OCFS2_ET_IO, "%s, %s", MOUNTED, strerror(errno)); } } my_endmntent(mfp); unlock_mtab(); } } my_free(mnt.mnt_fsname); my_free(mnt.mnt_dir); }
static int remove_from_mtab(char * mountpoint) { int rc; int num_matches; FILE * org_fd; FILE * new_fd; struct mntent * mount_entry; /* Do we need to check if it is a symlink to e.g. /proc/mounts in which case we probably do not want to update it? */ /* Do we first need to check if it is writable? */ atexit(unlock_mtab); if (lock_mtab()) { printf("Mount table locked\n"); return -EACCES; } if(verboseflg) printf("attempting to remove from mtab\n"); org_fd = setmntent(MOUNTED, "r"); if(org_fd == NULL) { printf("Can not open %s\n",MOUNTED); unlock_mtab(); return -EIO; } new_fd = setmntent(MOUNTED_TEMP,"w"); if(new_fd == NULL) { printf("Can not open temp file %s", MOUNTED_TEMP); endmntent(org_fd); unlock_mtab(); return -EIO; } /* BB fix so we only remove the last entry that matches BB */ num_matches = 0; while((mount_entry = getmntent(org_fd)) != NULL) { if(strcmp(mount_entry->mnt_dir, mountpoint) == 0) { num_matches++; } } if(verboseflg) printf("%d matching entries in mount table\n", num_matches); /* Is there a better way to seek back to the first entry in mtab? */ endmntent(org_fd); org_fd = setmntent(MOUNTED, "r"); if(org_fd == NULL) { printf("Can not open %s\n",MOUNTED); unlock_mtab(); return -EIO; } while((mount_entry = getmntent(org_fd)) != NULL) { if(strcmp(mount_entry->mnt_dir, mountpoint) != 0) { addmntent(new_fd, mount_entry); } else { if(num_matches != 1) { addmntent(new_fd, mount_entry); num_matches--; } else if(verboseflg) printf("entry not copied (ie entry is removed)\n"); } } if(verboseflg) printf("done updating tmp file\n"); rc = fchmod (fileno (new_fd), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(rc < 0) { printf("error %s changing mode of %s\n", strerror(errno), MOUNTED_TEMP); } endmntent(new_fd); rc = rename(MOUNTED_TEMP, MOUNTED); if(rc < 0) { printf("failure %s renaming %s to %s\n",strerror(errno), MOUNTED_TEMP, MOUNTED); unlock_mtab(); return -EIO; } unlock_mtab(); return rc; }
void update_mtab (const char *dir, struct mntent *instead) { mntFILE *mfp, *mftmp; const char *fnam = MOUNTED; struct mntentchn mtabhead; /* dummy */ struct mntentchn *mc, *mc0, *absent = NULL; if (mtab_does_not_exist() || !mtab_is_writable()) return; lock_mtab(); /* having locked mtab, read it again */ mc0 = mc = &mtabhead; mc->nxt = mc->prev = NULL; mfp = nfs_setmntent(fnam, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { int errsv = errno; nfs_error (_("cannot open %s (%s) - mtab not updated"), fnam, strerror (errsv)); goto leave; } read_mntentchn(mfp, fnam, mc); /* find last occurrence of dir */ for (mc = mc0->prev; mc && mc != mc0; mc = mc->prev) if (streq(mc->m.mnt_dir, dir)) break; if (mc && mc != mc0) { if (instead == NULL) { /* An umount - remove entry */ if (mc && mc != mc0) { mc->prev->nxt = mc->nxt; mc->nxt->prev = mc->prev; free(mc); } } else { /* A remount */ mc->m.mnt_opts = instead->mnt_opts; } } else if (instead) { /* not found, add a new entry */ absent = xmalloc(sizeof(*absent)); absent->m = *instead; absent->nxt = mc0; absent->prev = mc0->prev; mc0->prev = absent; if (mc0->nxt == NULL) mc0->nxt = absent; } /* write chain to mtemp */ mftmp = nfs_setmntent (MOUNTED_TEMP, "w"); if (mftmp == NULL || mftmp->mntent_fp == NULL) { int errsv = errno; nfs_error (_("cannot open %s (%s) - mtab not updated"), MOUNTED_TEMP, strerror (errsv)); goto leave; } for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) { if (nfs_addmntent(mftmp, &(mc->m)) == 1) { int errsv = errno; die (EX_FILEIO, _("error writing %s: %s"), MOUNTED_TEMP, strerror (errsv)); } } #if 0 /* the chain might have strings copied from 'instead', * so we cannot safely free it. * And there is no need anyway because we are going to exit * shortly. So just don't call discard_mntentchn.... */ discard_mntentchn(mc0); #endif if (fchmod (fileno (mftmp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) { int errsv = errno; nfs_error(_("%s: error changing mode of %s: %s"), progname, MOUNTED_TEMP, strerror (errsv)); } nfs_endmntent (mftmp); { /* * If mount is setuid and some non-root user mounts sth, * then mtab.tmp might get the group of this user. Copy uid/gid * from the present mtab before renaming. */ struct stat sbuf; if (stat (MOUNTED, &sbuf) == 0) { if (chown (MOUNTED_TEMP, sbuf.st_uid, sbuf.st_gid) < 0) { nfs_error(_("%s: error changing owner of %s: %s"), progname, MOUNTED_TEMP, strerror (errno)); } } } /* rename mtemp to mtab */ if (rename (MOUNTED_TEMP, MOUNTED) < 0) { int errsv = errno; nfs_error(_("%s: can't rename %s to %s: %s\n"), progname, MOUNTED_TEMP, MOUNTED, strerror(errsv)); } leave: unlock_mtab(); }
int main(int argc, char ** argv) { int c; int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */ char * orgoptions = NULL; char * share_name = NULL; const char * ipaddr = NULL; char * uuid = NULL; char * mountpoint = NULL; char * options = NULL; char * optionstail; char * resolved_path = NULL; char * temp; char * dev_name; int rc = 0; int rsize = 0; int wsize = 0; int nomtab = 0; int uid = 0; int gid = 0; int optlen = 0; int orgoptlen = 0; size_t options_size = 0; size_t current_len; int retry = 0; /* set when we have to retry mount with uppercase */ struct addrinfo *addrhead = NULL, *addr; struct stat statbuf; struct utsname sysinfo; struct mntent mountent; struct sockaddr_in *addr4; struct sockaddr_in6 *addr6; FILE * pmntfile; /* setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); */ if(argc && argv) { thisprogram = argv[0]; } else { mount_cifs_usage(); exit(EX_USAGE); } if(thisprogram == NULL) thisprogram = "mount.cifs"; uname(&sysinfo); /* BB add workstation name and domain and pass down */ /* #ifdef _GNU_SOURCE printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname); #endif */ if(argc > 2) { dev_name = argv[1]; share_name = strndup(argv[1], MAX_UNC_LEN); if (share_name == NULL) { fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM)); exit(EX_SYSERR); } mountpoint = argv[2]; } else if (argc == 2) { if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) { print_cifs_mount_version(); exit(0); } if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "--help") == 0)) { mount_cifs_usage(); exit(0); } mount_cifs_usage(); exit(EX_USAGE); } else { mount_cifs_usage(); exit(EX_USAGE); } /* add sharename in opts string as unc= parm */ while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:", longopts, NULL)) != -1) { switch (c) { /* No code to do the following options yet */ /* case 'l': list_with_volumelabel = 1; break; case 'L': volumelabel = optarg; break; */ /* case 'a': ++mount_all; break; */ case '?': case 'h': /* help */ mount_cifs_usage (); exit(EX_USAGE); case 'n': ++nomtab; break; case 'b': #ifdef MS_BIND flags |= MS_BIND; #else fprintf(stderr, "option 'b' (MS_BIND) not supported\n"); #endif break; case 'm': #ifdef MS_MOVE flags |= MS_MOVE; #else fprintf(stderr, "option 'm' (MS_MOVE) not supported\n"); #endif break; case 'o': orgoptions = strdup(optarg); break; case 'r': /* mount readonly */ flags |= MS_RDONLY; break; case 'U': uuid = optarg; break; case 'v': ++verboseflag; break; case 'V': print_cifs_mount_version(); exit (0); case 'w': flags &= ~MS_RDONLY; break; case 'R': rsize = atoi(optarg) ; break; case 'W': wsize = atoi(optarg); break; case '1': if (isdigit(*optarg)) { char *ep; uid = strtoul(optarg, &ep, 10); if (*ep) { printf("bad uid value \"%s\"\n", optarg); exit(EX_USAGE); } } else { struct passwd *pw; if (!(pw = getpwnam(optarg))) { printf("bad user name \"%s\"\n", optarg); exit(EX_USAGE); } uid = pw->pw_uid; endpwent(); } break; case '2': if (isdigit(*optarg)) { char *ep; gid = strtoul(optarg, &ep, 10); if (*ep) { printf("bad gid value \"%s\"\n", optarg); exit(EX_USAGE); } } else { struct group *gr; if (!(gr = getgrnam(optarg))) { printf("bad user name \"%s\"\n", optarg); exit(EX_USAGE); } gid = gr->gr_gid; endpwent(); } break; case 'u': got_user = 1; user_name = optarg; break; case 'd': domain_name = optarg; /* BB fix this - currently ignored */ got_domain = 1; break; case 'p': if(mountpassword == NULL) mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1); if(mountpassword) { got_password = 1; strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1); } break; case 'S': get_password_from_file(0 /* stdin */,NULL); break; case 't': break; case 'f': ++fakemnt; break; default: printf("unknown mount option %c\n",c); mount_cifs_usage(); exit(EX_USAGE); } } if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) { mount_cifs_usage(); exit(EX_USAGE); } if (getenv("PASSWD")) { if(mountpassword == NULL) mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1); if(mountpassword) { strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1); got_password = 1; } } else if (getenv("PASSWD_FD")) { get_password_from_file(atoi(getenv("PASSWD_FD")),NULL); } else if (getenv("PASSWD_FILE")) { get_password_from_file(0, getenv("PASSWD_FILE")); } if (orgoptions && parse_options(&orgoptions, &flags)) { rc = EX_USAGE; goto mount_exit; } addrhead = addr = parse_server(&share_name); if((addrhead == NULL) && (got_ip == 0)) { printf("No ip address specified and hostname not found\n"); rc = EX_USAGE; goto mount_exit; } /* BB save off path and pop after mount returns? */ resolved_path = (char *)malloc(PATH_MAX+1); if(resolved_path) { /* Note that if we can not canonicalize the name, we get another chance to see if it is valid when we chdir to it */ if (realpath(mountpoint, resolved_path)) { mountpoint = resolved_path; } } if(chdir(mountpoint)) { printf("mount error: can not change directory into mount target %s\n",mountpoint); rc = EX_USAGE; goto mount_exit; } if(stat (".", &statbuf)) { printf("mount error: mount point %s does not exist\n",mountpoint); rc = EX_USAGE; goto mount_exit; } if (S_ISDIR(statbuf.st_mode) == 0) { printf("mount error: mount point %s is not a directory\n",mountpoint); rc = EX_USAGE; goto mount_exit; } if((getuid() != 0) && (geteuid() == 0)) { if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) { #ifndef CIFS_ALLOW_USR_SUID /* Do not allow user mounts to control suid flag for mount unless explicitly built that way */ flags |= MS_NOSUID | MS_NODEV; #endif } else { printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n"); exit(EX_USAGE); } } if(got_user == 0) { /* Note that the password will not be retrieved from the USER env variable (ie user%password form) as there is already a PASSWD environment varaible */ if (getenv("USER")) user_name = strdup(getenv("USER")); if (user_name == NULL) user_name = getusername(); got_user = 1; } if(got_password == 0) { char *tmp_pass = getpass("Password: "******"Password not entered, exiting\n"); exit(EX_USAGE); } strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1); got_password = 1; } /* FIXME launch daemon (handles dfs name resolution and credential change) remember to clear parms and overwrite password field before launching */ if(orgoptions) { optlen = strlen(orgoptions); orgoptlen = optlen; } else optlen = 0; if(share_name) optlen += strlen(share_name) + 4; else { printf("No server share name specified\n"); printf("\nMounting the DFS root for server not implemented yet\n"); exit(EX_USAGE); } if(user_name) optlen += strlen(user_name) + 6; optlen += MAX_ADDRESS_LEN + 4; if(mountpassword) optlen += strlen(mountpassword) + 6; mount_retry: SAFE_FREE(options); options_size = optlen + 10 + DOMAIN_SIZE; options = (char *)malloc(options_size /* space for commas in password */ + 8 /* space for domain= , domain name itself was counted as part of the length username string above */); if(options == NULL) { printf("Could not allocate memory for mount options\n"); exit(EX_SYSERR); } strlcpy(options, "unc=", options_size); strlcat(options,share_name,options_size); /* scan backwards and reverse direction of slash */ temp = strrchr(options, '/'); if(temp > options + 6) *temp = '\\'; if(user_name) { /* check for syntax like user=domain\user */ if(got_domain == 0) domain_name = check_for_domain(&user_name); strlcat(options,",user="******",domain=",options_size); strlcat(options,domain_name,options_size); } } strlcat(options,",ver=",options_size); strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size); if(orgoptions) { strlcat(options,",",options_size); strlcat(options,orgoptions,options_size); } if(prefixpath) { strlcat(options,",prefixpath=",options_size); strlcat(options,prefixpath,options_size); /* no need to cat the / */ } /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */ replace_char(dev_name, '\\', '/', strlen(share_name)); if (!got_ip && addr) { strlcat(options, ",ip=", options_size); current_len = strnlen(options, options_size); optionstail = options + current_len; switch (addr->ai_addr->sa_family) { case AF_INET6: addr6 = (struct sockaddr_in6 *) addr->ai_addr; ipaddr = inet_ntop(AF_INET6, &addr6->sin6_addr, optionstail, options_size - current_len); break; case AF_INET: addr4 = (struct sockaddr_in *) addr->ai_addr; ipaddr = inet_ntop(AF_INET, &addr4->sin_addr, optionstail, options_size - current_len); break; } /* if the address looks bogus, try the next one */ if (!ipaddr) { addr = addr->ai_next; if (addr) goto mount_retry; rc = EX_SYSERR; goto mount_exit; } } if(verboseflag) fprintf(stderr, "\nmount.cifs kernel mount options: %s", options); if (mountpassword) { /* * Commas have to be doubled, or else they will * look like the parameter separator */ if(retry == 0) check_for_comma(&mountpassword); strlcat(options,",pass="******",pass=********"); } if (verboseflag) fprintf(stderr, "\n"); if (!fakemnt && mount(dev_name, mountpoint, "cifs", flags, options)) { switch (errno) { case ECONNREFUSED: case EHOSTUNREACH: if (addr) { addr = addr->ai_next; if (addr) goto mount_retry; } break; case ENODEV: printf("mount error: cifs filesystem not supported by the system\n"); break; case ENXIO: if(retry == 0) { retry = 1; if (uppercase_string(dev_name) && uppercase_string(share_name) && uppercase_string(prefixpath)) { printf("retrying with upper case share name\n"); goto mount_retry; } } } printf("mount error(%d): %s\n", errno, strerror(errno)); printf("Refer to the mount.cifs(8) manual page (e.g. man " "mount.cifs)\n"); rc = EX_FAIL; goto mount_exit; } if (nomtab) goto mount_exit; atexit(unlock_mtab); rc = lock_mtab(); if (rc) { printf("cannot lock mtab"); goto mount_exit; } pmntfile = setmntent(MOUNTED, "a+"); if (!pmntfile) { printf("could not update mount table\n"); unlock_mtab(); rc = EX_FILEIO; goto mount_exit; } mountent.mnt_fsname = dev_name; mountent.mnt_dir = mountpoint; mountent.mnt_type = CONST_DISCARD(char *,"cifs"); mountent.mnt_opts = (char *)malloc(220); if(mountent.mnt_opts) { char * mount_user = getusername(); memset(mountent.mnt_opts,0,200); if(flags & MS_RDONLY) strlcat(mountent.mnt_opts,"ro",220); else strlcat(mountent.mnt_opts,"rw",220); if(flags & MS_MANDLOCK) strlcat(mountent.mnt_opts,",mand",220); if(flags & MS_NOEXEC) strlcat(mountent.mnt_opts,",noexec",220); if(flags & MS_NOSUID) strlcat(mountent.mnt_opts,",nosuid",220); if(flags & MS_NODEV) strlcat(mountent.mnt_opts,",nodev",220); if(flags & MS_SYNCHRONOUS) strlcat(mountent.mnt_opts,",sync",220); if(mount_user) { if(getuid() != 0) { strlcat(mountent.mnt_opts, ",user=", 220); strlcat(mountent.mnt_opts, mount_user, 220); } } } mountent.mnt_freq = 0; mountent.mnt_passno = 0; rc = addmntent(pmntfile,&mountent); endmntent(pmntfile); unlock_mtab(); SAFE_FREE(mountent.mnt_opts); if (rc) rc = EX_FILEIO; mount_exit: if(mountpassword) { int len = strlen(mountpassword); memset(mountpassword,0,len); SAFE_FREE(mountpassword); } if (addrhead) freeaddrinfo(addrhead); SAFE_FREE(options); SAFE_FREE(orgoptions); SAFE_FREE(resolved_path); SAFE_FREE(share_name); exit(rc); }
static int mount_fuse(const char *mnt, const char *opts) { int res; int fd; char *dev; const char *type = "fuse"; struct stat stbuf; char *fsname = NULL; char *mnt_opts = NULL; const char *real_mnt = mnt; int currdir_fd = -1; int mountpoint_fd = -1; int mtablock = -1; fd = open_fuse_device(&dev); if (fd == -1) return -1; if (geteuid() == 0) mtablock = lock_mtab(); drop_privs(); read_conf(); if (getuid() != 0 && mount_max != -1) { int mount_count = count_fuse_fs(); if (mount_count >= mount_max) { fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); close(fd); unlock_mtab(mtablock); return -1; } } res = check_version(dev); if (res != -1) { res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd); restore_privs(); if (res != -1) res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts, dev, &fsname, &mnt_opts, stbuf.st_size); } else restore_privs(); if (currdir_fd != -1) { fchdir(currdir_fd); close(currdir_fd); } if (mountpoint_fd != -1) close(mountpoint_fd); if (res == -1) { close(fd); unlock_mtab(mtablock); return -1; } if (geteuid() == 0) { res = add_mount(fsname, mnt, type, mnt_opts); unlock_mtab(mtablock); if (res == -1) { umount2(mnt, 2); /* lazy umount */ close(fd); return -1; } } free(fsname); free(mnt_opts); free(dev); return fd; }
int main(int argc, char *argv[]) { int ch; int fd; int res; char *origmnt; char *mnt; static int unmount = 0; static int lazy = 0; static int quiet = 0; char *commfd; int cfd; const char *opts = ""; static const struct option long_opts[] = { {"unmount", no_argument, NULL, 'u'}, {"lazy", no_argument, NULL, 'z'}, {"quiet", no_argument, NULL, 'q'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, {0, 0, 0, 0}}; progname = strdup(argv[0]); if (progname == NULL) { fprintf(stderr, "%s: failed to allocate memory\n", argv[0]); exit(1); } while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, NULL)) != -1) { switch (ch) { case 'h': usage(); break; case 'V': show_version(); break; case 'o': opts = optarg; break; case 'u': unmount = 1; break; case 'z': lazy = 1; break; case 'q': quiet = 1; break; default: exit(1); } } if (lazy && !unmount) { fprintf(stderr, "%s: -z can only be used with -u\n", progname); exit(1); } if (optind >= argc) { fprintf(stderr, "%s: missing mountpoint argument\n", progname); exit(1); } origmnt = argv[optind]; drop_privs(); mnt = resolve_path(origmnt); restore_privs(); if (mnt == NULL) exit(1); umask(033); if (unmount) { if (geteuid() == 0) { int mtablock = lock_mtab(); res = unmount_fuse(mnt, quiet, lazy); unlock_mtab(mtablock); } else res = do_unmount(mnt, quiet, lazy); if (res == -1) exit(1); return 0; } commfd = getenv(FUSE_COMMFD_ENV); if (commfd == NULL) { fprintf(stderr, "%s: old style mounting not supported\n", progname); exit(1); } fd = mount_fuse(mnt, opts); if (fd == -1) exit(1); cfd = atoi(commfd); res = send_fd(cfd, fd); if (res == -1) exit(1); return 0; }
void update_mtab (const char *dir, struct my_mntent *instead) { mntFILE *mfp, *mftmp; const char *fnam = MOUNTED; struct mntentchn mtabhead; /* dummy */ struct mntentchn *mc, *mc0, *absent = NULL; if (mtab_does_not_exist() || mtab_is_a_symlink()) return; lock_mtab(); /* having locked mtab, read it again */ mc0 = mc = &mtabhead; mc->nxt = mc->prev = NULL; mfp = my_setmntent(fnam, "r"); if (mfp == NULL || mfp->mntent_fp == NULL) { int errsv = errno; error (_("cannot open %s (%s) - mtab not updated"), fnam, strerror (errsv)); goto leave; } read_mntentchn(mfp, fnam, mc); /* find last occurrence of dir */ for (mc = mc0->prev; mc && mc != mc0; mc = mc->prev) if (streq(mc->m.mnt_dir, dir)) break; if (mc && mc != mc0) { if (instead == NULL) { /* An umount - remove entry */ if (mc && mc != mc0) { mc->prev->nxt = mc->nxt; mc->nxt->prev = mc->prev; free(mc); } } else { /* A remount */ mc->m.mnt_opts = instead->mnt_opts; } } else if (instead) { /* not found, add a new entry */ absent = xmalloc(sizeof(*absent)); absent->m = *instead; absent->nxt = mc0; absent->prev = mc0->prev; mc0->prev = absent; if (mc0->nxt == NULL) mc0->nxt = absent; } /* write chain to mtemp */ mftmp = my_setmntent (MOUNTED_TEMP, "w"); if (mftmp == NULL || mftmp->mntent_fp == NULL) { int errsv = errno; error (_("cannot open %s (%s) - mtab not updated"), MOUNTED_TEMP, strerror (errsv)); goto leave; } for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) { if (my_addmntent(mftmp, &(mc->m)) == 1) { int errsv = errno; die (EX_FILEIO, _("error writing %s: %s"), MOUNTED_TEMP, strerror (errsv)); } } discard_mntentchn(mc0); if (fchmod (fileno (mftmp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) { int errsv = errno; fprintf(stderr, _("error changing mode of %s: %s\n"), MOUNTED_TEMP, strerror (errsv)); } my_endmntent (mftmp); { /* * If mount is setuid and some non-root user mounts sth, * then mtab.tmp might get the group of this user. Copy uid/gid * from the present mtab before renaming. */ struct stat sbuf; if (stat (MOUNTED, &sbuf) == 0) chown (MOUNTED_TEMP, sbuf.st_uid, sbuf.st_gid); } /* rename mtemp to mtab */ if (rename (MOUNTED_TEMP, MOUNTED) < 0) { int errsv = errno; fprintf(stderr, _("can't rename %s to %s: %s\n"), MOUNTED_TEMP, MOUNTED, strerror(errsv)); } leave: unlock_mtab(); }
int au_update_mtab(char *mntpnt, int do_remount, int do_verbose) { int err, fd, status, e2; pid_t pid; ino_t ino; struct stat st; struct statfs stfs; struct flock flock = { .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 0 }; char pid_file[sizeof(MTab "~.") + 20]; FILE *fp; err = statfs(MTab, &stfs); if (stfs.f_type == PROC_SUPER_MAGIC) return 0; snprintf(pid_file, sizeof(pid_file), MTab "~.%d", getpid()); fd = open(pid_file, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) AuFin("%s", pid_file); err = fcntl(fd, F_SETLK, &flock); if (err) AuFin("%s", pid_file); fp = fdopen(fd, "r+"); if (!fp) AuFin("%s", pid_file); pid = fork(); if (!pid) { lock_mtab(pid_file); update_mtab(fp, mntpnt, do_remount, do_verbose); unlock_mtab(); return 0; } else if (pid < 0) AuFin("fork"); err = fstat(fd, &st); if (err) perror(pid_file); ino = st.st_ino; err = waitpid(pid, &status, 0); if (err < 0) { perror(pid_file); goto out; } err = !WIFEXITED(status); if (!err) err = WEXITSTATUS(status); e2 = unlink(pid_file); if (e2 && errno != ENOENT) perror(pid_file); e2 = stat(MTab "~", &st); if (!e2) { if (st.st_ino == ino) { /* * The inode number is same, * it means it is we who made the file. * If someone else removed our file between stat(2) and * unlink(2), it is a breakage of the rule. */ e2 = unlink(MTab "~"); if (e2) perror(MTab); } } else if (errno != ENOENT) perror(MTab "~"); fclose(fp); out: return err; }