Commit | Line | Data |
---|---|---|
477d62ec | 1 | /* tty_pty.c 6.7 84/09/10 */ |
be4367b3 | 2 | |
45372428 MT |
3 | /* |
4 | * Pseudo-teletype Driver | |
5 | * (Actually two drivers, requiring two entries in 'cdevsw') | |
45372428 | 6 | */ |
647d645f MT |
7 | #include "pty.h" |
8 | ||
f12183e4 | 9 | #if NPTY > 0 |
94368568 JB |
10 | #include "param.h" |
11 | #include "systm.h" | |
12 | #include "ioctl.h" | |
13 | #include "tty.h" | |
14 | #include "dir.h" | |
15 | #include "user.h" | |
16 | #include "conf.h" | |
17 | #include "file.h" | |
18 | #include "proc.h" | |
19 | #include "uio.h" | |
20 | #include "kernel.h" | |
941944c9 | 21 | |
b3c8737d | 22 | #if NPTY == 1 |
c91c01fe BJ |
23 | #undef NPTY |
24 | #define NPTY 32 /* crude XXX */ | |
b3c8737d | 25 | #endif |
45372428 | 26 | |
2bb0bef9 | 27 | #define BUFSIZ 100 /* Chunk size iomoved to/from user */ |
e1d74936 | 28 | |
45372428 | 29 | /* |
e1d74936 BJ |
30 | * pts == /dev/tty[pP]? |
31 | * ptc == /dev/ptp[pP]? | |
45372428 | 32 | */ |
e1d74936 BJ |
33 | struct tty pt_tty[NPTY]; |
34 | struct pt_ioctl { | |
1a954a11 BJ |
35 | int pt_flags; |
36 | int pt_gensym; | |
37 | struct proc *pt_selr, *pt_selw; | |
38 | int pt_send; | |
e1d74936 | 39 | } pt_ioctl[NPTY]; |
45372428 | 40 | |
1a954a11 BJ |
41 | #define PF_RCOLL 0x01 |
42 | #define PF_WCOLL 0x02 | |
43 | #define PF_NBIO 0x04 | |
44 | #define PF_PKT 0x08 /* packet mode */ | |
1e6d24b1 | 45 | #define PF_STOPPED 0x10 /* user told stopped */ |
defdbcd1 | 46 | #define PF_REMOTE 0x20 /* remote and flow controlled input */ |
0a2bd708 | 47 | #define PF_NOSTOP 0x40 |
45372428 MT |
48 | |
49 | /*ARGSUSED*/ | |
50 | ptsopen(dev, flag) | |
73c77d38 | 51 | dev_t dev; |
e1d74936 | 52 | { |
45372428 MT |
53 | register struct tty *tp; |
54 | ||
f21c8fb8 BJ |
55 | if (minor(dev) >= NPTY) |
56 | return (ENXIO); | |
45372428 | 57 | tp = &pt_tty[minor(dev)]; |
941944c9 | 58 | if ((tp->t_state & TS_ISOPEN) == 0) { |
bdda6b91 | 59 | ttychars(tp); /* Set up default chars */ |
d2f24af0 | 60 | tp->t_ispeed = tp->t_ospeed = EXTB; |
bdda6b91 | 61 | tp->t_flags = 0; /* No features (nor raw mode) */ |
f21c8fb8 BJ |
62 | } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) |
63 | return (EBUSY); | |
e1d74936 | 64 | if (tp->t_oproc) /* Ctrlr still around. */ |
941944c9 BJ |
65 | tp->t_state |= TS_CARR_ON; |
66 | while ((tp->t_state & TS_CARR_ON) == 0) { | |
67 | tp->t_state |= TS_WOPEN; | |
45372428 MT |
68 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
69 | } | |
f21c8fb8 | 70 | return ((*linesw[tp->t_line].l_open)(dev, tp)); |
45372428 MT |
71 | } |
72 | ||
73 | ptsclose(dev) | |
73c77d38 | 74 | dev_t dev; |
941944c9 | 75 | { |
45372428 MT |
76 | register struct tty *tp; |
77 | ||
78 | tp = &pt_tty[minor(dev)]; | |
79 | (*linesw[tp->t_line].l_close)(tp); | |
4b39cb77 | 80 | ttyclose(tp); |
2bb0bef9 | 81 | ptcwakeup(tp); |
45372428 MT |
82 | } |
83 | ||
ae9a0a69 | 84 | ptsread(dev, uio) |
73c77d38 | 85 | dev_t dev; |
ae9a0a69 | 86 | struct uio *uio; |
e1d74936 | 87 | { |
defdbcd1 BJ |
88 | register struct tty *tp = &pt_tty[minor(dev)]; |
89 | register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; | |
840510a3 | 90 | int error = 0; |
defdbcd1 BJ |
91 | |
92 | again: | |
93 | if (pti->pt_flags & PF_REMOTE) { | |
94 | while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { | |
3622edaa MK |
95 | #define bit(a) (1<<(a-1)) |
96 | if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || | |
97 | (u.u_procp->p_sigmask & bit(SIGTTIN)) || | |
defdbcd1 BJ |
98 | /* |
99 | (u.u_procp->p_flag&SDETACH) || | |
100 | */ | |
101 | u.u_procp->p_flag&SVFORK) | |
840510a3 | 102 | return (EIO); |
defdbcd1 BJ |
103 | gsignal(u.u_procp->p_pgrp, SIGTTIN); |
104 | sleep((caddr_t)&lbolt, TTIPRI); | |
941944c9 | 105 | } |
3622edaa | 106 | #undef bit |
defdbcd1 | 107 | if (tp->t_rawq.c_cc == 0) { |
840510a3 BJ |
108 | if (tp->t_state & TS_NBIO) |
109 | return (EWOULDBLOCK); | |
defdbcd1 BJ |
110 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
111 | goto again; | |
112 | } | |
ae9a0a69 BJ |
113 | while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) |
114 | if (ureadc(getc(&tp->t_rawq), uio) < 0) { | |
840510a3 | 115 | error = EFAULT; |
ae9a0a69 BJ |
116 | break; |
117 | } | |
defdbcd1 BJ |
118 | if (tp->t_rawq.c_cc == 1) |
119 | (void) getc(&tp->t_rawq); | |
120 | if (tp->t_rawq.c_cc) | |
840510a3 | 121 | return (error); |
defdbcd1 BJ |
122 | } else |
123 | if (tp->t_oproc) | |
840510a3 | 124 | error = (*linesw[tp->t_line].l_read)(tp, uio); |
defdbcd1 BJ |
125 | wakeup((caddr_t)&tp->t_rawq.c_cf); |
126 | if (pti->pt_selw) { | |
127 | selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); | |
128 | pti->pt_selw = 0; | |
129 | pti->pt_flags &= ~PF_WCOLL; | |
45372428 | 130 | } |
840510a3 | 131 | return (error); |
45372428 MT |
132 | } |
133 | ||
941944c9 BJ |
134 | /* |
135 | * Write to pseudo-tty. | |
136 | * Wakeups of controlling tty will happen | |
137 | * indirectly, when tty driver calls ptsstart. | |
138 | */ | |
ae9a0a69 | 139 | ptswrite(dev, uio) |
73c77d38 | 140 | dev_t dev; |
ae9a0a69 | 141 | struct uio *uio; |
e1d74936 | 142 | { |
45372428 MT |
143 | register struct tty *tp; |
144 | ||
145 | tp = &pt_tty[minor(dev)]; | |
840510a3 BJ |
146 | if (tp->t_oproc == 0) |
147 | return (EIO); | |
148 | return ((*linesw[tp->t_line].l_write)(tp, uio)); | |
45372428 MT |
149 | } |
150 | ||
941944c9 BJ |
151 | /* |
152 | * Start output on pseudo-tty. | |
153 | * Wake up process selecting or sleeping for input from controlling tty. | |
154 | */ | |
45372428 | 155 | ptsstart(tp) |
e1d74936 BJ |
156 | struct tty *tp; |
157 | { | |
1e6d24b1 | 158 | register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; |
e1d74936 | 159 | |
941944c9 | 160 | if (tp->t_state & TS_TTSTOP) |
45372428 | 161 | return; |
1e6d24b1 BJ |
162 | if (pti->pt_flags & PF_STOPPED) { |
163 | pti->pt_flags &= ~PF_STOPPED; | |
164 | pti->pt_send = TIOCPKT_START; | |
165 | } | |
d427b3b2 BJ |
166 | ptcwakeup(tp); |
167 | } | |
168 | ||
169 | ptcwakeup(tp) | |
170 | struct tty *tp; | |
171 | { | |
172 | struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; | |
173 | ||
1a954a11 BJ |
174 | if (pti->pt_selr) { |
175 | selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); | |
176 | pti->pt_selr = 0; | |
177 | pti->pt_flags &= ~PF_RCOLL; | |
e1d74936 | 178 | } |
45372428 MT |
179 | wakeup((caddr_t)&tp->t_outq.c_cf); |
180 | } | |
181 | ||
182 | /*ARGSUSED*/ | |
183 | ptcopen(dev, flag) | |
e1d74936 BJ |
184 | dev_t dev; |
185 | int flag; | |
186 | { | |
45372428 | 187 | register struct tty *tp; |
1a954a11 | 188 | struct pt_ioctl *pti; |
45372428 | 189 | |
f21c8fb8 BJ |
190 | if (minor(dev) >= NPTY) |
191 | return (ENXIO); | |
45372428 | 192 | tp = &pt_tty[minor(dev)]; |
f21c8fb8 BJ |
193 | if (tp->t_oproc) |
194 | return (EIO); | |
e1d74936 | 195 | tp->t_oproc = ptsstart; |
941944c9 | 196 | if (tp->t_state & TS_WOPEN) |
45372428 | 197 | wakeup((caddr_t)&tp->t_rawq); |
941944c9 | 198 | tp->t_state |= TS_CARR_ON; |
1a954a11 BJ |
199 | pti = &pt_ioctl[minor(dev)]; |
200 | pti->pt_flags = 0; | |
201 | pti->pt_send = 0; | |
f21c8fb8 | 202 | return (0); |
45372428 MT |
203 | } |
204 | ||
205 | ptcclose(dev) | |
e1d74936 BJ |
206 | dev_t dev; |
207 | { | |
45372428 MT |
208 | register struct tty *tp; |
209 | ||
210 | tp = &pt_tty[minor(dev)]; | |
941944c9 | 211 | if (tp->t_state & TS_ISOPEN) |
45372428 | 212 | gsignal(tp->t_pgrp, SIGHUP); |
941944c9 | 213 | tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ |
88a7a62a | 214 | ttyflush(tp, FREAD|FWRITE); |
e1d74936 | 215 | tp->t_oproc = 0; /* mark closed */ |
45372428 MT |
216 | } |
217 | ||
ae9a0a69 | 218 | ptcread(dev, uio) |
1a954a11 | 219 | dev_t dev; |
ae9a0a69 | 220 | struct uio *uio; |
e1d74936 | 221 | { |
840510a3 | 222 | register struct tty *tp = &pt_tty[minor(dev)]; |
1a954a11 | 223 | struct pt_ioctl *pti; |
2bb0bef9 SL |
224 | char buf[BUFSIZ]; |
225 | int error = 0, cc; | |
45372428 | 226 | |
941944c9 | 227 | if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) |
a8d3bf7f | 228 | return (EIO); |
1a954a11 BJ |
229 | pti = &pt_ioctl[minor(dev)]; |
230 | if (pti->pt_flags & PF_PKT) { | |
231 | if (pti->pt_send) { | |
840510a3 BJ |
232 | error = ureadc(pti->pt_send, uio); |
233 | if (error) | |
234 | return (error); | |
1a954a11 | 235 | pti->pt_send = 0; |
840510a3 | 236 | return (0); |
1a954a11 | 237 | } |
840510a3 | 238 | error = ureadc(0, uio); |
1a954a11 | 239 | } |
8b8271ac | 240 | while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { |
2bb0bef9 SL |
241 | if ((tp->t_state&TS_CARR_ON) == 0) |
242 | return (EIO); | |
840510a3 BJ |
243 | if (pti->pt_flags&PF_NBIO) |
244 | return (EWOULDBLOCK); | |
45372428 | 245 | sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); |
8b8271ac | 246 | } |
2bb0bef9 SL |
247 | while (uio->uio_resid > 0 && error == 0) { |
248 | cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); | |
249 | if (cc <= 0) | |
ae9a0a69 | 250 | break; |
2bb0bef9 SL |
251 | error = uiomove(buf, cc, UIO_READ, uio); |
252 | } | |
941944c9 BJ |
253 | if (tp->t_outq.c_cc <= TTLOWAT(tp)) { |
254 | if (tp->t_state&TS_ASLEEP) { | |
255 | tp->t_state &= ~TS_ASLEEP; | |
256 | wakeup((caddr_t)&tp->t_outq); | |
257 | } | |
258 | if (tp->t_wsel) { | |
259 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
260 | tp->t_wsel = 0; | |
261 | tp->t_state &= ~TS_WCOLL; | |
262 | } | |
45372428 | 263 | } |
840510a3 | 264 | return (error); |
45372428 MT |
265 | } |
266 | ||
1a954a11 BJ |
267 | ptsstop(tp, flush) |
268 | register struct tty *tp; | |
269 | int flush; | |
270 | { | |
271 | struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; | |
272 | ||
1e6d24b1 BJ |
273 | /* note: FLUSHREAD and FLUSHWRITE already ok */ |
274 | if (flush == 0) { | |
275 | flush = TIOCPKT_STOP; | |
276 | pti->pt_flags |= PF_STOPPED; | |
277 | } else { | |
278 | pti->pt_flags &= ~PF_STOPPED; | |
279 | } | |
0a2bd708 | 280 | pti->pt_send |= flush; |
d427b3b2 | 281 | ptcwakeup(tp); |
1a954a11 BJ |
282 | } |
283 | ||
941944c9 | 284 | ptcselect(dev, rw) |
e1d74936 | 285 | dev_t dev; |
941944c9 | 286 | int rw; |
e1d74936 BJ |
287 | { |
288 | register struct tty *tp = &pt_tty[minor(dev)]; | |
defdbcd1 | 289 | struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; |
e1d74936 | 290 | struct proc *p; |
d427b3b2 | 291 | int s; |
e1d74936 | 292 | |
941944c9 | 293 | if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) |
e1d74936 | 294 | return (1); |
d427b3b2 | 295 | s = spl5(); |
941944c9 BJ |
296 | switch (rw) { |
297 | ||
298 | case FREAD: | |
d427b3b2 BJ |
299 | if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { |
300 | splx(s); | |
941944c9 | 301 | return (1); |
d427b3b2 | 302 | } |
1a954a11 BJ |
303 | if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) |
304 | pti->pt_flags |= PF_RCOLL; | |
941944c9 | 305 | else |
1a954a11 | 306 | pti->pt_selr = u.u_procp; |
d427b3b2 | 307 | break; |
941944c9 BJ |
308 | |
309 | case FWRITE: | |
defdbcd1 | 310 | if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { |
d427b3b2 | 311 | splx(s); |
941944c9 | 312 | return (1); |
d427b3b2 | 313 | } |
1a954a11 BJ |
314 | if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) |
315 | pti->pt_flags |= PF_WCOLL; | |
941944c9 | 316 | else |
1a954a11 | 317 | pti->pt_selw = u.u_procp; |
d427b3b2 | 318 | break; |
941944c9 | 319 | } |
d427b3b2 BJ |
320 | splx(s); |
321 | return (0); | |
e1d74936 BJ |
322 | } |
323 | ||
ae9a0a69 | 324 | ptcwrite(dev, uio) |
941944c9 | 325 | dev_t dev; |
ae9a0a69 | 326 | struct uio *uio; |
e1d74936 | 327 | { |
840510a3 | 328 | register struct tty *tp = &pt_tty[minor(dev)]; |
45372428 MT |
329 | register char *cp, *ce; |
330 | register int cc; | |
331 | char locbuf[BUFSIZ]; | |
941944c9 | 332 | int cnt = 0; |
defdbcd1 | 333 | struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; |
840510a3 | 334 | int error = 0; |
45372428 | 335 | |
941944c9 | 336 | if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) |
840510a3 | 337 | return (EIO); |
defdbcd1 | 338 | do { |
ae9a0a69 BJ |
339 | register struct iovec *iov; |
340 | ||
341 | if (uio->uio_iovcnt == 0) | |
342 | break; | |
343 | iov = uio->uio_iov; | |
344 | if (iov->iov_len == 0) { | |
2bb0bef9 SL |
345 | while (pti->pt_flags&PF_REMOTE && tp->t_rawq.c_cc != 0) |
346 | sleep((caddr_t)&tp->t_rawq.c_cf, TTIPRI); | |
347 | if (pti->pt_flags&PF_REMOTE) { | |
348 | (void) putc(0, &tp->t_rawq); | |
349 | wakeup((caddr_t)&tp->t_rawq); | |
350 | } | |
ae9a0a69 BJ |
351 | uio->uio_iovcnt--; |
352 | uio->uio_iov++; | |
353 | if (uio->uio_iovcnt < 0) | |
354 | panic("ptcwrite"); | |
355 | continue; | |
356 | } | |
357 | cc = MIN(iov->iov_len, BUFSIZ); | |
45372428 | 358 | cp = locbuf; |
840510a3 BJ |
359 | error = uiomove(cp, cc, UIO_WRITE, uio); |
360 | if (error) | |
45372428 MT |
361 | break; |
362 | ce = cp + cc; | |
defdbcd1 BJ |
363 | again: |
364 | if (pti->pt_flags & PF_REMOTE) { | |
365 | if (tp->t_rawq.c_cc) { | |
366 | if (pti->pt_flags & PF_NBIO) { | |
ae9a0a69 BJ |
367 | iov->iov_base -= ce - cp; |
368 | iov->iov_len += ce - cp; | |
369 | uio->uio_resid += ce - cp; | |
370 | uio->uio_offset -= ce - cp; | |
840510a3 | 371 | return (EWOULDBLOCK); |
defdbcd1 BJ |
372 | } |
373 | sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); | |
374 | goto again; | |
375 | } | |
668cc26d SL |
376 | (void) b_to_q(cp, cc, &tp->t_rawq); |
377 | (void) putc(0, &tp->t_rawq); | |
defdbcd1 | 378 | wakeup((caddr_t)&tp->t_rawq); |
840510a3 | 379 | return (0); |
defdbcd1 | 380 | } |
e1d74936 | 381 | while (cp < ce) { |
28b2d854 MK |
382 | if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && |
383 | (tp->t_canq.c_cc > 0)) { | |
45372428 | 384 | wakeup((caddr_t)&tp->t_rawq); |
941944c9 | 385 | if (tp->t_state & TS_NBIO) { |
ae9a0a69 BJ |
386 | iov->iov_base -= ce - cp; |
387 | iov->iov_len += ce - cp; | |
388 | uio->uio_resid += ce - cp; | |
389 | uio->uio_offset -= ce - cp; | |
941944c9 | 390 | if (cnt == 0) |
840510a3 BJ |
391 | return (EWOULDBLOCK); |
392 | return (0); | |
941944c9 | 393 | } |
45372428 MT |
394 | /* Better than just flushing it! */ |
395 | /* Wait for something to be read */ | |
396 | sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); | |
defdbcd1 | 397 | goto again; |
45372428 | 398 | } |
36612a8f | 399 | (*linesw[tp->t_line].l_rint)(*cp++, tp); |
941944c9 | 400 | cnt++; |
45372428 | 401 | } |
ae9a0a69 | 402 | } while (uio->uio_resid); |
840510a3 | 403 | return (error); |
45372428 MT |
404 | } |
405 | ||
45372428 | 406 | /*ARGSUSED*/ |
4b72e2f9 SL |
407 | ptyioctl(dev, cmd, data, flag) |
408 | caddr_t data; | |
e1d74936 BJ |
409 | dev_t dev; |
410 | { | |
0a2bd708 BJ |
411 | register struct tty *tp = &pt_tty[minor(dev)]; |
412 | register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; | |
f21c8fb8 | 413 | int error; |
45372428 | 414 | |
e1d74936 | 415 | /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ |
4b72e2f9 SL |
416 | if (cdevsw[major(dev)].d_open == ptcopen) |
417 | switch (cmd) { | |
418 | ||
419 | case TIOCPKT: | |
420 | if (*(int *)data) | |
1a954a11 BJ |
421 | pti->pt_flags |= PF_PKT; |
422 | else | |
423 | pti->pt_flags &= ~PF_PKT; | |
f21c8fb8 | 424 | return (0); |
4b72e2f9 SL |
425 | |
426 | case TIOCREMOTE: | |
427 | if (*(int *)data) | |
defdbcd1 BJ |
428 | pti->pt_flags |= PF_REMOTE; |
429 | else | |
430 | pti->pt_flags &= ~PF_REMOTE; | |
88a7a62a | 431 | ttyflush(tp, FREAD|FWRITE); |
f21c8fb8 | 432 | return (0); |
4b72e2f9 SL |
433 | |
434 | case FIONBIO: | |
435 | if (*(int *)data) | |
1a954a11 | 436 | pti->pt_flags |= PF_NBIO; |
8b8271ac | 437 | else |
1a954a11 | 438 | pti->pt_flags &= ~PF_NBIO; |
f21c8fb8 | 439 | return (0); |
4b72e2f9 SL |
440 | |
441 | case TIOCSETP: | |
442 | while (getc(&tp->t_outq) >= 0) | |
443 | ; | |
444 | break; | |
8b8271ac | 445 | } |
477d62ec | 446 | error = ttioctl(tp, cmd, data, flag); |
f21c8fb8 BJ |
447 | if (error < 0) |
448 | error = ENOTTY; | |
425a48ad SL |
449 | { int stop = (tp->t_stopc == ('s'&037) && |
450 | tp->t_startc == ('q'&037)); | |
0a2bd708 BJ |
451 | if (pti->pt_flags & PF_NOSTOP) { |
452 | if (stop) { | |
453 | pti->pt_send &= TIOCPKT_NOSTOP; | |
454 | pti->pt_send |= TIOCPKT_DOSTOP; | |
455 | pti->pt_flags &= ~PF_NOSTOP; | |
456 | ptcwakeup(tp); | |
457 | } | |
458 | } else { | |
459 | if (stop == 0) { | |
460 | pti->pt_send &= ~TIOCPKT_DOSTOP; | |
461 | pti->pt_send |= TIOCPKT_NOSTOP; | |
462 | pti->pt_flags |= PF_NOSTOP; | |
463 | ptcwakeup(tp); | |
464 | } | |
465 | } | |
466 | } | |
f21c8fb8 | 467 | return (error); |
45372428 | 468 | } |
4f07e6e5 | 469 | #endif |