Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	<trace.h>
3
#include	"tos.h"
4
#include	"../port/lib.h"
5
#include	"mem.h"
6
#include	"dat.h"
7
#include	"fns.h"
8
#include	"../port/error.h"
9
#include	"ureg.h"
10
#include	"../port/edf.h"
11
 
12
enum
13
{
14
	Qdir,
15
	Qtrace,
16
	Qargs,
17
	Qctl,
18
	Qfd,
19
	Qfpregs,
20
	Qkregs,
21
	Qmem,
22
	Qnote,
23
	Qnoteid,
24
	Qnotepg,
25
	Qns,
26
	Qproc,
27
	Qregs,
28
	Qsegment,
29
	Qstatus,
30
	Qtext,
31
	Qwait,
32
	Qprofile,
33
	Qsyscall,
34
};
35
 
36
enum
37
{
38
	CMclose,
39
	CMclosefiles,
40
	CMfixedpri,
41
	CMhang,
42
	CMkill,
43
	CMnohang,
44
	CMnoswap,
45
	CMpri,
46
	CMprivate,
47
	CMprofile,
48
	CMstart,
49
	CMstartstop,
50
	CMstartsyscall,
51
	CMstop,
52
	CMwaitstop,
53
	CMwired,
54
	CMtrace,
55
	/* real time */
56
	CMperiod,
57
	CMdeadline,
58
	CMcost,
59
	CMsporadic,
60
	CMdeadlinenotes,
61
	CMadmit,
62
	CMextra,
63
	CMexpel,
64
	CMevent,
65
};
66
 
67
enum{
68
	Nevents = 0x4000,
69
	Emask = Nevents - 1,
70
};
71
 
72
#define	STATSIZE	(2*KNAMELEN+12+9*12)
73
/*
74
 * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
75
 * particularly on shared servers.
76
 * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
77
 */
78
Dirtab procdir[] =
79
{
80
	"args",		{Qargs},	0,			0660,
81
	"ctl",		{Qctl},		0,			0000,
82
	"fd",		{Qfd},		0,			0444,
83
	"fpregs",	{Qfpregs},	sizeof(FPsave),		0000,
84
	"kregs",	{Qkregs},	sizeof(Ureg),		0400,
85
	"mem",		{Qmem},		0,			0000,
86
	"note",		{Qnote},	0,			0000,
87
	"noteid",	{Qnoteid},	0,			0664,
88
	"notepg",	{Qnotepg},	0,			0000,
89
	"ns",		{Qns},		0,			0444,
90
	"proc",		{Qproc},	0,			0400,
91
	"regs",		{Qregs},	sizeof(Ureg),		0000,
92
	"segment",	{Qsegment},	0,			0444,
93
	"status",	{Qstatus},	STATSIZE,		0444,
94
	"text",		{Qtext},	0,			0000,
95
	"wait",		{Qwait},	0,			0400,
96
	"profile",	{Qprofile},	0,			0400,
97
	"syscall",	{Qsyscall},	0,			0400,	
98
};
99
 
100
static
101
Cmdtab proccmd[] = {
102
	CMclose,		"close",		2,
103
	CMclosefiles,		"closefiles",		1,
104
	CMfixedpri,		"fixedpri",		2,
105
	CMhang,			"hang",			1,
106
	CMnohang,		"nohang",		1,
107
	CMnoswap,		"noswap",		1,
108
	CMkill,			"kill",			1,
109
	CMpri,			"pri",			2,
110
	CMprivate,		"private",		1,
111
	CMprofile,		"profile",		1,
112
	CMstart,		"start",		1,
113
	CMstartstop,		"startstop",		1,
114
	CMstartsyscall,		"startsyscall",		1,
115
	CMstop,			"stop",			1,
116
	CMwaitstop,		"waitstop",		1,
117
	CMwired,		"wired",		2,
118
	CMtrace,		"trace",		0,
119
	CMperiod,		"period",		2,
120
	CMdeadline,		"deadline",		2,
121
	CMcost,			"cost",			2,
122
	CMsporadic,		"sporadic",		1,
123
	CMdeadlinenotes,	"deadlinenotes",	1,
124
	CMadmit,		"admit",		1,
125
	CMextra,		"extra",		1,
126
	CMexpel,		"expel",		1,
127
	CMevent,		"event",		1,
128
};
129
 
130
/* Segment type from portdat.h */
131
static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
132
 
133
/*
134
 * Qids are, in path:
135
 *	 5 bits of file type (qids above)
136
 *	26 bits of process slot number + 1
137
 *	     in vers,
138
 *	32 bits of pid, for consistency checking
139
 * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
140
 */
141
#define	QSHIFT	5	/* location in qid of proc slot # */
142
 
143
#define	QID(q)		((((ulong)(q).path) & ((1<<QSHIFT)-1)) >> 0)
144
#define	SLOT(q)		(((((ulong)(q).path) & ~(1UL<<31)) >> QSHIFT) - 1)
145
#define	PID(q)		((q).vers)
146
#define	NOTEID(q)	((q).vers)
147
 
148
void	procctlreq(Proc*, char*, int);
149
int	procctlmemio(Proc*, ulong, int, void*, int);
150
Chan*	proctext(Chan*, Proc*);
151
Segment* txt2data(Proc*, Segment*);
152
int	procstopped(void*);
153
void	mntscan(Mntwalk*, Proc*);
154
 
155
static Traceevent *tevents;
156
static Lock tlock;
157
static int topens;
158
static int tproduced, tconsumed;
159
void (*proctrace)(Proc*, int, vlong);
160
 
161
extern int unfair;
162
 
163
static void
164
profclock(Ureg *ur, Timer *)
165
{
166
	Tos *tos;
167
 
168
	if(up == 0 || up->state != Running)
169
		return;
170
 
171
	/* user profiling clock */
172
	if(userureg(ur)){
173
		tos = (Tos*)(USTKTOP-sizeof(Tos));
174
		tos->clock += TK2MS(1);
175
		segclock(ur->pc);
176
	}
177
}
178
 
