xref: /plan9/sys/src/cmd/mk/plan9.c (revision 7f49a7ff54b1fd29a638d67350c7ceb952fbe2d6)
1219b2ee8SDavid du Colombier #include	"mk.h"
2219b2ee8SDavid du Colombier 
37dd7cddfSDavid du Colombier char 	*shell =	"/bin/rc";
47dd7cddfSDavid du Colombier char 	*shellname =	"rc";
57dd7cddfSDavid du Colombier 
67dd7cddfSDavid du Colombier static	Word	*encodenulls(char*, int);
77dd7cddfSDavid du Colombier 
8219b2ee8SDavid du Colombier void
97dd7cddfSDavid du Colombier readenv(void)
10219b2ee8SDavid du Colombier {
117dd7cddfSDavid du Colombier 	char *p;
12219b2ee8SDavid du Colombier 	int envf, f;
139a747e4fSDavid du Colombier 	Dir *e;
149a747e4fSDavid du Colombier 	char nam[1024];
15219b2ee8SDavid du Colombier 	int i, n, len;
16219b2ee8SDavid du Colombier 	Word *w;
17219b2ee8SDavid du Colombier 
187dd7cddfSDavid du Colombier 	rfork(RFENVG);	/*  use copy of the current environment variables */
197dd7cddfSDavid du Colombier 
20219b2ee8SDavid du Colombier 	envf = open("/env", OREAD);
21219b2ee8SDavid du Colombier 	if(envf < 0)
22219b2ee8SDavid du Colombier 		return;
239a747e4fSDavid du Colombier 	while((n = dirread(envf, &e)) > 0){
24219b2ee8SDavid du Colombier 		for(i = 0; i < n; i++){
25219b2ee8SDavid du Colombier 			len = e[i].length;
267dd7cddfSDavid du Colombier 				/* don't import funny names, NULL values,
277dd7cddfSDavid du Colombier 				 * or internal mk variables
287dd7cddfSDavid du Colombier 				 */
297dd7cddfSDavid du Colombier 			if(len <= 0 || *shname(e[i].name) != '\0')
307dd7cddfSDavid du Colombier 				continue;
317dd7cddfSDavid du Colombier 			if (symlook(e[i].name, S_INTERNAL, 0))
32219b2ee8SDavid du Colombier 				continue;
33276e7d6dSDavid du Colombier 			snprint(nam, sizeof nam, "/env/%s", e[i].name);
34219b2ee8SDavid du Colombier 			f = open(nam, OREAD);
35219b2ee8SDavid du Colombier 			if(f < 0)
36219b2ee8SDavid du Colombier 				continue;
377dd7cddfSDavid du Colombier 			p = Malloc(len+1);
387dd7cddfSDavid du Colombier 			if(read(f, p, len) != len){
39219b2ee8SDavid du Colombier 				perror(nam);
40219b2ee8SDavid du Colombier 				close(f);
41219b2ee8SDavid du Colombier 				continue;
42219b2ee8SDavid du Colombier 			}
43219b2ee8SDavid du Colombier 			close(f);
447dd7cddfSDavid du Colombier 			if (p[len-1] == 0)
45219b2ee8SDavid du Colombier 				len--;
46219b2ee8SDavid du Colombier 			else
477dd7cddfSDavid du Colombier 				p[len] = 0;
487dd7cddfSDavid du Colombier 			w = encodenulls(p, len);
497dd7cddfSDavid du Colombier 			free(p);
507dd7cddfSDavid du Colombier 			p = strdup(e[i].name);
517dd7cddfSDavid du Colombier 			setvar(p, (void *) w);
524de34a7eSDavid du Colombier 			symlook(p, S_EXPORTED, (void*)"")->u.ptr = "";
53219b2ee8SDavid du Colombier 		}
549a747e4fSDavid du Colombier 		free(e);
55219b2ee8SDavid du Colombier 	}
56219b2ee8SDavid du Colombier 	close(envf);
57219b2ee8SDavid du Colombier }
58219b2ee8SDavid du Colombier 
597dd7cddfSDavid du Colombier /* break string of values into words at 01's or nulls*/
607dd7cddfSDavid du Colombier static Word *
61219b2ee8SDavid du Colombier encodenulls(char *s, int n)
62219b2ee8SDavid du Colombier {
63219b2ee8SDavid du Colombier 	Word *w, *head;
64219b2ee8SDavid du Colombier 	char *cp;
65219b2ee8SDavid du Colombier 
66219b2ee8SDavid du Colombier 	head = w = 0;
67219b2ee8SDavid du Colombier 	while (n-- > 0) {
687dd7cddfSDavid du Colombier 		for (cp = s; *cp && *cp != '\0'; cp++)
69219b2ee8SDavid du Colombier 				n--;
70219b2ee8SDavid du Colombier 		*cp = 0;
71219b2ee8SDavid du Colombier 		if (w) {
72219b2ee8SDavid du Colombier 			w->next = newword(s);
73219b2ee8SDavid du Colombier 			w = w->next;
74219b2ee8SDavid du Colombier 		} else
75219b2ee8SDavid du Colombier 			head = w = newword(s);
76219b2ee8SDavid du Colombier 		s = cp+1;
77219b2ee8SDavid du Colombier 	}
78219b2ee8SDavid du Colombier 	if (!head)
79219b2ee8SDavid du Colombier 		head = newword("");
80219b2ee8SDavid du Colombier 	return head;
81219b2ee8SDavid du Colombier }
82219b2ee8SDavid du Colombier 
83219b2ee8SDavid du Colombier /* as well as 01's, change blanks to nulls, so that rc will
84219b2ee8SDavid du Colombier  * treat the words as separate arguments
85219b2ee8SDavid du Colombier  */
86219b2ee8SDavid du Colombier void
877dd7cddfSDavid du Colombier exportenv(Envy *e)
88219b2ee8SDavid du Colombier {
897dd7cddfSDavid du Colombier 	int f, n, hasvalue, first;
907dd7cddfSDavid du Colombier 	Word *w;
917dd7cddfSDavid du Colombier 	Symtab *sy;
929a747e4fSDavid du Colombier 	char nam[256];
93219b2ee8SDavid du Colombier 
947dd7cddfSDavid du Colombier 	for(;e->name; e++){
957dd7cddfSDavid du Colombier 		sy = symlook(e->name, S_VAR, 0);
967dd7cddfSDavid du Colombier 		if (e->values == 0 || e->values->s == 0 || e->values->s[0] == 0)
977dd7cddfSDavid du Colombier 			hasvalue = 0;
987dd7cddfSDavid du Colombier 		else
997dd7cddfSDavid du Colombier 			hasvalue = 1;
1007dd7cddfSDavid du Colombier 		if(sy == 0 && !hasvalue)	/* non-existant null symbol */
1017dd7cddfSDavid du Colombier 			continue;
102276e7d6dSDavid du Colombier 		snprint(nam, sizeof nam, "/env/%s", e->name);
1037dd7cddfSDavid du Colombier 		if (sy != 0 && !hasvalue) {	/* Remove from environment */
10499eb86a7SDavid du Colombier 				/* we could remove it from the symbol table
1057dd7cddfSDavid du Colombier 				 * too, but we're in the child copy, and it
1067dd7cddfSDavid du Colombier 				 * would still remain in the parent's table.
1077dd7cddfSDavid du Colombier 				 */
1087dd7cddfSDavid du Colombier 			remove(nam);
1097dd7cddfSDavid du Colombier 			delword(e->values);
1107dd7cddfSDavid du Colombier 			e->values = 0;		/* memory leak */
1117dd7cddfSDavid du Colombier 			continue;
1127dd7cddfSDavid du Colombier 		}
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 		f = create(nam, OWRITE, 0666L);
115219b2ee8SDavid du Colombier 		if(f < 0) {
1167dd7cddfSDavid du Colombier 			fprint(2, "can't create %s, f=%d\n", nam, f);
1177dd7cddfSDavid du Colombier 			perror(nam);
1187dd7cddfSDavid du Colombier 			continue;
119219b2ee8SDavid du Colombier 		}
1207dd7cddfSDavid du Colombier 		first = 1;
1217dd7cddfSDavid du Colombier 		for (w = e->values; w; w = w->next) {
1227dd7cddfSDavid du Colombier 			n = strlen(w->s);
123219b2ee8SDavid du Colombier 			if (n) {
1247dd7cddfSDavid du Colombier 				if(first)
1257dd7cddfSDavid du Colombier 					first = 0;
1267dd7cddfSDavid du Colombier 				else{
127219b2ee8SDavid du Colombier 					if (write (f, "\0", 1) != 1)
1287dd7cddfSDavid du Colombier 						perror(nam);
129219b2ee8SDavid du Colombier 				}
1307dd7cddfSDavid du Colombier 				if (write(f, w->s, n) != n)
1317dd7cddfSDavid du Colombier 					perror(nam);
1327dd7cddfSDavid du Colombier 			}
133219b2ee8SDavid du Colombier 		}
134219b2ee8SDavid du Colombier 		close(f);
135219b2ee8SDavid du Colombier 	}
136219b2ee8SDavid du Colombier }
137219b2ee8SDavid du Colombier 
138219b2ee8SDavid du Colombier int
139219b2ee8SDavid du Colombier waitfor(char *msg)
140219b2ee8SDavid du Colombier {
1419a747e4fSDavid du Colombier 	Waitmsg *w;
142219b2ee8SDavid du Colombier 	int pid;
143219b2ee8SDavid du Colombier 
1449a747e4fSDavid du Colombier 	if((w=wait()) == nil)
1459a747e4fSDavid du Colombier 		return -1;
1469a747e4fSDavid du Colombier 	strecpy(msg, msg+ERRMAX, w->msg);
1479a747e4fSDavid du Colombier 	pid = w->pid;
1489a747e4fSDavid du Colombier 	free(w);
149219b2ee8SDavid du Colombier 	return pid;
150219b2ee8SDavid du Colombier }
151219b2ee8SDavid du Colombier 
152219b2ee8SDavid du Colombier void
153219b2ee8SDavid du Colombier expunge(int pid, char *msg)
154219b2ee8SDavid du Colombier {
155219b2ee8SDavid du Colombier 	postnote(PNPROC, pid, msg);
156219b2ee8SDavid du Colombier }
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier int
1597dd7cddfSDavid du Colombier execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
1607dd7cddfSDavid du Colombier {
1617dd7cddfSDavid du Colombier 	char *p;
1627dd7cddfSDavid du Colombier 	int tot, n, pid, in[2], out[2];
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier 	if(buf && pipe(out) < 0){
1657dd7cddfSDavid du Colombier 		perror("pipe");
1667dd7cddfSDavid du Colombier 		Exit();
1677dd7cddfSDavid du Colombier 	}
1687dd7cddfSDavid du Colombier 	pid = rfork(RFPROC|RFFDG|RFENVG);
1697dd7cddfSDavid du Colombier 	if(pid < 0){
1707dd7cddfSDavid du Colombier 		perror("mk rfork");
1717dd7cddfSDavid du Colombier 		Exit();
1727dd7cddfSDavid du Colombier 	}
1737dd7cddfSDavid du Colombier 	if(pid == 0){
1747dd7cddfSDavid du Colombier 		if(buf)
1757dd7cddfSDavid du Colombier 			close(out[0]);
1767dd7cddfSDavid du Colombier 		if(pipe(in) < 0){
1777dd7cddfSDavid du Colombier 			perror("pipe");
1787dd7cddfSDavid du Colombier 			Exit();
1797dd7cddfSDavid du Colombier 		}
1807dd7cddfSDavid du Colombier 		pid = fork();
1817dd7cddfSDavid du Colombier 		if(pid < 0){
1827dd7cddfSDavid du Colombier 			perror("mk fork");
1837dd7cddfSDavid du Colombier 			Exit();
1847dd7cddfSDavid du Colombier 		}
1857dd7cddfSDavid du Colombier 		if(pid != 0){
1867dd7cddfSDavid du Colombier 			dup(in[0], 0);
1877dd7cddfSDavid du Colombier 			if(buf){
1887dd7cddfSDavid du Colombier 				dup(out[1], 1);
1897dd7cddfSDavid du Colombier 				close(out[1]);
1907dd7cddfSDavid du Colombier 			}
1917dd7cddfSDavid du Colombier 			close(in[0]);
1927dd7cddfSDavid du Colombier 			close(in[1]);
1937dd7cddfSDavid du Colombier 			if (e)
1947dd7cddfSDavid du Colombier 				exportenv(e);
1957dd7cddfSDavid du Colombier 			if(shflags)
196f19e7b74SDavid du Colombier 				execl(shell, shellname, shflags, args, nil);
1977dd7cddfSDavid du Colombier 			else
198f19e7b74SDavid du Colombier 				execl(shell, shellname, args, nil);
1997dd7cddfSDavid du Colombier 			perror(shell);
2007dd7cddfSDavid du Colombier 			_exits("exec");
2017dd7cddfSDavid du Colombier 		}
2027dd7cddfSDavid du Colombier 		close(out[1]);
2037dd7cddfSDavid du Colombier 		close(in[0]);
20499eb86a7SDavid du Colombier 		p = cmd+strlen(cmd);
20599eb86a7SDavid du Colombier 		while(cmd < p){
2067dd7cddfSDavid du Colombier 			n = write(in[1], cmd, p-cmd);
2077dd7cddfSDavid du Colombier 			if(n < 0)
2087dd7cddfSDavid du Colombier 				break;
20999eb86a7SDavid du Colombier 			cmd += n;
2107dd7cddfSDavid du Colombier 		}
2117dd7cddfSDavid du Colombier 		close(in[1]);
2127dd7cddfSDavid du Colombier 		_exits(0);
2137dd7cddfSDavid du Colombier 	}
2147dd7cddfSDavid du Colombier 	if(buf){
2157dd7cddfSDavid du Colombier 		close(out[1]);
2167dd7cddfSDavid du Colombier 		tot = 0;
2177dd7cddfSDavid du Colombier 		for(;;){
2187dd7cddfSDavid du Colombier 			if (buf->current >= buf->end)
2197dd7cddfSDavid du Colombier 				growbuf(buf);
2207dd7cddfSDavid du Colombier 			n = read(out[0], buf->current, buf->end-buf->current);
2217dd7cddfSDavid du Colombier 			if(n <= 0)
2227dd7cddfSDavid du Colombier 				break;
2237dd7cddfSDavid du Colombier 			buf->current += n;
2247dd7cddfSDavid du Colombier 			tot += n;
2257dd7cddfSDavid du Colombier 		}
2267dd7cddfSDavid du Colombier 		if (tot && buf->current[-1] == '\n')
2277dd7cddfSDavid du Colombier 			buf->current--;
2287dd7cddfSDavid du Colombier 		close(out[0]);
2297dd7cddfSDavid du Colombier 	}
2307dd7cddfSDavid du Colombier 	return pid;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier int
2347dd7cddfSDavid du Colombier pipecmd(char *cmd, Envy *e, int *fd)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier 	int pid, pfd[2];
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier 	if(DEBUG(D_EXEC))
2397dd7cddfSDavid du Colombier 		fprint(1, "pipecmd='%s'\n", cmd);/**/
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	if(fd && pipe(pfd) < 0){
2427dd7cddfSDavid du Colombier 		perror("pipe");
2437dd7cddfSDavid du Colombier 		Exit();
2447dd7cddfSDavid du Colombier 	}
2457dd7cddfSDavid du Colombier 	pid = rfork(RFPROC|RFFDG|RFENVG);
2467dd7cddfSDavid du Colombier 	if(pid < 0){
2477dd7cddfSDavid du Colombier 		perror("mk fork");
2487dd7cddfSDavid du Colombier 		Exit();
2497dd7cddfSDavid du Colombier 	}
2507dd7cddfSDavid du Colombier 	if(pid == 0){
2517dd7cddfSDavid du Colombier 		if(fd){
2527dd7cddfSDavid du Colombier 			close(pfd[0]);
2537dd7cddfSDavid du Colombier 			dup(pfd[1], 1);
2547dd7cddfSDavid du Colombier 			close(pfd[1]);
2557dd7cddfSDavid du Colombier 		}
2567dd7cddfSDavid du Colombier 		if(e)
2577dd7cddfSDavid du Colombier 			exportenv(e);
2587dd7cddfSDavid du Colombier 		if(shflags)
259f19e7b74SDavid du Colombier 			execl(shell, shellname, shflags, "-c", cmd, nil);
2607dd7cddfSDavid du Colombier 		else
261f19e7b74SDavid du Colombier 			execl(shell, shellname, "-c", cmd, nil);
2627dd7cddfSDavid du Colombier 		perror(shell);
2637dd7cddfSDavid du Colombier 		_exits("exec");
2647dd7cddfSDavid du Colombier 	}
2657dd7cddfSDavid du Colombier 	if(fd){
2667dd7cddfSDavid du Colombier 		close(pfd[1]);
2677dd7cddfSDavid du Colombier 		*fd = pfd[0];
2687dd7cddfSDavid du Colombier 	}
2697dd7cddfSDavid du Colombier 	return pid;
2707dd7cddfSDavid du Colombier }
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier void
2737dd7cddfSDavid du Colombier Exit(void)
2747dd7cddfSDavid du Colombier {
2759a747e4fSDavid du Colombier 	while(waitpid() >= 0)
2767dd7cddfSDavid du Colombier 		;
2777dd7cddfSDavid du Colombier 	exits("error");
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier int
2817dd7cddfSDavid du Colombier notifyf(void *a, char *msg)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier 	static int nnote;
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier 	USED(a);
2867dd7cddfSDavid du Colombier 	if(++nnote > 100){	/* until andrew fixes his program */
2877dd7cddfSDavid du Colombier 		fprint(2, "mk: too many notes\n");
2887dd7cddfSDavid du Colombier 		notify(0);
2897dd7cddfSDavid du Colombier 		abort();
2907dd7cddfSDavid du Colombier 	}
2917dd7cddfSDavid du Colombier 	if(strcmp(msg, "interrupt")!=0 && strcmp(msg, "hangup")!=0)
2927dd7cddfSDavid du Colombier 		return 0;
2937dd7cddfSDavid du Colombier 	killchildren(msg);
2947dd7cddfSDavid du Colombier 	return -1;
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier void
2987dd7cddfSDavid du Colombier catchnotes()
2997dd7cddfSDavid du Colombier {
3007dd7cddfSDavid du Colombier 	atnotify(notifyf, 1);
3017dd7cddfSDavid du Colombier }
3027dd7cddfSDavid du Colombier 
3037dd7cddfSDavid du Colombier char*
3047dd7cddfSDavid du Colombier maketmp(void)
3057dd7cddfSDavid du Colombier {
3067dd7cddfSDavid du Colombier 	static char temp[] = "/tmp/mkargXXXXXX";
3077dd7cddfSDavid du Colombier 
3087dd7cddfSDavid du Colombier 	mktemp(temp);
3097dd7cddfSDavid du Colombier 	return temp;
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier int
3137dd7cddfSDavid du Colombier chgtime(char *name)
3147dd7cddfSDavid du Colombier {
3157dd7cddfSDavid du Colombier 	Dir sbuf;
3167dd7cddfSDavid du Colombier 
3179a747e4fSDavid du Colombier 	if(access(name, AEXIST) >= 0) {
3189a747e4fSDavid du Colombier 		nulldir(&sbuf);
3197dd7cddfSDavid du Colombier 		sbuf.mtime = time((long *)0);
3207dd7cddfSDavid du Colombier 		return dirwstat(name, &sbuf);
3217dd7cddfSDavid du Colombier 	}
3227dd7cddfSDavid du Colombier 	return close(create(name, OWRITE, 0666));
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier 
3257dd7cddfSDavid du Colombier void
3267dd7cddfSDavid du Colombier rcopy(char **to, Resub *match, int n)
3277dd7cddfSDavid du Colombier {
3287dd7cddfSDavid du Colombier 	int c;
3297dd7cddfSDavid du Colombier 	char *p;
3307dd7cddfSDavid du Colombier 
3317dd7cddfSDavid du Colombier 	*to = match->sp;		/* stem0 matches complete target */
3327dd7cddfSDavid du Colombier 	for(to++, match++; --n > 0; to++, match++){
3337dd7cddfSDavid du Colombier 		if(match->sp && match->ep){
3347dd7cddfSDavid du Colombier 			p = match->ep;
3357dd7cddfSDavid du Colombier 			c = *p;
3367dd7cddfSDavid du Colombier 			*p = 0;
3377dd7cddfSDavid du Colombier 			*to = strdup(match->sp);
3387dd7cddfSDavid du Colombier 			*p = c;
3397dd7cddfSDavid du Colombier 		}
3407dd7cddfSDavid du Colombier 		else
3417dd7cddfSDavid du Colombier 			*to = 0;
3427dd7cddfSDavid du Colombier 	}
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier 
345dc5a79c1SDavid du Colombier void
346dc5a79c1SDavid du Colombier dirtime(char *dir, char *path)
3477dd7cddfSDavid du Colombier {
348dc5a79c1SDavid du Colombier 	int i, fd, n;
349*7f49a7ffSDavid du Colombier 	ulong mtime;
350dc5a79c1SDavid du Colombier 	Dir *d;
351dc5a79c1SDavid du Colombier 	char buf[4096];
3529a747e4fSDavid du Colombier 
353dc5a79c1SDavid du Colombier 	fd = open(dir, OREAD);
354dc5a79c1SDavid du Colombier 	if(fd >= 0){
355dc5a79c1SDavid du Colombier 		while((n = dirread(fd, &d)) > 0){
356dc5a79c1SDavid du Colombier 			for(i=0; i<n; i++){
357d1da931cSDavid du Colombier 				mtime = d[i].mtime;
358d1da931cSDavid du Colombier 				/* defensive driving: this does happen */
359d1da931cSDavid du Colombier 				if(mtime == 0)
360d1da931cSDavid du Colombier 					mtime = 1;
361d1da931cSDavid du Colombier 				snprint(buf, sizeof buf, "%s%s", path,
362d1da931cSDavid du Colombier 					d[i].name);
363d1da931cSDavid du Colombier 				if(symlook(buf, S_TIME, 0) == nil)
364d1da931cSDavid du Colombier 					symlook(strdup(buf), S_TIME,
365d1da931cSDavid du Colombier 						(void*)mtime)->u.value = mtime;
366dc5a79c1SDavid du Colombier 			}
367dc5a79c1SDavid du Colombier 			free(d);
368dc5a79c1SDavid du Colombier 		}
369dc5a79c1SDavid du Colombier 		close(fd);
370dc5a79c1SDavid du Colombier 	}
371dc5a79c1SDavid du Colombier }
372dc5a79c1SDavid du Colombier 
373dc5a79c1SDavid du Colombier void
374dc5a79c1SDavid du Colombier bulkmtime(char *dir)
375dc5a79c1SDavid du Colombier {
376dc5a79c1SDavid du Colombier 	char buf[4096];
37707a38badSDavid du Colombier 	char *ss, *s, *sym;
378dc5a79c1SDavid du Colombier 
379dc5a79c1SDavid du Colombier 	if(dir){
38007a38badSDavid du Colombier 		sym = dir;
381dc5a79c1SDavid du Colombier 		s = dir;
382dc5a79c1SDavid du Colombier 		if(strcmp(dir, "/") == 0)
383d1da931cSDavid du Colombier 			strecpy(buf, buf + sizeof buf - 1, dir);
384dc5a79c1SDavid du Colombier 		else
385d1da931cSDavid du Colombier 			snprint(buf, sizeof buf, "%s/", dir);
386dc5a79c1SDavid du Colombier 	}else{
387dc5a79c1SDavid du Colombier 		s = ".";
38807a38badSDavid du Colombier 		sym = "";
389dc5a79c1SDavid du Colombier 		buf[0] = 0;
390dc5a79c1SDavid du Colombier 	}
39107a38badSDavid du Colombier 	if(symlook(sym, S_BULKED, 0))
392dc5a79c1SDavid du Colombier 		return;
39307a38badSDavid du Colombier 	ss = strdup(sym);
394dc5a79c1SDavid du Colombier 	symlook(ss, S_BULKED, (void*)ss);
395dc5a79c1SDavid du Colombier 	dirtime(s, buf);
396dc5a79c1SDavid du Colombier }
397dc5a79c1SDavid du Colombier 
398dc5a79c1SDavid du Colombier ulong
399dc5a79c1SDavid du Colombier mkmtime(char *name, int force)
400dc5a79c1SDavid du Colombier {
401dc5a79c1SDavid du Colombier 	Dir *d;
402dc5a79c1SDavid du Colombier 	char *s, *ss, carry;
403dc5a79c1SDavid du Colombier 	ulong t;
404dc5a79c1SDavid du Colombier 	Symtab *sym;
40507a38badSDavid du Colombier 	char buf[4096];
40607a38badSDavid du Colombier 
407d1da931cSDavid du Colombier 	strecpy(buf, buf + sizeof buf - 1, name);
40807a38badSDavid du Colombier 	cleanname(buf);
40907a38badSDavid du Colombier 	name = buf;
410dc5a79c1SDavid du Colombier 
411dc5a79c1SDavid du Colombier 	s = utfrrune(name, '/');
412dc5a79c1SDavid du Colombier 	if(s == name)
413dc5a79c1SDavid du Colombier 		s++;
414dc5a79c1SDavid du Colombier 	if(s){
415dc5a79c1SDavid du Colombier 		ss = name;
416dc5a79c1SDavid du Colombier 		carry = *s;
417dc5a79c1SDavid du Colombier 		*s = 0;
418dc5a79c1SDavid du Colombier 	}else{
419dc5a79c1SDavid du Colombier 		ss = 0;
420dc5a79c1SDavid du Colombier 		carry = 0;
421dc5a79c1SDavid du Colombier 	}
422dc5a79c1SDavid du Colombier 	bulkmtime(ss);
423dc5a79c1SDavid du Colombier 	if(carry)
424dc5a79c1SDavid du Colombier 		*s = carry;
425dc5a79c1SDavid du Colombier 	if(!force){
426dc5a79c1SDavid du Colombier 		sym = symlook(name, S_TIME, 0);
427dc5a79c1SDavid du Colombier 		if(sym)
4284de34a7eSDavid du Colombier 			return sym->u.value;
4299a747e4fSDavid du Colombier 		return 0;
430dc5a79c1SDavid du Colombier 	}
431dc5a79c1SDavid du Colombier 	if((d = dirstat(name)) == nil)
432dc5a79c1SDavid du Colombier 		return 0;
433dc5a79c1SDavid du Colombier 	t = d->mtime;
434dc5a79c1SDavid du Colombier 	free(d);
4359a747e4fSDavid du Colombier 	return t;
4367dd7cddfSDavid du Colombier }
437dc5a79c1SDavid du Colombier 
438