- char *conf,*pos,*end;
-
- /* mmap the config file */
- if (-1!=(fd=open("/etc/mdev.conf",O_RDONLY))) {
- len=lseek(fd,0,SEEK_END);
- conf=mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
- if (conf) {
- int line=0;
-
- /* Loop through lines in mmaped file*/
- for (pos=conf;pos-conf<len;) {
- int field;
- char *end2;
-
- line++;
- /* find end of this line */
- for(end=pos;end-conf<len && *end!='\n';end++);
-
- /* Three fields: regex, uid:gid, mode */
- for (field=3;field;field--) {
- /* Skip whitespace */
- while (pos<end && isspace(*pos)) pos++;
- if (pos==end || *pos=='#') break;
- for (end2=pos;
- end2<end && !isspace(*end2) && *end2!='#'; end2++);
- switch(field) {
- /* Regex to match this device */
- case 3:
- {
- char *regex=strndupa(pos,end2-pos);
- regex_t match;
- regmatch_t off;
- int result;
-
- /* Is this it? */
- xregcomp(&match,regex,REG_EXTENDED);
- result=regexec(&match,device_name,1,&off,0);
- regfree(&match);
-
- /* If not this device, skip rest of line */
- if(result || off.rm_so
- || off.rm_eo!=strlen(device_name))
- goto end_line;
-
- break;
- }
- /* uid:gid */
- case 2:
- {
- char *s2;
-
- /* Find : */
- for(s=pos;s<end2 && *s!=':';s++);
- if(s==end2) goto end_line;
-
- /* Parse UID */
- uid=strtoul(pos,&s2,10);
- if(s!=s2) {
- struct passwd *pass;
- pass=getpwnam(strndupa(pos,s-pos));
- if(!pass) goto end_line;
- uid=pass->pw_uid;
- }
- s++;
- /* parse GID */
- gid=strtoul(s,&s2,10);
- if(end2!=s2) {
- struct group *grp;
- grp=getgrnam(strndupa(s,end2-s));
- if(!grp) goto end_line;
- gid=grp->gr_gid;
- }
- break;
- }
- /* mode */
- case 1:
- {
- mode=strtoul(pos,&pos,8);
- if(pos!=end2) goto end_line;
- goto found_device;
- }
+ FILE *fp;
+ char *line, *val, *next;
+ unsigned lineno = 0;
+
+ /* If we have config file, look up user settings */
+ fp = fopen_or_warn("/etc/mdev.conf", "r");
+ if (!fp)
+ goto end_parse;
+
+ while ((line = xmalloc_fgetline(fp)) != NULL) {
+ regmatch_t off[1+9*ENABLE_FEATURE_MDEV_RENAME_REGEXP];
+
+ ++lineno;
+ trim(line);
+ if (!line[0])
+ goto next_line;
+
+ /* Fields: regex uid:gid mode [alias] [cmd] */
+
+ /* 1st field: regex to match this device */
+ next = next_field(line);
+ {
+ regex_t match;
+ int result;
+
+ /* Is this it? */
+ xregcomp(&match, line, REG_EXTENDED);
+ result = regexec(&match, device_name, ARRAY_SIZE(off), off, 0);
+ regfree(&match);
+
+ //bb_error_msg("matches:");
+ //for (int i = 0; i < ARRAY_SIZE(off); i++) {
+ // if (off[i].rm_so < 0) continue;
+ // bb_error_msg("match %d: '%.*s'\n", i,
+ // (int)(off[i].rm_eo - off[i].rm_so),
+ // device_name + off[i].rm_so);
+ //}
+
+ /* If not this device, skip rest of line */
+ /* (regexec returns whole pattern as "range" 0) */
+ if (result || off[0].rm_so
+ || ((int)off[0].rm_eo != (int)strlen(device_name))
+ ) {
+ goto next_line;
+ }
+ }
+
+ /* This line matches: stop parsing the file
+ * after parsing the rest of fields */
+
+ /* 2nd field: uid:gid - device ownership */
+ if (!next) /* field must exist */
+ bb_error_msg_and_die("bad line %u", lineno);
+ val = next;
+ next = next_field(val);
+ {
+ struct passwd *pass;
+ struct group *grp;
+ char *str_uid = val;
+ char *str_gid = strchrnul(val, ':');
+
+ if (*str_gid)
+ *str_gid++ = '\0';
+ /* Parse UID */
+ pass = getpwnam(str_uid);
+ if (pass)
+ uid = pass->pw_uid;
+ else
+ uid = strtoul(str_uid, NULL, 10);
+ /* Parse GID */
+ grp = getgrnam(str_gid);
+ if (grp)
+ gid = grp->gr_gid;
+ else
+ gid = strtoul(str_gid, NULL, 10);
+ }
+
+ /* 3rd field: mode - device permissions */
+ if (!next) /* field must exist */
+ bb_error_msg_and_die("bad line %u", lineno);
+ val = next;
+ next = next_field(val);
+ mode = strtoul(val, NULL, 8);
+
+ /* 4th field (opt): >alias */
+#if ENABLE_FEATURE_MDEV_RENAME
+ if (!next)
+ break;
+ if (*next == '>' || *next == '=') {
+#if ENABLE_FEATURE_MDEV_RENAME_REGEXP
+ char *s, *p;
+ unsigned i, n;
+
+ aliaslink = *next;
+ val = next;
+ next = next_field(val);
+ /* substitute %1..9 with off[1..9], if any */
+ n = 0;
+ s = val;
+ while (*s)
+ if (*s++ == '%')
+ n++;
+
+ p = alias = xzalloc(strlen(val) + n * strlen(device_name));
+ s = val + 1;
+ while (*s) {
+ *p = *s;
+ if ('%' == *s) {
+ i = (s[1] - '0');
+ if (i <= 9 && off[i].rm_so >= 0) {
+ n = off[i].rm_eo - off[i].rm_so;
+ strncpy(p, device_name + off[i].rm_so, n);
+ p += n - 1;
+ s++;