179
static int
180
procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
181
{
182
	Qid qid;
183
	Proc *p;
184
	char *ename;
185
	Segment *q;
186
	ulong pid, path, perm, len;
187
 
188
	if(s == DEVDOTDOT){
189
		mkqid(&qid, Qdir, 0, QTDIR);
190
		devdir(c, qid, "#p", 0, eve, 0555, dp);
191
		return 1;
192
	}
193
 
194
	if(c->qid.path == Qdir){
195
		if(s == 0){
196
			strcpy(up->genbuf, "trace");
197
			mkqid(&qid, Qtrace, -1, QTFILE);
198
			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
199
			return 1;
200
		}
201
 
202
		if(name != nil){
203
			/* ignore s and use name to find pid */
204
			pid = strtol(name, &ename, 10);
205
			if(pid==0 || ename[0]!='\0')
206
				return -1;
207
			s = procindex(pid);
208
			if(s < 0)
209
				return -1;
210
		}
211
		else if(--s >= conf.nproc)
212
			return -1;
213
 
214
		p = proctab(s);
215
		pid = p->pid;
216
		if(pid == 0)
217
			return 0;
218
		snprint(up->genbuf, sizeof up->genbuf, "%lud", pid);
219
		/*
220
		 * String comparison is done in devwalk so name must match its formatted pid
221
		*/
222
		if(name != nil && strcmp(name, up->genbuf) != 0)
223
			return -1;
224
		mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
225
		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
226
		return 1;
227
	}
228
	if(c->qid.path == Qtrace){
229
		strcpy(up->genbuf, "trace");
230
		mkqid(&qid, Qtrace, -1, QTFILE);
231
		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
232
		return 1;
233
	}
234
	if(s >= nelem(procdir))
235
		return -1;
236
	if(tab)
237
		panic("procgen");
238
 
239
	tab = &procdir[s];
240
	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */
241
 
242
	/* p->procmode determines default mode for files in /proc */
243
	p = proctab(SLOT(c->qid));
244
	perm = tab->perm;
245
	if(perm == 0)
246
		perm = p->procmode;
247
	else	/* just copy read bits */
248
		perm |= p->procmode & 0444;
249
 
250
	len = tab->length;
251
	switch(QID(c->qid)) {
252
	case Qwait:
253
		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
254
		break;
255
	case Qprofile:
256
		q = p->seg[TSEG];
257
		if(q && q->profile) {
258
			len = (q->top-q->base)>>LRESPROF;
259
			len *= sizeof(*q->profile);
260
		}
261
		break;
262
	}
263
 
264
	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
265
	devdir(c, qid, tab->name, len, p->user, perm, dp);
266
	return 1;
267
}
268
 
269
static void
270
_proctrace(Proc* p, Tevent etype, vlong ts)
271
{
272
	Traceevent *te;
273
 
274
	if (p->trace == 0 || topens == 0 ||
275
		tproduced - tconsumed >= Nevents)
276
		return;
277
 
278
	te = &tevents[tproduced&Emask];
279
	te->pid = p->pid;
280
	te->etype = etype;
281
	if (ts == 0)
282
		te->time = todget(nil);
283
	else
284
		te->time = ts;
285
	tproduced++;
286
}
287
 
288
static void
289
procinit(void)
290
{
291
	if(conf.nproc >= (1<<(31-QSHIFT))-1)
292
		print("warning: too many procs for devproc\n");
293
	addclock0link((void (*)(void))profclock, 113);	/* Relative prime to HZ */
294
}
295
 
296
static Chan*
297
procattach(char *spec)
298
{
299
	return devattach('p', spec);
300
}
301
 
302
static Walkqid*
303
procwalk(Chan *c, Chan *nc, char **name, int nname)
304
{
305
	return devwalk(c, nc, name, nname, 0, 0, procgen);
306
}
307
 
308
static int
309
procstat(Chan *c, uchar *db, int n)
310
{
311
	return devstat(c, db, n, 0, 0, procgen);
312
}
313
 
314
/*
315
 *  none can't read or write state on other
316
 *  processes.  This is to contain access of
317
 *  servers running as none should they be
318
 *  subverted by, for example, a stack attack.
319
 */
320
static void
321
nonone(Proc *p)
322
{
323
	if(p == up)
324
		return;
325
	if(strcmp(up->user, "none") != 0)
326
		return;
327
	if(iseve())
328
		return;
329
	error(Eperm);
330
}
331
 
