Am Mon, 11. May 2009, 09:12:56 +0200 schrieb Jö Fahlke: > Am Sun, 10. May 2009, 22:18:48 +0200 schrieb Michael Biebl: > > Thanks a lot for the detailed bug report. Care to write a patch, now that > > you > > already did the analysis? I'm very busy atm. > > I'll have to see whether I find time myself. > > Using getline() would make this stuff much easier -- but getline() is a GNU > extension. So is it permissible to use getline() or would I have to provide a > replacement in case it isn't available?
Applied is a first version of a patch to improve ifparser_init(). I didn't use getline() after all. It compiles and I did some rudimentary testing. I'm still working on an improvement regarding the handling of continued lines. Comments? Bye, Jö. -- oil -- operation iraqi liberation http://www.mo.tecsamples.de/mahnwache/index.html
Index: network-manager-0.7.1/system-settings/plugins/ifupdown/interface_parser.c =================================================================== --- network-manager-0.7.1.orig/system-settings/plugins/ifupdown/interface_parser.c 2009-05-12 00:58:39.000000000 +0200 +++ network-manager-0.7.1/system-settings/plugins/ifupdown/interface_parser.c 2009-05-12 01:08:45.000000000 +0200 @@ -26,6 +26,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <ctype.h> #include "nm-utils.h" if_block* first; @@ -74,86 +75,204 @@ //printf("added data '%s' with key '%s'\n",data,key); } -#define SPACE_OR_TAB(string,ret) {ret = strchr(string,' ');ret=(ret == NULL?strchr(string,'\t'):ret);} + +/** Append a line read from a stream to a string + * + * Read a line from stream and append it at the location *str+*str_len. If + * the line terminated in a newline, it is stripped. *str_len is then updated + * to reflect the new size. On entrance, *str may be unterminated, but on + * exit it is always terminted with a newline (unless an allocation error + * occured). + * + * If the space available for *str is insufficient, new space is allocated + * using realloc(). *str_size is updated accordingly. + * + * On entrance, *str may be NULL. In this case the initial values of + * *str_size and *str_len don't matter and some space is allocated using + * malloc(). + * + * On success, the return value is the number of characters read, which is + * usually more than the number of characters actually appended because of the + * newline-stripping. On error or EOF -1 is returned. The return value will + * never be 0 size zero characters read is interpreted as EOF. + * + * \param str Pointer to the string to be appended to. + * \param str_size Allocated space for the string. + * \param str_len Length of string. + * \param stream The stream to read from. + */ +static ssize_t append_line(char **str, size_t *str_size, size_t *str_len, FILE *stream) +{ + + size_t chars_read; + size_t global_chars_read = 0; + + if(*str == NULL) + { + char *newstr = (char *)malloc(80); + if(newstr == NULL) + return -1; + *str = newstr; + *str_size = 80; + *str_len = 0; + (*str)[0] = '\0'; + } + + do { + if(*str_size <= *str_len + 1) + { + char *newstr = (char *)realloc(*str, *str_size * 2); + if(newstr == NULL) + return -1; + *str = newstr; + *str_size = *str_size * 2; + } + + if(fgets(*str+*str_len, *str_size-*str_len, stream) == NULL) + /* restore terminating \0 in case there was an error */ + (*str)[*str_len] = '\0'; + chars_read = strlen(*str+*str_len); + *str_len += chars_read; + global_chars_read += chars_read; + } while(chars_read > 0 && (*str)[*str_len-1] != '\n'); + + /* trim trailing newline */ + if(global_chars_read > 0 && (*str)[*str_len-1] == '\n') + (*str)[--*str_len] = '\0'; + + if(global_chars_read == 0) + return -1; + return global_chars_read; +} void ifparser_init(void) { FILE *inp = fopen(ENI_INTERFACES_FILE, "r"); - int ret = 0; - char *line; - char *space; - char rline[255]; + ssize_t ret = 0; + char *line = NULL; + size_t line_space = 0; /* reserved space for line */ + size_t line_length; /* actual string length of line */ + size_t word1, word1_end; + size_t word2; + size_t line_end; if (inp == NULL) { nm_warning ("Error: Can't open %s\n", ENI_INTERFACES_FILE); return; } - first = last = NULL; + while(1) { - line = space = NULL; - ret = fscanf(inp,"%255[^\n]\n",rline); - if (ret == EOF) - break; - // If the line did not match, skip it - if (ret == 0) { - char *ignored; + line_length = 0; - ignored = fgets(rline, 255, inp); + ret = append_line(&line, &line_space, &line_length, inp); + if(ret == -1) + break; /* failed to read line; probably EOF */ + + /* trim leading whitespace */ + word1 = 0; + while(isspace(line[word1])) + ++word1; + + /* skip comments and empty lines */ + if (line[word1] == '#' || line[word1] == '\0') continue; + + /* handle continued lines */ + while(line[line_length-1] == '\\') + { + --line_length; + ret = append_line(&line, &line_space, &line_length, inp); + if(ret == -1) + break; } - line = rline; - while(line[0] == ' ') - line++; - if (line[0]=='#' || line[0]=='\0') + /* find end of first word */ + word1_end = word1; + while(line[word1_end] != '\0' && !isspace(line[word1_end])) + ++word1_end; + /* find beginning of second word */ + word2 = word1_end; + while(isspace(line[word2])) + ++word2; + /* skip line if there is no second word */ + if(line[word2] == '\0') + { + nm_warning ("Error: Can't parse interface line '%s'\n",line); continue; + } - SPACE_OR_TAB(line,space) - if (space == NULL) - { - nm_warning ("Error: Can't parse interface line '%s'\n",line); - continue; - } - space[0] = '\0'; + /* trim end of line */ + line_end = line_length-1; + while(isspace(line[line_end])) + --line_end; + ++line_end; // There are four different stanzas: // iface, mapping, auto and allow-*. Create a block for each of them. - if (strcmp(line,"iface")==0) + if (word1_end == word1+5 && strncmp(line+word1,"iface",5)==0) { - char *space2 = strchr(space+1,' '); - if (space2 == NULL) + size_t word2_end; + size_t word3, word3_end; + size_t word4; + + /* find end of second word */ + word2_end = word2; + while(line[word2_end] != '\0' && !isspace(line[word2_end])) + ++word2_end; + + /* find beginning of third word */ + word3 = word2_end; + while(isspace(line[word3])) + ++word3; + if (line[word3] == '\0') { - nm_warning ("Error: Can't parse iface line '%s'\n",space+1); + nm_warning ("Error: Can't parse iface line '%s'\n",line); continue; } - space2[0]='\0'; - add_block(line,space+1); - if (space2[1]!='\0') + /* find end of third word */ + word3_end = word3; + while(line[word3_end] != '\0' && !isspace(line[word3_end])) + ++word3_end; + + /* find beginning of fourth word */ + word4 = word3_end; + while(isspace(line[word4])) + ++word4; + if (line[word4] == '\0') { - space = strchr(space2+1,' '); - if (space == NULL) - { - nm_warning ("Error: Can't parse data '%s'\n",space2+1); - continue; - } - space[0] = '\0'; - add_data(space2+1,space+1); + nm_warning ("Error: Can't parse iface line '%s'\n",line); + continue; } + + /* no more error-printing to be done here, we can modify line */ + /* add block with i.e. "iface" "eth0" */ + line[word1_end] = '\0'; + line[word2_end] = '\0'; + add_block(line+word1, line+word2); + + /* add data with i.e. "inet" "dhcp" */ + line[word3_end] = '\0'; + line[line_end] = '\0'; + add_data(line+word3, line+word4); } - else if (strcmp(line,"auto")==0) - add_block(line,space+1); - else if (strcmp(line,"mapping")==0) - add_block(line,space+1); - else if (strncmp(line,"allow-",6)==0) - add_block(line,space+1); else - add_data(line,space+1); + { + /* no more error-printing to be done here, we can modify line */ + line[word1_end] = '\0'; + line[line_end] = '\0'; + if(strcmp(line+word1,"auto")==0 || + strcmp(line+word1,"mapping")==0 || + strncmp(line+word1,"allow-",6)==0) + add_block(line+word1, line+word2); + else + add_data(line+word1, line+word2); + } - //printf("line: '%s' ret=%d\n",rline,ret); } + free(line); fclose(inp); }
signature.asc
Description: Digital signature