diff -Nur procps-3.2.6.orig/sysctl.c procps-3.2.6/sysctl.c --- procps-3.2.6.orig/sysctl.c 2006-07-20 13:06:21.000000000 +0200 +++ procps-3.2.6/sysctl.c 2006-07-20 13:43:42.000000000 +0200 @@ -39,6 +39,21 @@ static bool true = 1; static bool false = 0; +typedef struct sysctl /* by BL */ +{ + char *restrict token; + char *restrict path; +} sysctl_t; + +/* + * Function Prototypes + */ + +static char *token2path(const char *restrict path, int eth_workaround); /* by BL */ +static char *path2token(const char *restrict token); /* by BL */ +static int sysctl_init(sysctl_t *sys, const char *restrict name, int is_token); /* by BL */ +static void sysctl_destroy(sysctl_t *sys); /* by BL */ + /* * Globals... */ @@ -64,20 +79,6 @@ static const char WARN_BAD_LINE[] = "warning: %s(%d): invalid syntax, continuing...\n"; -static void slashdot(char *restrict p, char old, char new){ - p = strpbrk(p,"/."); - if(!p) return; /* nothing -- can't be, but oh well */ - if(*p==new) return; /* already in desired format */ - while(p){ - char c = *p; - if(c==old) *p=new; - if(c==new) *p=old; - p = strpbrk(p+1,"/."); - } -} - - - /* * Display the usage format * @@ -122,58 +123,54 @@ * Read a sysctl setting * */ -static int ReadSetting(const char *restrict const name) { +static int ReadSetting(const char *restrict const name, int is_token) { int rc = 0; - char *restrict tmpname; - char *restrict outname; char inbuf[1025]; FILE *restrict fp; + sysctl_t sys; if (!name || !*name) { fprintf(stderr, ERR_INVALID_KEY, name); return -1; } - /* used to open the file */ - tmpname = malloc(strlen(name)+strlen(PROC_PATH)+1); - strcpy(tmpname, PROC_PATH); - strcat(tmpname, name); - slashdot(tmpname+strlen(PROC_PATH),'.','/'); /* change . to / */ - - /* used to display the output */ - outname = strdup(name); - slashdot(outname,'/','.'); /* change / to . */ + if (sysctl_init(&sys,name,is_token)) + { + fprintf(stderr, ERR_INVALID_KEY, name); + return -2; + } - fp = fopen(tmpname, "r"); + fp = fopen(sys.path, "r"); if (!fp) { switch(errno) { case ENOENT: if (!IgnoreError) { - fprintf(stderr, ERR_INVALID_KEY, outname); + fprintf(stderr, ERR_INVALID_KEY, sys.token); rc = -1; } break; case EACCES: - fprintf(stderr, ERR_PERMISSION_DENIED, outname); + fprintf(stderr, ERR_PERMISSION_DENIED, sys.token); rc = -1; break; default: - fprintf(stderr, ERR_UNKNOWN_READING, strerror(errno), outname); + fprintf(stderr, ERR_UNKNOWN_READING, strerror(errno), sys.token); rc = -1; break; } } else { - if(fgets(inbuf, sizeof inbuf - 1, fp)) { + if(fgets(inbuf, sizeof(inbuf) - 1, fp)) { // this loop is required, see // /sbin/sysctl -a | egrep -6 dev.cdrom.info do { + inbuf[sizeof(inbuf) - 1]=0; if (NameOnly) { - fprintf(stdout, "%s\n", outname); + fprintf(stdout, "%s\n", sys.token); } else { /* already has the \n in it */ if (PrintName) { - fprintf(stdout, "%s = %s", outname, inbuf); + fprintf(stdout, "%s = %s", sys.token, inbuf); } else { if (!PrintNewline) { char *nlptr = strchr(inbuf,'\n'); @@ -186,19 +183,19 @@ } else { switch(errno) { case EACCES: - fprintf(stderr, ERR_PERMISSION_DENIED, outname); + fprintf(stderr, ERR_PERMISSION_DENIED, sys.token); rc = -1; break; case EISDIR:{ size_t len; - len = strlen(tmpname); - tmpname[len] = '/'; - tmpname[len+1] = '\0'; - rc = DisplayAll(tmpname); + len = strlen(sys.path); + sys.path[len] = '/'; + sys.path[len+1] = '\0'; + rc = DisplayAll(sys.path); break; } default: - fprintf(stderr, ERR_UNKNOWN_READING, strerror(errno), outname); + fprintf(stderr, ERR_UNKNOWN_READING, strerror(errno), sys.token); rc = -1; break; } @@ -206,8 +203,7 @@ fclose(fp); } - free(tmpname); - free(outname); + sysctl_destroy(&sys); return rc; } @@ -244,7 +240,7 @@ strcat(tmpdir, "/"); DisplayAll(tmpdir); } else { - rc |= ReadSetting(tmpdir+strlen(PROC_PATH)); + rc |= ReadSetting(tmpdir,0); } } free(tmpdir); @@ -259,14 +255,15 @@ * Write a sysctl setting * */ -static int WriteSetting(const char *setting) { +static int WriteSetting(const char *setting, int is_token) { int rc = 0; const char *name = setting; const char *value; const char *equals; - char *tmpname; + char *restrict tmpname; FILE *fp; - char *outname; + sysctl_t sys; + int name_len; if (!name) { /* probably don't want to display this err */ return 0; @@ -286,54 +283,52 @@ return -2; } - /* used to open the file */ - tmpname = malloc(equals-name+1+strlen(PROC_PATH)); - strcpy(tmpname, PROC_PATH); - strncat(tmpname, name, (int)(equals-name)); - tmpname[equals-name+strlen(PROC_PATH)] = 0; - slashdot(tmpname+strlen(PROC_PATH),'.','/'); /* change . to / */ - - /* used to display the output */ - outname = malloc(equals-name+1); - strncpy(outname, name, (int)(equals-name)); - outname[equals-name] = 0; - slashdot(outname,'/','.'); /* change / to . */ - - fp = fopen(tmpname, "w"); + name_len=equals - name; + tmpname = (char * restrict) malloc((name_len + 1) * sizeof (char)); + strncpy(tmpname, name, name_len)[name_len]=0; + rc=sysctl_init(&sys,tmpname,is_token); + free(tmpname); + if (rc) + { + fprintf(stderr, ERR_INVALID_KEY, setting); + return -2; + } + + fp = fopen(sys.path, "w"); if (!fp) { switch(errno) { case ENOENT: if (!IgnoreError) { - fprintf(stderr, ERR_INVALID_KEY, outname); + fprintf(stderr, ERR_INVALID_KEY, sys.token); rc = -1; } break; case EACCES: - fprintf(stderr, ERR_PERMISSION_DENIED, outname); + fprintf(stderr, ERR_PERMISSION_DENIED, sys.token); rc = -1; break; default: - fprintf(stderr, ERR_UNKNOWN_WRITING, strerror(errno), outname); + fprintf(stderr, ERR_UNKNOWN_WRITING, strerror(errno), sys.token); rc = -1; break; } } else { rc = fprintf(fp, "%s\n", value); if (rc < 0) { - fprintf(stderr, ERR_UNKNOWN_WRITING, strerror(errno), outname); + fprintf(stderr, ERR_UNKNOWN_WRITING, strerror(errno), sys.token); fclose(fp); } else { rc=fclose(fp); if (rc != 0) - fprintf(stderr, ERR_UNKNOWN_WRITING, strerror(errno), outname); + fprintf(stderr, ERR_UNKNOWN_WRITING, strerror(errno), sys.token); } if (rc==0 && !Quiet) { if (NameOnly) { - fprintf(stdout, "%s\n", outname); + fprintf(stdout, "%s\n", sys.token); } else { if (PrintName) { - fprintf(stdout, "%s = %s\n", outname, value); + fprintf(stdout, "%s = %s\n", sys.token, value); } else { if (PrintNewline) fprintf(stdout, "%s\n", value); @@ -344,8 +339,7 @@ } } - free(tmpname); - free(outname); + sysctl_destroy(&sys); return rc; } @@ -357,8 +351,8 @@ * */ static int Preload(const char *restrict const filename) { - char oneline[256]; - char buffer[256]; + char oneline[257]; + char buffer[257]; FILE *fp; char *t; int n = 0; @@ -376,7 +370,8 @@ return -1; } - while (fgets(oneline, sizeof oneline, fp)) { + while (fgets(oneline, sizeof(oneline)-1, fp)) { + oneline[sizeof(oneline)-1] = 0; n++; t = StripLeadingAndTrailingSpaces(oneline); @@ -405,7 +400,7 @@ // should NameOnly affect this? sprintf(buffer, "%s=%s", name, value); - rc |= WriteSetting(buffer); + rc |= WriteSetting(buffer,1); } if (!reading_stdin) @@ -507,9 +502,9 @@ return Usage(me); SwitchesAllowed = false; if (WriteMode || index(*argv, '=')) - ReturnCode = WriteSetting(*argv); + ReturnCode = WriteSetting(*argv,1); else - ReturnCode = ReadSetting(*argv); + ReturnCode = ReadSetting(*argv,1); } } @@ -517,3 +512,211 @@ } +/* These functions and calls to them were added by Bartosz Lis + * bartoszl@ics.p.lodz.pl on 12.11.2003 to solve dot in filename problem + */ + +/* + * Translation form token namespace to path namespace + * + * two consecutive dots changed to a single dot .. -> . + * if number of consecutive dots is even, last dot changed to slash . -> / + * any number of consecutive slashes changed to a single slash /// -> / + */ + +char * +token2path(const char *restrict token, int eth_workaround) +{ + const char *src; + char *path, *dst, *tmp, c; + size_t size, dots, i; + int is_first; + + if (!token) return 0; + size=sizeof(PROC_PATH)/sizeof(char); + src=token; + is_first=1; /* logical value of a sentence: "*src ponts to the first + * character in the current filename" */ + while (*src) + { + dots=0; + while (*src=='.') + { + ++dots; + ++src; + } + if (dots) + { + /* file name should not start with a dot */ + if (is_first) return 0; + size+=(dots+1)/2; + is_first=(dots&1); + } + else + { + if (!is_first || (*src!='/')) + { + is_first=(*src=='/'); + ++size; + } + ++src; + } + } + if (size<=1) return 0; /* empty string is not valid */ + path=(char *restrict)malloc(size*sizeof(char)+1); + strcpy(path,PROC_PATH); + dst=path+sizeof(PROC_PATH)/sizeof(char)-1; + src=token; + is_first=1; + while (*src) + { + dots=0; + while (*src=='.') + { + ++dots; + ++src; + } + if (dots) + { + for (i=dots/2; i>0; --i) *dst++='.'; + if ((is_first=(dots&1))==1) + { + c='/'; + if (eth_workaround && ('0'<=*src) && (*src<='9')) + { + tmp=src-2; + while ((token<=tmp) && ('0'<=*tmp) && (*tmp<='9')) --tmp; + if ((token+3<=tmp) && (tmp+2 .. + * any number of slashes is changed to a single dot /// -> . + */ + +char * +path2token(const char *restrict path) +{ + const char *src; + char *dst, *token, c; + size_t i, size; + int is_first; + + if (!path) return 0; + + /* skip path prefix */ + src=PROC_PATH; + for (i=0; i<2; ++i) + { + ++src; + while (*path=='/') ++path; + while ((*src!='/') && (*path==*src)) + { + ++src; + ++path; + } + if (*path!=*src) return 0; + } + while (*path=='/') ++path; + size=1; + src=path; + is_first=1; + while ((c=*src)!=0) switch (c) + { + case '/': + while (*src=='/') ++src; + ++size; + is_first=1; + break; + case '.': + /* file name should not start with a dot */ + if (is_first) return 0; + ++size; + /* intentionaly no break here */ + default: + ++size; + ++src; + is_first=0; + } + if (size<=1) return 0; /* empty string is not valid */ + token=(char *restrict)malloc(size*sizeof(char)); + src=path; + dst=token; + while ((c=*src)!=0) + { + switch (c) + { + case '/': + while (*src=='/') ++src; + c='.'; + break; + case '.': + *dst++='.'; + /* intentionaly no break here */ + default: + ++src; + } + *dst++=c; + } + *dst=0; + return token; +} + +/* + * Storing results of translations between token and path namespaces + * + * Assuming that sysctl_t *sys is not initialized. If initialized, first + * call destroy_sysctl. + */ + +static int +sysctl_init(sysctl_t *sys, const char *restrict name, int is_token) +{ + int ret; + ret=(is_token + ? (sys->token=path2token(sys->path=token2path(name,1)))==0 + : (sys->path=token2path(sys->token=path2token(name),0))==0); + if (ret) sysctl_destroy(sys); + return ret; +} + +/* + * Free char * ponters from struct sysctl + * + * Assumes that the former procedure was called to initialize + * sysctl_t *sys, or its fields pointing to char * were set to NULLs. + */ + +static void +sysctl_destroy(sysctl_t *sys) +{ + if (sys->token) + { + free (sys->token); + sys->token=0; + } + if (sys->path) + { + free (sys->path); + sys->path=0; + } +} +