static int srvFd(char* name, int mode, int fd, char** mntpnt) { int n, srvfd; char *p, buf[10]; /* * Drop a file descriptor with given name and mode into /srv. * Create with ORCLOSE and don't close srvfd so it will be removed * automatically on process exit. */ p = smprint("/srv/%s", name); if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ vtMemFree(p); p = smprint("#s/%s", name); if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ vtSetError("create %s: %r", p); vtMemFree(p); return -1; } } n = snprint(buf, sizeof(buf), "%d", fd); if(write(srvfd, buf, n) < 0){ close(srvfd); vtSetError("write %s: %r", p); vtMemFree(p); return -1; } *mntpnt = p; return srvfd; }
/* Taken from imapdial, replaces tlsclient call with stunnel */ static int smtpdial(char *server) { int p[2]; int fd[3]; char *tmp; char *fpath; if(pipe(p) < 0) return -1; fd[0] = dup(p[0], -1); fd[1] = dup(p[0], -1); fd[2] = dup(2, -1); #ifdef PLAN9PORT tmp = smprint("%s:587", server); fpath = searchpath("stunnel3"); if (!fpath) { werrstr("stunnel not found. it is required for tls support."); return -1; } if(threadspawnl(fd, fpath, "stunnel", "-n", "smtp" , "-c", "-r", tmp, nil) < 0) { #else tmp = smprint("tcp!%s!587", server); if(threadspawnl(fd, "/bin/tlsclient", "tlsclient", tmp, nil) < 0){ #endif free(tmp); close(p[0]); close(p[1]); close(fd[0]); close(fd[1]); close(fd[2]); return -1; } free(tmp); close(p[0]); return p[1]; } int mxdial(char *addr, char *ddomain, char *gdomain) { int fd; DS ds; char err[Errlen]; addr = netmkaddr(addr, 0, "smtp"); dial_string_parse(addr, &ds); /* try connecting to destination or any of it's mail routers */ fd = callmx(&ds, addr, ddomain); /* try our mail gateway */ rerrstr(err, sizeof(err)); if(fd < 0 && gdomain && strstr(err, "can't translate") != 0) fd = dial(netmkaddr(gdomain, 0, "smtp"), 0, 0, 0); return fd; }
void wwwauthenticate(HttpState *hs, char *line) { char cred[64], *user, *pass, *realm, *s, *spec, *name; Fmt fmt; UserPasswd *up; spec = nil; up = nil; cred[0] = 0; hs->autherror[0] = 0; if(cistrncmp(line, "basic ", 6) != 0){ werrstr("unknown auth: %s", line); goto error; } line += 6; if(cistrncmp(line, "realm=", 6) != 0){ werrstr("missing realm: %s", line); goto error; } line += 6; user = hs->c->url->user; pass = hs->c->url->passwd; if(user==nil || pass==nil){ realm = unquote(line, &line); fmtstrinit(&fmt); name = servername(hs->netaddr); fmtprint(&fmt, "proto=pass service=http server=%q realm=%q", name, realm); free(name); if(hs->c->url->user) fmtprint(&fmt, " user=%q", hs->c->url->user); spec = fmtstrflush(&fmt); if(spec == nil) goto error; if((up = auth_getuserpasswd(nil, "%s", spec)) == nil) goto error; user = up->user; pass = up->passwd; } if((s = smprint("%s:%s", user, pass)) == nil) goto error; free(up); enc64(cred, sizeof(cred), (uint8_t*)s, strlen(s)); memset(s, 0, strlen(s)); free(s); hs->credentials = smprint("Basic %s", cred); if(hs->credentials == nil) goto error; return; error: free(up); free(spec); snprint(hs->autherror, sizeof hs->autherror, "%r"); fprint(2, "%s: Authentication failed: %r\n", argv0); }
void extstart(void) { char *user, *disp; int fd, flags; static void *arg[2]; user = getenv("USER"); if(user == nil) return; disp = getenv("DISPLAY"); if(disp) exname = smprint("/tmp/.sam.%s.%s", user, disp); else exname = smprint("/tmp/.sam.%s", user); if(exname == nil){ fprint(2, "not posting for B: out of memory\n"); return; } if(mkfifo(exname, 0600) < 0){ struct stat st; if(errno != EEXIST || stat(exname, &st) < 0) return; if(!S_ISFIFO(st.st_mode)){ removeextern(); if(mkfifo(exname, 0600) < 0) return; } } fd = open(exname, OREAD|ONONBLOCK); if(fd == -1){ removeextern(); return; } /* * Turn off no-delay and provide ourselves as a lingering * writer so as not to get end of file on read. */ flags = fcntl(fd, F_GETFL, 0); if(flags<0 || fcntl(fd, F_SETFL, flags&~O_NONBLOCK)<0 ||open(exname, OWRITE) < 0){ close(fd); removeextern(); return; } plumbc = chancreate(sizeof(int), 0); chansetname(plumbc, "plumbc"); arg[0] = plumbc; arg[1] = (void*)(uintptr)fd; proccreate(extproc, arg, STACK); atexit(removeextern); }
void runcmd(int reqfd, int datafd, char *svc, char *cmd, char *arg1, char *arg2) { char *p; int fd, cmdpid, child; cmdpid = rfork(RFPROC|RFMEM|RFNOTEG|RFFDG|RFENVG); switch (cmdpid) { case -1: syslog(0, "ssh", "fork failed: %r"); exits("fork"); case 0: if (restdir == nil) { p = smprint("/usr/%s", uname); if (p && access(p, AREAD) == 0 && chdir(p) < 0) { syslog(0, "ssh", "can't chdir(%s): %r", p); exits("can't chdir"); } free(p); } p = strrchr(cmd, '/'); if (p) ++p; else p = cmd; dup(datafd, 0); dup(datafd, 1); dup(datafd, 2); close(datafd); putenv("service", svc); fprint(errfd, "starting %s\n", cmd); execl(cmd, p, arg1, arg2, nil); syslog(0, "ssh", "cannot exec %s: %r", cmd); exits("exec"); default: close(datafd); fprint(errfd, "waiting for child %d\n", cmdpid); while ((child = waitpid()) != cmdpid && child != -1) fprint(errfd, "child %d passed\n", child); if (child == -1) fprint(errfd, "wait failed: %r\n"); syslog(0, "ssh", "server closing ssh session for %s", uname); fprint(errfd, "closing connection\n"); fprint(reqfd, "close"); p = smprint("/proc/%d/notepg", toppid); if (p) { fd = open(p, OWRITE); fprint(fd, "interrupt"); close(fd); } exits(nil); } }
void reader(void *v) { int cfd, tfd, forking = 0, pid, newpid; char *ctl, *truss; Msg *s; pid = (int)(uintptr)v; ctl = smprint("/proc/%d/ctl", pid); if ((cfd = open(ctl, OWRITE)) < 0) die(smprint("%s: %r", ctl)); truss = smprint("/proc/%d/syscall", pid); if ((tfd = open(truss, OREAD)) < 0) die(smprint("%s: %r", truss)); cwrite(cfd, ctl, "stop", 4); cwrite(cfd, truss, "startsyscall", 12); s = mallocz(sizeof(Msg) + Bufsize, 1); s->pid = pid; s->buf = (char *)&s[1]; while(pread(tfd, s->buf, Bufsize - 1, 0) > 0){ if (forking && s->buf[1] == '=' && s->buf[3] != '-') { forking = 0; newpid = strtol(&s->buf[3], 0, 0); sendp(forkc, (void*)newpid); procrfork(reader, (void*)newpid, Stacksize, 0); } /* * There are three tests here and they (I hope) guarantee * no false positives. */ if (strstr(s->buf, " Rfork") != nil) { char *a[8]; char *rf; rf = strdup(s->buf); if (tokenize(rf, a, 8) == 5) { ulong flags; flags = strtoul(a[4], 0, 16); if (flags & RFPROC) forking = 1; } free(rf); } sendp(out, s); cwrite(cfd, truss, "startsyscall", 12); s = mallocz(sizeof(Msg) + Bufsize, 1); s->pid = pid; s->buf = (char *)&s[1]; } sendp(quit, nil); threadexitsall(nil); }
void reader(void *v) { char *ctl, *truss; int pid, newpid; int cfd, tfd; Str *s; int forking = 0; pid = (int)v; ctl = smprint("/proc/%d/ctl", pid); if ((cfd = open(ctl, OWRITE)) < 0) die(smprint("%s: %r", ctl)); truss = smprint("/proc/%d/syscall", pid); if ((tfd = open(truss, OREAD)) < 0) die(smprint("%s: %r", truss)); cwrite(cfd, ctl, "stop", 4); cwrite(cfd, truss, "startsyscall", 12); s = mallocz(sizeof(Str) + 8192, 1); s->buf = (char *)&s[1]; /* 8191 is not a typo. It ensures a null-terminated string. The device currently limits to 4096 anyway */ while((s->len = pread(tfd, s->buf, 8191, 0ULL)) > 0){ if (forking && (s->buf[1] == '=') && (s->buf[3] != '-')) { forking = 0; newpid = strtol(&s->buf[3], 0, 0); sendp(forkc, (void*)newpid); procrfork(reader, (void*)newpid, 8192, 0); } /* There are three tests here and they (I hope) guarantee no false positives */ if (strstr(s->buf, " Rfork") != nil) { char *a[8]; char *rf; rf = strdup(s->buf); if (tokenize(rf, a, 8) == 5) { unsigned long flags; flags = strtoul(a[4], 0, 16); if (flags & RFPROC) forking = 1; } free(rf); } sendp(out, s); cwrite(cfd, truss, "startsyscall", 12); s = mallocz(sizeof(Str) + 8192, 1); s->buf = (char *)&s[1]; } sendp(quit, nil); threadexitsall(nil); }
void hang(int pid) { char *ctl; int cfd; ctl = smprint("/proc/%d/ctl", pid); if ((cfd = open(ctl, OWRITE)) < 0) die(smprint("%s: %r", ctl)); if (write(cfd, "hang", 4) < 4) { print("%s: %r\n", ctl); exits("can't hang child"); } }
Tnode* initxentry(Entry e) { Xentry *t; t = mallocz(sizeof *t, 1); t->t.nkid = -1; t->t.str = smprint("Entry gen=%#ux psize=%d dsize=%d depth=%d flags=%#ux size=%lld score=%V", e.gen, e.psize, e.dsize, e.depth, e.flags, e.size, e.score); if(e.flags & VtEntryLocal) t->t.str = smprint("%s archive=%d snap=%d tag=%#ux", t->t.str, e.archive, e.snap, e.tag); t->t.expand = xentryexpand; t->e = e; return (Tnode*)t; }
void emitword(Bytes *b, Rune *r, int nr) { char *s; int space; if(nr == 0) return; s = smprint("%.*S", nr, r); space = b->n > 0 && !isspace(b->b[b->n-1]) && (!newitextitem || !closingpunct(*s)); if(col > 0 && col+space+nr > width){ growbytes(b, "\n", 1); space = 0; col = 0; } if(space && col > 0){ growbytes(b, " ", 1); col++; } growbytes(b, s, strlen(s)); col += nr; free(s); inword = 0; newitextitem = 0; }
void removeall(char *p) { DIR *d; struct dirent *dp; char *q; struct stat st; if(stat(p, &st) < 0) return; if(!S_ISDIR(st.st_mode)) { unlink(p); return; } d = opendir(p); while((dp = readdir(d)) != nil) { if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; q = smprint("%s/%s", p, dp->d_name); removeall(q); free(q); } closedir(d); rmdir(p); }
char* _applegetsnarf(void) { char *s, *t; CFArrayRef flavors; CFDataRef data; CFIndex nflavor, ndata, j; CFStringRef type; ItemCount nitem; PasteboardItemID id; PasteboardSyncFlags flags; UInt32 i; /* fprint(2, "applegetsnarf\n"); */ qlock(&clip.lk); if(clip.apple == nil){ if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){ fprint(2, "apple pasteboard create failed\n"); qunlock(&clip.lk); return nil; } } flags = PasteboardSynchronize(clip.apple); if(flags&kPasteboardClientIsOwner){ s = strdup(clip.buf); qunlock(&clip.lk); return s; } if(PasteboardGetItemCount(clip.apple, &nitem) != noErr){ fprint(2, "apple pasteboard get item count failed\n"); qunlock(&clip.lk); return nil; } for(i=1; i<=nitem; i++){ if(PasteboardGetItemIdentifier(clip.apple, i, &id) != noErr) continue; if(PasteboardCopyItemFlavors(clip.apple, id, &flavors) != noErr) continue; nflavor = CFArrayGetCount(flavors); for(j=0; j<nflavor; j++){ type = (CFStringRef)CFArrayGetValueAtIndex(flavors, j); if(!UTTypeConformsTo(type, CFSTR("public.utf16-plain-text"))) continue; if(PasteboardCopyItemFlavorData(clip.apple, id, type, &data) != noErr) continue; ndata = CFDataGetLength(data); qunlock(&clip.lk); s = smprint("%.*S", ndata/2, (Rune*)CFDataGetBytePtr(data)); CFRelease(flavors); CFRelease(data); for(t=s; *t; t++) if(*t == '\r') *t = '\n'; return s; } CFRelease(flavors); } qunlock(&clip.lk); return nil; }
void remoteside(void *v) { int srv_to_net[2]; int net_to_srv[2]; char *addr; int srvfd; if(ns == nil) ns = getns(); addr = smprint("unix!%s/%s", ns, srv); if(addr == nil) fatal("%r"); if(debug) fprint(dfd, "remoteside starting %s\n", addr); srvfd = dial(addr, 0, 0, 0); if(srvfd < 0) fatal("dial %s: %r", addr); if(debug) fprint(dfd, "remoteside dial %s succeeded\n", addr); fcntl(srvfd, F_SETFL, FD_CLOEXEC); /* threads to shuffle messages each way */ srv_to_net[0] = srvfd; srv_to_net[1] = netfd[1]; proccreate(shuffle, srv_to_net, Stack); net_to_srv[0] = netfd[0]; net_to_srv[1] = srvfd; shuffle(net_to_srv); threadexitsall(0); }
static void fscreate(Req *r) { FInfo fi; int rc, is_dir; char *npath; Aux *a = r->fid->aux; a->end = a->off = 0; a->cache = emalloc9p(max(Sess->mtu, MTU)); is_dir = (r->ifcall.perm & DMDIR) == DMDIR; npath = smprint("%s/%s", a->path, r->ifcall.name); if(Sess->caps & CAP_NT_SMBS) rc = ntcreateopen(a, mapfile(npath), r->ifcall.mode, r->ifcall.perm, 1, is_dir, &fi); else rc = smbcreateopen(a, mapfile(npath), r->ifcall.mode, r->ifcall.perm, 1, is_dir, &fi); if(rc == -1){ free(npath); responderrstr(r); return; } r->fid->qid = mkqid(npath, fi.attribs & ATTR_DIRECTORY, fi.changed, 0, 0); r->ofcall.qid = r->fid->qid; free(a->path); a->path = npath; respond(r, nil); }
void putenvq(char *name, char *val, int conf) { val = smprint("%q", val); ksetenv(name, val, conf); free(val); }
static void coutiprint(ASTNode *n, int ind, int env) { Symbol *s; Nodes *r; if(n == nil){ fmtprint(fout, "/* nil */ ;\n"); return; } switch(n->t){ case ASTDECL: break; case ASTMODULE: s = getfreesym(&cglob, smprint("run%s", n->sym->name)); fmtprint(fout, "int\n%s(void)\n{\n\tint rc;\n\n\trc = 0;\n", s->name); cloc = emalloc(sizeof(SymTab)); getsym(cloc, 0, "rc"); for(r = n->nl; r != nil; r = r->next) coutiprint(r->n, ind + 1, env); fmtprint(fout, "\treturn rc;\n}\n"); break; case ASTASS: coutass(n->n1, n->n2, ind, env); break; default: error(n, "coutiprint: unknown %A", n->t); } }
int dialfactotum(void) { int fd; struct sockaddr_un su; char *name; name = smprint("%s/factotum", getns()); if(name == nil || access(name, 0) < 0) return -1; memset(&su, 0, sizeof su); su.sun_family = AF_UNIX; if(strlen(name)+1 > sizeof su.sun_path){ werrstr("socket name too long"); return -1; } strcpy(su.sun_path, name); if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ werrstr("socket: %r"); return -1; } if(connect(fd, (struct sockaddr*)&su, sizeof su) < 0){ werrstr("connect %s: %r", name); close(fd); return -1; } return lfdfd(fd); }
int authdial(char *netroot, char *dom) { char *p; int rv; if(dom == nil) /* look for one relative to my machine */ return dial(netmkaddr("$auth", netroot, "ticket"), 0, 0, 0); /* look up an auth server in an authentication domain */ p = csgetvalue(netroot, "authdom", dom, "auth", nil); /* if that didn't work, just try the IP domain */ if(p == nil) p = csgetvalue(netroot, "dom", dom, "auth", nil); /* * if that didn't work, try p9auth.$dom. this is very helpful if * you can't edit /lib/ndb. */ if(p == nil) p = smprint("p9auth.%s", dom); if(p == nil){ /* should no longer ever happen */ werrstr("no auth server found for %s", dom); return -1; } rv = dial(netmkaddr(p, netroot, "ticket"), 0, 0, 0); free(p); return rv; }
/* * mount tunnel if there isn't one visible. */ static void mounttunnel(int ctlfd) { int fd; char *p, *np, *q; if (access(netdir, AEXIST) >= 0) return; p = smprint("/srv/%s", srvpt? srvpt: "ssh"); np = strdup(netdir); if (p == nil || np == nil) sysfatal("out of memory"); q = strstr(np, "/ssh"); if (q != nil) *q = '\0'; fd = open(p, ORDWR); if (fd < 0) { syslog(0, "ssh", "can't open %s: %r", p); hangup(ctlfd); exits("open"); } if (mount(fd, -1, np, MBEFORE, "") < 0) { syslog(0, "ssh", "can't mount %s in %s: %r", p, np); hangup(ctlfd); exits("can't mount"); } free(p); free(np); }
void partall(void) { Disk *d; Dir *ent; char *name; int fd, i, n; fd = open("#S", OREAD); if(fd == -1) { fprint(2, "No disk\n"); return; } while((n = dirread(fd, &ent)) > 0) { for(i = 0; i < n; i++) { if(ent[i].mode & DMDIR) { name = smprint("#S/%s/data", ent[i].name); d = opendisk(name, 1, 0); if(!d) { fprint(2, "%s: %r\n", name); continue; } // XXX not safe yet: if(!mbrpart(d) && !cdpart(d) && !p9part(d, "data", 0)) if(!mbrpart(d) && !cdpart(d)) fprint(2, "%s: no partitions\n", name); close(d->fd); } } } close(fd); }
void main(int argc, char **argv) { RSApriv *key; Attr *a; char *s; fmtinstall('A', _attrfmt); fmtinstall('B', mpfmt); quotefmtinstall(); ARGBEGIN{ default: usage(); }ARGEND if(argc > 1) usage(); if((key = getkey(argc, argv, 0, &a)) == nil) sysfatal("%r"); s = smprint("key %A size=%d ek=%lB n=%lB\n", a, mpsignif(key->pub.n), key->pub.ek, key->pub.n); if(s == nil) sysfatal("smprint: %r"); write(1, s, strlen(s)); exits(nil); }
char* guessmountplace(char *dev) { char *cmd, *q; int p[2], fd[3], n; char buf[100]; if(pipe(p) < 0) sysfatal("pipe: %r"); fd[0] = -1; fd[1] = p[1]; fd[2] = -1; cmd = smprint("mount | awk 'BEGIN{v=\"%s\"; u=v; sub(/rdisk/, \"disk\", u);} ($1==v||$1==u) && $2 == \"on\" {print $3}'", dev); if(threadspawnl(fd, "sh", "sh", "-c", cmd, nil) < 0) sysfatal("exec mount|awk (to find mtpt of %s): %r", dev); /* threadspawnl closed p[1] */ free(cmd); n = readn(p[0], buf, sizeof buf-1); close(p[0]); if(n <= 0) return dev; buf[n] = 0; if((q = strchr(buf, '\n')) == nil) return dev; *q = 0; q = buf+strlen(buf); if(q>buf && *(q-1) == '/') *--q = 0; return strdup(buf); }
void main(void) { int ret = 0; // success uint64_t start, end; char *msg; start = nsec(); sleep(1); end = nsec(); if (end <= start) ret = 1; if (verbose) print("nanotime: start %llx, end %llx\n", start, end); if(ret){ msg = smprint("nanotime: FAIL: start %llx end %llx", start, end); print("%s\n", msg); exits(msg); } print("PASS\n"); exits("PASS"); }
/* Test printer that loads unusual decimal point and separator */ char* mysmprint(char *fmt, ...) { Fmt f; if(fmtstrinit(&f) < 0) return 0; va_start(f.args, fmt); f.decimal = smprint("%C", lightsmiley); f.thousands = smprint("%C", darksmiley); f.grouping = "\1\2\3\4"; if(dofmt(&f, fmt) < 0) return 0; va_end(f.args); return fmtstrflush(&f); }
void main(int argc, char **argv) { DSApriv *key; Attr *a; char *s; fmtinstall('A', _attrfmt); fmtinstall('B', mpfmt); quotefmtinstall(); ARGBEGIN{ default: usage(); }ARGEND if(argc > 1) usage(); if((key = getdsakey(argc, argv, 0, &a)) == nil) sysfatal("%r"); s = smprint("key %A p=%lB q=%lB alpha=%lB key=%lB\n", a, key->pub.p, key->pub.q, key->pub.alpha, key->pub.key); if(s == nil) sysfatal("smprint: %r"); write(1, s, strlen(s)); exits(nil); }
char* system(void) { char *cpu, *p, *q; static char *kernel; cpu = getenv("cputype"); if(cpu == 0) { cpu = "mips"; print("$cputype not set; assuming %s\n", cpu); } p = getenv("terminal"); if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) { p = "ch"; print("missing or bad $terminal; assuming %s\n", p); } else{ p++; q = strchr(p, ' '); if(q) *q = 0; } if(kernel != nil) free(kernel); kernel = smprint("/%s/9%s", cpu, p); return kernel; }
void threadmain(int argc, char* argv[]) { char* mnt; char* srv; int mflag; Biobuf* b; char* user; srv = nil; mnt = nil; mflag = MREPL|MCREATE; ARGBEGIN{ case 'a': mflag = MAFTER|MCREATE; break; case 'b': mflag = MBEFORE|MCREATE; break; case 'c': mflag = MREPL|MCREATE; break; case 's': srv = EARGF(usage()); break; case 'm': mnt = EARGF(usage()); break; case 'D': debug = 1; chatty9p++; break; default: usage(); }ARGEND; if(argc != 1) usage(); tfname = argv[0]; ttfname = smprint("%s.new", tfname); b = Bopen(tfname, OREAD); if(b == nil) sysfatal("%s: %r", tfname); trie = rdtrie(b); Bterm(b); if(trie == nil) sysfatal("%s: %r", tfname); if(srv == nil && mnt == nil){ mnt = "/mnt/tags"; srv = srvname(tfname); } if(!chatty9p) rfork(RFNOTEG); sfs.tree = alloctree(nil, nil, DMDIR|0777, nil); user = getuser(); ctlf = createfile(sfs.tree->root, "ctl", user, 0666, nil); threadpostmountsrv(&sfs, srv, mnt, mflag); threadexits(nil); }
void sendplaylist(char *file, char *onum) { static int fd = -1; char *b; if(file == nil){ if(fd >= 0) close(fd); fd = open(playlistfile, OWRITE|OTRUNC); if(fd < 0) sysfatal("%s: truncate: %r", playlistfile); return; } if(fd < 0){ fd = open(playlistfile, OWRITE); if(fd < 0) sysfatal("%s: %r", playlistfile); } b = smprint("%q %q\n", file, onum); if(debug & DBGPLAY) fprint(2, "sendplaylist @%s@\n", b); if(write(fd , b, strlen(b)) != strlen(b)) sysfatal("sendplaylist: %r"); }
void removeall(char *p) { int fd, n, i; Dir *d; char *q; if(remove(p) >= 0) return; if((d = dirstat(p)) == nil) return; if(!(d->mode & DMDIR)) { free(d); return; } free(d); if((fd = open(p, OREAD)) < 0) return; n = dirreadall(fd, &d); close(fd); for(i=0; i<n; i++) { q = smprint("%s/%s", p, d[i].name); removeall(q); free(q); } free(d); }
void addstrdata(char *name, char *value) { LSym *s, *sp; char *p; uchar reachable; p = smprint("%s.str", name); sp = linklookup(ctxt, p, 0); free(p); addstring(sp, value); sp->type = SRODATA; s = linklookup(ctxt, name, 0); s->size = 0; s->dupok = 1; reachable = s->reachable; addaddr(ctxt, s, sp); adduint32(ctxt, s, strlen(value)); if(PtrSize == 8) adduint32(ctxt, s, 0); // round struct to pointer width // addstring, addaddr, etc., mark the symbols as reachable. // In this case that is not necessarily true, so stick to what // we know before entering this function. s->reachable = reachable; sp->reachable = reachable; }