#include #include #include #include #include #include "fstab.h" #include "../paths.h" #include #include "internal.h" #include "fstab.m" #include #include #include FSTAB_HELP_FILE help_mount ("mountpoint"); extern FSTAB_HELP_FILE help_fstab; static FSTAB_HELP_FILE help_control ("ctrlmount"); static FSTAB_HELP_FILE help_manualnfs ("manualnfs"); /* Return the numeric value of a SSTRING or a default value */ static int fstab_get_opt_val(SSTRING &str, int defval) { int ret = defval; if (!str.is_empty()){ ret = str.getval(); } return ret; } static int fstab_rootaccess() { return perm_rootaccess("to maintain volumes"); } /* Unmount interactivly a file system Return -1 if any error */ PUBLIC int FSTAB_ENTRY::umount_control() { int ret = -1; if (fstab_rootaccess() && dialog_yesno (MSG_U(Q_UMOUNT,"Unmount file system") ,MSG_U(I_UMOUNT,"Do you want to unmount this file system") ,help_control)==MENU_YES){ ret = doumount(); if (ret == 0){ xconf_notice (MSG_U(N_UMOUNTOK,"Umount successful")); }else{ net_showlastlog(); } } return ret; } /* Mount interactivly a file system Return -1 if any error */ PUBLIC int FSTAB_ENTRY::mount_control() { int ret = -1; if (fstab_rootaccess() && dialog_yesno (MSG_U(Q_MOUNT,"Mount file system") ,MSG_U(I_MOUNT,"Do you want to mount this file system") ,help_control)==MENU_YES){ ret = domount(); if (ret == 0){ xconf_notice (MSG_U(N_MOUNTOK,"Mount successful")); }else{ net_showlastlog(); } } return ret; } static char K_NFSID[]="nfsid"; static char K_LOCALID[]="localid"; /* Edit one entry of the /etc/fstab file. Return 0 if the user accepted the changes Return -1 if the user escape the dialog Return 1 if the user want to delete this entry */ PUBLIC int FSTAB_ENTRY::edit(FSTAB_ENTRY_TYPE fstype) { DIALOG dia; SSTRING server,volume; dia.newf_title (MSG_U(P_BASE,"Base"),1,"",MSG_R(P_BASE)); if (fstype == FSTAB_ENTRY_NFS){ dia.set_registry_id (K_NFSID); server = source; const char *pt = server.strchr(':'); if (pt != NULL){ volume = pt+1; server.truncate (pt); } dia.newf_str (MSG_U(F_SERVER,"Server"),server); dia.newf_str (MSG_U(F_VOLUME,"Volume"),volume); type.setfrom ("nfs"); }else if (fstype == FSTAB_ENTRY_SAMBA){ const char *pt = source.get(); while (*pt == '/') pt++; server = pt; pt = server.strchr ('/'); if (pt != NULL){ volume = pt+1; server.truncate (pt); } dia.newf_str (MSG_R(F_SERVER),server); dia.newf_str (MSG_U(F_SHARE,"Share"),volume); type.setfrom ("smbfs"); }else{ dia.set_registry_id (K_LOCALID); FIELD_COMBO *co = dia.newf_combo(MSG_U(F_PARTITION,"Partition") ,source); PARTITIONS *parts = partition_load(); for (int i=0; igetnb(); i++){ PARTITION *p = parts->getitem(i); SSTRING bufstr; p->formatinfo (bufstr,false); const char *str = bufstr.get(); if (fstype == FSTAB_ENTRY_SWAP){ if (p->isswap()) co->addopt(p->getdevice(),str); }else{ if (p->isdos() || p->islinux()){ co->addopt(p->getdevice(),str); } SSTRING label; if (p->readlabel(label)!=-1){ SSTRING line; line.setfromf("LABEL=%s",label.get()); co->addopt(line.get(),str); } } } dia.last_noempty(); if (fstype == FSTAB_ENTRY_SWAP){ type.setfrom ("swap"); mpoint.setfrom ("none"); }else{ FIELD_COMBO *cot = dia.newf_combo(MSG_U(F_TYPE,"Type"),type); cot->addopt("ext3",MSG_U(F_EXT3,"Standard Linux with journalling")); cot->addopt("ext2",MSG_U(F_EXT2,"Standard Linux")); cot->addopt("reseirfs",MSG_U(F_RESEIRFS,"Btree based fs")); cot->addopt("xfs",MSG_U(F_XFS,"SGI high performance fs")); cot->addopt("jfs",MSG_U(F_JFS,"IBM journalling fs")); cot->addopt("minix",MSG_U(F_MINIX,"Sometime for floppy")); cot->addopt("msdos"," "); cot->addopt("umsdos",MSG_U(F_UMSDOS,"Superset of msdos")); cot->addopt("vfat",MSG_U(F_VFAT,"DOS with long file name")); cot->addopt("hpfs",MSG_U(F_OS2,"OS/2 High Performance FS")); cot->addopt("sysv",MSG_U(F_UNIXV,"Unix system V old fs")); cot->addopt("xiafs",MSG_U(F_XIAFS,"Old linux fs")); cot->addopt("iso9660",MSG_U(F_ISOFS,"Cdrom file system")); dia.last_noempty(); } } if (fstype != FSTAB_ENTRY_SWAP){ dia.newf_str (MSG_U(F_MPOINT,"Mount point"),mpoint); dia.last_noempty(); dia.newf_title (MSG_U(P_OPTIONS,"Options"),1,"" ,MSG_U(T_GENOPTIONS,"General options")); dia.newf_chk (MSG_U(F_OPTIONS,"Options"),bool_opt.readonly ,MSG_U(F_READONLY,"Read only")); dia.newf_chk ("",bool_opt.user,MSG_U(F_USERMNT,"User mountable")); dia.newf_chk ("",bool_opt.owner,MSG_U(F_OWNERMNT,"Mountable by device owner")); dia.newf_chk ("",bool_opt.noauto,MSG_U(F_BOOTTIME,"Not mount at boot time")); dia.newf_chk ("",bool_opt.usrquota,MSG_U(F_USRQUOTA,"User quota enabled")); dia.newf_chk ("",bool_opt.grpquota,MSG_U(F_GRPQUOTA,"Group quota enabled")); dia.newf_title (MSG_U(P_SECURITY,"Security"),1,"",MSG_R(P_SECURITY)); dia.newf_chk ("",bool_opt.noexec,MSG_U(F_NOEXEC,"No program allowed to execute")); dia.newf_chk ("",bool_opt.nodev,MSG_U(F_NOSPC,"No special device file support")); dia.newf_chk ("",bool_opt.nosuid,MSG_U(F_NOSUID,"No setuid programs allowed")); } SSTRING msdos_uid,msdos_gid,msdos_umask; SSTRING nfs_rsize,nfs_wsize; GROUPS groups; groups.sortbyname(); USERS users; users.sortbyname(); if (fstype == FSTAB_ENTRY_LOCAL){ dia.newf_title (MSG_U(P_MSDOS,"Dos options"),1,"" ,MSG_U(T_MSOPT,"(U)MsDOS and HPFS options")); USER *user = users.getfromuid(msdos_opt.uid); if (user != NULL){ msdos_uid.setfrom(user->getname()); }else if (msdos_opt.uid != MSDOS_OPT_UNUSE){ msdos_uid.setfrom(msdos_opt.uid); } FIELD_COMBO *cv = dia.newf_combo (MSG_U(F_DEFUID,"default user id") ,msdos_uid); int i; for (i=0; iaddopt(user->getname(),user->getgecos()); } GROUP *grp = groups.getfromgid(msdos_opt.gid); if (grp != NULL){ msdos_gid.setfrom(grp->getname()); }else if(msdos_opt.gid != MSDOS_OPT_UNUSE){ msdos_gid.setfrom(msdos_opt.gid); } cv = dia.newf_combo (MSG_U(F_DEFGID,"default group id"), msdos_gid); for (i=0; iaddopt(grp->getname()); } if (msdos_opt.perm != MSDOS_OPT_UNUSE){ msdos_umask.setfrom (msdos_opt.perm); } dia.newf_str (MSG_U(F_DEFPERM,"default permission") , msdos_umask); FIELD_COMBO *conv = dia.newf_combo ( MSG_U(F_TRAMODE,"translation mode") ,msdos_opt.conv); conv->addopt ("binary",MSG_U(F_NOTRA,"No file translation")); conv->addopt ("auto",MSG_U(F_EXTTRA,"Translate based on extension")); conv->addopt ("text",MSG_U(F_ALWTRANS,"Always translate")); }else if (fstype == FSTAB_ENTRY_NFS){ dia.newf_title (MSG_U(T_NFSOPT,"NFS options"),1,"",MSG_R(T_NFSOPT)); dia.newf_chk ("",nfs_opt.soft,MSG_U(F_SOFTMNT,"Soft mount")); dia.newf_chk ("",nfs_opt.bg,MSG_U(F_BGMOUNT,"Background mount")); dia.newf_chk ("",nfs_opt.nolock,MSG_U(F_NOLOCKMNT, "Nolock mount")); if (nfs_opt.rsize != NFS_OPT_UNUSE){ nfs_rsize.setfrom(nfs_opt.rsize); } dia.newf_str (MSG_U(F_READSIZE,"read size"),nfs_rsize); if (nfs_opt.wsize != NFS_OPT_UNUSE){ nfs_wsize.setfrom(nfs_opt.wsize); } dia.newf_str (MSG_U(F_WRITESIZE,"write size"),nfs_wsize); } dia.newf_title (MSG_U(P_MISC,"Misc."),1,"",""); dia.newf_str(MSG_U(F_OTHEROPT,"Other options"),options); dia.newf_str(MSG_U(F_COMMENT,"Comment"),comment); if (fstype == FSTAB_ENTRY_LOCAL){ dia.newf_chk ("",bool_opt.acl,MSG_U(F_ACLOPT,"Posix ACLs")); dia.newf_chk ("",bool_opt.loop,MSG_U(F_LOOPOPT,"The device is a file (loop)")); dia.newf_str (MSG_U(F_LOOPDEV,"Loop device (opt)"),loopdev); dia.newf_num (MSG_U(F_DUMPFREQ,"Dump frequency"),dumpfreq); static int vals[]={0,0}; static const char *valsopt[]={MSG_U(I_NEVER,"Never"),NULL}; dia.newf_chkm_num (MSG_U(F_CHKPRI,"Fsck priority"),fsckpriority ,1,vals,valsopt); } int extra_buttons = 0; if (fstype != FSTAB_ENTRY_SWAP){ dia.setbutinfo (MENU_USR1,MSG_U(B_MOUNT,"Mount"),MSG_R(B_MOUNT)); dia.setbutinfo (MENU_USR2,MSG_U(B_UMOUNT,"Unmount"),MSG_R(B_UMOUNT)); extra_buttons = MENUBUT_USR1|MENUBUT_USR2; } int ret = -1; int nof = 0; while (1){ MENU_STATUS code = dia.edit( MSG_U(T_VOLSPEC,"Volume specification") ,MSG_U(I_VOLSPEC,"You must enter the specification of a volume\n" "or partition and the position (mount point)\n" "where you want to install this volume\n" "in the directory structure of this workstation\n") ,help_mount ,nof,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL |extra_buttons); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_DEL){ if (xconf_areyousure(MSG_U(Q_DELENTRY ,"Confirm deletion of /etc/fstab entry"))){ ret = 1; break; } }else{ if (!fstab_rootaccess()) continue; dia.save(); if (code == MENU_USR1){ if (is_mounted()){ xconf_error (MSG_U(E_ISMOUNTED ,"This file system is already mounted")); }else{ mount_control(); } }else if (code == MENU_USR2){ if (!is_mounted()){ xconf_error (MSG_U(E_ISNOTMOUNTED ,"This file system is not mounted")); }else{ umount_control (); } }else if (code == MENU_ACCEPT){ if (fstype == FSTAB_ENTRY_NFS){ source.setfromf ("%s:%s",server.get(),volume.get()); nfs_opt.rsize = fstab_get_opt_val(nfs_rsize ,NFS_OPT_UNUSE); nfs_opt.wsize = fstab_get_opt_val(nfs_wsize ,NFS_OPT_UNUSE); }else if (fstype == FSTAB_ENTRY_SAMBA){ source.setfromf ("//%s/%s",server.get(),volume.get()); }else{ if (msdos_gid.is_empty()){ msdos_opt.gid = MSDOS_OPT_UNUSE; }else{ GROUP *grp = groups.getitem(msdos_gid.get()); if (grp != NULL){ msdos_opt.gid = grp->getgid(); }else{ msdos_opt.gid = fstab_get_opt_val( msdos_gid,MSDOS_OPT_UNUSE); } } if (msdos_uid.is_empty()){ msdos_opt.uid = MSDOS_OPT_UNUSE; }else{ USER *usr = users.getitem(msdos_uid.get()); if (usr != NULL){ msdos_opt.uid = usr->getuid(); }else{ msdos_opt.uid = fstab_get_opt_val( msdos_uid,MSDOS_OPT_UNUSE); } } msdos_opt.perm = fstab_get_opt_val( msdos_umask,MSDOS_OPT_UNUSE); } valid = 1; if (check() == 0){ // Reformat the fstab original line SSTREAM_BUF ss; ss.printf ("%s\t%s\t%s\t",source.get(),mpoint.get() ,type.get()); char str[200]; format_opt (true,str); ss.printf (" %s %d %d",str,dumpfreq,fsckpriority); original.setfrom (ss.getbuf()); ret = 0; break; } } } } if (ret != 0) dia.restore(); return ret; } #define _TLMP_fstabsel struct _F_fstabsel{ #define _F_fstabsel_editone(x) void x editone(int no) virtual _F_fstabsel_editone( )=0; #define _F_fstabsel_add(x) void x add() virtual _F_fstabsel_add( ); }; void _F_fstabsel::add(){} /* Edit, add, delete entry of /etc/fstab. seltype: 0 local partition 1 Remote volume 2 swap */ static void fstabsel ( _F_fstabsel &c, FSTAB *fs, FSTAB_ENTRY_TYPE fstype, bool may_add, const char *intro, HELP_FILE &help) { glocal _F_fstabsel *c = &c; glocal FSTAB *fs = fs; glocal FSTAB_ENTRY_TYPE fstype = fstype; glocal bool may_add = may_add; glocal bool part_show = fstype == FSTAB_ENTRY_LOCAL || fstype == FSTAB_ENTRY_SWAP; glocal PARTITIONS *parts = glocal.part_show ? partition_load() : (PARTITIONS*)NULL; static const char *tbfs[]={ MSG_U(T_LOCALVOL,"Local volume"), MSG_U(T_NFSVOL,"NFS volume"), MSG_U(T_SMBVOL,"SMB volume"), MSG_U(T_SWAPSPACE,"Swap space"), MSG_U(T_NOVELL,"NOVELL volume") }; (tbfs[fstype],intro,help); newf_head (glocal.part_show ? MSG_U(H_FSTAB,"Source\tMount point\tFsType\t Size\tPartition type\tStatus") : MSG_U(H_FSTABNET,"Source\tMount point\tFsType\tStatus") ); if (glocal.may_add){ addwhat(MSG_U(I_ADDDEF,"Select [Add] to add a new definition")); } sortable(); sortpolicy (glocal.part_show ? "aaana" : "aaaa"); int nb = glocal.fs->size(); for (int i=0; igetitem(i); if (ent->is_valid() && ent->gettype() == glocal.fstype){ const char *source = ent->getsource(); SSTRING str; if (glocal.part_show){ struct stat64 s; PARTITION *p = glocal.parts != NULL ? glocal.parts->getitem(source) : (PARTITION*)NULL; if (p != NULL){ p->formatinfo (str,false); }else if (stat64(source,&s)!=-1 && s.st_size > 0){ str.setfromf("%7ldM\t",s.st_size/(1024*1024l)); }else if (glocal.part_show){ str = "\t"; } str.append ('\t'); } new_menuitemf (source,"%s\t%s\t%s%s" ,ent->getmpoint(),ent->getfs(),str.get() ,ent->is_mounted() ? MSG_U(I_MOUNTED,"Mounted") : ""); set_lookup (i); } } glocal.c->editone (no); glocal.c->add(); } PUBLIC void FSTAB::edit (FSTAB_ENTRY_TYPE fstype) { glocal FSTAB *fs = this; glocal FSTAB_ENTRY_TYPE fstype = fstype; (this,fstype,true ,MSG_U(I_MOUNTS,"You can edit, add, or delete mounts") ,help_fstab); FSTAB_ENTRY *ent = glocal.fs->getitem(no); int ok = ent->edit(glocal.fstype); if (ok != -1){ if (ok == 1) glocal.fs->remove_del (ent); glocal.fs->write(); } if (fstab_rootaccess()){ FSTAB_ENTRY *ent = new FSTAB_ENTRY(); if (ent->edit(glocal.fstype)==0){ glocal.fs->add (ent); glocal.fs->write(); }else{ delete ent; } } } /* Mount/Umount file systems from a menu */ PUBLIC void FSTAB::control (FSTAB_ENTRY_TYPE fstype) { glocal FSTAB *fs = this; (this,fstype,false ,MSG_U(I_CTRLMOUNTS,"You can mount or unmount file systems") ,help_control); FSTAB_ENTRY *ent = glocal.fs->getitem(no); if (fstab_rootaccess()){ if (ent->is_mounted()){ ent->umount_control(); }else{ ent->mount_control(); } } } /* Edit, add, delete entry of /etc/fstab */ void fstab_edit (FSTAB_ENTRY_TYPE fstype) { FSTAB fs; fs.edit (fstype); } static void fstab_manualnfs() { DIALOG dia; SSTRING server,volume,mpoint; dia.newf_str (MSG_R(F_SERVER),server); dia.last_noempty(); dia.newf_str (MSG_R(F_VOLUME),volume); dia.last_noempty(); dia.newf_str (MSG_R(F_MPOINT),mpoint); dia.last_noempty(); int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_MANUALNFS,"Mounting manually") ,MSG_U(I_MANUALNFS,"You can extend the current file system tree\n" "by appending one NFS volume anywhere") ,help_manualnfs ,nof); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (fstab_rootaccess()){ if (file_type (mpoint.get())!=1){ xconf_error (MSG_U(E_NOMPT,"Mount point directory does not exist")); nof = 2; }else{ char buf[2*PATH_MAX]; snprintf (buf,sizeof(buf)-1,"%s:%s %s",server.get() ,volume.get(),mpoint.get()); if (netconf_system_if ("mount",buf)!=-1) break; } } } } /* Let the admin mount/unmount file systems */ void fstab_control () { int choice=0; static const char *local_partition = MSG_U(M_CTRLLOCAL,"Control configured local drives"); static const char *remote_nfs = MSG_U(M_CTRLNFS,"Control configured nfs volumes"); static const char *manual_nfs = MSG_U(M_MANUAL,"Mount other NFS file systems"); static const char *menuopt[]={ "", local_partition, "", remote_nfs, "", manual_nfs, NULL }; DIALOG_MENU dia; dia.new_menuitems (menuopt); while (1){ MENU_STATUS code = dia.editmenu ( MSG_U(T_FSCONTROL,"Control file systems") ,MSG_U(I_FSCONTROL,"You can mount/unmount file systems from here") ,help_control ,choice,0); if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else{ const char *key = dia.getmenustr (choice); FSTAB fstab; if (key == local_partition){ fstab.control (FSTAB_ENTRY_LOCAL); }else if (key == remote_nfs){ fstab.control (FSTAB_ENTRY_NFS); }else if (key == manual_nfs){ fstab_manualnfs(); } } } } #include static void fstab_type_locate ( FSTAB_ENTRY_TYPE fstype, const char *mpoint, bool setting) { FSTAB fstab; FSTAB_ENTRY *ent = fstab.locate_mpoint(mpoint); if (ent != NULL){ if (ent->gettype()==fstype){ if (ent->edit(fstype)==0) fstab.write(); } }else if (setting){ ent = new FSTAB_ENTRY; if (ent->edit(fstype)==0){ fstab.add (ent); fstab.write(); }else{ delete ent; } } } static void fstab_type_list ( FSTAB_ENTRY_TYPE fstype, SSTRINGS &tb) { FSTAB fstab; for (int i=0; igettype()==fstype){ tb.add (new SSTRING(ent->getmpoint())); } } } static void fstab_local_locate (const char *mpoint, bool setting) { fstab_type_locate (FSTAB_ENTRY_LOCAL,mpoint,setting); } static void fstab_local_list (SSTRINGS &tb) { fstab_type_list (FSTAB_ENTRY_LOCAL,tb); } static PUBLISH_VARIABLES_MSG fstab_var_list1[]={ {"partition",P_MSG_R(F_PARTITION)}, {"type",P_MSG_R(F_TYPE)}, {"mountpoint",P_MSG_R(F_MPOINT)}, {"readonly",P_MSG_R(F_READONLY)}, {"user",P_MSG_R(F_USERMNT)}, {"owner",P_MSG_R(F_OWNERMNT)}, {"noauto",P_MSG_R(F_BOOTTIME)}, {"noexec",P_MSG_R(F_NOEXEC)}, {"nospecial",P_MSG_R(F_NOSPC)}, {"nosetuid",P_MSG_R(F_NOSUID)}, {"usrquota",P_MSG_R(F_USRQUOTA)}, {"grpquota",P_MSG_R(F_GRPQUOTA)}, { NULL, NULL } }; static REGISTER_VARIABLES fstab_registry1("fstab-local","locals" ,fstab_var_list1,K_LOCALID,fstab_local_locate,fstab_local_list); static void fstab_nfs_locate (const char *mpoint, bool setting) { fstab_type_locate (FSTAB_ENTRY_NFS,mpoint,setting); } static void fstab_nfs_list (SSTRINGS &tb) { fstab_type_list (FSTAB_ENTRY_NFS,tb); } static PUBLISH_VARIABLES_MSG fstab_var_list2[]={ {"server",P_MSG_R(F_SERVER)}, {"volume",P_MSG_R(F_VOLUME)}, {"mountpoint",P_MSG_R(F_MPOINT)}, {"readonly",P_MSG_R(F_READONLY)}, {"user",P_MSG_R(F_USERMNT)}, {"owner",P_MSG_R(F_OWNERMNT)}, {"noauto",P_MSG_R(F_BOOTTIME)}, {"noexec",P_MSG_R(F_NOEXEC)}, {"nospecial",P_MSG_R(F_NOSPC)}, {"nosetuid",P_MSG_R(F_NOSUID)}, { NULL, NULL } }; static REGISTER_VARIABLES fstab_registry2("fstab-nfs","dirs" ,fstab_var_list2,K_NFSID,fstab_nfs_locate,fstab_nfs_list);