332
static Chan*
333
procopen(Chan *c, int omode)
334
{
335
	Proc *p;
336
	Pgrp *pg;
337
	Chan *tc;
338
	int pid;
339
 
340
	if(c->qid.type & QTDIR)
341
		return devopen(c, omode, 0, 0, procgen);
342
 
343
	if(QID(c->qid) == Qtrace){
344
		if (omode != OREAD) 
345
			error(Eperm);
346
		lock(&tlock);
347
		if (waserror()){
348
			unlock(&tlock);
349
			nexterror();
350
		}
351
		if (topens > 0)
352
			error("already open");
353
		topens++;
354
		if (tevents == nil){
355
			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
356
			if(tevents == nil)
357
				error(Enomem);
358
			tproduced = tconsumed = 0;
359
		}
360
		proctrace = _proctrace;
361
		unlock(&tlock);
362
		poperror();
363
 
364
		c->mode = openmode(omode);
365
		c->flag |= COPEN;
366
		c->offset = 0;
367
		return c;
368
	}
369
 
370
	p = proctab(SLOT(c->qid));
371
	qlock(&p->debug);
372
	if(waserror()){
373
		qunlock(&p->debug);
374
		nexterror();
375
	}
376
	pid = PID(c->qid);
377
	if(p->pid != pid)
378
		error(Eprocdied);
379
 
380
	omode = openmode(omode);
381
 
382
	switch(QID(c->qid)){
383
	case Qtext:
384
		if(omode != OREAD)
385
			error(Eperm);
386
		tc = proctext(c, p);
387
		tc->offset = 0;
388
		qunlock(&p->debug);
389
		poperror();
390
		cclose(c);
391
		return tc;
392
 
393
	case Qproc:
394
	case Qkregs:
395
	case Qsegment:
396
	case Qprofile:
397
	case Qfd:
398
		if(omode != OREAD)
399
			error(Eperm);
400
		break;
401
 
402
	case Qnote:
403
		if(p->privatemem)
404
			error(Eperm);
405
		break;
406
 
407
	case Qmem:
408
	case Qctl:
409
		if(p->privatemem)
410
			error(Eperm);
411
		nonone(p);
412
		break;
413
 
414
	case Qargs:
415
	case Qnoteid:
416
	case Qstatus:
417
	case Qwait:
418
	case Qregs:
419
	case Qfpregs:
420
	case Qsyscall:	
421
		nonone(p);
422
		break;
423
 
424
	case Qns:
425
		if(omode != OREAD)
426
			error(Eperm);
427
		c->aux = malloc(sizeof(Mntwalk));
428
		break;
429
 
430
	case Qnotepg:
431
		nonone(p);
432
		pg = p->pgrp;
433
		if(pg == nil)
434
			error(Eprocdied);
435
		if(omode!=OWRITE || pg->pgrpid == 1)
436
			error(Eperm);
437
		c->pgrpid.path = pg->pgrpid+1;
438
		c->pgrpid.vers = p->noteid;
439
		break;
440
 
441
	default:
442
		pprint("procopen %#lux\n", QID(c->qid));
443
		error(Egreg);
444
	}
445
 
446
	/* Affix pid to qid */
447
	if(p->state != Dead)
448
		c->qid.vers = p->pid;
449
 
450
	/* make sure the process slot didn't get reallocated while we were playing */
451
	coherence();
452
	if(p->pid != pid)
453
		error(Eprocdied);
454
 
455
	tc = devopen(c, omode, 0, 0, procgen);
456
	qunlock(&p->debug);
457
	poperror();
458
 
459
	return tc;
460
}
461
 
462
static int
463
procwstat(Chan *c, uchar *db, int n)
464
{
465
	Proc *p;
466
	Dir *d;
467
 
468
	if(c->qid.type&QTDIR)
469
		error(Eperm);
470
 
471
	if(QID(c->qid) == Qtrace)
472
		return devwstat(c, db, n);
473
 
474
	p = proctab(SLOT(c->qid));
475
	nonone(p);
476
	d = nil;
477
	if(waserror()){
478
		free(d);
479
		qunlock(&p->debug);
480
		nexterror();
481
	}
482
	qlock(&p->debug);
483
 
484
	if(p->pid != PID(c->qid))
485
		error(Eprocdied);
486
 
487
	if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
488
		error(Eperm);
489
 
490
	d = smalloc(sizeof(Dir)+n);
491
	n = convM2D(db, n, &d[0], (char*)&d[1]);
492
	if(n == 0)
493
		error(Eshortstat);
494
	if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
495
		if(strcmp(up->user, eve) != 0)
496
			error(Eperm);
497
		else
498
			kstrdup(&p->user, d->uid);
499
	}
500
	/* p->procmode determines default mode for files in /proc */
501
	if(d->mode != ~0UL)
502
		p->procmode = d->mode&0777;
503
 
504
	poperror();
505
	free(d);
506
	qunlock(&p->debug);
507
	return n;
508
}
509
 
510
 
511
static long
512
procoffset(long offset, char *va, int *np)
513
{
514
	if(offset > 0) {
515
		offset -= *np;
516
		if(offset < 0) {
517
			memmove(va, va+*np+offset, -offset);
518
			*np = -offset;
519
		}
520
		else
521
			*np = 0;
522
	}
523
	return offset;
524
}
525
 
526
static int
527
procqidwidth(Chan *c)
528
{
529
	char buf[32];
530
 
531
	return snprint(buf, sizeof buf, "%lud", c->qid.vers);
532
}
533
 
534
int
535
procfdprint(Chan *c, int fd, int w, char *s, int ns)
536
{
537
	int n;
538
 
539
	if(w == 0)
540
		w = procqidwidth(c);
541
	n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
542
		fd,
543
		&"r w rw"[(c->mode&3)<<1],
544
		devtab[c->type]->dc, c->dev,
545
		c->qid.path, w, c->qid.vers, c->qid.type,
546
		c->iounit, c->offset, c->path->s);
547
	return n;
548
}
549
 
550
static int
551
procfds(Proc *p, char *va, int count, long offset)
552
{
553
	Fgrp *f;
554
	Chan *c;
555
	char buf[256];
556
	int n, i, w, ww;
557
	char *a;
558
 
559
	/* print to buf to avoid holding fgrp lock while writing to user space */
560
	if(count > sizeof buf)
561
		count = sizeof buf;
562
	a = buf;
563
 
564
	qlock(&p->debug);
565
	f = p->fgrp;
566
	if(f == nil){
567
		qunlock(&p->debug);
568
		return 0;
569
	}
570
	lock(f);
571
	if(waserror()){
572
		unlock(f);
573
		qunlock(&p->debug);
574
		nexterror();
575
	}
576
 
577
	n = readstr(0, a, count, p->dot->path->s);
578
	n += snprint(a+n, count-n, "\n");
579
	offset = procoffset(offset, a, &n);
580
	/* compute width of qid.path */
581
	w = 0;
582
	for(i = 0; i <= f->maxfd; i++) {
583
		c = f->fd[i];
584
		if(c == nil)
585
			continue;
586
		ww = procqidwidth(c);
587
		if(ww > w)
588
			w = ww;
589
	}
590
	for(i = 0; i <= f->maxfd; i++) {
591
		c = f->fd[i];
592
		if(c == nil)
593
			continue;
594
		n += procfdprint(c, i, w, a+n, count-n);
595
		offset = procoffset(offset, a, &n);
596
	}
597
	unlock(f);
598
	qunlock(&p->debug);
599
	poperror();
600
 
601
	/* copy result to user space, now that locks are released */
602
	memmove(va, buf, n);
603
 
604
	return n;
605
}
606
 
607
static void
608
procclose(Chan * c)
609
{
610
	if(QID(c->qid) == Qtrace){
611
		lock(&tlock);
612
		if(topens > 0)
613
			topens--;
614
		if(topens == 0)
615
			proctrace = nil;
616
		unlock(&tlock);
617
	}
618
	if(QID(c->qid) == Qns && c->aux != 0)
619
		free(c->aux);
620
}
621
 
