/* *libproc * *common utilities needed to process /proc. * *A library interface for finding process information from /proc. *This is also an interface into various things which haven't yet been integrated into sysfs, * as appropriate. Copyright (C) 2004 Joseph Pingenot This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include /*Internal func. Takes in a string of length oldlen, spits out a new string * of length newlen. Allocates memory itself, but doesn't free the old string.*/ char *lengthen(const char* old, ssize_t oldlen, ssize_t increase); /*Appends a '\0' to the end of a string.*/ int capstring(char* string, ssize_t datlen, ssize_t bufflen); /*this is for printing a non-null-terminated string*/ void print_parts(char* string, int len); #define BUFFLEN 1024 /*Input buffer length*/ #define STRINGBUMP 32 /*String length increase unit*/ #define MAXSTRINGLEN 1024 /*Longest lengthen will lengthen*/ /*our struct for the line-value pairs*/ struct lv { char *line; char *value; struct lv *next; }; /*Error conditions: * 1: no filename specified. * 2: Open failed * 4: unable to create line, value buffers. * 8: unable to create lv struct * 16: missed at least one line */ void *readfile_init(const char *file, int *err) { int fd; /*File descriptor*/ char buff[BUFFLEN]; /*Holds data read in from the file*/ ssize_t buffpoint; /*Our current location in buff*/ char *tmpstr; /*Temporary string holder*/ char *line; /*Holder for the line string*/ ssize_t linelen; /*Length of the line string*/ char *value; /*Value string*/ ssize_t valuelen; /*Value string length*/ ssize_t buffread; /*How much of the buffer is filled with data*/ int lvpoint; /*Current position in the {line,value} string*/ struct lv *head = NULL; /*Top of the linked list.*/ struct lv *current = NULL; /*Current node in the linked list*/ struct lv *tmplv = NULL; /*Temp pointer for lined list.*/ int neededlengthen; /*String needed lengthening.*/ int linestate; /*Are we: * 0: reading the line * 1: reading the value * 2: throwing away whitespace * 3: throwing away everything up to a newline */ //printf("*readfile_init(%s, %x)\n", file, err); *err = 0; /*We'll accumulate error points via or-ing them in.*/ if(file == NULL){ *err |= 1; return NULL; } /*Alright. Now we open up the info file for reading.*/ if((fd = open(file, O_RDONLY)) < 0){ /*Open failed. return.*/ *err |= 2; return NULL; } /*Now just walk through the file, creating the list.*/ /*First off, initialize: * . We're not reading in the value (we're reading in the line) * . We're at the beginning of line */ linestate = 0; lvpoint = 0; /*We set these to empty values, so that, on the beginning of the loop, we'll * create the buffers as needed. */ line = NULL; linelen = 0; value = NULL; valuelen = 0; while((buffread = read(fd, buff, BUFFLEN)) > 0) { //while(1) { //printf("*WHILE: buffread=%d, BUFFLEN=%d, fd=%d\n", buffread, BUFFLEN, fd); //buffread = read(fd, buff, BUFFLEN); //printf("*WHILE: buffread=%d, BUFFLEN=%d, fd=%d\n", buffread, BUFFLEN, fd); //printf(" errno=%d\n", errno); //if(buffread <= 0) break; /*Now walk through buff, copying until we hit a colon*/ //printf("buff='"); for(buffpoint = 0; buffpoint < buffread; buffpoint++){ //printf("%c", buff[buffpoint]); //continue; //printf("*foo, buffpoint=%d\n", buffpoint); /*printf("*buff[%d]==%c; lvpoint=%d; linestate=%d; line=\"%s\"(%d); value=\"%s\"(%d)\n", buffpoint, buff[buffpoint], lvpoint, linestate, (line==NULL)? "":line, linelen, (value==NULL)? "":value, valuelen);*/ /*Are we throwing away whitespace?*/ if(linestate == 2) { //printf("linestate is 2. Discarding all whitespace.\n"); if(!((buff[buffpoint] == ' ') || (buff[buffpoint] == '\t'))) { /*We're reading in whitespace, but this isn't whitespace!*/ linestate = 1; /*Now we'll drop through to reading the value. This way we don't * lose this character. */ }else{ continue; } }else if(linestate == 3) { //printf("linestate is 3. Discarding up to newline.\n"); /*We're discarding everything up to a newline.*/ if(buff[buffpoint] != '\n') continue; /*Newline! Reset everything.*/ linestate = 0; lvpoint = 0; line = NULL; linelen = 0; value = NULL; valuelen = 0; } /*Re-allocate the value string if needed.*/ neededlengthen=0; if(linestate == 0){ if(lvpoint >= linelen) { tmpstr = lengthen(line, linelen, STRINGBUMP); linelen += STRINGBUMP; /*Even if the data didn't get transferred, we will be discarding * the data. (since it's no good)*/ if(line != NULL) free(line); line = tmpstr; neededlengthen=1; } }else /* if(linestate == 1) */ { if(lvpoint >= valuelen) { tmpstr = lengthen(value, valuelen, STRINGBUMP); valuelen += STRINGBUMP; /*Even if the data didn't get transferred, we will be discarding * the data.*/ if(value != NULL) free(value); value = tmpstr; neededlengthen=1; } } if(neededlengthen) { //printf("*needed lengthening! tmpstr==%x\n", tmpstr); } if((tmpstr == NULL) && (neededlengthen)) { //printf("needed lengthening, and tmpstr was null. Bork.\n"); /*Nope. Not gonna work. Free line, value, and then try the next line.*/ *err |= 8; linestate = 3; continue; } if(linestate == 1){ //printf("*copying into value.\n"); /*Reading in value. Are we at a newline?*/ if(buff[buffpoint] == '\n'){ /*Yep. Tie it off. First, allocate the struct, then fill it.*/ /*Cap off the value string. It's unlikely that this will fail. If it * does, we still are terminated with a null */ //print_parts(value, lvpoint); capstring(value, lvpoint, valuelen); //print_parts(value, lvpoint+1); /*Current node is NULL. Start the linked list!*/ tmplv = (struct lv*) malloc(sizeof(struct lv)); if(tmplv == NULL){ /*Unable to make new struct. We'll drop a line.*/ *err |= 8 | 16; free(value); free(line); /*Now set to discard-to-newline mode.*/ linestate=3; } /*Now we have a struct. Stick the data in.*/ tmplv->line=line; tmplv->value=value; /*Make sure the new struct's next pointer is NULL*/ tmplv->next=NULL; /*And put it in the list*/ if(head == NULL) { //printf("*Setting head.\n"); current = head = tmplv; }else{ //printf("*Just linking in.\n"); current->next = tmplv; current = tmplv; } //printf("*Linked in. current=%x, head=%x\n", current, head); /*Now simply set the pointers to NULL and the sizes to 0*/ line = NULL; linelen = 0; value = NULL; valuelen = 0; /*And reset our lvpoint*/ lvpoint = 0; /*And back to the line!*/ linestate=0; }else{ /*Still not the end of the line. Simply copy.*/ value[lvpoint++] = buff[buffpoint]; } }else{ //printf("*copying into line.\n"); /*We are working on the line porition.*/ /*Have we hit the colon?*/ if(buff[buffpoint] == ':'){ //printf("*ended the line\n"); //print_parts(line, lvpoint); capstring(line, lvpoint, linelen); //print_parts(line, lvpoint+1); /*Move into the whitespace condensing region*/ linestate = 2; /*Also remember to reset lvpoint!*/ lvpoint = 0; continue; }else{ /*We're still copying. *NOTE that we're incrementing lvpoint here!*/ line[lvpoint++] = buff[buffpoint]; //printf("*done copying\n"); } } } //printf("'\n"); } close(fd); if(line != NULL) free(line); if(value != NULL) free (value); //printf("*returning. head=%x, current=%x, current->next=%x\n", head, current, (current == NULL)? NULL:current->next); return head; } char *readfile_getline(void *handle, const char *line, int *err){ /*Recursive.*/ if((handle == NULL) || (line == NULL)) { /*if we hit a NULL in the list, there's no match!*/ *err = 1; return NULL; } //printf("handle: %x, line:'%s', value='%s'\n", handle, ((struct lv*)handle)->line, ((struct lv*)handle)->value); if(!strcmp(line, ((struct lv*)handle)->line)) { *err = 0; return ((struct lv*)handle)->value; }else{ return readfile_getline(((struct lv*)handle)->next, line, err); } } /*This grabs the nth value in the list*/ char *readfile_get_valuen(void *handle, unsigned int line, int *err){ int index; struct lv* node = (struct lv*)handle; if(node == NULL) { *err = 1; return NULL; } /*iterative.*/ for(index=0; index < line; index++) { if(node->next == NULL) { /*We're not there yet! Return!*/ *err = 2; return NULL; } node = node->next; } /*This is the node number we want. Go for it.*/ *err = 0; return node->value; } char *readfile_get_linen(void *handle, unsigned int line, int *err){ int index; struct lv* node = (struct lv*)handle; if(node == NULL) { *err = 1; return NULL; } /*iterative.*/ for(index=0; index < line; index++) { if(node->next == NULL) { /*We're not there yet! Return!*/ *err = 2; return NULL; } node = node->next; } /*This is the node number we want. Go for it.*/ *err = 0; return node->line; } int readfile_getline_int(void *handle, const char *line, int *err) { int i; char *value = readfile_getline(handle, line, err); if(value == NULL) return -1; if(sscanf(value, "%d", &i) != 1) { /*Error: value was not found.*/ *err = 100; return -1; } *err = 0; return i; } long int readfile_getline_lint(void *handle, const char *line, int *err) { long int i; char *value = readfile_getline(handle, line, err); if(value == NULL) return -1; //printf("value=%s\n", value); if(sscanf(value, "%ld", &i) != 1) { //printf("*NOT FOUND\n"); /*Error: value was not found.*/ *err = 100; return -1; } *err = 0; return i; } float readfile_getline_float(void *handle, const char *line, int *err) { float i; char *value = readfile_getline(handle, line, err); if(value == NULL) return -1; if(sscanf(value, "%f", &i) != 1) { /*Error: value was not found.*/ *err = 100; return -1; } *err = 0; return i; } double readfile_getline_double(void *handle, const char *line, int *err) { double i; char *value = readfile_getline(handle, line, err); if(value == NULL) return -1; if(sscanf(value, "%lf", &i) != 1) { /*Error: value was not found.*/ *err = 100; return -1; } *err = 0; return i; } /*This frees the list when you're done with it.*/ void readfile_end(void *handle){ /*Recursive. Free after the child is freed.*/ if(handle == NULL) return; readfile_end(((struct lv*)handle)->next); /*Free the strings, then the struct.*/ free(((struct lv*)handle)->line); free(((struct lv*)handle)->value); free(handle); } /*Recursive version of readfile_getnum; this is an internal implementation, * since it requires an extra arg [line number counter]; */ int _readfile_getlinenum(void *handle, const char* line, int *err, int level){ /*Recursive.*/ if((handle == NULL) || (line == NULL)) { //printf("readfile_getlinenum(%x, %s, %d, %d): end of list.\n", (int)handle, line, *err, level); /*if we hit a NULL in the list, there's no match!*/ *err = 1; return -1; } if(!strcmp(line, ((struct lv*)handle)->line)) { //printf("readfile_getlinenum(%x, %s, %d, %d): found.\n", (int)handle, line, *err, level); *err = 0; return level; }else{ //printf("readfile_getlinenum(%x, %s, %d, %d): recursing.\n", (int)handle, line, *err, level); return _readfile_getlinenum(((struct lv*)handle)->next, line, err, ++level); } } int readfile_getlinenum(void *handle, const char* line, int *err){ /*We call the recursive version; recursive version requires an extra arg.*/ return _readfile_getlinenum(handle, line, err, 0); } char *lengthen(const char *old, ssize_t oldlen, ssize_t increase) { /*First, allocate the memory.*/ char *new; ssize_t i; /*Make sure that a) we're not going over the max string len and * b) we're not overflowing the ssize_t. */ if(((oldlen + increase) > MAXSTRINGLEN) || ((oldlen + increase) < oldlen)) { return NULL; } new = (char *) malloc(sizeof(char)*(oldlen + increase)); /*Make sure the new string actually got allocated.*/ if(new == NULL) return NULL; //printf("**lengthen(%x, %d, %d); new=%x\n", old, oldlen, increase, new); for(i=0; i< oldlen; i++) { //printf("***old(%d)\n", i); new[i] = old[i]; } //printf("***done\n"); return new; } /*Return values: * 0: Success * 1: Bad arguments * 2: Couldn't add a last byte for the null char. */ int capstring(char* string, ssize_t slen, ssize_t bufflen) { char* tmp; if((string == NULL) || (slen <= 0) || (slen > bufflen)) { return 1; } //printf("capstring(slen=%d, bufflen=%d):", slen, bufflen); //print_parts(string, slen); if(slen < (bufflen - 1)) { /*String + '\0' will fit comfortably within this string.*/ //printf("*will fit.\n"); string[slen] = '\0'; }else{ /*slen is at the end of the buffer (hopefully not past it!)*/ //printf("*won't fit.\n"); tmp = lengthen(string, bufflen, 1); if(tmp == NULL){ /*Ewps. We can't even get *one* more byte. *Not even a waffer-theen meent. *Make the last char a null for safety's sake, but return an error. */ //printf("**outta space.\n"); string[slen - 1] = '\0'; return 2; }else{ /*Just add in the null now.*/ //printf("**fixed.\n"); string[slen] = '\0'; } return 0; } return 0; } void print_parts(char* string, int len) { int i; for(i=0; i