diff -ur linux.org/Documentation/Configure.help linux/Documentation/Configure.help --- linux.org/Documentation/Configure.help Thu Sep 12 07:27:33 1996 +++ linux/Documentation/Configure.help Wed Oct 2 13:12:16 1996 @@ -2794,6 +2794,119 @@ writing none of these are available. So it's safest to say N here unless you really know that you need this feature. +Filename translation support +CONFIG_TRANS_NAMES + Normally used only when you want diskless clients to mount the root + filesystem of the server. If unsure, or if you don't have clients, select N. + When selected, filenames, directory names etc become context-sensitive. + If you have a file named "/etc/config#host=banana#", it will appear + (by default) as hardlinked to "/etc/config" on host "banana", while on host + "mango" another file "/etc/config#host=mango#" will appear as been + hardlinked to "/etc/config". The default behaviour can be changed + by setting the _first_ environment variable NAMETRANS to a colon-separated + list of suffixes which are tried in the specified order. For example, + in 'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' the + command will see the same files as if it had been executed on host "mango" + with a diskless kernel. Using NAMETRANS supersedes _all_ default + translations. Thus translations can be generally switched off by an + empty list, e.g. 'env - NAMETRANS= "`env`" command ...'. + Note that some system utililies like tar, dump, restore should + be used with translation switched off, in order to avoid doubled + space in archive files and when extracting from them. Also, make sure + that nfsd, mountd (and similar ones like samba daemons) run without + translation, in order to avoid doubled (or even wrong) translation + at the server and at the client. You can automatically force the creation + of context-dependent filenames if there exists a template filename like + "/etc/mtab#host=CREATE#". As soon as a process running on "mango" tries + to create a file "/etc/mtab", the version "/etc/mtab#host=mango#" is + created instead (which appears as hardlinked to "/etc/mtab"). + Note that if you want to make "/etc/fstab" context-dependend, you should + execute "touch /etc/mtab#host=CREATE#" and + "touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others + running on different hosts would otherwise try to create one shared + /etc/mtab which would result in a clash. Also one should execute + "touch /etc/nologin#host=CREATE#" to prevent global side effects from + shutdown resp. runlevel. + +Failproof translation +CONFIG_TRANS_PROOF + When selected, context-sensitive files will take precedence over + normal files. For example, if you have an ordinary file "/etc/config" + and you later create another file "/etc/config#host=banana#", both + the pseudo-hardlinked version "/etc/config" whose contents is identical + with "/etc/config#host=banana#" and your original "/etc/config" will + appear in your directory listing, showing the name "config" twice + (but perhaps with different length, flags etc). By enabling this option, + you will get the contents of "/etc/config#host=banana#" in preference + over the old "/etc/config" if there is any conflict. You can disable + this option if you are either sure that you have no such conflicts + in your system, or if you explicitly want the original "/etc/config" to take + precedence, or if you absolutely need some small performance gain + when switching this option off. In unsure, say Y. + +Restrict translation to gid +CONFIG_TRANS_RESTRICT + When selected, default translations are carried out only if the parent + directory of the context-sensitive file belongs to a specific group id + (gid). Trying to translate names everywhere will decrease performance of + file openings. Normally translations are used only in system configuration + files but not in ordinary user filespace. So you should change the gid of + directories containing context-dependent files to some special group like + "adm" (group id 4) and enable this option. As a result, users will not + notice any performance degradation resulting from filename translation. + Note that translations resulting from the first environment variable + "NAMETRANS=..." are always carried out regardless of the gid of directories. + Beware, before turning on this option make sure all directories containing + context-dependent files belong to the special group, or system + initialization may fail. In unsure, select N. + +Group id (gid) for translation restriction +CONFIG_TRANS_GID + Default name translations will be carried out only inside directories + belonging to the group id (gid) you can specify here. + Default is 4 (group "adm"). + +Nodename (hostname) translation +CONFIG_TR_NODENAME + Enables translation of name suffixes like in "/etc/config#host=banana#". + The syntax is #host=#. The hostname can be queried + with the command "uname -n". Normally this option is used heavily when + translation is enabled. If unsure, say Y. + +Kerneltype translation +CONFIG_TR_KERNTYPE + Enables translation of name suffixes like in "/etc/config#ktype=default#". + The syntax is #ktype=#. The string is hard compiled + in the kernel by the following option. Use if you want to create + different kernels with different behaviour. For example, use the string + "default" on your server, and use "diskless" on all your diskless clients + (and perhaps "dataless" on dataless clients). This way you can avoid + dozens of "config#host=# with same contents and you have no + effort when new machines are added. If unsure, say Y. + +String for kerneltype translation +CONFIG_KERNTYPE + Enter the string you want to compile into the kernel. The string + will be used as context in context-depenant file like + "/etc/config#ktype=default#". If your kernel is to be used on a server, + you probably can use "default" here. If your kernel is intended for + a diskless client, you probably should enter "diskless" here. + +Machine type translation +CONFIG_TR_MACHINE + Enables translation of name suffixes like in "/etc/config#machine=i486#". + The syntax is #machine=#. The machine types can be queried + with the command "uname -m". Normally used only on multi-architecture + installations. If unsure, say Y. + +System name translation +CONFIG_TR_SYSNAME + Enables translation of name suffixes like in "/etc/config#system=Linux#". + The syntax is #system=#. The system name can be queried + with the command "uname -s". Currently only supportet by Linux, but + hopefully other operating systems will pick up the idea of context-dependent + translations. If unsure, say Y. + Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about diff -ur linux.org/arch/i386/defconfig linux/arch/i386/defconfig --- linux.org/arch/i386/defconfig Mon Aug 5 07:41:50 1996 +++ linux/arch/i386/defconfig Wed Oct 2 13:12:16 1996 @@ -129,6 +129,15 @@ # # CONFIG_QUOTA is not set # CONFIG_LOCK_MANDATORY is not set +# CONFIG_TRANS_NAMES is not set +CONFIG_TRANS_PROOF=y +# CONFIG_TRANS_RESTRICT is not set +CONFIG_TRANS_GID=4 +CONFIG_TR_NODENAME=y +CONFIG_TR_KERNTYPE=y +CONFIG_KERNTYPE="default" +# CONFIG_TR_MACHINE is not set +# CONFIG_TR_SYSNAME is not set CONFIG_MINIX_FS=y # CONFIG_EXT_FS is not set CONFIG_EXT2_FS=y diff -ur linux.org/fs/Config.in linux/fs/Config.in --- linux.org/fs/Config.in Wed Jun 5 12:24:45 1996 +++ linux/fs/Config.in Wed Oct 2 13:12:17 1996 @@ -6,6 +6,22 @@ bool 'Quota support' CONFIG_QUOTA bool 'Mandatory lock support' CONFIG_LOCK_MANDATORY +bool 'Translate filename suffixes' CONFIG_TRANS_NAMES +if [ "$CONFIG_TRANS_NAMES" = "y" ]; then + bool ' Failproof translation mode' CONFIG_TRANS_PROOF + bool ' Restrict translation to specific gid' CONFIG_TRANS_RESTRICT + if [ "$CONFIG_TRANS_RESTRICT" = "y" ]; then + int ' Enter gid to compile in' CONFIG_TRANS_GID 4 + fi + bool ' Translate nodename' CONFIG_TR_NODENAME + bool ' Translate compiled-in kerneltype' CONFIG_TR_KERNTYPE + if [ "$CONFIG_TR_KERNTYPE" = "y" ]; then + string ' Enter kerneltype string to compile in' CONFIG_KERNTYPE 'default' + fi + bool ' Translate machine type' CONFIG_TR_MACHINE + bool ' Translate sysname' CONFIG_TR_SYSNAME +fi + tristate 'Minix fs support' CONFIG_MINIX_FS tristate 'Extended fs support' CONFIG_EXT_FS tristate 'Second extended fs support' CONFIG_EXT2_FS diff -ur linux.org/fs/namei.c linux/fs/namei.c --- linux.org/fs/namei.c Fri Sep 20 12:17:18 1996 +++ linux/fs/namei.c Wed Oct 2 13:17:56 1996 @@ -17,6 +17,8 @@ #include #include #include +#include + #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) @@ -148,6 +150,157 @@ inode->i_writecount--; } +#ifdef CONFIG_TRANS_NAMES + +/* see file readdir.c */ +extern char * env_transl(void); +extern char * transl_names[]; + +/* If a normal filename is seen, try to determine whether a + * "#keyword=context#" file exists and return the new filename. + * If the name is to be created (create_mode), check whether a + * "#keyword=CREATE" name exists and optionally return the corresponding + * context name even if it didn't exist before. + */ +static char* _check_name(struct inode * dir, const char * name, int len, + int create_mode, int * reslen, + struct inode ** result, int * error) +{ + unsigned long page; + char * newname; + char * tmp; + char * p1; + char * p2; + char * env = env_transl(); + char c1; + int newlen; + + if(env && !get_user(env)) + return NULL; +#ifdef CONFIG_TRANS_RESTRICT + if(!env && dir->i_gid != CONFIG_TRANS_GID) + return NULL; +#endif + if(!(page = __get_free_page(GFP_KERNEL))) { + *error = -ENOMEM; + return NULL; + } + newname = tmp = (char *) page; + memcpy(tmp, name, len); + tmp += len; + if(env) { + for(p1 = env; (c1=get_user(p1)); ) { + char* oldpos1 = 0; + char* oldpos2 = 0; + for(p2 = tmp; (c1=get_user(p1)) && c1 != ':'; p1++, p2++) { + *p2 = c1; + if(c1 == '=') { + oldpos1 = p1+1; + oldpos2 = p2+1; + } + } + *p2 = 0; + newlen=(long)p2 - (long)newname; + dir->i_count++; + *error = dir->i_op->lookup(dir,newname,newlen,result); + if(!*error) { + *reslen = newlen; + return newname; + } + if(create_mode && oldpos1) { + char * p1 = "CREATE#"; + char * p2 = oldpos2; + while(*p1) + *p2++ = *p1++; + *p2 = 0; + newlen=(long)p2 - (long)newname; + dir->i_count++; + *error = dir->i_op->lookup(dir,newname,newlen,result); + if(!*error) { + p1 = oldpos1; + p2 = oldpos2; + while((c1=get_user(p1++)) && c1 != ':') + *p2++ = c1; + *p2 = 0; + *reslen=(long)p2 - (long)newname; + return newname; + } + } + if(c1==':') + p1++; + } + } else { + char ** try; + *tmp++ = '#'; + for(try = transl_names; *try; try++) { + char* oldpos; + p1 = *try++; + p2 = tmp; + while(*p1) + *p2++ = *p1++; + oldpos = p2; + p1 = *try; + while(*p1) + *p2++ = *p1++; + *p2++ = '#'; + *p2 = 0; + newlen=(long)p2 - (long)newname; + dir->i_count++; + *error = dir->i_op->lookup(dir,newname,newlen,result); + if(!*error) { + *reslen = newlen; + return newname; + } + if(create_mode) { + p1 = "CREATE#"; + p2 = oldpos; + while(*p1) + *p2++ = *p1++; + *p2 = 0; + newlen=(long)p2 - (long)newname; + dir->i_count++; + *error = dir->i_op->lookup(dir,newname,newlen,result); + if(!*error) { + p1 = *try; + p2 = oldpos; + while(*p1) + *p2++ = *p1++; + *p2++ = '#'; + *p2 = 0; + *reslen=(long)p2 - (long)newname; + return newname; + } + } + } + } + free_page(page); + return NULL; +} + +static char * check_name(struct inode * dir, const char * name, int len, + int create_mode, int * reslen) { + struct inode * dummy = 0; + int error; + char * res = _check_name(dir,name,len,create_mode,reslen,&dummy,&error); + if(res) + iput(dummy); + return res; +} + +/* try with the name suffixed by + * "#keyword=context#". + */ +static inline int try_transl(struct inode * dir, const char * name, int len, + struct inode ** result) { + int error = -ENOENT; + int reslen; + char* dummy = _check_name(dir,name,len,0,&reslen,result,&error); + if(dummy) + putname(dummy); + return error; +} +#endif + /* * lookup() looks up one part of a pathname, using the fs-dependent * routines (currently minix_lookup) for it. It also checks for @@ -188,7 +341,22 @@ *result = dir; return 0; } - return dir->i_op->lookup(dir, name, len, result); +#ifdef CONFIG_TRANS_NAMES + dir->i_count++; +#ifdef CONFIG_TRANS_PROOF + perm = try_transl(dir,name,len,result); + if(perm) +#endif +#endif + perm = dir->i_op->lookup(dir, name, len, result); +#ifdef CONFIG_TRANS_NAMES +#ifndef CONFIG_TRANS_PROOF + if(perm) + perm = try_transl(dir,name,len,result); +#endif + iput(dir); +#endif + return perm; } int follow_link(struct inode * dir, struct inode * inode, @@ -373,12 +541,25 @@ else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) ; /* error is already set! */ else { +#ifdef CONFIG_TRANS_NAMES + char* newname; + int newlen; + newname = check_name(dir,basename,namelen,1,&newlen); + if(newname) { + basename = newname; + namelen = newlen; + } +#endif dir->i_count++; /* create eats the dir */ if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); error = dir->i_op->create(dir, basename, namelen, mode, res_inode); up(&dir->i_sem); iput(dir); +#ifdef CONFIG_TRANS_NAMES + if(newname) + putname(newname); +#endif return error; } up(&dir->i_sem); @@ -464,6 +645,10 @@ const char * basename; int namelen, error; struct inode * dir; +#ifdef CONFIG_TRANS_NAMES + char * newname; + int newlen; +#endif mode &= ~current->fs->umask; error = dir_namei(filename, &namelen, &basename, NULL, &dir); @@ -486,11 +671,21 @@ return -EPERM; } dir->i_count++; +#ifdef CONFIG_TRANS_NAMES + if((newname=check_name(dir,basename,namelen,1,&newlen))) { + basename = newname; + namelen = newlen; + } +#endif if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->mknod(dir,basename,namelen,mode,dev); up(&dir->i_sem); +#ifdef CONFIG_TRANS_NAMES + if(newname) + putname(newname); +#endif iput(dir); return error; } @@ -561,6 +756,10 @@ const char * basename; int namelen, error; struct inode * dir; +#ifdef CONFIG_TRANS_NAMES + char * newname; + int newlen; +#endif error = dir_namei(pathname, &namelen, &basename, NULL, &dir); if (error) @@ -582,11 +781,21 @@ return -EPERM; } dir->i_count++; +#ifdef CONFIG_TRANS_NAMES + if((newname=check_name(dir,basename,namelen,1,&newlen))) { + basename = newname; + namelen = newlen; + } +#endif if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->mkdir(dir, basename, namelen, mode & 01777 & ~current->fs->umask); up(&dir->i_sem); +#ifdef CONFIG_TRANS_NAMES + if(newname) + putname(newname); +#endif iput(dir); return error; } @@ -610,6 +819,10 @@ const char * basename; int namelen, error; struct inode * dir; +#ifdef CONFIG_TRANS_NAMES + char * newname; + int newlen; +#endif error = dir_namei(name, &namelen, &basename, NULL, &dir); if (error) @@ -639,7 +852,23 @@ } if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); - return dir->i_op->rmdir(dir,basename,namelen); +#ifdef CONFIG_TRANS_NAMES + dir->i_count++; +#endif + error = dir->i_op->rmdir(dir,basename,namelen); +#ifdef CONFIG_TRANS_NAMES + if(error == -ENOENT) { + if((newname=check_name(dir,basename,namelen,0,&newlen))) { + basename = newname; + namelen = newlen; + dir->i_count++; + error = dir->i_op->rmdir(dir,basename,namelen); + putname(newname); + } + } + iput(dir); +#endif + return error; } asmlinkage int sys_rmdir(const char * pathname) @@ -661,6 +890,10 @@ const char * basename; int namelen, error; struct inode * dir; +#ifdef CONFIG_TRANS_NAMES + char * newname; + int newlen; +#endif error = dir_namei(name, &namelen, &basename, NULL, &dir); if (error) @@ -690,7 +923,23 @@ } if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); - return dir->i_op->unlink(dir,basename,namelen); +#ifdef CONFIG_TRANS_NAMES + dir->i_count++; +#endif + error = dir->i_op->unlink(dir,basename,namelen); +#ifdef CONFIG_TRANS_NAMES + if(error == -ENOENT) { + if((newname=check_name(dir,basename,namelen,0,&newlen))) { + basename = newname; + namelen = newlen; + dir->i_count++; + error = dir->i_op->unlink(dir,basename,namelen); + putname(newname); + } + } + iput(dir); +#endif + return error; } asmlinkage int sys_unlink(const char * pathname) @@ -711,6 +960,10 @@ struct inode * dir; const char * basename; int namelen, error; +#ifdef CONFIG_TRANS_NAMES + char * new2name; + int new2len; +#endif error = dir_namei(newname, &namelen, &basename, NULL, &dir); if (error) @@ -732,11 +985,21 @@ return -EPERM; } dir->i_count++; +#ifdef CONFIG_TRANS_NAMES + if((new2name=check_name(dir,basename,namelen,1,&new2len))) { + basename = new2name; + namelen = new2len; + } +#endif if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->symlink(dir,basename,namelen,oldname); up(&dir->i_sem); +#ifdef CONFIG_TRANS_NAMES + if(new2name) + putname(new2name); +#endif iput(dir); return error; } @@ -763,6 +1026,10 @@ struct inode * dir; const char * basename; int namelen, error; +#ifdef CONFIG_TRANS_NAMES + char * new2name; + int new2len; +#endif error = dir_namei(newname, &namelen, &basename, NULL, &dir); if (error) { @@ -803,11 +1070,21 @@ return -EPERM; } dir->i_count++; +#ifdef CONFIG_TRANS_NAMES + if((new2name=check_name(dir,basename,namelen,1,&new2len))) { + basename = new2name; + namelen = new2len; + } +#endif if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); error = dir->i_op->link(oldinode, dir, basename, namelen); up(&dir->i_sem); +#ifdef CONFIG_TRANS_NAMES + if(new2name) + putname(new2name); +#endif iput(dir); return error; } @@ -836,6 +1113,12 @@ struct inode * old_dir, * new_dir; const char * old_base, * new_base; int old_len, new_len, error; +#ifdef CONFIG_TRANS_NAMES + char * new2name; + char * old2name; + int new2len; + int old2len; +#endif error = dir_namei(oldname, &old_len, &old_base, NULL, &old_dir); if (error) @@ -891,12 +1174,47 @@ return -EPERM; } new_dir->i_count++; +#ifdef CONFIG_TRANS_NAMES + new2name = 0; + old2name = check_name(old_dir,old_base,old_len,0,&old2len); + if(old2name) { + char * p1 = old2name; + char * p2 = (char*) __get_free_page(GFP_KERNEL); + if(p2) { + const char * p3 = (const char *)new_base; + old_base = old2name; + old_len = old2len; + new2name = p2; + while(new_len--) + *p2++ = *p3++; + while(*p1 != '#') + p1++; + while(*p1) + *p2++ = *p1++; + *p2 = 0; + new_base = new2name; + new_len = (int)p2 - (int)new_base; + } + } else { + new2name = check_name(new_dir,new_base,new_len,1,&new2len); + if(new2name) { + new_base = new2name; + new_len = new2len; + } + } +#endif if (new_dir->i_sb && new_dir->i_sb->dq_op) new_dir->i_sb->dq_op->initialize(new_dir, -1); down(&new_dir->i_sem); error = old_dir->i_op->rename(old_dir, old_base, old_len, new_dir, new_base, new_len, must_be_dir); up(&new_dir->i_sem); +#ifdef CONFIG_TRANS_NAMES + if(old2name) + putname(old2name); + if(new2name) + putname(new2name); +#endif iput(new_dir); return error; } diff -ur linux.org/fs/proc/array.c linux/fs/proc/array.c --- linux.org/fs/proc/array.c Wed Aug 21 08:12:49 1996 +++ linux/fs/proc/array.c Wed Oct 2 13:12:18 1996 @@ -962,6 +962,30 @@ return destptr-buf; } +#ifdef CONFIG_TRANS_NAMES +extern char * transl_names[]; + +static int get_nametrans (char * buf) { + char * res = buf; + char ** entry; + char * ptr; + for (entry = transl_names; *entry; entry++) { + *res++ = '#'; + for(ptr = *entry; *ptr; ptr++) + *res++ = *ptr; + entry++; + for(ptr = *entry; *ptr; ptr++) + *res++ = *ptr; + *res++ = '#'; + *res++ = ':'; + } + res--; + *res++ = '\n'; + *res = '\0'; + return (int)res - (int)buf; +} +#endif + #ifdef CONFIG_MODULES extern int get_module_list(char *); extern int get_ksyms_list(char *, char **, off_t, int); @@ -1047,11 +1071,15 @@ case PROC_MTAB: return get_filesystem_info( page ); #ifdef CONFIG_RTC - case PROC_RTC: + case PROC_RTC: return get_rtc_status(page); #endif - case PROC_LOCKS: + case PROC_LOCKS: return get_locks_status(page); +#ifdef CONFIG_TRANS_NAMES + case PROC_NAMETRANS: + return get_nametrans(page); +#endif } return -EBADF; } diff -ur linux.org/fs/proc/root.c linux/fs/proc/root.c --- linux.org/fs/proc/root.c Tue Apr 30 12:09:45 1996 +++ linux/fs/proc/root.c Wed Oct 2 13:12:18 1996 @@ -372,6 +372,10 @@ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, }); } +#ifdef CONFIG_TRANS_NAMES + proc_register( &proc_root, &(struct proc_dir_entry) + { PROC_NAMETRANS, 9, "nametrans", S_IFREG | S_IRUGO, 1, 0, 0, } ); +#endif } diff -ur linux.org/fs/readdir.c linux/fs/readdir.c --- linux.org/fs/readdir.c Mon Sep 11 19:15:45 1995 +++ linux/fs/readdir.c Wed Oct 2 13:12:18 1996 @@ -10,9 +10,120 @@ #include #include #include +#include #include +#ifdef CONFIG_TRANS_NAMES +#include + +/* patch by Thomas Schoebel-Theuer: + * translates names of the form "filename#host=myhost#" to "filename" + * as if both names were hardlinked to the same file. + * benefit: diskless clients can mount the / filesystem of the + * server if /etc/fstab (and other config files) are organized using + * context-suffixes. + */ + +char *transl_names[] = { +#ifdef CONFIG_TR_NODENAME + "host=", system_utsname.nodename, +#endif +#ifdef CONFIG_TR_KERNTYPE + "ktype=", CONFIG_KERNTYPE, +#endif +#ifdef CONFIG_TR_MACHINE + "machine=", system_utsname.machine, +#endif +#ifdef CONFIG_TR_SYSNAME + "system=", system_utsname.sysname, +#endif + 0, 0 +}; + +/* if the _first_ environment variable is "NAMETRANS", return + * a pointer to the list of appendices. + * You can set the first environment variable using + * 'env - NAMETRANS=... "`env`" command ...' + */ +char* env_transl(void) { + char* env; + int i; + if(current && current->mm && (env = (char*)current->mm->env_start) + && get_ds() != get_fs() + && current->mm->env_end>=current->mm->env_start+10 + && !verify_area(VERIFY_READ,env,10)) { + for(i=0; i<10; i++) + if(get_user(env++) != "NAMETRANS="[i]) + return 0; + return env; + } + return 0; +} + +/* if name has the correct suffix "#keyword=correct_context#", + * return position of the suffix, else 0. + */ +static char* testname(int restricted, char* name) { + char* ptr = name; + char** try; + char* p1; + char* p2; + char* cut; + char* env; + char c1, c2; + + while((c1=get_user(ptr++)) && c1 != '#') ; + if(!c1) + return 0; + cut = ptr; + while ((c1=get_user(ptr++)) && c1 != '#'); + if(!c1 || get_user(ptr)) + return 0; + env = env_transl(); + if(env) { + for(p2 = env; (c2=get_user(p2)); p2++) { + p1 = cut-1; + c1 = ':'; + while (c2 && c2 != ':') { + if((c1=get_user(p1++)) != (c2=get_user(p2++))) + break; + } + if(!c1 && (!c2 || c2==':')) { + return cut-1; + } + while ((c2=get_user(p2)) && c2 != ':') p2++; + } + } else { +#ifdef CONFIG_TRANS_RESTRICT + if(restricted) + return 0; +#else + (void) restricted; /* inhibit usage warning */ +#endif + for(try = transl_names; *try; ) { + p1 = cut; + for(p2 = *try++; *p2; p2++) { + if(get_user(p1++) != *p2) + break; + } + if(!*p2) { + for(p2 = *try++; *p2; p2++) { + if(get_user(p1++) != *p2) + break; + } + if(!*p2 && ++p1 == ptr) { + return cut-1; + } + return 0; + } + try++; + } + } + return 0; +} +#endif + /* * Traditional linux readdir() handling.. * @@ -68,6 +179,20 @@ return error; buf.count = 0; buf.dirent = dirent; +#ifdef CONFIG_TRANS_NAMES + { + char * cut; +#ifdef CONFIG_TRANS_RESTRICT + cut = testname(file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID, buf.dirent->d_name); +#else + cut = testname(1, buf.dirent->d_name); +#endif + if(cut) { + put_user(0, cut); + return 1; + } + } +#endif error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir); if (error < 0) return error; @@ -89,7 +214,10 @@ struct linux_dirent * current_dir; struct linux_dirent * previous; int count; - int error; + int error; +#ifdef CONFIG_TRANS_RESTRICT + int restricted; +#endif }; static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) @@ -105,11 +233,36 @@ if (dirent) put_user(offset, &dirent->d_off); dirent = buf->current_dir; - buf->previous = dirent; - put_user(ino, &dirent->d_ino); - put_user(reclen, &dirent->d_reclen); memcpy_tofs(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); +#ifdef CONFIG_TRANS_NAMES + { + char * cut; +#ifdef CONFIG_TRANS_RESTRICT + cut = testname(buf->restricted, dirent->d_name); +#else + cut = testname(1, dirent->d_name); +#endif + if(cut) { + int newlen = (int)cut - (int)dirent->d_name; + int newreclen = ROUND_UP(NAME_OFFSET(dirent) + newlen + 1); + if (reclen+newlen > buf->count) + return -EINVAL; + put_user(0, cut); + put_user(ino, &dirent->d_ino); + put_user(newreclen, &dirent->d_reclen); + put_user(offset, &dirent->d_off); + ((char *) dirent) += newreclen; + buf->count -= newreclen; + put_user(offset, &dirent->d_off); + memcpy_tofs(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + } + } +#endif + put_user(ino, &dirent->d_ino); + put_user(reclen, &dirent->d_reclen); + buf->previous = dirent; ((char *) dirent) += reclen; buf->current_dir = dirent; buf->count -= reclen; @@ -134,6 +287,9 @@ buf.previous = NULL; buf.count = count; buf.error = 0; +#ifdef CONFIG_TRANS_RESTRICT + buf.restricted = file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID; +#endif error = file->f_op->readdir(file->f_inode, file, &buf, filldir); if (error < 0) return error; diff -ur linux.org/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- linux.org/include/linux/proc_fs.h Fri Sep 20 15:23:29 1996 +++ linux/include/linux/proc_fs.h Wed Oct 2 13:12:18 1996 @@ -38,6 +38,7 @@ PROC_SMP_PROF, #endif PROC_PROFILE, /* whether enabled or not */ + PROC_NAMETRANS, /* whether enabled or not */ PROC_CMDLINE, PROC_SYS, PROC_MTAB, diff -ur linux.org/scripts/Configure linux/scripts/Configure --- linux.org/scripts/Configure Fri May 31 12:46:27 1996 +++ linux/scripts/Configure Wed Oct 2 13:12:19 1996 @@ -329,6 +329,28 @@ } # +# define_string sets the value of a string argument +# +# define_string define value +# +function define_string () { + echo "$1="'"'$2'"' >>$CONFIG + echo "#define $1 "'"'$2'"' >>$CONFIG_H + eval "$1=$2" +} + +# +# string processes a string argument +# +# string question define default +# +function string () { + old=$(eval echo "\${$2}") + def=${old:-$3} + readln "$1 ($2) [$def] " "$def" "$old" + define_string "$2" "$ans" +} +# # choice processes a choice list (1-out-of-n) # # choice question choice-list default diff -ur linux.org/scripts/header.tk linux/scripts/header.tk --- linux.org/scripts/header.tk Sat Apr 13 13:20:03 1996 +++ linux/scripts/header.tk Wed Oct 2 13:12:19 1996 @@ -209,6 +209,10 @@ set cmd "global $var; set $var $value" eval $cmd } + if [regexp {([0-9A-Za-z_]+)="([0-9A-Za-z]+)"} $line foo var value] { + set cmd "global $var; set $var $value" + eval $cmd + } } close $file1 update_choices @@ -260,6 +264,16 @@ } } +proc write_string { file1 file2 varname variable dep } { + if { $dep == 0 } \ + then { puts $file1 "# $varname is not set"; \ + puts $file2 "#undef $varname"} \ + else { + puts $file1 "$varname=\"$variable\""; \ + puts $file2 "#define $varname \"$variable\""; \ + } +} + proc option_name {w mnum line text helpidx} { button $w.x$line.l -text "$text" -relief groove -anchor w $w.x$line.l configure -activefore [cget $w.x$line.l -fg] \ @@ -310,6 +324,15 @@ proc hex { w mnum line text variable } { int $w $mnum $line $text $variable +} + +proc istring { w mnum line text variable } { + frame $w.x$line + entry $w.x$line.x -width 18 -relief sunken -borderwidth 2 \ + -textvariable $variable + option_name $w $mnum $line $text $variable + pack $w.x$line.x -anchor w -side right -fill y + pack $w.x$line -anchor w -fill both -expand on } proc minimenu { w mnum line text variable helpidx } { diff -ur linux.org/scripts/tkcond.c linux/scripts/tkcond.c --- linux.org/scripts/tkcond.c Mon May 6 11:26:18 1996 +++ linux/scripts/tkcond.c Wed Oct 2 13:12:19 1996 @@ -195,6 +195,7 @@ if( cfg->tok != tok_bool && cfg->tok != tok_int && cfg->tok != tok_hex + && cfg->tok != tok_string && cfg->tok != tok_tristate && cfg->tok != tok_choice && cfg->tok != tok_dep_tristate) @@ -358,6 +359,7 @@ case tok_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choice: case tok_make: /* @@ -402,6 +404,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next) { switch(cfg1->tok) @@ -412,6 +415,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: if( strcmp(cfg->optionname, cfg1->optionname) == 0) { cfg->flags |= CFG_DUP; diff -ur linux.org/scripts/tkgen.c linux/scripts/tkgen.c --- linux.org/scripts/tkgen.c Thu Jun 6 12:30:41 1996 +++ linux/scripts/tkgen.c Wed Oct 2 13:12:19 1996 @@ -289,6 +289,7 @@ break; case tok_int: case tok_hex: + case tok_string: printf("} then { "); printf(".menu%d.config.f.x%d.x configure -state normal -fore [ cget .ref -foreground ]; ", menu_num, line_num); printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num); @@ -487,6 +488,10 @@ printf("} then { write_hex $cfg $autocfg %s $%s $notmod }\n", item->optionname, item->optionname); break; + case tok_string: + printf("} then { write_string $cfg $autocfg %s $%s $notmod }\n", + item->optionname, item->optionname); + break; case tok_make: printf("} then { do_make {%s} }\n",item->value); break; @@ -646,6 +651,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choose: tot++; break; @@ -702,6 +708,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choose: /* * If we have overfilled the menu, then go to the next one. @@ -862,6 +869,19 @@ cfg->label, cfg->optionname); break; + case tok_string: + if( cfg->menu_number != menu_num ) + { + end_proc(menu_num); + start_proc(menulabel, cfg->menu_number, FALSE); + menu_num = cfg->menu_number; + } + printf("\tistring $w.config.f %d %d \"%s\" %s\n", + cfg->menu_number, + cfg->menu_line, + cfg->label, + cfg->optionname); + break; default: break; } @@ -951,6 +971,7 @@ break; case tok_int: case tok_hex: + case tok_string: printf("set %s %s\n", cfg->optionname, cfg->value); break; case tok_choose: @@ -984,6 +1005,7 @@ { case tok_int: case tok_hex: + case tok_string: case tok_bool: case tok_tristate: case tok_dep_tristate: @@ -1046,6 +1068,12 @@ else if (cfg->tok == tok_hex ) { printf("\twrite_hex $cfg $autocfg %s $%s $notmod\n", + cfg->optionname, + cfg->optionname); + } + else if (cfg->tok == tok_string ) + { + printf("\twrite_string $cfg $autocfg %s $%s $notmod\n", cfg->optionname, cfg->optionname); } diff -ur linux.org/scripts/tkparse.c linux/scripts/tkparse.c --- linux.org/scripts/tkparse.c Mon May 6 11:26:18 1996 +++ linux/scripts/tkparse.c Wed Oct 2 13:12:19 1996 @@ -370,6 +370,11 @@ tok = tok_hex; pnt += 3; } + else if (strncmp(pnt, "string", 6) == 0) + { + tok = tok_string; + pnt += 6; + } else if (strncmp(pnt, "if", 2) == 0) { tok = tok_if; @@ -457,6 +462,7 @@ break; case tok_int: case tok_hex: + case tok_string: pnt = get_qstring(pnt, &kcfg->label); pnt = get_string(pnt, &kcfg->optionname); pnt = get_string(pnt, &kcfg->value); @@ -702,6 +708,9 @@ case tok_hex: printf("hex "); break; + case tok_string: + printf("istring "); + break; case tok_comment: printf("comment "); break; @@ -732,6 +741,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: printf("%s %s\n", cfg->label, cfg->optionname); break; case tok_if: diff -ur linux.org/scripts/tkparse.h linux/scripts/tkparse.h --- linux.org/scripts/tkparse.h Sun Mar 17 08:58:21 1996 +++ linux/scripts/tkparse.h Wed Oct 2 13:12:20 1996 @@ -12,6 +12,7 @@ tok_fi, tok_int, tok_hex, + tok_string, tok_make, tok_define, tok_choose,