622
static void
623
int2flag(int flag, char *s)
624
{
625
	if(flag == 0){
626
		*s = '\0';
627
		return;
628
	}
629
	*s++ = '-';
630
	if(flag & MAFTER)
631
		*s++ = 'a';
632
	if(flag & MBEFORE)
633
		*s++ = 'b';
634
	if(flag & MCREATE)
635
		*s++ = 'c';
636
	if(flag & MCACHE)
637
		*s++ = 'C';
638
	*s = '\0';
639
}
640
 
641
static int
642
procargs(Proc *p, char *buf, int nbuf)
643
{
644
	int j, k, m;
645
	char *a;
646
	int n;
647
 
648
	a = p->args;
649
	if(p->setargs){
650
		snprint(buf, nbuf, "%s [%s]", p->text, p->args);
651
		return strlen(buf);
652
	}
653
	n = p->nargs;
654
	for(j = 0; j < nbuf - 1; j += m){
655
		if(n <= 0)
656
			break;
657
		if(j != 0)
658
			buf[j++] = ' ';
659
		m = snprint(buf+j, nbuf-j, "%q",  a);
660
		k = strlen(a) + 1;
661
		a += k;
662
		n -= k;
663
	}
664
	return j;
665
}
666
 
667
static int
668
eventsavailable(void *)
669
{
670
	return tproduced > tconsumed;
671
}
672
 
