#include #include #include #include #include "fstab.h" #include "../paths.h" #include "internal.h" FSTAB_HELP_FILE help_fstab ("fstab"); static CONFIG_FILE f_fstab (ETC_FSTAB,help_fstab ,CONFIGF_MANAGED|CONFIGF_NOARCH|CONFIGF_DIST); class CONFIG_FILE_FSTAB: public CONFIG_FILE{ bool local; /*~PROTOBEG~ CONFIG_FILE_FSTAB */ public: CONFIG_FILE_FSTAB (const char *_path, bool _local, const char *subsys); int archive (SSTREAM&ss)const; int extract (SSTREAM&ss); private: void walk_do (FSTAB&fs, bool del, SSTREAM *ss)const; public: /*~PROTOEND~ CONFIG_FILE_FSTAB */ }; PUBLIC CONFIG_FILE_FSTAB::CONFIG_FILE_FSTAB( const char *_path, bool _local, // Archive local aspect of the file const char *subsys) : CONFIG_FILE (_path,help_fstab,CONFIGF_MANAGED|CONFIGF_VIRTUAL ,subsys) { local = _local; } PRIVATE void CONFIG_FILE_FSTAB::walk_do( FSTAB &fs, bool del, SSTREAM *ss) const { int n = fs.getnb(); int last_comment = 0; for (int i=0; iis_valid()){ if (e->is_remote()){ if (!local) must_do = true; }else if (local){ must_do = true; } if (must_do){ if (del){ for (int j=last_comment; j<=i; j++){ fs.remove_del (last_comment); } int nbdel = i-last_comment + 1; i-=nbdel; n-=nbdel; }else{ for (int j=last_comment; j<=i; j++){ if (ss != NULL) fs.getitem(j)->print (*ss); } } } last_comment = i+1; } } } PUBLIC int CONFIG_FILE_FSTAB::archive(SSTREAM &ss) const { configf_sendexist (ss,true); FSTAB fs; walk_do (fs,false,&ss); return 0; } PUBLIC int CONFIG_FILE_FSTAB::extract(SSTREAM &ss) { FSTAB fs; walk_do (fs,true,NULL); char line[1000]; while (ss.gets(line,sizeof(line)-1) != NULL){ strip_end (line); fs.add (new FSTAB_ENTRY(line)); } return fs.write(); } static CONFIG_FILE_FSTAB fstab_local (ETC_FSTAB "-local",true,subsys_hardware); static CONFIG_FILE_FSTAB fstab_remfs (ETC_FSTAB "-remfs",false,subsys_netclient); PRIVATE void FSTAB_ENTRY::init() { valid = 0; memset (&bool_opt,0,sizeof(bool_opt)); msdos_opt.uid = msdos_opt.gid = msdos_opt.perm = MSDOS_OPT_UNUSE; nfs_opt.rsize = nfs_opt.wsize = NFS_OPT_UNUSE; nfs_opt.soft = nfs_opt.bg = nfs_opt.nolock = 0; dumpfreq = fsckpriority = 1; } PUBLIC FSTAB_ENTRY::FSTAB_ENTRY() { init(); } /* Analyse the option string xxx,yyy,zzz=val,... Some option are "known" by fsconf. Unknown one are left in an "option" string editable by the user. The known one have there own field in the FSTAB_ENTRY structure. */ PUBLIC void FSTAB_ENTRY::parseopt(char *opts) { char other[200]; other[0] = '\0'; while (*opts != '\0'){ char *debut = opts; char *equal = ""; bool seen_equal = false; while (1){ char *pt_carac = opts; char carac = *opts++; if (carac == '\0'){ opts--; break; }else if (carac == ','){ *pt_carac = '\0'; break; }else if (carac == '='){ equal = opts; *pt_carac = '\0'; seen_equal = true; } } if (strcmp(debut,"defaults")==0){ // Do nothing here. The keyword defaults // is silently write back if no other option // is specified. }else if (strcmp(debut,"conv")==0){ msdos_opt.conv.setfrom(equal); }else if (strcmp(debut,"uid")==0){ msdos_opt.uid = atoi(equal); }else if (strcmp(debut,"gid")==0){ msdos_opt.gid = atoi(equal); }else if (strcmp(debut,"umask")==0){ msdos_opt.perm = atoi(equal); }else if (strcmp(debut,"noexec")==0){ bool_opt.noexec = 1; }else if (strcmp(debut,"exec")==0){ bool_opt.noexec = 0; }else if (strcmp(debut,"nosuid")==0){ bool_opt.nosuid = 1; }else if (strcmp(debut,"suid")==0){ bool_opt.nosuid = 0; }else if (strcmp(debut,"nodev")==0){ bool_opt.nodev = 1; }else if (strcmp(debut,"dev")==0 && !seen_equal){ bool_opt.nodev = 0; }else if (strcmp(debut,"user")==0){ bool_opt.user = 1; bool_opt.nodev = 1; bool_opt.noexec = 1; bool_opt.nosuid = 1; }else if (strcmp(debut,"owner")==0){ bool_opt.owner = 1; }else if (strcmp(debut,"ro")==0){ bool_opt.readonly = 1; }else if (strcmp(debut,"usrquota")==0){ bool_opt.usrquota = 1; }else if (strcmp(debut,"grpquota")==0){ bool_opt.grpquota = 1; }else if (strcmp(debut,"rw")==0){ bool_opt.readonly = 0; }else if (strcmp(debut,"noauto")==0){ bool_opt.noauto = 1; }else if (strcmp(debut,"auto")==0){ bool_opt.noauto = 0; }else if (strcmp(debut,"soft")==0){ nfs_opt.soft = 1; }else if (strcmp(debut,"bg")==0){ nfs_opt.bg = 1; }else if (strcmp(debut,"nolock")==0){ nfs_opt.nolock = 1; }else if (strcmp(debut,"rsize")==0){ nfs_opt.rsize = atoi(equal); }else if (strcmp(debut,"wsize")==0){ nfs_opt.wsize = atoi(equal); }else if (strcmp(debut,"loop")==0){ bool_opt.loop = true; loopdev = equal; }else if (strcmp(debut,"addr")!=0){ // This is the other option still unknown by linuxconf // note that the simili addr option used by NFS in /etc/mtab // is ignored. if (other[0] != '\0') strcat (other,","); strcat (other,debut); if (seen_equal){ strcat (other,"="); strcat (other,equal); } } } options.setfrom (other); } /* Build an FSTAB_ENTRY from a line of the /etc/fstab file */ PUBLIC FSTAB_ENTRY::FSTAB_ENTRY (const char *line) { original.setfrom (line); init(); line = str_skip (line); if (*line != '\0'){ if (*line == '#'){ comment.setfrom(line); }else{ char buf[1000]; strcpy (buf,line); char *pt1 = strtok (buf," \t"); char *pt2 = strtok (NULL," \t"); char *pt3 = strtok (NULL," \t"); char *pt4 = strtok (NULL," \t"); char *pt5 = strtok (NULL," \t"); char *pt6 = strtok (NULL," \t"); if (pt4 != NULL && strcmp(pt3,"ignore")!=0){ source.setfrom(pt1); mpoint.setfrom(pt2); type.setfrom (pt3); parseopt (pt4); if (pt5 != NULL) dumpfreq = atoi(pt5); if (pt6 != NULL) fsckpriority = atoi(pt6); valid = 1; /* #Spécification: /etc/fstab / auto-fixing There is different errors in many /etc/fstab which are generally ignore by mount utility. Nevertheless those /etc/fstab are broken. Linuxconf automatically repairs some of those errors. # proc fs: the source is set to none, whatever was written there # */ if (gettype()==FSTAB_ENTRY_PROC) source.setfrom("none"); }else{ comment.setfrom(str_skip(line)); } } } } static void opt_put_if ( char *out, char bool_opt, const char *name, bool &was_written) { if (bool_opt){ if (was_written) strcat (out,","); was_written = true; strcat (out,name); } } static void opt_put_if ( char *out, char bool_opt, const char *noname, const char *name, bool &was_written) { if (was_written) strcat (out,","); was_written = true; strcat (out,bool_opt ? noname : name); } static void opt_put_if ( char *out, int value, const char *name, bool &was_written) { if (value != MSDOS_OPT_UNUSE){ if (was_written) strcat (out,","); was_written = true; char buf[100]; sprintf (buf,"%s=%d",name,value); strcat (out,buf); } } static void opt_put_if ( char *out, const char *value, const char *name, bool &was_written) { if (value[0] != '\0'){ if (was_written) strcat (out,","); was_written = true; char buf[100]; sprintf (buf,"%s=%s",name,value); strcat (out,buf); } } /* Format all the mount option in a string suitable for the mount command if tosave is true, it also adds the options only meaningful in /etc/fstab (user,noauto,...) */ PUBLIC void FSTAB_ENTRY::format_opt(bool tosave, char *str) const { bool one = false; str[0] = '\0'; if (tosave) opt_put_if (str,bool_opt.user,"user",one); char nosuid = bool_opt.nosuid; char nodev = bool_opt.nodev; if (tosave){ opt_put_if (str,bool_opt.owner,"owner",one); }else if (bool_opt.owner){ nosuid = nodev = 1; } opt_put_if (str,bool_opt.noexec,"noexec","exec",one); opt_put_if (str,nodev,"nodev","dev",one); opt_put_if (str,nosuid,"nosuid","suid",one); opt_put_if (str,bool_opt.readonly,"ro","rw",one); opt_put_if (str,bool_opt.usrquota,"usrquota",one); opt_put_if (str,bool_opt.grpquota,"grpquota",one); if (tosave) opt_put_if (str,bool_opt.noauto,"noauto",one); opt_put_if (str,msdos_opt.conv.get(),"conv",one); opt_put_if (str,msdos_opt.uid,"uid",one); opt_put_if (str,msdos_opt.gid,"gid",one); opt_put_if (str,msdos_opt.perm,"umask",one); opt_put_if (str,nfs_opt.bg,"bg",one); opt_put_if (str,nfs_opt.soft,"soft",one); opt_put_if (str,nfs_opt.nolock,"nolock",one); opt_put_if (str,nfs_opt.rsize,"rsize",one); opt_put_if (str,nfs_opt.wsize,"wsize",one); if (bool_opt.loop){ if (loopdev.is_filled()){ opt_put_if (str,loopdev.get(),"loop",one); }else{ if (one) strcat (str,","); strcat (str,"loop"); one = true; } } if (options.is_filled()){ SSTRINGS tb; str_splitline (options.get(),',',tb); for (int i=0; iget(); if (tosave || (strcasecmp(opt,"kudzu")!=0 && strncmp(opt,"user=",5)!=0)){ if (one) strcat (str,","); strcat (str,opt); one = true; } } }else if (!one){ if (tosave) strcpy (str,"defaults"); } } /* Write an entry into /etc/fstab */ PUBLIC void FSTAB_ENTRY::print (SSTREAM &ss) const { ss.printf ("%s\n",original.get()); #if 0 if (valid){ 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); }else{ ss.puts (comment.get()); } ss.putch ('\n'); #endif } /* Return != 0 if this entry is ok (not a comment). */ PUBLIC int FSTAB_ENTRY::is_valid() const { return valid; } /* Tell if this mount should be done at boot time. */ PUBLIC int FSTAB_ENTRY::is_auto() { return !bool_opt.noauto; } /* Return != 0 if the entry describe a mount of a remote volume either with NFS or SMBFS. */ PUBLIC int FSTAB_ENTRY::is_remote() const { return type.cmp("nfs")==0 || type.cmp("smbfs")==0; } /* Return != 0 if the entry describe a swap file or partition. */ PUBLIC int FSTAB_ENTRY::is_swap() const { return type.cmp("swap")==0; } PUBLIC bool FSTAB_ENTRY::has_quota_u() const { return bool_opt.usrquota; } PUBLIC bool FSTAB_ENTRY::has_quota_g() const { return bool_opt.grpquota; } /* Return the file system type ID */ PUBLIC FSTAB_ENTRY_TYPE FSTAB_ENTRY::gettype() const { FSTAB_ENTRY_TYPE ret = FSTAB_ENTRY_LOCAL; if (is_swap()){ ret = FSTAB_ENTRY_SWAP; }else if (type.cmp("nfs")==0){ ret = FSTAB_ENTRY_NFS; }else if (type.cmp("smbfs")==0){ ret = FSTAB_ENTRY_SAMBA; }else if (type.cmp("proc")==0){ ret = FSTAB_ENTRY_PROC; }else if (type.cmp("devpts")==0){ ret = FSTAB_ENTRY_DEVPTS; }else if (type.cmp("tmpfs")==0){ ret = FSTAB_ENTRY_TMPFS; }else if (type.cmp("supermount")==0){ ret = FSTAB_ENTRY_SUPERMOUNT; } return ret; } /* Return the file systeme type (ascii). */ PUBLIC const char *FSTAB_ENTRY::getfs() const { return type.get(); } /* Return the source of the mount (either the device or the remote volume) */ PUBLIC const char *FSTAB_ENTRY::getsource() const { const char *ret = source.get(); if (gettype()==FSTAB_ENTRY_PROC) ret = "none"; return ret; } /* Record a new device / remote volume for a FSTAB_ENTRY */ PUBLIC void FSTAB_ENTRY::setsource(const char *path) { source.setfrom (path); setmodified(); } /* Return the mount point */ PUBLIC const char *FSTAB_ENTRY::getmpoint() const { return mpoint.get(); } PUBLIC bool FSTAB_ENTRY::getloop(SSTRING &dev) { dev = loopdev; return bool_opt.loop; } PUBLIC void FSTAB_ENTRY::setloop (bool on, const char *dev) { bool_opt.loop = on; loopdev = dev; } /* Return the comment of the entry */ PUBLIC const char *FSTAB_ENTRY::getcomment() { return comment.get(); } PUBLIC FSTAB::FSTAB () { FILE_CFG *fin = f_fstab.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(); } /* Return one entry of the fstab file. Returne NULL if the entry is out of range. */ PUBLIC FSTAB_ENTRY *FSTAB_GEN::getitem(int no) { return (FSTAB_ENTRY*)ARRAY::getitem(no); } /* Write a /etc/fstab file Return -1 if any error. */ PUBLIC int FSTAB::write () { int ret = -1; FILE_CFG *fout = f_fstab.fopen ("w"); if (fout != NULL){ ret = 0; SSTREAM_FILE_CFG ss (fout); for (int i=0; iprint (ss); fclose (fout); } return ret; } #ifdef TEST int main (int argc, char *argv[]) { FSTAB fs; fs.write(); return 0; } #endif