+#endif
+
+unp_externalize(rights)
+ struct mbuf *rights;
+{
+ int newfds = rights->m_len / sizeof (int);
+ register int i;
+ register struct file **rp = mtod(rights, struct file **);
+ register struct file *fp;
+ int f;
+
+ if (newfds > ufavail()) {
+ for (i = 0; i < newfds; i++) {
+ fp = *rp;
+ unp_discard(fp);
+ *rp++ = 0;
+ }
+ return (EMSGSIZE);
+ }
+ for (i = 0; i < newfds; i++) {
+ f = ufalloc(0);
+ if (f < 0)
+ panic("unp_externalize");
+ fp = *rp;
+ u.u_ofile[f] = fp;
+ fp->f_msgcount--;
+ *(int *)rp++ = f;
+ }
+ return (0);
+}
+
+unp_internalize(rights)
+ struct mbuf *rights;
+{
+ register struct file **rp;
+ int oldfds = rights->m_len / sizeof (int);
+ register int i;
+ register struct file *fp;
+
+ rp = mtod(rights, struct file **);
+ for (i = 0; i < oldfds; i++)
+ if (getf(*(int *)rp++) == 0)
+ return (EBADF);
+ rp = mtod(rights, struct file **);
+ for (i = 0; i < oldfds; i++) {
+ fp = getf(*(int *)rp);
+ *rp++ = fp;
+ fp->f_count++;
+ fp->f_msgcount++;
+ }
+ return (0);
+}
+
+int unp_defer, unp_gcing;
+int unp_mark();
+extern struct domain unixdomain;
+
+unp_gc()
+{
+ register struct file *fp;
+ register struct socket *so;
+
+ if (unp_gcing)
+ return;
+ unp_gcing = 1;
+restart:
+ unp_defer = 0;
+ for (fp = file; fp < fileNFILE; fp++)
+ fp->f_flag &= ~(FMARK|FDEFER);
+ do {
+ for (fp = file; fp < fileNFILE; fp++) {
+ if (fp->f_count == 0)
+ continue;
+ if (fp->f_flag & FDEFER) {
+ fp->f_flag &= ~FDEFER;
+ unp_defer--;
+ } else {
+ if (fp->f_flag & FMARK)
+ continue;
+ if (fp->f_count == fp->f_msgcount)
+ continue;
+ fp->f_flag |= FMARK;
+ }
+ if (fp->f_type != DTYPE_SOCKET)
+ continue;
+ so = (struct socket *)fp->f_data;
+ if (so->so_proto->pr_domain != &unixdomain ||
+ (so->so_proto->pr_flags&PR_RIGHTS) == 0)
+ continue;
+ if (so->so_rcv.sb_flags & SB_LOCK) {
+ sbwait(&so->so_rcv);
+ goto restart;
+ }
+ unp_scan(so->so_rcv.sb_mb, unp_mark);
+ }
+ } while (unp_defer);
+ for (fp = file; fp < fileNFILE; fp++) {
+ if (fp->f_count == 0)
+ continue;
+ if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
+ if (fp->f_type != DTYPE_SOCKET)
+ panic("unp_gc");
+ (void) soshutdown((struct socket *)fp->f_data, 0);
+ }
+ }
+ unp_gcing = 0;
+}
+
+unp_dispose(m)
+ struct mbuf *m;
+{
+ int unp_discard();
+
+ if (m)
+ unp_scan(m, unp_discard);
+}
+
+unp_scan(m0, op)
+ register struct mbuf *m0;
+ int (*op)();
+{
+ register struct mbuf *m;
+ register struct file **rp;
+ register int i;
+ int qfds;
+
+ while (m0) {
+ for (m = m0; m; m = m->m_next)
+ if (m->m_type == MT_RIGHTS && m->m_len) {
+ qfds = m->m_len / sizeof (struct file *);
+ rp = mtod(m, struct file **);
+ for (i = 0; i < qfds; i++)
+ (*op)(*rp++);
+ break; /* XXX, but saves time */
+ }
+ m0 = m0->m_act;
+ }
+}
+
+unp_mark(fp)
+ struct file *fp;
+{
+
+ if (fp->f_flag & FMARK)
+ return;
+ unp_defer++;
+ fp->f_flag |= (FMARK|FDEFER);
+}
+
+unp_discard(fp)
+ struct file *fp;
+{
+
+ fp->f_msgcount--;
+ closef(fp);
+}