673
static long
674
procread(Chan *c, void *va, long n, vlong off)
675
{
676
	/* NSEG*32 was too small for worst cases */
677
	char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
678
	int i, j, m, navail, ne, pid, rsize;
679
	long l;
680
	uchar *rptr;
681
	ulong offset;
682
	Confmem *cm;
683
	Mntwalk *mw;
684
	Proc *p;
685
	Segment *sg, *s;
686
	Ureg kur;
687
	Waitq *wq;
688
 
689
	a = va;
690
	offset = off;
691
 
692
	if(c->qid.type & QTDIR)
693
		return devdirread(c, a, n, 0, 0, procgen);
694
 
695
	if(QID(c->qid) == Qtrace){
696
		if(!eventsavailable(nil))
697
			return 0;
698
 
699
		rptr = (uchar*)va;
700
		navail = tproduced - tconsumed;
701
		if(navail > n / sizeof(Traceevent))
702
			navail = n / sizeof(Traceevent);
703
		while(navail > 0) {
704
			ne = ((tconsumed & Emask) + navail > Nevents)? 
705
					Nevents - (tconsumed & Emask): navail;
706
			memmove(rptr, &tevents[tconsumed & Emask], 
707
					ne * sizeof(Traceevent));
708
 
709
			tconsumed += ne;
710
			rptr += ne * sizeof(Traceevent);
711
			navail -= ne;
712
		}
713
		return rptr - (uchar*)va;
714
	}
715
 
716
	p = proctab(SLOT(c->qid));
717
	if(p->pid != PID(c->qid))
718
		error(Eprocdied);
719
 
720
	switch(QID(c->qid)){
721
	case Qargs:
722
		qlock(&p->debug);
723
		j = procargs(p, up->genbuf, sizeof up->genbuf);
724
		qunlock(&p->debug);
725
		if(offset >= j)
726
			return 0;
727
		if(offset+n > j)
728
			n = j-offset;
729
		memmove(a, &up->genbuf[offset], n);
730
		return n;
731
	case Qsyscall:
732
		if(!p->syscalltrace)
733
			return 0;
734
		n = readstr(offset, a, n, p->syscalltrace);
735
		return n;
736
 
737
	case Qmem:
738
		if(offset < KZERO)
739
			return procctlmemio(p, offset, n, va, 1);
740
 
741
		if(!iseve())
742
			error(Eperm);
743
 
744
		/* validate kernel addresses */
745
		if(offset < (ulong)end) {
746
			if(offset+n > (ulong)end)
747
				n = (ulong)end - offset;
748
			memmove(a, (char*)offset, n);
749
			return n;
750
		}
751
		for(i=0; i<nelem(conf.mem); i++){
752
			cm = &conf.mem[i];
753
			/* klimit-1 because klimit might be zero! */
754
			if(cm->kbase <= offset && offset <= cm->klimit-1){
755
				if(offset+n >= cm->klimit-1)
756
					n = cm->klimit - offset;
757
				memmove(a, (char*)offset, n);
758
				return n;
759
			}
760
		}
761
		error(Ebadarg);
762
 
763
	case Qprofile:
764
		s = p->seg[TSEG];
765
		if(s == 0 || s->profile == 0)
766
			error("profile is off");
767
		i = (s->top-s->base)>>LRESPROF;
768
		i *= sizeof(*s->profile);
769
		if(offset >= i)
770
			return 0;
771
		if(offset+n > i)
772
			n = i - offset;
773
		memmove(a, ((char*)s->profile)+offset, n);
774
		return n;
775
 
776
	case Qnote:
777
		qlock(&p->debug);
778
		if(waserror()){
779
			qunlock(&p->debug);
780
			nexterror();
781
		}
782
		if(p->pid != PID(c->qid))
783
			error(Eprocdied);
784
		if(n < 1)	/* must accept at least the '\0' */
785
			error(Etoosmall);
786
		if(p->nnote == 0)
787
			n = 0;
788
		else {
789
			m = strlen(p->note[0].msg) + 1;
790
			if(m > n)
791
				m = n;
792
			memmove(va, p->note[0].msg, m);
793
			((char*)va)[m-1] = '\0';
794
			p->nnote--;
795
			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
796
			n = m;
797
		}
798
		if(p->nnote == 0)
799
			p->notepending = 0;
800
		poperror();
801
		qunlock(&p->debug);
802
		return n;
803
 
804
	case Qproc:
805
		if(offset >= sizeof(Proc))
806
			return 0;
807
		if(offset+n > sizeof(Proc))
808
			n = sizeof(Proc) - offset;
809
		memmove(a, ((char*)p)+offset, n);
810
		return n;
811
 
812
	case Qregs:
813
		rptr = (uchar*)p->dbgreg;
814
		rsize = sizeof(Ureg);
815
		goto regread;
816
 
817
	case Qkregs:
818
		memset(&kur, 0, sizeof(Ureg));
819
		setkernur(&kur, p);
820
		rptr = (uchar*)&kur;
821
		rsize = sizeof(Ureg);
822
		goto regread;
823
 
824
	case Qfpregs:
825
		rptr = (uchar*)&p->fpsave;
826
		rsize = sizeof(FPsave);
827
	regread:
828
		if(rptr == 0)
829
			error(Enoreg);
830
		if(offset >= rsize)
831
			return 0;
832
		if(offset+n > rsize)
833
			n = rsize - offset;
834
		memmove(a, rptr+offset, n);
835
		return n;
836
 
837
	case Qstatus:
838
		if(offset >= STATSIZE)
839
			return 0;
840
		if(offset+n > STATSIZE)
841
			n = STATSIZE - offset;
842
 
843
		sps = p->psstate;
844
		if(sps == 0)
845
			sps = statename[p->state];
846
		memset(statbuf, ' ', sizeof statbuf);
847
		readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
848
		readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
849
		readstr(0, statbuf+2*KNAMELEN, 11, sps);
850
		j = 2*KNAMELEN + 12;
851
 
852
		for(i = 0; i < 6; i++) {
853
			l = p->time[i];
854
			if(i == TReal)
855
				l = MACHP(0)->ticks - l;
856
			l = TK2MS(l);
857
			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
858
		}
859
		/* ignore stack, which is mostly non-existent */
860
		l = 0;
861
		for(i=1; i<NSEG; i++){
862
			s = p->seg[i];
863
			if(s)
864
				l += s->top - s->base;
865
		}
866
		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
867
		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
868
		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
869
		memmove(a, statbuf+offset, n);
870
		return n;
871
 
872
	case Qsegment:
873
		j = 0;
874
		for(i = 0; i < NSEG; i++) {
875
			sg = p->seg[i];
876
			if(sg == 0)
877
				continue;
878
			j += snprint(statbuf+j, sizeof statbuf - j,
879
				"%-6s %c%c %.8lux %.8lux %4ld\n",
880
				sname[sg->type&SG_TYPE],
881
				sg->type&SG_RONLY ? 'R' : ' ',
882
				sg->profile ? 'P' : ' ',
883
				sg->base, sg->top, sg->ref);
884
		}
885
		if(offset >= j)
886
			return 0;
887
		if(offset+n > j)
888
			n = j-offset;
889
		if(n == 0 && offset == 0)
890
			exhausted("segments");
891
		memmove(a, &statbuf[offset], n);
892
		return n;
893
 
894
	case Qwait:
895
		if(!canqlock(&p->qwaitr))
896
			error(Einuse);
897
 
898
		if(waserror()) {
899
			qunlock(&p->qwaitr);
900
			nexterror();
901
		}
902
 
903
		lock(&p->exl);
904
		if(up == p && p->nchild == 0 && p->waitq == 0) {
905
			unlock(&p->exl);
906
			error(Enochild);
907
		}
908
		pid = p->pid;
909
		while(p->waitq == 0) {
910
			unlock(&p->exl);
911
			sleep(&p->waitr, haswaitq, p);
912
			if(p->pid != pid)
913
				error(Eprocdied);
914
			lock(&p->exl);
915
		}
916
		wq = p->waitq;
917
		p->waitq = wq->next;
918
		p->nwait--;
919
		unlock(&p->exl);
920
 
921
		qunlock(&p->qwaitr);
922
		poperror();
923
		n = snprint(a, n, "%d %lud %lud %lud %q",
924
			wq->w.pid,
925
			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
926
			wq->w.msg);
927
		free(wq);
928
		return n;
929
 
930
	case Qns:
931
		qlock(&p->debug);
932
		if(waserror()){
933
			qunlock(&p->debug);
934
			nexterror();
935
		}
936
		if(p->pgrp == nil || p->pid != PID(c->qid))
937
			error(Eprocdied);
938
		mw = c->aux;
939
		if(mw == nil)
940
			error(Enomem);
941
		if(mw->cddone){
942
			qunlock(&p->debug);
943
			poperror();
944
			return 0;
945
		}
946
		mntscan(mw, p);
947
		if(mw->mh == 0){
948
			mw->cddone = 1;
949
			i = snprint(a, n, "cd %s\n", p->dot->path->s);
950
			qunlock(&p->debug);
951
			poperror();
952
			return i;
953
		}
954
		int2flag(mw->cm->mflag, flag);
955
		if(strcmp(mw->cm->to->path->s, "#M") == 0){
956
			srv = srvname(mw->cm->to->mchan);
957
			i = snprint(a, n, "mount %s %s %s %s\n", flag,
958
				srv==nil? mw->cm->to->mchan->path->s : srv,
959
				mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
960
			free(srv);
961
		}else
962
			i = snprint(a, n, "bind %s %s %s\n", flag,
963
				mw->cm->to->path->s, mw->mh->from->path->s);
964
		qunlock(&p->debug);
965
		poperror();
966
		return i;
967
 
968
	case Qnoteid:
969
		return readnum(offset, va, n, p->noteid, NUMSIZE);
970
	case Qfd:
971
		return procfds(p, va, n, offset);
972
	}
973
	error(Egreg);
974
	return 0;		/* not reached */
975
}
976
 
977
void
978
mntscan(Mntwalk *mw, Proc *p)
979
{
980
	Pgrp *pg;
981
	Mount *t;
982
	Mhead *f;
983
	int nxt, i;
984
	ulong last, bestmid;
985
 
986
	pg = p->pgrp;
987
	rlock(&pg->ns);
988
 
989
	nxt = 0;
990
	bestmid = ~0;
991
 
992
	last = 0;
993
	if(mw->mh)
994
		last = mw->cm->mountid;
995
 
996
	for(i = 0; i < MNTHASH; i++) {
997
		for(f = pg->mnthash[i]; f; f = f->hash) {
998
			for(t = f->mount; t; t = t->next) {
999
				if(mw->mh == 0 ||
1000
				  (t->mountid > last && t->mountid < bestmid)) {
1001
					mw->cm = t;
1002
					mw->mh = f;
1003
					bestmid = mw->cm->mountid;
1004
					nxt = 1;
1005
				}
1006
			}
1007
		}
1008
	}
1009
	if(nxt == 0)
1010
		mw->mh = 0;
1011
 
1012
	runlock(&pg->ns);
1013
}
1014
 
1015
static long
1016
procwrite(Chan *c, void *va, long n, vlong off)
1017
{
1018
	int id, m;
1019
	Proc *p, *t, *et;
1020
	char *a, *arg, buf[ERRMAX];
1021
	ulong offset = off;
1022
 
1023
	a = va;
1024
	if(c->qid.type & QTDIR)
1025
		error(Eisdir);
1026
 
1027
	p = proctab(SLOT(c->qid));
1028
 
1029
	/* Use the remembered noteid in the channel rather
1030
	 * than the process pgrpid
1031
	 */
1032
	if(QID(c->qid) == Qnotepg) {
1033
		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1034
		return n;
1035
	}
1036
 
1037
	qlock(&p->debug);
1038
	if(waserror()){
1039
		qunlock(&p->debug);
1040
		nexterror();
1041
	}
1042
	if(p->pid != PID(c->qid))
1043
		error(Eprocdied);
1044
 
1045
	switch(QID(c->qid)){
1046
	case Qargs:
1047
		if(n == 0)
1048
			error(Eshort);
1049
		if(n >= ERRMAX)
1050
			error(Etoobig);
1051
		arg = malloc(n+1);
1052
		if(arg == nil)
1053
			error(Enomem);
1054
		memmove(arg, va, n);
1055
		m = n;
1056
		if(arg[m-1] != 0)
1057
			arg[m++] = 0;
1058
		free(p->args);
1059
		p->nargs = m;
1060
		p->args = arg;
1061
		p->setargs = 1;
1062
		break;
1063
 
1064
	case Qmem:
1065
		if(p->state != Stopped)
1066
			error(Ebadctl);
1067
 
1068
		n = procctlmemio(p, offset, n, va, 0);
1069
		break;
1070
 
1071
	case Qregs:
1072
		if(offset >= sizeof(Ureg))
1073
			n = 0;
1074
		else if(offset+n > sizeof(Ureg))
1075
			n = sizeof(Ureg) - offset;
1076
		if(p->dbgreg == 0)
1077
			error(Enoreg);
1078
		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1079
		break;
1080
 
1081
	case Qfpregs:
1082
		if(offset >= sizeof(FPsave))
1083
			n = 0;
1084
		else if(offset+n > sizeof(FPsave))
1085
			n = sizeof(FPsave) - offset;
1086
		memmove((uchar*)&p->fpsave+offset, va, n);
1087
		break;
1088
 
1089
	case Qctl:
1090
		procctlreq(p, va, n);
1091
		break;
1092
 
1093
	case Qnote:
1094
		if(p->kp)
1095
			error(Eperm);
1096
		if(n >= ERRMAX-1)
1097
			error(Etoobig);
1098
		memmove(buf, va, n);
1099
		buf[n] = 0;
1100
		if(!postnote(p, 0, buf, NUser))
1101
			error("note not posted");
1102
		break;
1103
	case Qnoteid:
1104
		id = atoi(a);
1105
		if(id == p->pid) {
1106
			p->noteid = id;
1107
			break;
1108
		}
1109
		t = proctab(0);
1110
		for(et = t+conf.nproc; t < et; t++) {
1111
			if(t->state == Dead)
1112
				continue;
1113
			if(id == t->noteid) {
1114
				if(strcmp(p->user, t->user) != 0)
1115
					error(Eperm);
1116
				p->noteid = id;
1117
				break;
1118
			}
1119
		}
1120
		if(p->noteid != id)
1121
			error(Ebadarg);
1122
		break;
1123
	default:
1124
		pprint("unknown qid in procwrite\n");
1125
		error(Egreg);
1126
	}
1127
	poperror();
1128
	qunlock(&p->debug);
1129
	return n;
1130
}
1131
 
1132
Dev procdevtab = {
1133
	'p',
1134
	"proc",
1135
 
1136
	devreset,
1137
	procinit,
1138
	devshutdown,
1139
	procattach,
1140
	procwalk,
1141
	procstat,
1142
	procopen,
1143
	devcreate,
1144
	procclose,
1145
	procread,
1146
	devbread,
1147
	procwrite,
1148
	devbwrite,
1149
	devremove,
1150
	procwstat,
1151
};
1152
 
1153
Chan*
1154
proctext(Chan *c, Proc *p)
1155
{
1156
	Chan *tc;
1157
	Image *i;
1158
	Segment *s;
1159
 
1160
	s = p->seg[TSEG];
1161
	if(s == 0)
1162
		error(Enonexist);
1163
	if(p->state==Dead)
1164
		error(Eprocdied);
1165
 
1166
	lock(s);
1167
	i = s->image;
1168
	if(i == 0) {
1169
		unlock(s);
1170
		error(Eprocdied);
1171
	}
1172
	unlock(s);
1173
 
1174
	lock(i);
1175
	if(waserror()) {
1176
		unlock(i);
1177
		nexterror();
1178
	}
1179
 
1180
	tc = i->c;
1181
	if(tc == 0)
1182
		error(Eprocdied);
1183
 
1184
	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1185
		cclose(tc);
1186
		error(Eprocdied);
1187
	}
1188
 
1189
	if(p->pid != PID(c->qid)){
1190
		cclose(tc);
1191
		error(Eprocdied);
1192
	}
1193
 
1194
	unlock(i);
1195
	poperror();
1196
 
1197
	return tc;
1198
}
1199
 
