Commit | Line | Data |
---|---|---|
01395141 C |
1 | /* mx1.c 4.6 81/03/11 */ |
2 | ||
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
5 | #include "../h/dir.h" | |
6 | #include "../h/user.h" | |
7 | #include "../h/reg.h" | |
8 | #include "../h/proc.h" | |
9 | #include "../h/tty.h" | |
10 | #include "../h/inode.h" | |
11 | #include "../h/mx.h" | |
12 | #include "../h/file.h" | |
13 | #include "../h/conf.h" | |
14 | ||
15 | /* | |
16 | * Multiplexor: clist version | |
17 | * | |
18 | * installation: | |
19 | * requires a line in cdevsw - | |
20 | * mxopen, mxclose, mxread, mxwrite, mxioctl, 0, | |
21 | * | |
22 | * also requires a line in linesw - | |
23 | * mxopen, mxclose, mcread, mcwrite, mxioctl, nulldev, nulldev, | |
24 | * | |
25 | * The linesw entry for mpx should be the last one in the table. | |
26 | * 'nldisp' (number of line disciplines) should not include the | |
27 | * mpx line. This is to prevent mpx from being enabled by an ioctl. | |
28 | */ | |
29 | struct chan chans[NCHANS]; | |
30 | struct schan schans[NPORTS]; | |
31 | struct group *groups[NGROUPS]; | |
32 | int mpxline; | |
33 | struct chan *xcp(); | |
34 | dev_t mpxdev = -1; | |
35 | ||
36 | ||
37 | char mcdebugs[NDEBUGS]; | |
38 | ||
39 | ||
40 | /* | |
41 | * Allocate a channel, set c_index to index. | |
42 | */ | |
43 | struct chan * | |
44 | challoc(index, isport) | |
45 | { | |
46 | register s,i; | |
47 | register struct chan *cp; | |
48 | ||
49 | s = spl6(); | |
50 | for(i=0;i<((isport)?NPORTS:NCHANS);i++) { | |
51 | cp = (isport)? (struct chan *)(schans+i): chans+i; | |
52 | if(cp->c_group == NULL) { | |
53 | cp->c_index = index; | |
54 | cp->c_pgrp = 0; | |
55 | cp->c_flags = 0; | |
56 | splx(s); | |
57 | return(cp); | |
58 | } | |
59 | } | |
60 | splx(s); | |
61 | return(NULL); | |
62 | } | |
63 | ||
64 | ||
65 | ||
66 | /* | |
67 | * Allocate a group table cell. | |
68 | */ | |
69 | gpalloc() | |
70 | { | |
71 | register i; | |
72 | ||
73 | for (i=NGROUPS-1; i>=0; i--) | |
74 | if (groups[i]==NULL) { | |
75 | groups[i]++; | |
76 | return(i); | |
77 | } | |
78 | u.u_error = ENXIO; | |
79 | return(i); | |
80 | } | |
81 | ||
82 | ||
83 | /* | |
84 | * Add a channel to the group in | |
85 | * inode ip. | |
86 | */ | |
87 | struct chan * | |
88 | addch(ip, isport) | |
89 | struct inode *ip; | |
90 | { | |
91 | register struct chan *cp; | |
92 | register struct group *gp; | |
93 | register i; | |
94 | ||
95 | plock(ip); | |
96 | gp = &ip->i_un.i_group; | |
97 | for(i=0;i<NINDEX;i++) { | |
98 | cp = (struct chan *)gp->g_chans[i]; | |
99 | if (cp == NULL) { | |
100 | if ((cp=challoc(i, isport)) != NULL) { | |
101 | gp->g_chans[i] = cp; | |
102 | cp->c_group = gp; | |
103 | } | |
104 | break; | |
105 | } | |
106 | cp = NULL; | |
107 | } | |
108 | prele(ip); | |
109 | return(cp); | |
110 | } | |
111 | ||
112 | /* | |
113 | * Mpxchan system call. | |
114 | */ | |
115 | ||
116 | mpxchan() | |
117 | { | |
118 | extern mxopen(), mcread(), sdata(), scontrol(); | |
119 | struct inode *ip, *gip; | |
120 | struct tty *tp; | |
121 | struct file *fp, *chfp, *gfp; | |
122 | struct chan *cp; | |
123 | struct group *gp, *ngp; | |
124 | struct mx_args vec; | |
125 | struct a { | |
126 | int cmd; | |
127 | int *argvec; | |
128 | } *uap; | |
129 | dev_t dev; | |
130 | register int i; | |
131 | ||
132 | /* | |
133 | * Common setup code. | |
134 | */ | |
135 | ||
136 | uap = (struct a *)u.u_ap; | |
137 | (void) copyin((caddr_t)uap->argvec, (caddr_t)&vec, sizeof vec); | |
138 | gp = NULL; gfp = NULL; cp = NULL; | |
139 | ||
140 | switch(uap->cmd) { | |
141 | ||
142 | case NPGRP: | |
143 | if (vec.m_arg[1] < 0) | |
144 | break; | |
145 | case CHAN: | |
146 | case JOIN: | |
147 | case EXTR: | |
148 | case ATTACH: | |
149 | case DETACH: | |
150 | case CSIG: | |
151 | gfp = getf(vec.m_arg[1]); | |
152 | if (gfp==NULL) | |
153 | return; | |
154 | gip = gfp->f_inode; | |
155 | gp = &gip->i_un.i_group; | |
156 | if (gp->g_inode != gip) { | |
157 | u.u_error = ENXIO; | |
158 | return; | |
159 | } | |
160 | } | |
161 | ||
162 | switch(uap->cmd) { | |
163 | ||
164 | /* | |
165 | * Create an MPX file. | |
166 | */ | |
167 | ||
168 | case MPX: | |
169 | case MPXN: | |
170 | if (mpxdev < 0) { | |
171 | for (i=0; linesw[i].l_open; i++) { | |
172 | if (linesw[i].l_read==mcread) { | |
173 | mpxline = i; | |
174 | for (i=0; cdevsw[i].d_open; i++) { | |
175 | if (cdevsw[i].d_open==mxopen) { | |
176 | mpxdev = (dev_t)(i<<8); | |
177 | } | |
178 | } | |
179 | } | |
180 | } | |
181 | if (mpxdev < 0) { | |
182 | u.u_error = ENXIO; | |
183 | return; | |
184 | } | |
185 | } | |
186 | if (uap->cmd==MPXN) { | |
187 | if ((ip=ialloc(pipedev))==NULL) | |
188 | return; | |
189 | ip->i_mode = ((vec.m_arg[1]&0777)+IFMPC) & ~u.u_cmask; | |
190 | ip->i_flag = IACC|IUPD|ICHG; | |
191 | } else { | |
192 | u.u_dirp = vec.m_name; | |
193 | ip = namei(uchar,1); | |
194 | if (ip != NULL) { | |
195 | i = ip->i_mode&IFMT; | |
196 | u.u_error = EEXIST; | |
197 | if (i==IFMPC || i==IFMPB) { | |
198 | i = minor(ip->i_un.i_rdev); | |
199 | gp = groups[i]; | |
200 | if (gp && gp->g_inode==ip) | |
201 | u.u_error = EBUSY; | |
202 | } | |
203 | iput(ip); | |
204 | return; | |
205 | } | |
206 | if (u.u_error) | |
207 | return; | |
208 | ip = maknode((vec.m_arg[1]&0777)+IFMPC); | |
209 | if (ip == NULL) | |
210 | return; | |
211 | } | |
212 | if ((i=gpalloc()) < 0) { | |
213 | iput(ip); | |
214 | return; | |
215 | } | |
216 | if ((fp=falloc()) == NULL) { | |
217 | iput(ip); | |
218 | groups[i] = NULL; | |
219 | return; | |
220 | } | |
221 | ip->i_un.i_rdev = (daddr_t)(mpxdev+i); | |
222 | ip->i_count++; | |
223 | prele(ip); | |
224 | ||
225 | gp = &ip->i_un.i_group; | |
226 | groups[i] = gp; | |
227 | gp->g_inode = ip; | |
228 | gp->g_state = INUSE|ISGRP; | |
229 | gp->g_group = NULL; | |
230 | gp->g_file = fp; | |
231 | gp->g_index = 0; | |
232 | gp->g_rotmask = 1; | |
233 | gp->g_rot = 0; | |
234 | gp->g_datq = 0; | |
235 | for(i=0;i<NINDEX;) | |
236 | gp->g_chans[i++] = NULL; | |
237 | ||
238 | fp->f_flag = FREAD|FWRITE|FMP; | |
239 | fp->f_inode = ip; | |
240 | fp->f_un.f_chan = NULL; | |
241 | return; | |
242 | ||
243 | /* | |
244 | * join file descriptor (arg 0) to group (arg 1) | |
245 | * return channel number | |
246 | */ | |
247 | ||
248 | case JOIN: | |
249 | if ((fp=getf(vec.m_arg[0]))==NULL) | |
250 | return; | |
251 | ip = fp->f_inode; | |
252 | switch (ip->i_mode & IFMT) { | |
253 | ||
254 | case IFMPC: | |
255 | if ((fp->f_flag&FMP) != FMP) { | |
256 | u.u_error = ENXIO; | |
257 | return; | |
258 | } | |
259 | ngp = &ip->i_un.i_group; | |
260 | if (mtree(ngp, gp) == NULL) | |
261 | return; | |
262 | fp->f_count++; | |
263 | u.u_r.r_val1 = cpx((struct chan *)ngp); | |
264 | return; | |
265 | ||
266 | case IFCHR: | |
267 | dev = (dev_t)ip->i_un.i_rdev; | |
268 | tp = cdevsw[major(dev)].d_ttys; | |
269 | if (tp==NULL) { | |
270 | u.u_error = ENXIO; | |
271 | return; | |
272 | } | |
273 | tp = &tp[minor(dev)]; | |
274 | if (tp->t_chan) { | |
275 | u.u_error = ENXIO; | |
276 | return; | |
277 | } | |
278 | if ((cp=addch(gip, 1))==NULL) { | |
279 | u.u_error = ENXIO; | |
280 | return; | |
281 | } | |
282 | tp->t_chan = cp; | |
283 | cp->c_fy = fp; | |
284 | fp->f_count++; | |
285 | cp->c_ttyp = tp; | |
286 | cp->c_line = tp->t_line; | |
287 | cp->c_flags = XGRP+PORT; | |
288 | u.u_r.r_val1 = cpx(cp); | |
289 | return; | |
290 | ||
291 | default: | |
292 | u.u_error = ENXIO; | |
293 | return; | |
294 | ||
295 | } | |
296 | ||
297 | /* | |
298 | * Attach channel (arg 0) to group (arg 1). | |
299 | */ | |
300 | ||
301 | case ATTACH: | |
302 | cp = xcp(gp, vec.m_arg[0]); | |
303 | if (cp==NULL || cp->c_flags&ISGRP) { | |
304 | u.u_error = ENXIO; | |
305 | return; | |
306 | } | |
307 | u.u_r.r_val1 = cpx(cp); | |
308 | wakeup((caddr_t)cp); | |
309 | return; | |
310 | ||
311 | case DETACH: | |
312 | cp = xcp(gp, vec.m_arg[0]); | |
313 | if (cp==NULL) { | |
314 | u.u_error = ENXIO; | |
315 | return; | |
316 | } | |
317 | (void) detach(cp); | |
318 | return; | |
319 | ||
320 | /* | |
321 | * Extract channel (arg 0) from group (arg 1). | |
322 | */ | |
323 | ||
324 | case EXTR: | |
325 | cp = xcp(gp, vec.m_arg[0]); | |
326 | if (cp==NULL) { | |
327 | u.u_error = ENXIO; | |
328 | return; | |
329 | } | |
330 | if (cp->c_flags & ISGRP) { | |
331 | (void) mxfalloc(((struct group *)cp)->g_file); | |
332 | return; | |
333 | } | |
334 | if ((fp=cp->c_fy) != NULL) { | |
335 | (void) mxfalloc(fp); | |
336 | return; | |
337 | } | |
338 | if ((fp=falloc()) == NULL) | |
339 | return; | |
340 | fp->f_inode = gip; | |
341 | gip->i_count++; | |
342 | fp->f_un.f_chan = cp; | |
343 | fp->f_flag = (vec.m_arg[2]) ? | |
344 | (FREAD|FWRITE|FMPY) : (FREAD|FWRITE|FMPX); | |
345 | cp->c_fy = fp; | |
346 | return; | |
347 | ||
348 | /* | |
349 | * Make new chan on group (arg 1). | |
350 | */ | |
351 | ||
352 | case CHAN: | |
353 | if((gfp->f_flag&FMP)==FMP)cp = addch(gip, 0); | |
354 | if(cp == NULL){ | |
355 | u.u_error = ENXIO; | |
356 | return; | |
357 | } | |
358 | cp->c_flags = XGRP; | |
359 | cp->c_fy = NULL; | |
360 | cp->c_ttyp = cp->c_ottyp = (struct tty *)cp; | |
361 | cp->c_line = cp->c_oline = mpxline; | |
362 | u.u_r.r_val1 = cpx(cp); | |
363 | return; | |
364 | ||
365 | /* | |
366 | * Connect fd (arg 0) to channel fd (arg 1). | |
367 | * (arg 2 < 0) => fd to chan only | |
368 | * (arg 2 > 0) => chan to fd only | |
369 | * (arg 2 == 0) => both directions | |
370 | */ | |
371 | ||
372 | case CONNECT: | |
373 | if ((fp=getf(vec.m_arg[0]))==NULL) | |
374 | return; | |
375 | if ((chfp=getf(vec.m_arg[1]))==NULL) | |
376 | return; | |
377 | ip = fp->f_inode; | |
378 | i = ip->i_mode&IFMT; | |
379 | if (i!=IFCHR) { | |
380 | u.u_error = ENXIO; | |
381 | return; | |
382 | } | |
383 | dev = (dev_t)ip->i_un.i_rdev; | |
384 | tp = cdevsw[major(dev)].d_ttys; | |
385 | if (tp==NULL) { | |
386 | u.u_error = ENXIO; | |
387 | return; | |
388 | } | |
389 | tp = &tp[minor(dev)]; | |
390 | if (!(chfp->f_flag&FMPY)) { | |
391 | u.u_error = ENXIO; | |
392 | return; | |
393 | } | |
394 | cp = chfp->f_un.f_chan; | |
395 | if (cp==NULL || cp->c_flags&PORT) { | |
396 | u.u_error = ENXIO; | |
397 | return; | |
398 | } | |
399 | i = vec.m_arg[2]; | |
400 | if (i>=0) { | |
401 | cp->c_ottyp = tp; | |
402 | cp->c_oline = tp->t_line; | |
403 | } | |
404 | if (i<=0) { | |
405 | tp->t_chan = cp; | |
406 | cp->c_ttyp = tp; | |
407 | cp->c_line = tp->t_line; | |
408 | } | |
409 | u.u_r.r_val1 = 0; | |
410 | return; | |
411 | ||
412 | case NPGRP: { | |
413 | register struct proc *pp; | |
414 | ||
415 | if (gp != NULL) { | |
416 | cp = xcp(gp, vec.m_arg[0]); | |
417 | if (cp==NULL) { | |
418 | u.u_error = ENXIO; | |
419 | return; | |
420 | } | |
421 | } | |
422 | pp = u.u_procp; | |
423 | pp->p_pgrp = pp->p_pid; | |
424 | if (vec.m_arg[2]) | |
425 | pp->p_pgrp = vec.m_arg[2]; | |
426 | if (gp != NULL) | |
427 | cp->c_pgrp = pp->p_pgrp; | |
428 | u.u_r.r_val1 = pp->p_pgrp; | |
429 | return; | |
430 | } | |
431 | ||
432 | case CSIG: | |
433 | cp = xcp(gp, vec.m_arg[0]); | |
434 | if (cp==NULL) { | |
435 | u.u_error = ENXIO; | |
436 | return; | |
437 | } | |
438 | gsignal(cp->c_pgrp, vec.m_arg[2]); | |
439 | u.u_r.r_val1 = vec.m_arg[2]; | |
440 | return; | |
441 | ||
442 | case DEBUG: | |
443 | i = vec.m_arg[0]; | |
444 | if (i<0 || i>NDEBUGS) | |
445 | return; | |
446 | mcdebugs[i] = vec.m_arg[1]; | |
447 | if (i==ALL) | |
448 | for(i=0;i<NDEBUGS;i++) | |
449 | mcdebugs[i] = vec.m_arg[1]; | |
450 | return; | |
451 | ||
452 | default: | |
453 | u.u_error = ENXIO; | |
454 | return; | |
455 | } | |
456 | ||
457 | } | |
458 | detach(cp) | |
459 | register struct chan *cp; | |
460 | { | |
461 | register struct group *master,*sub; | |
462 | register index; | |
463 | ||
464 | if (cp==NULL) | |
465 | return(0); | |
466 | if (cp->c_flags&ISGRP) { | |
467 | sub = (struct group *)cp; | |
468 | master = sub->g_group; index = sub->g_index; | |
469 | closef(sub->g_file); | |
470 | if (master != NULL) | |
471 | master->g_chans[index] = NULL; | |
472 | return(0); | |
473 | } else if (cp->c_flags&PORT && cp->c_ttyp != NULL) { | |
474 | closef(cp->c_fy); | |
475 | chdrain(cp); | |
476 | chfree(cp); | |
477 | return(0); | |
478 | } | |
479 | if (cp->c_flags & WCLOSE) { | |
480 | if (cp->c_fy) { | |
481 | if (cp->c_fy->f_count) | |
482 | return(1); | |
483 | chdrain(cp); | |
484 | chfree(cp); | |
485 | return(0); | |
486 | } | |
487 | } | |
488 | cp->c_flags |= WCLOSE; | |
489 | chwake(cp); | |
490 | return(1); | |
491 | } | |
492 | ||
493 | ||
494 | mxfalloc(fp) | |
495 | register struct file *fp; | |
496 | { | |
497 | register i; | |
498 | ||
499 | if (fp==NULL) { | |
500 | u.u_error = ENXIO; | |
501 | return(-1); | |
502 | } | |
503 | i = ufalloc(); | |
504 | if (i < 0) | |
505 | return(i); | |
506 | u.u_ofile[i] = fp; | |
507 | fp->f_count++; | |
508 | u.u_r.r_val1 = i; | |
509 | return(i); | |
510 | } | |
511 | ||
512 | /* | |
513 | * Grow a branch on a tree. | |
514 | */ | |
515 | ||
516 | mtree(sub,master) | |
517 | register struct group *sub, *master; | |
518 | { | |
519 | register i; | |
520 | int mtresiz, stresiz; | |
521 | ||
522 | if ((mtresiz=mup(master,sub)) == NULL) { | |
523 | u.u_error = ENXIO; | |
524 | return(NULL); | |
525 | } | |
526 | if ((stresiz=mdown(sub,master)) <= 0) { | |
527 | u.u_error = ENXIO; | |
528 | return(NULL); | |
529 | } | |
530 | if (sub->g_group != NULL) { | |
531 | u.u_error = ENXIO; | |
532 | return(NULL); | |
533 | } | |
534 | if (stresiz+mtresiz > NLEVELS) { | |
535 | u.u_error = ENXIO; | |
536 | return(NULL); | |
537 | } | |
538 | for (i=0;i<NINDEX;i++) { | |
539 | if (master->g_chans[i] != NULL) | |
540 | continue; | |
541 | master->g_chans[i] = (struct chan *)sub; | |
542 | sub->g_group = master; | |
543 | sub->g_index = i; | |
544 | return(1); | |
545 | } | |
546 | u.u_error = ENXIO; | |
547 | return(NULL); | |
548 | } | |
549 | ||
550 | mup(master,sub) | |
551 | struct group *master, *sub; | |
552 | { | |
553 | register struct group *top; | |
554 | register int depth; | |
555 | ||
556 | depth = 1; top = master; | |
557 | while (top->g_group) { | |
558 | depth++; | |
559 | top = top->g_group; | |
560 | } | |
561 | if(top == sub) | |
562 | return(NULL); | |
563 | return(depth); | |
564 | } | |
565 | ||
566 | ||
567 | mdown(sub,master) | |
568 | struct group *sub, *master; | |
569 | { | |
570 | register int maxdepth, i, depth; | |
571 | ||
572 | if(sub == (struct group *)NULL || (sub->g_state&ISGRP) == 0) | |
573 | return(0); | |
574 | if(sub == master) | |
575 | return(-1); | |
576 | maxdepth = 0; | |
577 | for(i=0; i<NINDEX; i++) { | |
578 | if((depth=mdown((struct group *)sub->g_chans[i],master)) == -1) | |
579 | return(-1); | |
580 | maxdepth = (depth>maxdepth) ? depth: maxdepth; | |
581 | } | |
582 | return(maxdepth+1); | |
583 | } |