|
|
1.1 root 1: /*
2:
1.1.1.3 ! root 3: Copyright 1991,1992 Eric R. Smith.
! 4:
! 5: Copyright 1992 Atari Corporation.
! 6:
! 7: All rights reserved.
1.1 root 8:
9: */
10:
11:
12:
13: /* simple pipefs.c */
14:
15:
16:
17: #include "mint.h"
18:
19:
20:
21: static int pipetime, pipedate; /* root directory time/date stamp */
22:
23:
24:
1.1.1.2 root 25: static long ARGS_ON_STACK pipe_root P_((int drv, fcookie *fc));
1.1 root 26:
1.1.1.2 root 27: static long ARGS_ON_STACK pipe_lookup P_((fcookie *dir, const char *name, fcookie *fc));
1.1 root 28:
1.1.1.2 root 29: static long ARGS_ON_STACK pipe_getxattr P_((fcookie *file, XATTR *xattr));
1.1 root 30:
1.1.1.2 root 31: static long ARGS_ON_STACK pipe_chattr P_((fcookie *file, int attrib));
1.1 root 32:
1.1.1.2 root 33: static long ARGS_ON_STACK pipe_chown P_((fcookie *file, int uid, int gid));
1.1 root 34:
1.1.1.2 root 35: static long ARGS_ON_STACK pipe_chmode P_((fcookie *file, unsigned mode));
1.1 root 36:
1.1.1.2 root 37: static long ARGS_ON_STACK pipe_rmdir P_((fcookie *dir, const char *name));
1.1 root 38:
1.1.1.2 root 39: static long ARGS_ON_STACK pipe_remove P_((fcookie *dir, const char *name));
1.1 root 40:
1.1.1.3 ! root 41: static long ARGS_ON_STACK pipe_getname P_((fcookie *root, fcookie *dir,
! 42:
! 43: char *pathname, int size));
1.1 root 44:
1.1.1.2 root 45: static long ARGS_ON_STACK pipe_rename P_((fcookie *olddir, char *oldname,
1.1 root 46:
47: fcookie *newdir, const char *newname));
48:
1.1.1.2 root 49: static long ARGS_ON_STACK pipe_opendir P_((DIR *dirh, int flags));
1.1 root 50:
1.1.1.2 root 51: static long ARGS_ON_STACK pipe_readdir P_((DIR *dirh, char *nm, int nmlen, fcookie *));
1.1 root 52:
1.1.1.2 root 53: static long ARGS_ON_STACK pipe_rewinddir P_((DIR *dirh));
1.1 root 54:
1.1.1.2 root 55: static long ARGS_ON_STACK pipe_closedir P_((DIR *dirh));
1.1 root 56:
1.1.1.2 root 57: static long ARGS_ON_STACK pipe_pathconf P_((fcookie *dir, int which));
1.1 root 58:
1.1.1.2 root 59: static long ARGS_ON_STACK pipe_dfree P_((fcookie *dir, long *buf));
1.1 root 60:
1.1.1.2 root 61: static long ARGS_ON_STACK pipe_creat P_((fcookie *dir, const char *name, unsigned mode,
1.1 root 62:
63: int attrib, fcookie *fc));
64:
1.1.1.2 root 65: static DEVDRV * ARGS_ON_STACK pipe_getdev P_((fcookie *fc, long *devsp));
1.1 root 66:
67:
68:
1.1.1.2 root 69: static long ARGS_ON_STACK pipe_open P_((FILEPTR *f));
1.1 root 70:
1.1.1.2 root 71: static long ARGS_ON_STACK pipe_write P_((FILEPTR *f, const char *buf, long bytes));
1.1 root 72:
1.1.1.2 root 73: static long ARGS_ON_STACK pipe_read P_((FILEPTR *f, char *buf, long bytes));
1.1 root 74:
1.1.1.2 root 75: static long ARGS_ON_STACK pipe_lseek P_((FILEPTR *f, long where, int whence));
1.1 root 76:
1.1.1.2 root 77: static long ARGS_ON_STACK pipe_ioctl P_((FILEPTR *f, int mode, void *buf));
1.1 root 78:
1.1.1.2 root 79: static long ARGS_ON_STACK pipe_datime P_((FILEPTR *f, short *time, int rwflag));
1.1 root 80:
1.1.1.2 root 81: static long ARGS_ON_STACK pipe_close P_((FILEPTR *f, int pid));
1.1 root 82:
1.1.1.2 root 83: static long ARGS_ON_STACK pipe_select P_((FILEPTR *f, long p, int mode));
1.1 root 84:
1.1.1.2 root 85: static void ARGS_ON_STACK pipe_unselect P_((FILEPTR *f, long p, int mode));
1.1 root 86:
87:
88:
89: DEVDRV pipe_device = {
90:
91: pipe_open, pipe_write, pipe_read, pipe_lseek, pipe_ioctl, pipe_datime,
92:
93: pipe_close, pipe_select, pipe_unselect
94:
95: };
96:
97:
98:
99: /* ptys and pipes can share the same driver, for now */
100:
101: #define pty_device pipe_device
102:
103:
104:
105: FILESYS pipe_filesys = {
106:
107: (FILESYS *)0,
108:
109: 0,
110:
111: pipe_root,
112:
113: pipe_lookup, pipe_creat, pipe_getdev, pipe_getxattr,
114:
115: pipe_chattr, pipe_chown, pipe_chmode,
116:
117: nomkdir, pipe_rmdir, pipe_remove, pipe_getname, pipe_rename,
118:
119: pipe_opendir, pipe_readdir, pipe_rewinddir, pipe_closedir,
120:
121: pipe_pathconf, pipe_dfree,
122:
123: nowritelabel, noreadlabel, nosymlink, noreadlink,
124:
125: nohardlink, nofscntl, nodskchng
126:
127: };
128:
129:
130:
131: /* size of pipes */
132:
133: #define PIPESIZ 4096 /* MUST be a multiple of 4 */
134:
135:
136:
137: /* writes smaller than this are atomic */
138:
139: #define PIPE_BUF 1024 /* should be a multiple of 4 */
140:
141:
142:
143: /* magic flag: indicates that nobody but the creator has opened this pipe */
144:
145: /* note: if this many processes open the pipe, we lose :-( */
146:
147: #define VIRGIN_PIPE 0x7fff
148:
149:
150:
151: struct pipe {
152:
153: int readers; /* number of readers of this pipe */
154:
155: int writers; /* number of writers of this pipe */
156:
157: int head, tail; /* pipe head, tail (head == tail for empty) */
158:
159: long rsel; /* process that did select() for reads */
160:
161: long wsel; /* process that did select() for writes */
162:
163: char buf[PIPESIZ]; /* pipe data */
164:
165: };
166:
167:
168:
169: struct fifo {
170:
171: char name[NAME_MAX+1]; /* FIFO's name */
172:
173: short date, time; /* date & time of last write */
174:
175: short dosflags; /* DOS flags, e.g. FA_RDONLY, FA_HIDDEN */
176:
177: ushort mode; /* file access mode, for XATTR */
178:
179: ushort uid, gid; /* file owner; uid and gid */
180:
181: short flags; /* various other flags (e.g. O_TTY) */
182:
183: short lockpid; /* pid of locking process */
184:
1.1.1.2 root 185: short cursrate; /* cursor flash rate for pseudo TTY's */
186:
1.1 root 187: struct tty *tty; /* tty struct for pseudo TTY's */
188:
189: struct pipe *inp; /* pipe for reads */
190:
191: struct pipe *outp; /* pipe for writes (0 if unidirectional) */
192:
193: struct fifo *next; /* link to next FIFO in list */
194:
195: FILEPTR *open; /* open file pointers for this fifo */
196:
197: } *rootlist;
198:
199:
200:
201:
202:
1.1.1.2 root 203: static long ARGS_ON_STACK
1.1 root 204:
205: pipe_root(drv, fc)
206:
207: int drv;
208:
209: fcookie *fc;
210:
211: {
212:
213: if (drv == PIPEDRV) {
214:
215: fc->fs = &pipe_filesys;
216:
217: fc->dev = drv;
218:
219: fc->index = 0L;
220:
221: return 0;
222:
223: }
224:
225: fc->fs = 0;
226:
227: return EINTRN;
228:
229: }
230:
231:
232:
1.1.1.2 root 233: static long ARGS_ON_STACK
1.1 root 234:
235: pipe_lookup(dir, name, fc)
236:
237: fcookie *dir;
238:
239: const char *name;
240:
241: fcookie *fc;
242:
243: {
244:
245: struct fifo *b;
246:
247:
248:
1.1.1.2 root 249: TRACE(("pipe_lookup(%s)", name));
1.1 root 250:
251:
252:
253: if (dir->index != 0) {
254:
1.1.1.2 root 255: DEBUG(("pipe_lookup(%s): bad directory", name));
1.1 root 256:
257: return EPTHNF;
258:
259: }
260:
261: /* special case: an empty name in a directory means that directory */
262:
263: /* so does "." */
264:
265: if (!*name || (name[0] == '.' && name[1] == 0)) {
266:
267: *fc = *dir;
268:
269: return 0;
270:
271: }
272:
273:
274:
275: /* another special case: ".." could be a mount point */
276:
277: if (!strcmp(name, "..")) {
278:
279: *fc = *dir;
280:
281: return EMOUNT;
282:
283: }
284:
285:
286:
287: for (b = rootlist; b; b = b->next) {
288:
1.1.1.3 ! root 289: if (!strnicmp(b->name, name, NAME_MAX)) {
1.1 root 290:
291: fc->fs = &pipe_filesys;
292:
293: fc->index = (long)b;
294:
295: fc->dev = dir->dev;
296:
297: return 0;
298:
299: }
300:
301: }
302:
1.1.1.2 root 303: DEBUG(("pipe_lookup: name `%s' not found", name));
1.1 root 304:
305: return EFILNF;
306:
307: }
308:
309:
310:
1.1.1.2 root 311: static long ARGS_ON_STACK
1.1 root 312:
313: pipe_getxattr(fc, xattr)
314:
315: fcookie *fc;
316:
317: XATTR *xattr;
318:
319: {
320:
321: struct fifo *this;
322:
323:
324:
325: xattr->index = fc->index;
326:
327: xattr->dev = fc->dev;
328:
329: xattr->nlink = 1;
330:
331: xattr->blksize = 1;
332:
333:
334:
335: if (fc->index == 0) { /* root directory? */
336:
337: xattr->uid = xattr->gid = 0;
338:
339: xattr->mtime = xattr->atime = xattr->ctime = pipetime;
340:
341: xattr->mdate = xattr->adate = xattr->cdate = pipedate;
342:
343: xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
344:
345: xattr->attr = FA_DIR;
346:
347: xattr->size = xattr->nblocks = 0;
348:
349: } else {
350:
351: this = (struct fifo *)fc->index;
352:
353: xattr->uid = this->uid;
354:
355: xattr->gid = this->gid;
356:
357: xattr->mtime = xattr->atime = xattr->ctime = this->time;
358:
359: xattr->mdate = xattr->adate = xattr->cdate = this->date;
360:
361: xattr->mode = this->mode;
362:
363: xattr->attr = this->dosflags;
364:
365: /* note: fifo's that haven't been opened yet can be written to */
366:
367: if (this->flags & O_HEAD) {
368:
369: xattr->attr &= ~FA_RDONLY;
370:
371: }
372:
373:
374:
375: xattr->nblocks = PIPESIZ;
376:
377: if (this->dosflags & FA_SYSTEM) { /* pseudo-tty */
378:
379: xattr->size = PIPESIZ/4;
380:
381: } else {
382:
383: xattr->size = PIPESIZ;
384:
385: }
386:
387: }
388:
389: return 0;
390:
391: }
392:
393:
394:
1.1.1.2 root 395: static long ARGS_ON_STACK
1.1 root 396:
397: pipe_chattr(fc, attrib)
398:
399: fcookie *fc;
400:
401: int attrib;
402:
403: {
404:
1.1.1.2 root 405: UNUSED(fc); UNUSED(attrib);
406:
1.1 root 407: return EACCDN;
408:
409: }
410:
411:
412:
1.1.1.2 root 413: static long ARGS_ON_STACK
1.1 root 414:
415: pipe_chown(fc, uid, gid)
416:
417: fcookie *fc;
418:
419: int uid, gid;
420:
421: {
422:
423: struct fifo *this;
424:
425:
426:
1.1.1.2 root 427: if ((this = (struct fifo *)fc->index) == 0)
428:
429: return EACCDN;
1.1 root 430:
431:
432:
433: this->uid = uid;
434:
435: this->gid = gid;
436:
437: return 0;
438:
439: }
440:
441:
442:
1.1.1.2 root 443: static long ARGS_ON_STACK
1.1 root 444:
445: pipe_chmode(fc, mode)
446:
447: fcookie *fc;
448:
449: unsigned mode;
450:
451: {
452:
453: struct fifo *this;
454:
455:
456:
1.1.1.2 root 457: if ((this = (struct fifo *)fc->index) == 0)
458:
459: return EACCDN;
1.1 root 460:
461:
462:
463: this->mode = (this->mode & S_IFMT) | (mode & ~S_IFMT);
464:
465: return 0;
466:
467: }
468:
469:
470:
1.1.1.2 root 471: static long ARGS_ON_STACK
1.1 root 472:
473: pipe_rmdir(dir, name)
474:
475: fcookie *dir;
476:
477: const char *name;
478:
479: {
480:
1.1.1.2 root 481: UNUSED(dir); UNUSED(name);
482:
483:
484:
1.1 root 485: /* the kernel already checked to see if the file exists */
486:
487: return EACCDN;
488:
489: }
490:
491:
492:
1.1.1.2 root 493: static long ARGS_ON_STACK
1.1 root 494:
495: pipe_remove(dir, name)
496:
497: fcookie *dir;
498:
499: const char *name;
500:
501: {
502:
1.1.1.2 root 503: UNUSED(dir); UNUSED(name);
504:
505:
506:
1.1 root 507: /* the kernel already checked to see if the file exists */
508:
509: return EACCDN;
510:
511: }
512:
513:
514:
1.1.1.2 root 515: static long ARGS_ON_STACK
1.1 root 516:
1.1.1.3 ! root 517: pipe_getname(root, dir, pathname, size)
1.1 root 518:
519: fcookie *root, *dir; char *pathname;
520:
1.1.1.3 ! root 521: int size;
! 522:
1.1 root 523: {
524:
1.1.1.2 root 525: UNUSED(root);
526:
1.1.1.3 ! root 527: UNUSED(size); /* BUG: we should support 'size' */
! 528:
1.1.1.2 root 529:
530:
1.1 root 531: if (dir->index == 0)
532:
533: *pathname = 0;
534:
535: else
536:
537: strcpy(pathname, ((struct fifo *)dir->index)->name);
538:
539: return 0;
540:
541: }
542:
543:
544:
1.1.1.2 root 545: static long ARGS_ON_STACK
1.1 root 546:
547: pipe_rename(olddir, oldname, newdir, newname)
548:
549: fcookie *olddir;
550:
551: char *oldname;
552:
553: fcookie *newdir;
554:
555: const char *newname;
556:
557: {
558:
1.1.1.2 root 559: UNUSED(olddir); UNUSED(oldname);
560:
561: UNUSED(newdir); UNUSED(newname);
562:
563:
564:
1.1 root 565: return EACCDN;
566:
567: }
568:
569:
570:
1.1.1.2 root 571: static long ARGS_ON_STACK
1.1 root 572:
573: pipe_opendir(dirh, flags)
574:
575: DIR *dirh;
576:
577: int flags;
578:
579: {
580:
1.1.1.2 root 581: UNUSED(flags);
582:
583:
584:
1.1 root 585: if (dirh->fc.index != 0) {
586:
1.1.1.2 root 587: DEBUG(("pipe_opendir: bad directory"));
1.1 root 588:
589: return EPTHNF;
590:
591: }
592:
593: dirh->index = 0;
594:
595: return 0;
596:
597: }
598:
599:
600:
1.1.1.2 root 601: static long ARGS_ON_STACK
1.1 root 602:
603: pipe_readdir(dirh, name, namelen, fc)
604:
605: DIR *dirh;
606:
607: char *name;
608:
609: int namelen;
610:
611: fcookie *fc;
612:
613: {
614:
615: struct fifo *this;
616:
617: int i;
618:
619: int giveindex = dirh->flags == 0;
620:
621:
622:
623: i = dirh->index++;
624:
625: this = rootlist;
626:
627: while (i > 0 && this) {
628:
629: --i; this = this->next;
630:
631: }
632:
633: if (!this)
634:
635: return ENMFIL;
636:
637:
638:
639: fc->fs = &pipe_filesys;
640:
641: fc->index = (long)this;
642:
643: fc->dev = dirh->fc.dev;
644:
645: if (giveindex) {
646:
1.1.1.2 root 647: namelen -= (int) sizeof(long);
1.1 root 648:
649: if (namelen <= 0) return ERANGE;
650:
651: *((long *)name) = (long)this;
652:
653: name += sizeof(long);
654:
655: }
656:
657: strncpy(name, this->name, namelen-1);
658:
659: if (strlen(this->name) >= namelen)
660:
661: return ENAMETOOLONG;
662:
663: return 0;
664:
665: }
666:
667:
668:
1.1.1.2 root 669: static long ARGS_ON_STACK
1.1 root 670:
671: pipe_rewinddir(dirh)
672:
673: DIR *dirh;
674:
675: {
676:
677: dirh->index = 0;
678:
679: return 0;
680:
681: }
682:
683:
684:
1.1.1.2 root 685: static long ARGS_ON_STACK
1.1 root 686:
687: pipe_closedir(dirh)
688:
689: DIR *dirh;
690:
691: {
692:
1.1.1.2 root 693: UNUSED(dirh);
694:
1.1 root 695: return 0;
696:
697: }
698:
699:
700:
1.1.1.2 root 701: static long ARGS_ON_STACK
1.1 root 702:
703: pipe_pathconf(dir, which)
704:
705: fcookie *dir;
706:
707: int which;
708:
709: {
710:
1.1.1.2 root 711: UNUSED(dir);
712:
713:
714:
1.1 root 715: switch(which) {
716:
717: case -1:
718:
719: return DP_MAXREQ;
720:
721: case DP_IOPEN:
722:
723: return UNLIMITED; /* no internal limit on open files */
724:
725: case DP_MAXLINKS:
726:
727: return 1; /* no hard links */
728:
729: case DP_PATHMAX:
730:
731: return PATH_MAX;
732:
733: case DP_NAMEMAX:
734:
735: return NAME_MAX;
736:
737: case DP_ATOMIC:
738:
739: /* BUG: for pty's, this should actually be PIPE_BUF/4 */
740:
741: return PIPE_BUF;
742:
743: case DP_TRUNC:
744:
745: return DP_AUTOTRUNC;
746:
747: case DP_CASE:
748:
749: return DP_CASEINSENS;
750:
751: default:
752:
753: return EINVFN;
754:
755: }
756:
757: }
758:
759:
760:
1.1.1.2 root 761: static long ARGS_ON_STACK
1.1 root 762:
763: pipe_dfree(dir, buf)
764:
765: fcookie *dir;
766:
767: long *buf;
768:
769: {
770:
771: int i;
772:
773: struct fifo *b;
774:
775: long freemem;
776:
777:
778:
1.1.1.2 root 779: UNUSED(dir);
780:
781:
782:
1.1 root 783: /* the "sector" size is the number of bytes per pipe */
784:
785: /* so we get the total number of sectors used by counting pipes */
786:
787:
788:
789: i = 0;
790:
791: for (b = rootlist; b; b = b->next) {
792:
793: if (b->inp) i++;
794:
795: if (b->outp) i++;
796:
797: }
798:
799:
800:
801: freemem = tot_rsize(core, 0) + tot_rsize(alt, 0);
802:
803:
804:
805: /* note: the "free clusters" isn't quite accurate, since there's overhead
806:
807: * in the fifo structure; but we're not looking for 100% accuracy here
808:
809: */
810:
811: buf[0] = freemem/PIPESIZ; /* number of free clusters */
812:
813: buf[1] = buf[0]+i; /* total number of clusters */
814:
815: buf[2] = PIPESIZ; /* sector size (bytes) */
816:
817: buf[3] = 1; /* cluster size (sectors) */
818:
819: return 0;
820:
821: }
822:
823:
824:
825: /* create a new pipe.
826:
827: * this only gets called by the kernel if a lookup already failed,
828:
829: * so we know that the new pipe creation is OK
830:
831: */
832:
833:
834:
1.1.1.2 root 835: static long ARGS_ON_STACK
1.1 root 836:
837: pipe_creat(dir, name, mode, attrib, fc)
838:
839: fcookie *dir;
840:
841: const char *name;
842:
843: unsigned mode;
844:
845: int attrib;
846:
847: fcookie *fc;
848:
849: {
850:
851: struct pipe *inp, *outp;
852:
853: struct tty *tty;
854:
855: struct fifo *b;
856:
857: /* selfread == 1 if we want reads to wait even if no other processes
858:
859: have currently opened the file, and writes to succeed in the same
860:
861: event. This is useful for servers who want to wait for requests.
862:
863: Pipes should always have selfread == 0.
864:
865: */
866:
867: int selfread = (attrib & FA_HIDDEN) ? 0 : 1;
868:
869:
870:
871:
872:
873: /* create the new pipe */
874:
1.1.1.2 root 875: if (0 == (inp = (struct pipe *)kmalloc(SIZEOF(struct pipe)))) {
1.1 root 876:
877: return ENSMEM;
878:
879: }
880:
881: if (attrib & FA_RDONLY) { /* read only FIFOs are unidirectional */
882:
883: outp = 0;
884:
885: } else {
886:
887: outp = (struct pipe *)kmalloc(SIZEOF(struct pipe));
888:
889: if (!outp) {
890:
891: kfree(inp);
892:
893: return ENSMEM;
894:
895: }
896:
897: }
898:
899: b = (struct fifo *)kmalloc(SIZEOF(struct fifo));
900:
901: if (!b) {
902:
903: kfree(inp);
904:
905: if (outp) kfree(outp);
906:
907: return ENSMEM;
908:
909: }
910:
911: if (attrib & FA_SYSTEM) { /* pseudo-tty */
912:
913: tty = (struct tty *)kmalloc(SIZEOF(struct tty));
914:
915: if (!tty) {
916:
917: kfree(inp);
918:
919: kfree(b);
920:
921: if (outp) kfree(outp);
922:
923: return ENSMEM;
924:
925: }
926:
927: tty->use_cnt = 0;
928:
929: /* do_open does the rest of tty initialization */
930:
931: } else tty = 0;
932:
933:
934:
935: /* set up the pipes appropriately */
936:
937: inp->head = inp->tail = 0;
938:
939: inp->readers = selfread ? 1 : VIRGIN_PIPE; inp->writers = 1;
940:
941: inp->rsel = inp->wsel = 0;
942:
943: if (outp) {
944:
945: outp->head = outp->tail = 0;
946:
947: outp->readers = 1; outp->writers = selfread ? 1 : VIRGIN_PIPE;
948:
949: outp->wsel = outp->rsel = 0;
950:
951: }
952:
953: strncpy(b->name, name, NAME_MAX);
954:
955: b->time = timestamp;
956:
957: b->date = datestamp;
958:
959: b->dosflags = attrib;
960:
961: b->mode = ((attrib & FA_SYSTEM) ? S_IFCHR : S_IFIFO) | mode;
962:
963: b->uid = curproc->ruid;
964:
965: b->gid = curproc->rgid;
966:
967:
968:
969: /* the O_HEAD flag indicates that the file hasn't actually been opened
970:
971: * yet; the next open gets to be the pty master. pipe_open will
972:
973: * clear the flag when this happens.
974:
975: */
976:
977: b->flags = ((attrib & FA_SYSTEM) ? O_TTY : 0) | O_HEAD;
978:
979: b->inp = inp; b->outp = outp; b->tty = tty;
980:
981:
982:
983: b->next = rootlist;
984:
985: b->open = (FILEPTR *)0;
986:
987: rootlist = b;
988:
989:
990:
991: /* we have to return a file cookie as well */
992:
993: fc->fs = &pipe_filesys;
994:
995: fc->index = (long)b;
996:
997: fc->dev = dir->dev;
998:
999:
1000:
1001: /* update time/date stamps for u:\pipe */
1002:
1003: pipetime = timestamp;
1004:
1005: pipedate = datestamp;
1006:
1007:
1008:
1009: return 0;
1010:
1011: }
1012:
1013:
1014:
1.1.1.2 root 1015: static DEVDRV * ARGS_ON_STACK
1.1 root 1016:
1017: pipe_getdev(fc, devsp)
1018:
1019: fcookie *fc;
1020:
1021: long *devsp;
1022:
1023: {
1024:
1025: struct fifo *b = (struct fifo *)fc->index;
1026:
1027:
1028:
1.1.1.2 root 1029: UNUSED(devsp);
1030:
1.1 root 1031: return (b->flags & O_TTY) ? &pty_device : &pipe_device;
1032:
1033: }
1034:
1035:
1036:
1037: /*
1038:
1039: * PIPE device driver
1040:
1041: */
1042:
1043:
1044:
1.1.1.2 root 1045: static long ARGS_ON_STACK
1.1 root 1046:
1047: pipe_open(f)
1048:
1049: FILEPTR *f;
1050:
1051: {
1052:
1053: struct fifo *p;
1054:
1055: int rwmode = f->flags & O_RWMODE;
1056:
1057:
1058:
1059: p = (struct fifo *)f->fc.index;
1060:
1061: f->flags |= p->flags;
1062:
1063: /*
1064:
1065: * if this is the first open for this file, then the O_HEAD flag is
1066:
1067: * set in p->flags. If not, and someone was trying to create the file,
1068:
1069: * return an error
1070:
1071: */
1072:
1073: if (p->flags & O_HEAD) {
1074:
1075: if (!(f->flags & O_CREAT)) {
1076:
1.1.1.2 root 1077: DEBUG(("pipe_open: file hasn't been created yet"));
1.1 root 1078:
1079: return EINTRN;
1080:
1081: }
1082:
1083: p->flags &= ~O_HEAD;
1084:
1085: } else {
1086:
1087: if (f->flags & O_CREAT) {
1088:
1.1.1.2 root 1089: DEBUG(("pipe_open: fifo already exists"));
1.1 root 1090:
1091: return EACCDN;
1092:
1093: }
1094:
1095: }
1096:
1097: /*
1098:
1099: * check for file sharing compatibility. note that O_COMPAT gets mutated
1100:
1101: * into O_DENYNONE, because any old programs that know about pipes will
1102:
1103: * already handle multitasking correctly
1104:
1105: */
1106:
1107: if ( (f->flags & O_SHMODE) == O_COMPAT ) {
1108:
1109: f->flags = (f->flags & ~O_SHMODE) | O_DENYNONE;
1110:
1111: }
1112:
1113: if (denyshare(p->open, f))
1114:
1115: return EACCDN;
1116:
1117: f->next = p->open; /* add this open fileptr to the list */
1118:
1119: p->open = f;
1120:
1121:
1122:
1123: /*
1124:
1125: * add readers/writers to the list
1126:
1127: */
1128:
1129: if (!(f->flags & O_HEAD)) {
1130:
1131: if (rwmode == O_RDONLY || rwmode == O_RDWR) {
1132:
1133: if (p->inp->readers == VIRGIN_PIPE)
1134:
1135: p->inp->readers = 1;
1136:
1137: else
1138:
1139: p->inp->readers++;
1140:
1141: }
1142:
1143: if ((rwmode == O_WRONLY || rwmode == O_RDWR) && p->outp) {
1144:
1145: if (p->outp->writers == VIRGIN_PIPE)
1146:
1147: p->outp->writers = 1;
1148:
1149: else
1150:
1151: p->outp->writers++;
1152:
1153: }
1154:
1155: }
1156:
1157:
1158:
1159: /* TTY devices need a tty structure in f->devinfo */
1160:
1161: f->devinfo = (long)p->tty;
1162:
1163:
1164:
1165: return 0;
1166:
1167: }
1168:
1169:
1170:
1.1.1.2 root 1171: static long ARGS_ON_STACK
1.1 root 1172:
1173: pipe_write(f, buf, nbytes)
1174:
1175: FILEPTR *f; const char *buf; long nbytes;
1176:
1177: {
1178:
1179: int ptail, phead, j;
1180:
1181: char *pbuf;
1182:
1183: struct pipe *p;
1184:
1185: struct fifo *this;
1186:
1187: long bytes_written = 0;
1188:
1189: long r;
1190:
1191:
1192:
1193: this = (struct fifo *)f->fc.index;
1194:
1195: p = (f->flags & O_HEAD) ? this->inp : this->outp;
1196:
1197: if (!p) {
1198:
1.1.1.2 root 1199: DEBUG(("pipe_write: write on wrong end of pipe"));
1.1 root 1200:
1201: return EACCDN;
1202:
1203: }
1204:
1205:
1206:
1207: if (nbytes > 0 && nbytes <= PIPE_BUF) {
1208:
1209: check_atomicity:
1210:
1211: r = p->tail - p->head;
1212:
1213: if (r < 0) r += PIPESIZ;
1214:
1215: r = (PIPESIZ-1) - r; /* r is the number of bytes we can write */
1216:
1217: if (r < nbytes) {
1218:
1219: /* check for broken pipes */
1220:
1221: if (p->readers == 0 || p->readers == VIRGIN_PIPE) {
1222:
1223: check_sigs();
1224:
1.1.1.2 root 1225: DEBUG(("pipe_write: broken pipe"));
1.1 root 1226:
1227: raise(SIGPIPE);
1228:
1.1.1.3 ! root 1229: return EPIPE;
1.1 root 1230:
1231: }
1232:
1233: /* wake up any readers, and wait for them to gobble some data */
1234:
1235: if (p->rsel) {
1236:
1237: wakeselect(p->rsel);
1238:
1239: p->rsel = 0;
1240:
1241: }
1242:
1243: wake(IO_Q, (long)p);
1244:
1245: sleep(IO_Q, (long)p);
1246:
1247: goto check_atomicity;
1248:
1249: }
1250:
1251: }
1252:
1253:
1254:
1255: while (nbytes > 0) {
1256:
1257: ptail = p->tail; phead = p->head;
1258:
1259: j = ptail+1;
1260:
1261: if (j >= PIPESIZ) j = 0;
1262:
1263: if (j != phead) {
1264:
1265: pbuf = &p->buf[ptail];
1266:
1267: do {
1268:
1269: *pbuf++ = *buf++;
1270:
1271: nbytes--; bytes_written++;
1272:
1273: if ( (ptail = j) == 0 )
1274:
1275: pbuf = &p->buf[0];
1276:
1277: j++;
1278:
1279: if (j >= PIPESIZ) j = 0;
1280:
1281: } while ( (nbytes > 0) && (j != phead) );
1282:
1283: p->tail = ptail;
1284:
1285: } else { /* pipe full */
1286:
1287: if (p->readers == 0 || p->readers == VIRGIN_PIPE) {
1288:
1289: /* maybe some other signal is waiting for us? */
1290:
1291: check_sigs();
1292:
1.1.1.2 root 1293: DEBUG(("pipe_write: broken pipe"));
1.1 root 1294:
1295: raise(SIGPIPE);
1296:
1.1.1.3 ! root 1297: return EPIPE;
1.1 root 1298:
1299: }
1300:
1301: if (f->flags & O_NDELAY) {
1302:
1303: break;
1304:
1305: }
1306:
1307: /* is someone select()ing the other end of the pipe for reading? */
1308:
1309: if (p->rsel) {
1310:
1311: wakeselect(p->rsel);
1312:
1313: p->rsel = 0;
1314:
1315: }
1316:
1317: wake(IO_Q, (long)p); /* readers may continue */
1318:
1.1.1.2 root 1319: DEBUG(("pipe_write: sleep on %lx", p));
1.1 root 1320:
1321: sleep(IO_Q, (long)p);
1322:
1323: }
1324:
1325: }
1326:
1327: this->time = timestamp;
1328:
1329: this->date = datestamp;
1330:
1331: if (bytes_written > 0) {
1332:
1333: if (p->rsel) {
1334:
1335: wakeselect(p->rsel);
1336:
1337: p->rsel = 0;
1338:
1339: }
1340:
1341: wake(IO_Q, (long)p); /* maybe someone wants this data */
1342:
1343: }
1344:
1345:
1346:
1347: return bytes_written;
1348:
1349: }
1350:
1351:
1352:
1.1.1.2 root 1353: static long ARGS_ON_STACK
1.1 root 1354:
1355: pipe_read(f, buf, nbytes)
1356:
1357: FILEPTR *f; char *buf; long nbytes;
1358:
1359: {
1360:
1361: int phead, ptail;
1362:
1363: struct fifo *this;
1364:
1365: struct pipe *p;
1366:
1367: long bytes_read = 0;
1368:
1369: char *pbuf;
1370:
1371:
1372:
1373: this = (struct fifo *)f->fc.index;
1374:
1375: p = (f->flags & O_HEAD) ? this->outp : this->inp;
1376:
1377: if (!p) {
1378:
1.1.1.2 root 1379: DEBUG(("pipe_read: read on the wrong end of a pipe"));
1.1 root 1380:
1381: return EACCDN;
1382:
1383: }
1384:
1385:
1386:
1387: while (nbytes > 0) {
1388:
1389: phead = p->head; ptail = p->tail;
1390:
1391: if (ptail != phead) {
1392:
1393: pbuf = &p->buf[phead];
1394:
1395: do {
1396:
1397: *buf++ = *pbuf++;
1398:
1399: nbytes--; bytes_read++;
1400:
1401: phead++;
1402:
1403: if (phead >= PIPESIZ) {
1404:
1405: phead = 0;
1406:
1407: pbuf = &p->buf[phead];
1408:
1409: }
1410:
1411: } while ( (nbytes > 0) && (phead != ptail) );
1412:
1413: p->head = phead;
1414:
1415: }
1416:
1417: else if (p->writers <= 0 || p->writers == VIRGIN_PIPE) {
1418:
1.1.1.2 root 1419: TRACE(("pipe_read: no more writers"));
1.1 root 1420:
1421: break;
1422:
1423: }
1424:
1.1.1.2 root 1425: else if ((f->flags & O_NDELAY) ||
1426:
1427: ((this->dosflags & FA_CHANGED) && bytes_read > 0) )
1428:
1429: {
1.1 root 1430:
1431: break;
1432:
1433: }
1434:
1435: else {
1436:
1437: /* is someone select()ing the other end of the pipe for writing? */
1438:
1439: if (p->wsel) {
1440:
1441: wakeselect(p->wsel);
1442:
1443: p->wsel = 0;
1444:
1445: }
1446:
1447: wake(IO_Q, (long)p); /* writers may continue */
1448:
1449: sleep(IO_Q, (long)p);
1450:
1451: }
1452:
1453: }
1454:
1455: if (bytes_read > 0) {
1456:
1457: if (p->wsel) {
1458:
1459: wakeselect(p->wsel);
1460:
1461: p->wsel = 0;
1462:
1463: }
1464:
1465: wake(IO_Q, (long)p); /* wake writers */
1466:
1467: }
1468:
1469: return bytes_read;
1470:
1471: }
1472:
1473:
1474:
1.1.1.2 root 1475: static long ARGS_ON_STACK
1.1 root 1476:
1477: pipe_ioctl(f, mode, buf)
1478:
1479: FILEPTR *f; int mode; void *buf;
1480:
1481: {
1482:
1483: struct pipe *p;
1484:
1485: struct fifo *this;
1486:
1487: struct flock *lck;
1488:
1489:
1490:
1491: long r;
1492:
1493:
1494:
1495: this = (struct fifo *)f->fc.index;
1496:
1497:
1498:
1499: if (mode == FIONREAD) {
1500:
1501: p = (f->flags & O_HEAD) ? this->outp : this->inp;
1502:
1503: assert(p != 0);
1504:
1505: if (p->writers <= 0 || p->writers == VIRGIN_PIPE) {
1506:
1.1.1.2 root 1507: DEBUG(("pipe FIONREAD: no writers"));
1.1 root 1508:
1509: r = -1;
1510:
1511: } else {
1512:
1513: r = p->tail - p->head;
1514:
1515: if (r < 0) r += PIPESIZ;
1516:
1517: if (is_terminal(f))
1518:
1519: r = r >> 2; /* r /= 4 */
1520:
1521: }
1522:
1523: *((long *) buf) = r;
1524:
1525: }
1526:
1527: else if (mode == FIONWRITE) {
1528:
1529: p = (f->flags & O_HEAD) ? this->inp : this->outp;
1530:
1531: assert(p != 0);
1532:
1533: if (p->readers <= 0) {
1534:
1535: r = -1;
1536:
1537: } else {
1538:
1539: r = p->tail - p->head;
1540:
1541: if (r < 0) r += PIPESIZ;
1542:
1543: r = (PIPESIZ-1) - r;
1544:
1545: if (is_terminal(f))
1546:
1547: r = r >> 2; /* r /= 4 */
1548:
1549: }
1550:
1551: *((long *) buf) = r;
1552:
1553: }
1554:
1.1.1.2 root 1555: else if (mode == F_SETLK || mode == F_SETLKW) {
1.1 root 1556:
1557: lck = (struct flock *)buf;
1558:
1.1.1.2 root 1559: while (this->flags & O_LOCK) {
1.1 root 1560:
1561: if (this->lockpid != curproc->pid) {
1562:
1.1.1.2 root 1563: DEBUG(("pipe_ioctl: pipe already locked"));
1.1 root 1564:
1.1.1.2 root 1565: if (mode == F_SETLKW && lck->l_type != F_UNLCK) {
1.1 root 1566:
1.1.1.2 root 1567: sleep(IO_Q, (long)this); /* sleep a while */
1568:
1569: }
1570:
1571: else
1572:
1573: return ELOCKED;
1574:
1575: } else
1576:
1577: break;
1.1 root 1578:
1579: }
1580:
1581: if (lck->l_type == F_UNLCK) {
1582:
1583: if (!(f->flags & O_LOCK)) {
1584:
1.1.1.2 root 1585: DEBUG(("pipe_ioctl: wrong file descriptor for UNLCK"));
1.1 root 1586:
1587: return ENSLOCK;
1588:
1589: }
1590:
1591: this->flags &= ~O_LOCK;
1592:
1593: this->lockpid = 0;
1594:
1595: f->flags &= ~O_LOCK;
1596:
1.1.1.2 root 1597: wake(IO_Q, (long)this); /* wake up anyone waiting on the lock */
1598:
1.1 root 1599: }
1600:
1601: else {
1602:
1603: this->flags |= O_LOCK;
1604:
1605: this->lockpid = curproc->pid;
1606:
1607: f->flags |= O_LOCK;
1608:
1609: }
1610:
1611: }
1612:
1613: else if (mode == F_GETLK) {
1614:
1615: lck = (struct flock *)buf;
1616:
1617: if (this->flags & O_LOCK) {
1618:
1619: lck->l_type = F_WRLCK;
1620:
1621: lck->l_start = lck->l_len = 0;
1622:
1623: lck->l_pid = this->lockpid;
1624:
1625: }
1626:
1627: else
1628:
1629: lck->l_type = F_UNLCK;
1630:
1631: }
1632:
1633: else if (mode == TIOCFLUSH) {
1634:
1635: if (this->inp) {
1636:
1637: this->inp->head = this->inp->tail;
1638:
1639: wake(IO_Q, (long)this->inp);
1640:
1641: }
1642:
1643: if (this->outp) {
1644:
1645: this->outp->head = this->outp->tail;
1646:
1647: wake(IO_Q, (long)this->outp);
1648:
1649: }
1650:
1651: } else if (mode == TIOCIBAUD || mode == TIOCOBAUD) {
1652:
1653: *(long *)buf = -1L;
1654:
1655: } else if (mode == TIOCGFLAGS) {
1656:
1657: *((unsigned short *)buf) = 0;
1658:
1.1.1.2 root 1659: } else if (mode >= TCURSOFF && mode <= TCURSGRATE) {
1660:
1661: /* kludge: this assumes TOSWIN style escape sequences */
1662:
1663: tty_putchar(f, (long)'\033', RAW);
1664:
1665: switch (mode) {
1666:
1667: case TCURSOFF:
1668:
1669: tty_putchar(f, (long)'f', RAW);
1670:
1671: break;
1672:
1673: case TCURSON:
1674:
1675: tty_putchar(f, (long)'e', RAW);
1676:
1677: break;
1678:
1679: case TCURSSRATE:
1680:
1681: this->cursrate = *((int *)buf);
1682:
1683: /* fall through */
1684:
1685: case TCURSBLINK:
1686:
1687: tty_putchar(f, (long)'t', RAW);
1688:
1689: tty_putchar(f, (long)this->cursrate+32, RAW);
1690:
1691: break;
1692:
1693: case TCURSSTEADY:
1694:
1695: tty_putchar(f, (long)'t', RAW);
1696:
1697: tty_putchar(f, (long)32, RAW);
1698:
1699: break;
1700:
1701: case TCURSGRATE:
1702:
1703: return this->cursrate;
1704:
1705: }
1706:
1.1 root 1707: } else {
1708:
1709: /* if the file is a terminal, Fcntl will automatically
1710:
1711: * call tty_ioctl for us to handle 'generic' terminal
1712:
1713: * functions
1714:
1715: */
1716:
1717: return EINVFN;
1718:
1719: }
1720:
1721:
1722:
1723: return 0;
1724:
1725: }
1726:
1727:
1728:
1.1.1.2 root 1729: static long ARGS_ON_STACK
1.1 root 1730:
1731: pipe_lseek(f, where, whence)
1732:
1733: FILEPTR *f; long where; int whence;
1734:
1735: {
1736:
1.1.1.2 root 1737: UNUSED(f); UNUSED(where); UNUSED(whence);
1738:
1.1 root 1739: return EACCDN;
1740:
1741: }
1742:
1743:
1744:
1.1.1.2 root 1745: static long ARGS_ON_STACK
1.1 root 1746:
1747: pipe_datime(f, timeptr, rwflag)
1748:
1749: FILEPTR *f;
1750:
1751: short *timeptr;
1752:
1753: int rwflag;
1754:
1755: {
1756:
1757: struct fifo *this;
1758:
1759:
1760:
1761: this = (struct fifo *)f->fc.index;
1762:
1763: if (rwflag) {
1764:
1765: this->time = timeptr[0];
1766:
1767: this->date = timeptr[1];
1768:
1769: }
1770:
1771: else {
1772:
1773: timeptr[0] = this->time;
1774:
1775: timeptr[1] = this->date;
1776:
1777: }
1778:
1779: return 0;
1780:
1781: }
1782:
1783:
1784:
1.1.1.2 root 1785: static long ARGS_ON_STACK
1.1 root 1786:
1787: pipe_close(f, pid)
1788:
1789: FILEPTR *f;
1790:
1791: int pid;
1792:
1793: {
1794:
1795: struct fifo *this, *old;
1796:
1797: struct pipe *p;
1798:
1799: int rwmode;
1800:
1801: FILEPTR **old_x, *x;
1802:
1803:
1804:
1805: this = (struct fifo *)f->fc.index;
1806:
1807:
1808:
1809: /* wake any processes waiting on this pipe */
1810:
1811: wake(IO_Q, (long)this->inp);
1812:
1813: if (this->inp->rsel)
1814:
1815: wakeselect(this->inp->rsel);
1816:
1817: if (this->inp->wsel)
1818:
1819: wakeselect(this->inp->wsel);
1820:
1821:
1822:
1823: if (this->outp) {
1824:
1825: wake(IO_Q, (long)this->outp);
1826:
1827: if (this->outp->wsel)
1828:
1829: wakeselect(this->outp->wsel);
1830:
1831: if (this->outp->rsel)
1832:
1833: wakeselect(this->outp->rsel);
1834:
1835: }
1836:
1837:
1838:
1839: if (f->links <= 0) {
1840:
1841: /* remove the file pointer from the list of open file pointers
1842:
1843: * of this pipe
1844:
1845: */
1846:
1847: old_x = &this->open;
1848:
1849: x = this->open;
1850:
1851: while (x && x != f) {
1852:
1853: old_x = &x->next;
1854:
1855: x = x->next;
1856:
1857: }
1858:
1859: assert(x);
1860:
1861: *old_x = f->next;
1862:
1863: /* f->next = 0; */
1864:
1865:
1866:
1867: rwmode = f->flags & O_RWMODE;
1868:
1869: if (rwmode == O_RDONLY || rwmode == O_RDWR) {
1870:
1871: p = (f->flags & O_HEAD) ? this->outp : this->inp;
1872:
1873: /* note that this can never be a virgin pipe, since we had a handle
1874:
1875: * on it!
1876:
1877: */ if (p)
1878:
1879: p->readers--;
1880:
1881: }
1882:
1883: if (rwmode == O_WRONLY || rwmode == O_RDWR) {
1884:
1885: p = (f->flags & O_HEAD) ? this->inp : this->outp;
1886:
1887: if (p) p->writers--;
1888:
1889: }
1890:
1891:
1892:
1893: /* correct for the "selfread" flag (see pipe_creat) */
1894:
1895: if ((f->flags & O_HEAD) && !(this->dosflags & 0x02))
1896:
1897: this->inp->readers--;
1898:
1899:
1900:
1901: /* check for locks */
1902:
1903: if ((f->flags & O_LOCK) && (this->lockpid == pid)) {
1904:
1905: this->flags &= ~O_LOCK;
1906:
1.1.1.2 root 1907: wake(IO_Q, (long)this); /* wake up anyone waiting on the lock */
1908:
1.1 root 1909: }
1910:
1911: }
1912:
1913:
1914:
1915: /* see if we're finished with the pipe */
1916:
1917: if (this->inp->readers == VIRGIN_PIPE)
1918:
1919: this->inp->readers = 0;
1920:
1921: if (this->inp->writers == VIRGIN_PIPE)
1922:
1923: this->inp->writers = 0;
1924:
1925:
1926:
1927: if (this->inp->readers <= 0 && this->inp->writers <= 0) {
1928:
1.1.1.2 root 1929: TRACE(("disposing of closed fifo"));
1.1 root 1930:
1931: /* unlink from list of FIFOs */
1932:
1933: if (rootlist == this)
1934:
1935: rootlist = this->next;
1936:
1937: else {
1938:
1939: for (old = rootlist; old->next != this;
1940:
1941: old = old->next) {
1942:
1943: if (!old) {
1944:
1945: ALERT("fifo not on list???");
1946:
1947: return EINTRN;
1948:
1949: }
1950:
1951: }
1952:
1953: old->next = this->next;
1954:
1955: }
1956:
1957: kfree(this->inp);
1958:
1959: if (this->outp) kfree(this->outp);
1960:
1961: kfree(this);
1962:
1963: pipetime = timestamp;
1964:
1965: pipedate = datestamp;
1966:
1967: }
1968:
1969:
1970:
1971: return 0;
1972:
1973: }
1974:
1975:
1976:
1.1.1.2 root 1977: static long ARGS_ON_STACK
1.1 root 1978:
1979: pipe_select(f, proc, mode)
1980:
1981: FILEPTR *f;
1982:
1983: long proc;
1984:
1985: int mode;
1986:
1987: {
1988:
1989: struct fifo *this;
1990:
1991: struct pipe *p;
1992:
1993: int j;
1994:
1995:
1996:
1997: this = (struct fifo *)f->fc.index;
1998:
1999:
2000:
2001: if (mode == O_RDONLY) {
2002:
2003: p = (f->flags & O_HEAD) ? this->outp : this->inp;
2004:
2005: if (!p) {
2006:
1.1.1.2 root 2007: DEBUG(("read select on wrong end of pipe"));
1.1 root 2008:
2009: return 0;
2010:
2011: }
2012:
2013:
2014:
2015: /* NOTE: if p->writers <= 0 then reads won't block (they'll fail) */
2016:
2017: if (p->tail != p->head || p->writers <= 0) {
2018:
2019: return 1;
2020:
2021: }
2022:
2023:
2024:
2025: /* BUG: multiple selects fail, only the first one works */
2026:
2027: if (!p->rsel)
2028:
2029: p->rsel = proc;
2030:
2031: return 0;
2032:
2033: } else if (mode == O_WRONLY) {
2034:
2035: p = (f->flags & O_HEAD) ? this->inp : this->outp;
2036:
2037: if (!p) {
2038:
1.1.1.2 root 2039: DEBUG(("write select on wrong end of pipe"));
1.1 root 2040:
2041: return 0;
2042:
2043: }
2044:
2045: j = p->tail+1;
2046:
2047: if (j >= PIPESIZ) j = 0;
2048:
2049: if (j != p->head || p->readers <= 0)
2050:
2051: return 1; /* data may be written */
2052:
2053: if (!p->wsel)
2054:
2055: p->wsel = proc;
2056:
2057: return 0;
2058:
2059: }
2060:
2061: return 0;
2062:
2063: }
2064:
2065:
2066:
1.1.1.2 root 2067: static void ARGS_ON_STACK
1.1 root 2068:
2069: pipe_unselect(f, proc, mode)
2070:
2071: FILEPTR *f;
2072:
2073: long proc;
2074:
2075: int mode;
2076:
2077: {
2078:
2079: struct fifo *this;
2080:
2081: struct pipe *p;
2082:
2083:
2084:
2085: this = (struct fifo *)f->fc.index;
2086:
2087:
2088:
2089: if (mode == O_RDONLY) {
2090:
2091: p = (f->flags & O_HEAD) ? this->outp : this->inp;
2092:
2093: if (!p) {
2094:
2095: return;
2096:
2097: }
2098:
2099: if (p->rsel == proc)
2100:
2101: p->rsel = 0;
2102:
2103: } else if (mode == O_WRONLY) {
2104:
2105: p = (f->flags & O_HEAD) ? this->inp : this->outp;
2106:
2107: if (!p) {
2108:
2109: return;
2110:
2111: }
2112:
2113: if (p->wsel == proc)
2114:
2115: p->wsel = 0;
2116:
2117: }
2118:
2119: }
2120:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.