1200
void
1201
procstopwait(Proc *p, int ctl)
1202
{
1203
	int pid;
1204
 
1205
	if(p->pdbg)
1206
		error(Einuse);
1207
	if(procstopped(p) || p->state == Broken)
1208
		return;
1209
 
1210
	if(ctl != 0)
1211
		p->procctl = ctl;
1212
	p->pdbg = up;
1213
	pid = p->pid;
1214
	qunlock(&p->debug);
1215
	up->psstate = "Stopwait";
1216
	if(waserror()) {
1217
		p->pdbg = 0;
1218
		qlock(&p->debug);
1219
		nexterror();
1220
	}
1221
	sleep(&up->sleep, procstopped, p);
1222
	poperror();
1223
	qlock(&p->debug);
1224
	if(p->pid != pid)
1225
		error(Eprocdied);
1226
}
1227
 
1228
static void
1229
procctlcloseone(Proc *p, Fgrp *f, int fd)
1230
{
1231
	Chan *c;
1232
 
1233
	c = f->fd[fd];
1234
	if(c == nil)
1235
		return;
1236
	f->fd[fd] = nil;
1237
	unlock(f);
1238
	qunlock(&p->debug);
1239
	cclose(c);
1240
	qlock(&p->debug);
1241
	lock(f);
1242
}
1243
 
