void disablekey(Key *k) { Attr *a; if(sflag) /* not on servers */ return; for(a=k->attr; a; a=a->next){ if(a->type==AttrNameval && strcmp(a->name, "disabled") == 0) return; if(a->next == nil) break; } if(a) a->next = _mkattr(AttrNameval, "disabled", "by.factotum", nil); else k->attr = _mkattr(AttrNameval, "disabled", "by.factotum", nil); /* not reached: always a proto attribute */ }
Attr* _parseattr(char *s) { char *p, *t, *tok[256]; int i, ntok, type; Attr *a; s = strdup(s); if(s == nil) sysfatal("_parseattr strdup: %r"); ntok = tokenize(s, tok, nelem(tok)); a = nil; for(i=ntok-1; i>=0; i--) { t = tok[i]; if((p = strchr(t, '='))) { *p++ = '\0'; // if(p-2 >= t && p[-2] == ':'){ // p[-2] = '\0'; // type = AttrDefault; // }else type = AttrNameval; a = _mkattr(type, t, p, a); setmalloctag(a, getcallerpc(&s)); } else if(t[strlen(t)-1] == '?') { t[strlen(t)-1] = '\0'; a = _mkattr(AttrQuery, t, "", a); setmalloctag(a, getcallerpc(&s)); } else { /* really a syntax error, but better to provide some indication */ a = _mkattr(AttrNameval, t, "", a); setmalloctag(a, getcallerpc(&s)); } } free(s); return cleanattr(a); }
Attr* _copyattr(Attr *a) { Attr **la, *na; na = nil; la = &na; for(; a; a=a->next) { *la = _mkattr(a->type, a->name, a->val, nil); setmalloctag(*la, getcallerpc(&a)); la = &(*la)->next; } *la = nil; return na; }
int ctlwrite(char *a, int atzero) { char *p; int i, nmatch, ret; Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos; Key *k; Proto *proto; if(a[0] == '#' || a[0] == '\0') return 0; /* * it would be nice to emit a warning of some sort here. * we ignore all but the first line of the write. this helps * both with things like "echo delkey >/mnt/factotum/ctl" * and writes that (incorrectly) contain multiple key lines. */ if((p = strchr(a, '\n')) != nil){ if(p[1] != '\0'){ werrstr("multiline write not allowed"); return -1; } *p = '\0'; } if((p = strchr(a, ' ')) == nil) p = ""; else *p++ = '\0'; switch(classify(a, ctltab, nelem(ctltab))){ default: case Vunknown: werrstr("unknown verb"); return -1; case Vdebug: debug ^= 1; return 0; case Vdelkey: nmatch = 0; attr = _parseattr(p); for(pa=attr; pa; pa=pa->next){ if(pa->type != AttrQuery && pa->name[0]=='!'){ werrstr("only !private? patterns are allowed for private fields"); _freeattr(attr); return -1; } } for(i=0; i<ring->nkey; ){ if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){ nmatch++; closekey(ring->key[i]); ring->nkey--; memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0])); }else i++; } _freeattr(attr); if(nmatch == 0){ werrstr("found no keys to delete"); return -1; } return 0; case Vaddkey: attr = _parseattr(p); /* separate out proto= attributes */ lprotos = &protos; for(l=&attr; (*l); ){ if(strcmp((*l)->name, "proto") == 0){ *lprotos = *l; lprotos = &(*l)->next; *l = (*l)->next; }else l = &(*l)->next; } *lprotos = nil; if(protos == nil){ werrstr("key without protos"); _freeattr(attr); return -1; } /* separate out private attributes */ lpriv = &priv; for(l=&attr; (*l); ){ if((*l)->name[0] == '!'){ *lpriv = *l; lpriv = &(*l)->next; *l = (*l)->next; }else l = &(*l)->next; } *lpriv = nil; /* add keys */ ret = 0; for(pa=protos; pa; pa=pa->next){ if((proto = findproto(pa->val)) == nil){ werrstr("unknown proto %s", pa->val); ret = -1; continue; } if(proto->addkey == nil){ werrstr("proto %s doesn't take keys", proto->name); ret = -1; continue; } k = emalloc(sizeof(Key)); k->attr = _mkattr(AttrNameval, "proto", proto->name, _copyattr(attr)); k->privattr = _copyattr(priv); k->ref = 1; k->proto = proto; if(proto->addkey(k, atzero) < 0){ ret = -1; closekey(k); continue; } closekey(k); } _freeattr(attr); _freeattr(priv); _freeattr(protos); return ret; } }