+/*------------------------------------------------------------------*/
+/*
+ * Add a sysfs selector to a mapping
+ */
+static int
+mapping_addsysfs(struct if_mapping * ifnode,
+ int * active,
+ char * string,
+ size_t len,
+ struct add_extra * extra,
+ int linenum)
+{
+ int findex; /* filename index */
+ char * sdup;
+
+ /* Check if we have a modifier */
+ if((extra == NULL) || (extra->modif_pos == NULL))
+ {
+ fprintf(stderr, "Error: No SYSFS filename at line %d\n", linenum);
+ return(-1);
+ }
+
+ /* Search if the filename already exist */
+ for(findex = 0; findex < sysfs_global.filenum; findex++)
+ {
+ if(!strcmp(extra->modif_pos, sysfs_global.filename[findex]))
+ break;
+ }
+
+ /* If filename does not exist, creates it */
+ if(findex == sysfs_global.filenum)
+ {
+ if(findex == SYSFS_MAX_FILE)
+ {
+ fprintf(stderr, "Error: Too many SYSFS filenames at line %d\n", linenum);
+ return(-1);
+ }
+ sdup = strndup(extra->modif_pos, extra->modif_len);
+ if(sdup == NULL)
+ {
+ fprintf(stderr, "Error: Can't allocate SYSFS file\n");
+ return(-1);
+ }
+ sysfs_global.filename[findex] = sdup;
+ sysfs_global.filenum++;
+ }
+
+ /* Store value */
+ sdup = strndup(string, len);
+ if(sdup == NULL)
+ {
+ fprintf(stderr, "Error: Can't allocate SYSFS value\n");
+ return(-1);
+ }
+ ifnode->sysfs[findex] = sdup;
+
+ /* Activate */
+ ifnode->active[SELECT_SYSFS] = 1;
+ active[SELECT_SYSFS] = 1;
+
+ if(verbose)
+ fprintf(stderr,
+ "Parsing : Added SYSFS filename `%s' value `%s' from line %d.\n",
+ sysfs_global.filename[findex], ifnode->sysfs[findex], linenum);
+
+ return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Compare all the sysfs values of two mappings
+ */
+static int
+mapping_cmpsysfs(struct if_mapping * ifnode,
+ struct if_mapping * target)
+{
+ int findex; /* filename index */
+ int match = 1;
+
+ /* Loop on all sysfs selector */
+ for(findex = 0; findex < sysfs_global.filenum; findex++)
+ {
+ /* If the mapping defines this sysfs selector.. */
+ if(ifnode->sysfs[findex] != NULL)
+ /* And if the sysfs values don't match */
+ if((target->sysfs[findex] == NULL) ||
+ (fnmatch(ifnode->sysfs[findex], target->sysfs[findex],
+ FNM_CASEFOLD)))
+ /* Then the sysfs selector doesn't match */
+ match = 0;
+ }
+
+ return(!match);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Extract all the sysfs values of an interface
+ */
+static int
+mapping_getsysfs(int skfd,
+ const char * ifname,
+ struct if_mapping * target,
+ int flag)
+{
+ FILE * stream;
+ char * linebuf = NULL;
+ size_t linelen = 0;
+ char * sdup;
+ int findex; /* filename index */
+
+ /* Avoid "Unused parameter" warning */
+ skfd = skfd;
+ flag = flag;
+
+ /* Check if we know the root of the sysfs filesystem */
+ if(sysfs_global.root == NULL)
+ {
+ /* Open the mount file for reading */
+ stream = fopen("/proc/mounts", "r");
+ if(!stream)
+ {
+ fprintf(stderr, "Error: Can't open /proc/mounts file: %s\n",
+ strerror(errno));
+ return(-1);
+ }
+
+ /* Read each line of file
+ * getline is a GNU extension :-( The buffer is recycled and increased
+ * as needed by getline. */
+ while(getline(&linebuf, &linelen, stream) > 0)
+ {
+ char * p;
+ size_t n;
+
+ /* Get the line starting with sysfs */
+ p = linebuf;
+ while(isspace(*p))
+ ++p;
+ if(!strncasecmp(p, "sysfs ", 6))
+ {
+ /* Find the mount point */
+ p += 6;
+ while(isspace(*p))
+ ++p;
+ n = strcspn(p, " \t\n");
+ sdup = strndup(p, n);
+ if((n == 0) || (sdup == NULL))
+ {
+ fprintf(stderr, "Error: Can't parse /proc/mounts file: %s\n",
+ strerror(errno));
+ return(-1);
+ }
+ /* Store it */
+ sysfs_global.root = sdup;
+ sysfs_global.rlen = n;
+ break;
+ }
+ /* Finished -> next line */
+ }
+
+ /* Cleanup */
+ fclose(stream);
+
+ /* Check if we found it */
+ if(sysfs_global.root == NULL)
+ {
+ fprintf(stderr, "Error: Can't find sysfs in /proc/mounts file\n");
+ free(linebuf);
+ return(-1);
+ }
+ }
+
+ /* Loop on all sysfs selector */
+ for(findex = 0; findex < sysfs_global.filenum; findex++)
+ {
+ char * fname;
+ int flen;
+ char * p;
+ ssize_t n;
+
+ /* Construct complete filename for the sysfs selector */
+ flen = (sysfs_global.rlen + 11 + strlen(ifname) + 1 +
+ strlen(sysfs_global.filename[findex]) + 1);
+ fname = malloc(flen);
+ if(fname == NULL)
+ {
+ fprintf(stderr, "Error: Can't allocate SYSFS filename\n");
+ free(linebuf);
+ return(-1);
+ }
+ sprintf(fname, "%s/class/net/%s/%s", sysfs_global.root, ifname,
+ sysfs_global.filename[findex]);
+
+ /* Open the sysfs file for reading */
+ stream = fopen(fname, "r");
+ if(!stream)
+ {
+ /* Some sysfs attribute may no exist for some interface */
+ if(verbose)
+ fprintf(stderr, "Error: Can't open file `%s': %s\n", fname,
+ strerror(errno));
+ /* Next sysfs selector */
+ continue;
+ }
+
+ /* Read file. Only one line in file. */
+ n = getline(&linebuf, &linelen, stream);
+ fclose(stream);
+ if(n <= 0)
+ {
+ /* Some sysfs attribute are void for some interface */
+ if(verbose)
+ fprintf(stderr, "Error: Can't read file `%s'\n", fname);
+ /* Next sysfs selector */
+ continue;
+ }
+
+ /* Get content, remove trailing '/n', save it */
+ p = linebuf;
+ if(p[n - 1] == '\n')
+ n--;
+ sdup = strndup(p, n);
+ if(sdup == NULL)
+ {
+ fprintf(stderr, "Error: Can't allocate SYSFS value\n");
+ free(linebuf);
+ return(-1);
+ }
+ target->sysfs[findex] = sdup;
+
+ /* Activate */
+ target->active[SELECT_SYSFS] = 1;
+
+ if(verbose)
+ fprintf(stderr,
+ "Querying %s : Got SYSFS filename `%s' value `%s'.\n",
+ ifname, sysfs_global.filename[findex], target->sysfs[findex]);
+
+ /* Finished : Next sysfs selector */
+ }
+
+ /* Cleanup */
+ free(linebuf);
+
+ return(target->active[SELECT_SYSFS] ? 0 : -1);
+}
+