1244
void
1245
procctlclosefiles(Proc *p, int all, int fd)
1246
{
1247
	int i;
1248
	Fgrp *f;
1249
 
1250
	f = p->fgrp;
1251
	if(f == nil)
1252
		error(Eprocdied);
1253
 
1254
	lock(f);
1255
	f->ref++;
1256
	if(all)
1257
		for(i = 0; i < f->maxfd; i++)
1258
			procctlcloseone(p, f, i);
1259
	else
1260
		procctlcloseone(p, f, fd);
1261
	unlock(f);
1262
	closefgrp(f);
1263
}
1264
 
1265
static char *
1266
parsetime(vlong *rt, char *s)
1267
{
1268
	uvlong ticks;
1269
	ulong l;
1270
	char *e, *p;
1271
	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1272
 
1273
	if (s == nil)
1274
		return("missing value");
1275
	ticks=strtoul(s, &e, 10);
1276
	if (*e == '.'){
1277
		p = e+1;
1278
		l = strtoul(p, &e, 10);
1279
		if(e-p > nelem(p10))
1280
			return "too many digits after decimal point";
1281
		if(e-p == 0)
1282
			return "ill-formed number";
1283
		l *= p10[e-p-1];
1284
	}else
1285
		l = 0;
1286
	if (*e == '\0' || strcmp(e, "s") == 0){
1287
		ticks = 1000000000 * ticks + l;
1288
	}else if (strcmp(e, "ms") == 0){
1289
		ticks = 1000000 * ticks + l/1000;
1290
	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1291
		ticks = 1000 * ticks + l/1000000;
1292
	}else if (strcmp(e, "ns") != 0)
1293
		return "unrecognized unit";
1294
	*rt = ticks;
1295
	return nil;
1296
}
1297
 
1298
void
1299
procctlreq(Proc *p, char *va, int n)
1300
{
1301
	Segment *s;
1302
	int npc, pri;
1303
	Cmdbuf *cb;
1304
	Cmdtab *ct;
1305
	vlong time;
1306
	char *e;
1307
	void (*pt)(Proc*, int, vlong);
1308
 
1309
	if(p->kp)	/* no ctl requests to kprocs */
1310
		error(Eperm);
1311
 
1312
	cb = parsecmd(va, n);
1313
	if(waserror()){
1314
		free(cb);
1315
		nexterror();
1316
	}
1317
 
1318
	ct = lookupcmd(cb, proccmd, nelem(proccmd));
1319
 
1320
	switch(ct->index){
1321
	case CMclose:
1322
		procctlclosefiles(p, 0, atoi(cb->f[1]));
1323
		break;
1324
	case CMclosefiles:
1325
		procctlclosefiles(p, 1, 0);
1326
		break;
1327
	case CMhang:
1328
		p->hang = 1;
1329
		break;
1330
	case CMkill:
1331
		switch(p->state) {
1332
		case Broken:
1333
			unbreak(p);
1334
			break;
1335
		case Stopped:
1336
			p->procctl = Proc_exitme;
1337
			postnote(p, 0, "sys: killed", NExit);
1338
			ready(p);
1339
			break;
1340
		default:
1341
			p->procctl = Proc_exitme;
1342
			postnote(p, 0, "sys: killed", NExit);
1343
		}
1344
		break;
1345
	case CMnohang:
1346
		p->hang = 0;
1347
		break;
1348
	case CMnoswap:
1349
		p->noswap = 1;
1350
		break;
1351
	case CMpri:
1352
		pri = atoi(cb->f[1]);
1353
		if(pri > PriNormal && !iseve())
1354
			error(Eperm);
1355
		procpriority(p, pri, 0);
1356
		break;
1357
	case CMfixedpri:
1358
		pri = atoi(cb->f[1]);
1359
		if(pri > PriNormal && !iseve())
1360
			error(Eperm);
1361
		procpriority(p, pri, 1);
1362
		break;
1363
	case CMprivate:
1364
		p->privatemem = 1;
1365
		break;
1366
	case CMprofile:
1367
		s = p->seg[TSEG];
1368
		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1369
			error(Ebadctl);
1370
		if(s->profile != 0)
1371
			free(s->profile);
1372
		npc = (s->top-s->base)>>LRESPROF;
1373
		s->profile = malloc(npc*sizeof(*s->profile));
1374
		if(s->profile == 0)
1375
			error(Enomem);
1376
		break;
1377
	case CMstart:
1378
		if(p->state != Stopped)
1379
			error(Ebadctl);
1380
		ready(p);
1381
		break;
1382
	case CMstartstop:
1383
		if(p->state != Stopped)
1384
			error(Ebadctl);
1385
		p->procctl = Proc_traceme;
1386
		ready(p);
1387
		procstopwait(p, Proc_traceme);
1388
		break;
1389
	case CMstartsyscall:
1390
		if(p->state != Stopped)
1391
			error(Ebadctl);
1392
		p->procctl = Proc_tracesyscall;
1393
		ready(p);
1394
		procstopwait(p, Proc_tracesyscall);
1395
		break;
1396
	case CMstop:
1397
		procstopwait(p, Proc_stopme);
1398
		break;
1399
	case CMwaitstop:
1400
		procstopwait(p, 0);
1401
		break;
1402
	case CMwired:
1403
		procwired(p, atoi(cb->f[1]));
1404
		break;
1405
	case CMtrace:
1406
		switch(cb->nf){
1407
		case 1:
1408
			p->trace ^= 1;
1409
			break;
1410
		case 2:
1411
			p->trace = (atoi(cb->f[1]) != 0);
1412
			break;
1413
		default:
1414
			error("args");
1415
		}
1416
		break;
1417
	/* real time */
1418
	case CMperiod:
1419
		if(p->edf == nil)
1420
			edfinit(p);
1421
		if(e=parsetime(&time, cb->f[1]))	/* time in ns */
1422
			error(e);
1423
		edfstop(p);
1424
		p->edf->T = time/1000;	/* Edf times are in µs */
1425
		break;
1426
	case CMdeadline:
1427
		if(p->edf == nil)
1428
			edfinit(p);
1429
		if(e=parsetime(&time, cb->f[1]))
1430
			error(e);
1431
		edfstop(p);
1432
		p->edf->D = time/1000;
1433
		break;
1434
	case CMcost:
1435
		if(p->edf == nil)
1436
			edfinit(p);
1437
		if(e=parsetime(&time, cb->f[1]))
1438
			error(e);
1439
		edfstop(p);
1440
		p->edf->C = time/1000;
1441
		break;
1442
	case CMsporadic:
1443
		if(p->edf == nil)
1444
			edfinit(p);
1445
		p->edf->flags |= Sporadic;
1446
		break;
1447
	case CMdeadlinenotes:
1448
		if(p->edf == nil)
1449
			edfinit(p);
1450
		p->edf->flags |= Sendnotes;
1451
		break;
1452
	case CMadmit:
1453
		if(p->edf == 0)
1454
			error("edf params");
1455
		if(e = edfadmit(p))
1456
			error(e);
1457
		break;
1458
	case CMextra:
1459
		if(p->edf == nil)
1460
			edfinit(p);
1461
		p->edf->flags |= Extratime;
1462
		break;
1463
	case CMexpel:
1464
		if(p->edf)
1465
			edfstop(p);
1466
		break;
1467
	case CMevent:
1468
		pt = proctrace;
1469
		if(up->trace && pt)
1470
			pt(up, SUser, 0);
1471
		break;
1472
	}
1473
 
1474
	poperror();
1475
	free(cb);
1476
}
1477
 
