#include #include #include "fstab.h" #include #include #include "../paths.h" #include #include #include "fstab.m" static FSTAB_HELP_FILE help_mtab ("mtab"); static CONFIG_FILE f_mtab (ETC_MTAB,help_mtab ,CONFIGF_NOARCH|CONFIGF_PROBED|CONFIGF_NOARCH); PUBLIC MTAB::MTAB () { FILE_CFG *fin = f_mtab.fopen("r"); if (fin != NULL){ char buf[1000]; while (fgets_cont(buf,sizeof(buf)-1,fin) != -1){ add (new FSTAB_ENTRY(buf)); } fclose (fin); } rstmodified(); } /* Locate one FSTAB_ENTRY using the mount point as the key */ PUBLIC FSTAB_ENTRY *FSTAB_GEN::locate_mpoint(const char *str) { FSTAB_ENTRY *ret = NULL; int n = getnb(); for (int i=0; igetmpoint(),str)==0){ ret = e; break; } } return ret; } /* Locate one FSTAB_ENTRY using the device/source as the key */ PUBLIC FSTAB_ENTRY *FSTAB_GEN::locate_source(const char *str) { FSTAB_ENTRY *ret = NULL; int n = getnb(); for (int i=0; igetsource(),str)==0){ ret = e; break; } } return ret; } /* Mount a file system. Return -1 if any error */ PUBLIC int FSTAB_ENTRY::domount() { char buf[2*PATH_MAX]; int len = snprintf (buf,sizeof(buf)-1,"-t %s ",getfs()); char opt[200]; format_opt (false,opt); if (opt[0] != '\0'){ len += sprintf (buf+len," -o %s",opt); } SSTRING tmp; const char *source = getsource(); if (strncasecmp(source,"LABEL=",6)==0){ tmp.setfromf ("-L %s",source+6); source = tmp.get(); } sprintf (buf+len," %s %s",source,getmpoint()); return netconf_system_if ("mount",buf); } /* Unmount a file system. Return -1 if any error. */ PUBLIC int FSTAB_ENTRY::doumount() { return netconf_system_if("umount",getmpoint()); } /* Get the device number of a file. This way we are sure that both point to the same fs. Return 0 if not found. */ static dev_t mtab_getdevice(const char *path) { struct stat st; dev_t ret = 0; if (stat(path,&st)!=-1){ ret = st.st_rdev; } return ret; } static int fstab_checkmount( FSTAB_ENTRY *efs, // Entry in fstab FSTAB_ENTRY *emt) // Corresponding entry found in /etc/mtab { int ret = 0; if (emt == NULL){ /* #Specification: fstab / consistency / mount auto Only mount spec with the option "auto" (mount at boot time) are managed during the integrity check. If they are already mount, then a check is done to insure they are corectly mounted. If they are not mounted, nothing is done. */ if (efs->is_auto()){ // Not mount, let's do it net_prtlog (NETLOG_WHY,MSG_U(I_NOTMOUNTED ,"%s is not mounted\n"),efs->getsource()); ret = efs->domount (); } }else{ /* If the mount was done using the loopback, we have a situation The user is allowed to tell which loopback is used. In /etc/mtab, it always contains which one was used. If the user specified which one, we must check if it is properly mounted. If the user did not specify it, we avoid the check. The format_opt will format the loop option either as "loop" or "loop=/dev...". So if the user did not specify which device, we clear it in the emt (and restore it after). */ SSTRING emt_loopdev,efs_loopdev; bool emt_loop = emt->getloop(emt_loopdev); efs->getloop(efs_loopdev); if (efs_loopdev.is_empty()) emt->setloop (emt_loop,""); char old_opt[200]; emt->format_opt (false,old_opt); char new_opt[200]; efs->format_opt (false,new_opt); emt->setloop (emt_loop,emt_loopdev.get()); const char *efs_source = efs->getsource(); if (strncasecmp(efs_source,"label=",6)==0){ const char *s = partition_findfromlabel(efs_source+6); if (s != NULL) efs_source=s; } const char *emt_source = emt->getsource(); dev_t efs_dev = mtab_getdevice(efs_source); dev_t emt_dev = mtab_getdevice(emt_source); bool source_differ = false; if (efs_dev != 0){ source_differ = efs_dev != emt_dev; }else{ source_differ = strcmp(efs_source,emt_source)!=0; } if (source_differ){ /* #Specification: fstab / consistency / changing mount source When we detect that the source of a mount has changed (for a given mount point), we must ask the operator for a permission to unmount and mount again. A failure to answer we be taken as a "NO, don't do it" after a timeout which may be active for this session. Anyway, this will often fail because something is currently accessing the mounted resource. */ char buf[1000]; sprintf (buf,MSG_U(I_FIXMOUNT ,"The directory %s was originally mounted\n" "on %s. It should now be mounted\n" "on %s.\n" "\n" "Should I unmount/mount to fix it ?") ,efs->getmpoint(),emt->getsource(),efs->getsource()); if (simul_ison() || dialog_yesno(MSG_U(Q_FIXMOUNT,"Fix target of a mount") ,buf,help_mtab)==MENU_YES){ // Pretty much the same message as above, but on a single line net_prtlog (NETLOG_WHY,MSG_U(I_NEWSOURCE ,"Directory %s was mounted on %s, should be %s\n") ,efs->getmpoint(),emt->getsource(),efs->getsource()); ret = efs->doumount(); if (ret == 0) ret = efs->domount (); } }else if(strcmp(old_opt,new_opt)!=0){ /* #Specification: fstab / consistency / changing mount option When we detect that the options of a mount have changed (for a given mount point), we must ask the operator for a permission to remount. A failure to answer we be taken as a "NO, don't do it" after a timeout which may be active for this session. Anyway, this will often fail because something is currently accessing the mounted resource. */ char buf[1000]; sprintf (buf,MSG_U(I_REMOUNT ,"The directory %s was originally mounted\n" "with option %s.\n" "It should now be mounted\n" "with options %s.\n" "\n" "Should I remount to fix it ?") ,efs->getmpoint(),old_opt,new_opt); if (simul_ison() || dialog_yesno(MSG_U(Q_REMOUNT,"activate new mount options") ,buf,help_mtab)==MENU_YES){ net_prtlog (NETLOG_WHY,MSG_U(I_NEWMOUNTOPTS ,"Directory %s was originally mounted with option %s\n") ,efs->getmpoint(),old_opt); int len = sprintf (buf,new_opt[0] == '\0' ? "-o remount" : "-o remount,%s" ,new_opt); sprintf (buf+len," %s",efs->getmpoint()); ret = netconf_system_if("mount",buf); } } } return ret; } /* Return true if this fstab entry is currently mounted */ PUBLIC bool FSTAB_ENTRY::is_mounted() { MTAB mtab; return mtab.locate_mpoint(getmpoint()) != NULL; } /* Check that all mountable file system are currently mounted. */ int fstab_checkmount( bool local_fs) // Local or network mount { FSTAB fstab; MTAB mtab; /* #Specification: fstab / check fstab and mtab Linuxconf can check if all file system specified in /etc/fstab are currently mounted. Furthermore it can even check that something else is mounted in place of what is specified in /etc/fstab. In this situation it will umount and remount. This situation generally occur when we edit /etc/fstab, changing the source (server) of a volume. However, linuxconf will not unmount something that is not specify in /etc/fstab. The mount may have been done manually or by an automounter. */ int nbfs = fstab.getnb(); int ret = 0; for (int i=0; iis_valid()){ FSTAB_ENTRY_TYPE type = efs->gettype(); const char *mpoint = efs->getmpoint(); FSTAB_ENTRY *emt = mtab.locate_mpoint(mpoint); if (type == FSTAB_ENTRY_PROC){ // We check if /proc is mounted using a different strategy // because it is not always part of /etc/mtab // as seen in RedHat 5.0 char pathcmd[PATH_MAX]; sprintf (pathcmd,"%s/cmdline",mpoint); if (!file_exist (pathcmd) && efs->is_auto()){ // Not mount, let's do it net_prtlog (NETLOG_WHY,MSG_R(I_NOTMOUNTED) ,efs->getsource()); ret |= efs->domount (); } }else if (local_fs){ if (type == FSTAB_ENTRY_LOCAL || type == FSTAB_ENTRY_PROC){ ret |= fstab_checkmount (efs,emt); } }else{ if (type == FSTAB_ENTRY_NFS){ ret |= fstab_checkmount (efs,emt); } } } } return ret; }