1478
int
1479
procstopped(void *a)
1480
{
1481
	Proc *p = a;
1482
	return p->state == Stopped;
1483
}
1484
 
1485
int
1486
procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1487
{
1488
	KMap *k;
1489
	Pte *pte;
1490
	Page *pg;
1491
	Segment *s;
1492
	ulong soff, l;
1493
	char *a = va, *b;
1494
 
1495
	for(;;) {
1496
		s = seg(p, offset, 1);
1497
		if(s == 0)
1498
			error(Ebadarg);
1499
 
1500
		if(offset+n >= s->top)
1501
			n = s->top-offset;
1502
 
1503
		if(!read && (s->type&SG_TYPE) == SG_TEXT)
1504
			s = txt2data(p, s);
1505
 
1506
		s->steal++;
1507
		soff = offset-s->base;
1508
		if(waserror()) {
1509
			s->steal--;
1510
			nexterror();
1511
		}
1512
		if(fixfault(s, offset, read, 0) == 0)
1513
			break;
1514
		poperror();
1515
		s->steal--;
1516
	}
1517
	poperror();
1518
	pte = s->map[soff/PTEMAPMEM];
1519
	if(pte == 0)
1520
		panic("procctlmemio");
1521
	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1522
	if(pagedout(pg))
1523
		panic("procctlmemio1");
1524
 
1525
	l = BY2PG - (offset&(BY2PG-1));
1526
	if(n > l)
1527
		n = l;
1528
 
1529
	k = kmap(pg);
1530
	if(waserror()) {
1531
		s->steal--;
1532
		kunmap(k);
1533
		nexterror();
1534
	}
1535
	b = (char*)VA(k);
1536
	b += offset&(BY2PG-1);
1537
	if(read == 1)
1538
		memmove(a, b, n);	/* This can fault */
1539
	else
1540
		memmove(b, a, n);
1541
	kunmap(k);
1542
	poperror();
1543
 
1544
	/* Ensure the process sees text page changes */
1545
	if(s->flushme)
1546
		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1547
 
1548
	s->steal--;
1549
 
1550
	if(read == 0)
1551
		p->newtlb = 1;
1552
 
1553
	return n;
1554
}
1555
 
1556
Segment*
1557
txt2data(Proc *p, Segment *s)
1558
{
1559
	int i;
1560
	Segment *ps;
1561
 
1562
	ps = newseg(SG_DATA, s->base, s->size);
1563
	ps->image = s->image;
1564
	incref(ps->image);
1565
	ps->fstart = s->fstart;
1566
	ps->flen = s->flen;
1567
	ps->flushme = 1;
1568
 
1569
	qlock(&p->seglock);
1570
	for(i = 0; i < NSEG; i++)
1571
		if(p->seg[i] == s)
1572
			break;
1573
	if(i == NSEG)
1574
		panic("segment gone");
1575
 
1576
	qunlock(&s->lk);
1577
	putseg(s);
1578
	qlock(&ps->lk);
1579
	p->seg[i] = ps;
1580
	qunlock(&p->seglock);
1581
 
1582
	return ps;
1583
}
1584
 
1585
Segment*
1586
data2txt(Segment *s)
1587
{
1588
	Segment *ps;
1589
 
1590
	ps = newseg(SG_TEXT, s->base, s->size);
1591
	ps->image = s->image;
1592
	incref(ps->image);
1593
	ps->fstart = s->fstart;
1594
	ps->flen = s->flen;
1595
	ps->flushme = 1;
1596
 
1597
	return ps;
1598
}