Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcs/css.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1990-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
22
/*
23
* Glenn Fowler
24
* AT&T Research
25
*
26
* connect stream server support
27
*/
28
29
#include "csslib.h"
30
31
#include <dirent.h>
32
33
#define OPEN_MIN 20
34
35
#if !defined(O_NONBLOCK) && defined(FNDELAY)
36
#define O_NONBLOCK FNDELAY
37
#endif
38
39
static Common_t state;
40
41
static int signals[] = /* caught by interrupt() */
42
{
43
SIGINT,
44
SIGQUIT,
45
SIGALRM,
46
SIGTERM,
47
#ifdef SIGCHLD
48
SIGCHLD,
49
#endif
50
};
51
52
/*
53
* catch interrupts
54
*/
55
56
static void
57
interrupt(int sig)
58
{
59
#if defined(SIGCHLD) && !_WINIX
60
if (sig != SIGCHLD)
61
#endif
62
signal(sig, interrupt);
63
#ifdef SIGCHLD
64
if (cs.interrupt != SIGCHLD)
65
#endif
66
cs.interrupt = sig;
67
}
68
69
/*
70
* called on exit
71
*/
72
73
static void
74
done(void)
75
{
76
cssclose(NiL);
77
}
78
79
/*
80
* drop fd ip
81
*/
82
83
static void
84
drop(Css_t* css, register Cspoll_t* pp)
85
{
86
register Cssfd_t* ip;
87
register int fd;
88
register int user;
89
90
if (!css)
91
css = state.main;
92
fd = pp->fd;
93
ip = &state.fdinfo[fd];
94
if (ip->css == css)
95
{
96
user = (ip->events & CS_POLL_USER) != 0;
97
ip->events = 0;
98
if (css->auth)
99
state.auth[fd].seq = 0;
100
if (ip->actionf)
101
{
102
ip->status = CS_POLL_CLOSE;
103
if ((*ip->actionf)(css, ip, css->disc) > 0)
104
fd = -1;
105
}
106
if (state.fdpolling > 0)
107
{
108
state.fdpolling--;
109
*pp = state.fdpoll[state.fdpolling];
110
}
111
css->fdpolling--;
112
if (ip->events & CS_POLL_CONNECT)
113
css->fdlistening--;
114
if (user)
115
css->fduser--;
116
else if (fd >= 0)
117
close(fd);
118
}
119
}
120
121
/*
122
* open the service
123
*/
124
125
Css_t*
126
cssopen(const char* path, Cssdisc_t* disc)
127
{
128
register Css_t* css;
129
int type;
130
int n;
131
char* s;
132
char* t;
133
struct stat st;
134
135
if (!state.servers)
136
{
137
csprotect(&cs);
138
if ((n = (int)strtol(astconf("OPEN_MAX", NiL, NiL), NiL, 0)) < OPEN_MIN)
139
n = OPEN_MIN;
140
if (!(s = newof(0, char, n * (sizeof(Cssfd_t) + sizeof(Cspoll_t) + sizeof(Auth_t)), 0)))
141
return 0;
142
state.fdpoll = (Cspoll_t*)(s);
143
state.fdinfo = (Cssfd_t*)(state.fdpoll + n);
144
state.auth = (Auth_t*)(state.fdinfo + n);
145
state.fdmax = n;
146
state.fdnext = -1;
147
state.pid = getpid();
148
if (!(css = newof(0, Css_t, 1, sizeof(Cssdisc_t))))
149
return 0;
150
css->id = cs.id;
151
css->disc = (Cssdisc_t*)(css + 1);
152
css->disc->version = CSS_VERSION;
153
state.servers = state.main = css;
154
atexit(done);
155
}
156
if (!path || (n = strlen(path) + 2) < 2 * CS_NAME_MAX)
157
n = 2 * CS_NAME_MAX;
158
if (!(css = newof(0, Css_t, 1, n)))
159
return 0;
160
n = n / 2 + 1;
161
css->next = state.servers;
162
state.servers = css;
163
if (!(css->state = csalloc(NiL)))
164
goto bad;
165
css->service = (char*)(css + 1);
166
css->path = css->service + n;
167
css->id = state.main->id;
168
css->disc = disc;
169
css->fdmax = state.fdmax;
170
if (path && strchr(path, '/'))
171
{
172
strcpy(css->path, path);
173
if (tokscan(css->path, NiL, "/dev/%s/%s/%s", &s, NiL, &t) != 3)
174
{
175
if (css->disc->errorf)
176
(*css->disc->errorf)(css, css->disc, 3, "%s: invalid connect stream path", path);
177
goto bad;
178
}
179
type = *s;
180
if (s = strchr(t, '/'))
181
*s = 0;
182
strncpy(css->service, t, n);
183
errno = EBADF;
184
if ((css->fd = csopen(css->state, path, CS_OPEN_CREATE)) < 0)
185
{
186
if (css->disc->errorf)
187
{
188
if (errno == EEXIST)
189
(*css->disc->errorf)(css, css->disc, 3, "%s: server already running", path);
190
else
191
(*css->disc->errorf)(css, css->disc, ERROR_SYSTEM|3, "%s: cannot create connect stream", path);
192
}
193
goto bad;
194
}
195
css->disc->flags &= ~CSS_AUTHENTICATE;
196
}
197
else
198
{
199
sfsprintf(css->service, n, "/dev/fdp/local/%s", path);
200
path = (char*)cspath(css->state, 0, 0);
201
type = strmatch(path, "/dev/??p/*/*") ? path[5] : 'f';
202
css->perm = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
203
if ((css->disc->flags & CSS_AUTHENTICATE) && csopen(css->state, css->service, CS_OPEN_CREATE|CS_OPEN_MOUNT))
204
{
205
if (css->disc->errorf)
206
(*css->disc->errorf)(css, css->disc, ERROR_SYSTEM|3, "%s: cannot create authentication directory", css->service);
207
goto bad;
208
}
209
}
210
strcpy(css->path, path);
211
if ((css->disc->flags & CSS_DAEMON) && csdaemon(css->state, (css->disc->flags & CSS_PRESERVE) ? ~0L : ((1<<css->fd)|(1<<2))))
212
{
213
if (css->disc->errorf)
214
(*css->disc->errorf)(css, css->disc, 3, "cannot dive into background");
215
goto bad;
216
}
217
if (css->state->control)
218
{
219
strcpy(css->mount, css->state->mount);
220
css->control = strrchr(css->mount, '/') + 1;
221
strcpy(css->control + 1, CS_MNT_TAIL);
222
s = css->control - 1;
223
*s = 0;
224
if (stat(css->mount, &st))
225
{
226
if (css->disc->errorf)
227
(*css->disc->errorf)(css, css->disc, 3, "%s: cannot stat service directory", css->mount);
228
goto bad;
229
}
230
if ((css->disc->flags & CSS_DAEMON) && chdir(css->mount))
231
{
232
if (css->disc->errorf)
233
(*css->disc->errorf)(css, css->disc, 3, "%s: cannot set service directory", css->mount);
234
goto bad;
235
}
236
*s = '/';
237
238
/*
239
* get the fid for the global and local authentication dirs
240
* authentication files can only be in these dirs and
241
* must not be symlinks -- symlinks can point to untrusted
242
* places and other dirs may get untrusted filesystems
243
* mounted via the automounter
244
*/
245
246
n = 0;
247
while (s > css->mount)
248
if (*--s == '/' && ++n >= 3)
249
break;
250
if (n != 3)
251
{
252
if (css->disc->errorf)
253
(*css->disc->errorf)(css, css->disc, 3, "%s: invalid mount directory", css->mount);
254
goto bad;
255
}
256
*s = 0;
257
if (lstat(css->mount, &st))
258
{
259
if (css->disc->errorf)
260
(*css->disc->errorf)(css, css->disc, 3, "%s: invalid global authentication directory", css->mount);
261
goto bad;
262
}
263
*s = '/';
264
css->fid[0].dev = st.st_dev;
265
css->fid[0].ino = st.st_ino;
266
s = csvar(css->state, CS_VAR_LOCAL, 0);
267
if (lstat(s, &st) && (mkdir(s, S_IRWXU|S_IRWXG|S_IRWXO) || chmod(s, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) || lstat(s, &st)))
268
{
269
if (css->disc->errorf)
270
(*css->disc->errorf)(css, css->disc, 3, "%s: invalid local authentication directory", s);
271
goto bad;
272
}
273
css->fid[1].dev = st.st_dev;
274
css->fid[1].ino = st.st_ino;
275
css->uid = st.st_uid;
276
css->gid = st.st_gid;
277
if (type == 't' && *(css->control - 2) != CS_MNT_OTHER && *(css->control - 2) != '.' && *(css->control - 2) != '*')
278
{
279
css->auth = 1;
280
state.nauth++;
281
CSTIME();
282
state.expire = cs.time + KEYEXPIRE;
283
css->conkey = state.pid + getppid() + css->uid + st.st_ino;
284
TOSS(css->conkey);
285
*css->control = CS_MNT_AUTH;
286
remove(css->mount);
287
css->newkey = css->conkey & KEYMASK;
288
if (close(open(css->mount, O_WRONLY|O_CREAT|O_TRUNC, st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))) ||
289
chmod(css->mount, st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) ||
290
cschallenge(css->state, css->mount, NiL, &css->newkey))
291
{
292
if (css->disc->errorf)
293
(*css->disc->errorf)(css, css->disc, 3, "%s: cannot create service authentication file", css->mount);
294
goto bad;
295
}
296
chown(css->mount, -1, css->gid);
297
css->oldkey = css->newkey;
298
for (n = 0; n < (css->newkey & 0xff); n++)
299
CSTOSS(css->conkey, n);
300
css->challenge = (st.st_mode & S_IXOTH) ? 2 : 0;
301
}
302
*css->control = CS_MNT_PROCESS;
303
remove(css->mount);
304
s = css->buf;
305
if (type != 'f') s += sfsprintf(s, sizeof(css->buf) - (s - css->buf), "/n/%s", csname(css->state, 0));
306
sfsprintf(s, sizeof(css->buf) - (s - css->buf), "/proc/%d", getpid());
307
pathsetlink(css->buf, css->mount);
308
if (css->disc->flags & CSS_LOG)
309
{
310
*css->control = CS_MNT_OLDLOG;
311
strcpy(css->buf, css->mount);
312
*css->control = CS_MNT_LOG;
313
rename(css->mount, css->buf);
314
close(2);
315
open(css->mount, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
316
}
317
*css->control = CS_MNT_AUTH;
318
css->perm = st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
319
if (css->disc->flags & CSS_DAEMON)
320
umask(~css->perm & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH));
321
}
322
if ((css->disc->flags & CSS_INTERRUPT) && !(state.flags & CSS_INTERRUPT))
323
{
324
state.flags |= CSS_INTERRUPT;
325
for (n = 0; n < elementsof(signals); n++)
326
if (signal(signals[n], SIG_IGN) != SIG_IGN)
327
signal(signals[n], interrupt);
328
}
329
cssfd(css, css->fd, type == 'u' ? CS_POLL_READ : (CS_POLL_AUTH|CS_POLL_CONNECT|CS_POLL_READ));
330
CSTIME();
331
return css;
332
bad:
333
cssclose(css);
334
return 0;
335
}
336
337
/*
338
* close the service
339
*/
340
341
int
342
cssclose(register Css_t* css)
343
{
344
register Css_t* pss;
345
register Css_t* xss;
346
register Css_t* oss;
347
register int i;
348
register int k;
349
350
static char mnt[] =
351
{
352
CS_MNT_AUTH,
353
CS_MNT_LOCK,
354
CS_MNT_PROCESS,
355
CS_MNT_STREAM
356
};
357
358
pss = 0;
359
xss = state.servers;
360
while (xss)
361
{
362
if (xss == css || !css)
363
{
364
if (xss->disc->exceptf && (xss->disc->flags & CSS_CLOSE))
365
(*xss->disc->exceptf)(css, CSS_CLOSE, 0, xss->disc);
366
if (state.fdinfo)
367
{
368
for (i = k = 0; i < state.fdpolling;)
369
{
370
if (state.fdinfo[state.fdpoll[i].fd].css == xss)
371
drop(xss, &state.fdpoll[i]);
372
else
373
state.fdpoll[k++] = state.fdpoll[i++];
374
}
375
state.fdpolling = k;
376
}
377
if (state.pid == getpid() && xss->control)
378
for (i = 0; i < elementsof(mnt); i++)
379
{
380
*xss->control = mnt[i];
381
remove(xss->control);
382
}
383
if (xss->auth)
384
state.nauth--;
385
oss = xss;
386
xss = xss->next;
387
if (pss)
388
pss->next = oss->next;
389
else
390
state.servers = oss->next;
391
if (oss->state)
392
csfree(oss->state);
393
free(oss);
394
if (css)
395
return 0;
396
}
397
else
398
{
399
pss = xss;
400
xss = xss->next;
401
}
402
}
403
if (css)
404
return -1;
405
if (!state.servers && state.fdpoll)
406
{
407
free(state.fdpoll);
408
state.fdpoll = 0;
409
}
410
return 0;
411
}
412
413
/*
414
* file descriptor manipulation
415
*
416
* CS_POLL_DUP(n) move fd to n
417
* CS_POLL_MOVE(n) move fd to n
418
* CS_POLL_PRI(n) set fd priority (not yet)
419
* CS_POLL_CLOSE close+delete fd from table
420
* CS_POLL_AUTH|* authenticate then poll
421
* CS_POLL_* poll
422
* CS_POLL_USER| don't close unless CS_POLL_CLOSE
423
*/
424
425
Cssfd_t*
426
cssfd(register Css_t* css, register int fd, unsigned long op)
427
{
428
register Cssfd_t* ip;
429
register Cspoll_t* pp;
430
register int n;
431
register int nfd;
432
register int cmd;
433
int flags;
434
#if DEBUG
435
int ofd = fd;
436
unsigned long oop = op;
437
#endif
438
439
if (!css)
440
css = state.main;
441
again:
442
if (fd < 0 || fd >= state.fdmax)
443
return 0;
444
ip = state.fdinfo + fd;
445
if (op == 0)
446
return ip->events ? ip : (Cssfd_t*)0;
447
if (op & CS_POLL_ARG)
448
{
449
cmd = op & CS_POLL_MASK;
450
nfd = (op >> CS_POLL_SHIFT) & CS_POLL_MASK;
451
op = nfd == CS_POLL_MASK ? CS_POLL_CLOSE : 0;
452
}
453
else
454
cmd = 0;
455
if (op != CS_POLL_CLOSE)
456
{
457
if (op & CS_POLL_AUTH)
458
{
459
if (!css->auth)
460
op &= ~CS_POLL_AUTH;
461
}
462
if (op & CS_POLL_CONNECT)
463
{
464
op &= ~(CS_POLL_CONTROL|CS_POLL_WRITE);
465
op |= CS_POLL_READ;
466
}
467
for (n = 0;; n++)
468
{
469
if (n >= state.fdpolling)
470
{
471
if (!(op & CS_POLL_AUTH|CS_POLL_CONNECT|CS_POLL_READ|CS_POLL_WRITE))
472
return 0;
473
if (fcntl(fd, F_SETFD, FD_CLOEXEC) && errno == EBADF)
474
return 0;
475
if ((op & (CS_POLL_AUTH|CS_POLL_CONNECT)) == CS_POLL_AUTH)
476
{
477
state.auth[fd].seq = 1;
478
state.auth[fd].expire = cs.time + EXPIRE;
479
}
480
pp = state.fdpoll + state.fdpolling++;
481
pp->fd = fd;
482
pp->events = op;
483
pp->status = 0;
484
ip->css = css;
485
ip->fd = fd;
486
ip->actionf = css->disc->actionf;
487
ip->data = 0;
488
ip->events = op;
489
ip->set = 0;
490
css->fdpolling++;
491
if (ip->events & CS_POLL_BEFORE)
492
state.fdbefore++;
493
if (ip->events & CS_POLL_CONNECT)
494
css->fdlistening++;
495
if (ip->events & CS_POLL_USER)
496
css->fduser++;
497
#if DEBUG
498
goto show;
499
#else
500
return ip;
501
#endif
502
}
503
if (state.fdpoll[n].fd == fd)
504
{
505
switch (cmd)
506
{
507
case 0:
508
if (ip->css != css)
509
return 0;
510
if (css->fd != fd)
511
{
512
if (ip->events & CS_POLL_BEFORE)
513
state.fdbefore--;
514
if (ip->events & CS_POLL_CONNECT)
515
css->fdlistening--;
516
if (ip->events & CS_POLL_USER)
517
css->fduser--;
518
state.fdpoll[n].events = ip->events = op;
519
if (ip->events & CS_POLL_BEFORE)
520
state.fdbefore++;
521
if (ip->events & CS_POLL_CONNECT)
522
css->fdlistening++;
523
if (ip->events & CS_POLL_USER)
524
css->fduser++;
525
if (op & CS_POLL_WRITE)
526
{
527
#ifdef O_NONBLOCK
528
if (!(ip->set & CS_POLL_WRITE))
529
{
530
ip->set |= CS_POLL_WRITE;
531
if ((flags = fcntl(fd, F_GETFL, 0)) >= 0)
532
{
533
flags |= O_NONBLOCK;
534
fcntl(fd, F_SETFL, flags);
535
messagef((state.main->id, NiL, -4, "cssfd: %d O_NONBLOCK", fd));
536
}
537
}
538
#endif
539
messagef((state.main->id, NiL, -4, "cssfd: %d CS_POLL_WRITE", fd));
540
}
541
}
542
break;
543
case CS_POLL_DUP:
544
/*ip->actionf = 0;*/
545
css = ip->css;
546
fd = nfd;
547
op = state.fdpoll[n].events;
548
goto again;
549
case CS_POLL_MOVE:
550
if (fcntl(nfd, F_SETFD, FD_CLOEXEC) && errno == EBADF)
551
return 0;
552
state.fdpoll[n].fd = nfd;
553
if (fd == css->fd)
554
css->fd = nfd;
555
state.fdinfo[nfd] = *ip;
556
ip = state.fdinfo + nfd;
557
ip->fd = nfd;
558
break;
559
case CS_POLL_PRI:
560
break;
561
}
562
#if DEBUG
563
show:
564
if (error_info.trace <= -9)
565
{
566
errorf(state.main->id, NiL, -9, "cssfd: pending=%d polling=%d next=%d fd=%d op=0x%08lx", state.fdpending, state.fdpolling, state.fdnext, ofd, oop);
567
for (n = 0; n < state.fdpolling; n++)
568
errorf(state.main->id, NiL, -9, "cssfd: index=%d fd=%d events=%06o actionf=%p", n, state.fdpoll[n].fd, state.fdpoll[n].events, state.fdinfo[state.fdpoll[n].fd].actionf);
569
}
570
#endif
571
return ip;
572
}
573
}
574
}
575
else if (css->fd != fd)
576
{
577
for (n = 0; n < state.fdpolling; n++)
578
if (state.fdpoll[n].fd == fd)
579
{
580
drop(state.fdinfo[fd].css, &state.fdpoll[n]);
581
break;
582
}
583
if (n >= state.fdpolling)
584
close(fd);
585
#if DEBUG
586
ip = 0;
587
goto show;
588
#endif
589
}
590
return 0;
591
}
592
593
/*
594
* poll for the next fd event
595
* some events may be pending from the last call
596
*/
597
598
Cssfd_t*
599
csspoll(unsigned long ms, unsigned long flags)
600
{
601
register Css_t* css;
602
register Cspoll_t* pp;
603
register Cssfd_t* ip;
604
register Auth_t* ap;
605
register int fd;
606
char* s;
607
char* t;
608
int n;
609
int fdnew;
610
int status;
611
int to;
612
int oerrno;
613
int err;
614
int clrerr;
615
int sig;
616
int clrsig;
617
unsigned long key;
618
unsigned long z;
619
unsigned long timeout;
620
Csid_t id;
621
struct stat st;
622
char** vp;
623
char* va[8];
624
625
if (state.polling && !(flags & CSS_RECURSIVE))
626
{
627
errno = EBUSY;
628
return 0;
629
}
630
state.polling++;
631
if (ms == CS_NEVER)
632
timeout = 0;
633
else
634
timeout = CSTIME() + ((ms + 999) / 1000);
635
oerrno = errno;
636
for (;;)
637
{
638
while (state.fdpending <= 0)
639
{
640
CSTIME();
641
if (timeout && timeout >= cs.time)
642
{
643
errno = oerrno;
644
return 0;
645
}
646
if (state.nauth && cs.time > state.expire)
647
{
648
state.expire = cs.time + KEYEXPIRE;
649
for (css = state.servers; css; css = css->next)
650
if (css->auth)
651
{
652
css->oldkey = css->newkey;
653
n = cs.time & 077;
654
do TOSS(css->newkey); while (n--);
655
css->newkey &= KEYMASK;
656
*css->control = CS_MNT_AUTH;
657
if (cschallenge(css->state, css->mount, NiL, &css->newkey))
658
css->newkey = css->oldkey;
659
}
660
for (pp = state.fdpoll; pp < state.fdpoll + state.fdpolling;)
661
{
662
ap = state.auth + pp->fd;
663
if (ap->seq && cs.time > ap->expire)
664
drop(state.fdinfo[pp->fd].css, pp);
665
else
666
pp++;
667
}
668
}
669
to = ms;
670
for (css = state.servers; css; css = css->next)
671
{
672
css->fdpending = 0;
673
if (css->disc->timeout)
674
{
675
if (css->timeout_last != css->disc->timeout)
676
css->timeout_last = css->timeout_remain = css->disc->timeout;
677
if (to > css->timeout_remain)
678
to = css->timeout_remain;
679
}
680
if (css->disc->wakeup)
681
{
682
if (css->wakeup_last != css->disc->wakeup)
683
css->wakeup_last = css->wakeup_remain = css->disc->wakeup;
684
if (to > css->wakeup_remain)
685
to = css->wakeup_remain;
686
}
687
}
688
if (state.fdbefore)
689
for (pp = state.fdpoll; pp < state.fdpoll + state.fdpolling;)
690
{
691
if (pp->events & CS_POLL_BEFORE)
692
{
693
ip = state.fdinfo + pp->fd;
694
ip->status = CS_POLL_BEFORE;
695
if (ip->actionf && (*ip->actionf)(ip->css, ip, ip->css->disc) < 0)
696
{
697
drop(ip->css, pp);
698
continue;
699
}
700
}
701
pp++;
702
}
703
z = cs.time;
704
if ((state.fdpending = cspoll(&cs, state.fdpoll, state.fdpolling, to)) < 0)
705
{
706
err = errno;
707
sig = (err == EINTR) ? cs.interrupt : 0;
708
clrsig = 0;
709
clrerr = 0;
710
}
711
else
712
{
713
err = 0;
714
sig = 0;
715
}
716
state.fdloop = 1;
717
CSTIME();
718
if (state.fdpending)
719
z = (cs.time - z) * 1000;
720
else
721
z = to;
722
if (ms != CS_NEVER)
723
{
724
if (ms > z)
725
ms -= z;
726
else
727
timeout = cs.time;
728
}
729
if (state.fdpending > 0)
730
for (pp = state.fdpoll; pp < state.fdpoll + state.fdpolling; pp++)
731
if (pp->status & (CS_POLL_READ|CS_POLL_WRITE))
732
state.fdinfo[pp->fd].css->fdpending++;
733
for (css = state.servers; css; css = css->next)
734
if (css->disc->exceptf)
735
{
736
if (css->disc->timeout)
737
{
738
if (css->fdpending)
739
css->timeout_remain = css->disc->timeout;
740
else if (css->timeout_remain <= z)
741
{
742
if ((css->disc->flags & CSS_DORMANT) && css->fdpolling <= (css->fdlistening + css->fduser))
743
(*css->disc->exceptf)(css, CSS_DORMANT, 0, css->disc);
744
else if (css->disc->flags & CSS_TIMEOUT)
745
(*css->disc->exceptf)(css, CSS_TIMEOUT, 0, css->disc);
746
css->timeout_last = css->timeout_remain = css->disc->timeout;
747
}
748
else
749
css->timeout_remain -= z;
750
}
751
if (css->disc->wakeup)
752
{
753
messagef((state.main->id, NiL, -4, "csspoll: pending=%d polling=%d z=%I*d wakeup=%I*d remain=%I*d", state.fdpending, state.fdpolling, sizeof(z), z, sizeof(css->disc->wakeup), css->disc->wakeup, sizeof(css->wakeup_remain), css->wakeup_remain));
754
if (css->wakeup_remain <= z)
755
{
756
(*css->disc->exceptf)(css, CSS_WAKEUP, 0, css->disc);
757
css->wakeup_last = css->wakeup_remain = css->disc->wakeup;
758
}
759
else
760
css->wakeup_remain -= z;
761
}
762
if (err)
763
{
764
if ((css->disc->flags & CSS_INTERRUPT) && (sig || err == EINTR))
765
{
766
if (!sig)
767
clrerr = 1;
768
else if ((*css->disc->exceptf)(css, CSS_INTERRUPT, sig, css->disc) >= 0)
769
clrsig = 1;
770
}
771
else if (css->disc->flags & CSS_ERROR)
772
{
773
if ((*css->disc->exceptf)(css, CSS_ERROR, err, css->disc) >= 0)
774
clrerr = 1;
775
}
776
}
777
}
778
if (err && (ms != CS_NEVER || (flags & CSS_INTERRUPT) && (sig || err == EINTR) && !clrsig || (flags & CSS_ERROR) && !sig && err != EINTR && !clrerr))
779
{
780
errno = err;
781
state.polling--;
782
return 0;
783
}
784
}
785
do
786
{
787
if (++state.fdnext >= state.fdpolling)
788
{
789
if (state.fdloop-- < 0)
790
break;
791
state.fdnext = 0;
792
}
793
pp = state.fdpoll + state.fdnext;
794
fd = pp->fd;
795
messagef((state.main->id, NiL, -9, "csspoll: pending=%d polling=%d next=%d fd=%d status=%06o", state.fdpending, state.fdpolling, state.fdnext, fd, pp->status));
796
ip = state.fdinfo + fd;
797
css = ip->css;
798
status = pp->status & ~(CS_POLL_BEFORE|CS_POLL_USER);
799
pp->status = 0;
800
switch (status)
801
{
802
case CS_POLL_AUTH|CS_POLL_CONNECT|CS_POLL_READ:
803
if (css->auth)
804
{
805
if (csrecv(css->state, fd, &id, &fdnew, 1) == 1)
806
{
807
state.auth[fdnew].id = id;
808
cssfd(css, fdnew, CS_POLL_AUTH|CS_POLL_READ);
809
}
810
break;
811
}
812
/*FALLTHROUGH*/
813
case CS_POLL_CONNECT|CS_POLL_READ:
814
if (csrecv(css->state, fd, &id, &fdnew, 1) == 1 &&
815
(ip = cssfd(css, fdnew, CS_POLL_READ)) &&
816
css->disc->acceptf &&
817
(fdnew = (*css->disc->acceptf)(css, ip, &id, NiL, css->disc)) != ip->fd)
818
cssfd(css, ip->fd, fdnew >= 0 ? CS_POLL_CMD(fdnew, CS_POLL_MOVE) : CS_POLL_CLOSE);
819
break;
820
case CS_POLL_AUTH|CS_POLL_READ:
821
switch ((ap = state.auth + fd)->seq)
822
{
823
case 1:
824
if ((n = csread(css->state, fd, css->buf, sizeof(css->buf), CS_LINE)) <= 0)
825
goto reject;
826
css->buf[n - 1] = 0;
827
if (tokscan(css->buf, &t, "%lu", &key) != 1)
828
goto reject;
829
switch (key)
830
{
831
case CS_KEY_SEND:
832
n = sfsprintf(css->tmp, sizeof(css->tmp), "%s\n", css->mount);
833
if (cswrite(css->state, fd, css->tmp, n) != n)
834
goto reject;
835
break;
836
default:
837
if (key <= CS_KEY_MAX || key != css->newkey && key != css->oldkey || tokscan(t, NiL, "%ld", &ap->id.pid) != 1)
838
goto reject;
839
if (!(ap->seq = css->challenge))
840
{
841
st.st_uid = css->uid;
842
st.st_gid = css->gid;
843
goto ok;
844
}
845
css->conkey ^= cs.time ^ ap->id.pid;
846
n = cs.time & 017;
847
do TOSS(css->conkey); while (n--);
848
ap->atime = css->conkey & KEYMASK;
849
n = cs.time & 07;
850
do TOSS(css->conkey); while (n--);
851
ap->mtime = css->conkey & KEYMASK;
852
n = sfsprintf(css->tmp, sizeof(css->tmp), "%lu %lu\n", (unsigned long)ap->atime, (unsigned long)ap->mtime);
853
if (cswrite(css->state, fd, css->tmp, n) != n)
854
goto reject;
855
ap->expire = cs.time + EXPIRE;
856
break;
857
}
858
break;
859
case 2:
860
ap->seq = 0;
861
if (cs.time > ap->expire || (n = csread(css->state, fd, css->buf, sizeof(css->buf), CS_LINE)) <= 1)
862
goto reject;
863
css->buf[n - 1] = 0;
864
if (t = strchr(css->buf, ' '))
865
*t++ = 0;
866
if (!(s = strrchr(css->buf, '/')))
867
goto reject;
868
*s = 0;
869
if (lstat(css->buf, &st))
870
goto reject;
871
*s = '/';
872
for (n = 0; n < elementsof(css->fid); n++)
873
#if _UWIN
874
if (css->fid[n].dev == st.st_dev)
875
#else
876
if (css->fid[n].dev == st.st_dev && css->fid[n].ino == st.st_ino)
877
#endif
878
break;
879
if (n >= elementsof(css->fid))
880
goto reject;
881
if (lstat(css->buf, &st))
882
{
883
/*
884
* kick the NonFS cache
885
*/
886
887
if (!(s = strrchr(css->buf, '.')))
888
goto reject;
889
*s = 0;
890
close(open(css->buf, O_WRONLY|O_CREAT|O_TRUNC, 0));
891
remove(css->buf);
892
*s = '.';
893
if (lstat(css->buf, &st))
894
goto reject;
895
}
896
if ((st.st_mode & CS_AUTH_MODE) != CS_AUTH_MODE ||
897
ap->atime != st.st_atime ||
898
ap->mtime != st.st_mtime)
899
goto reject;
900
ok:
901
if (cswrite(css->state, fd, "\n", 1) != 1)
902
goto reject;
903
pp->events &= ~CS_POLL_AUTH;
904
if (css->disc->acceptf)
905
{
906
ip = state.fdinfo + pp->fd;
907
ap->id.uid = st.st_uid;
908
ap->id.gid = st.st_gid;
909
vp = va;
910
while ((vp < &va[elementsof(va) - 1]) &&
911
(*vp++ = t) && (t = strchr(t, ' ')))
912
*t++ = 0;
913
*vp = 0;
914
if ((fdnew = (*css->disc->acceptf)(css, ip, &ap->id, *va ? va : (char**)0, css->disc)) != ip->fd)
915
cssfd(css, ip->fd, fdnew >= 0 ? CS_POLL_CMD(fdnew, CS_POLL_MOVE) : CS_POLL_CLOSE);
916
}
917
break;
918
default:
919
goto reject;
920
}
921
break;
922
case CS_POLL_READ|CS_POLL_WRITE:
923
case CS_POLL_WRITE:
924
pp->events &= ~CS_POLL_WRITE;
925
/*FALLTHROUGH*/
926
case CS_POLL_READ:
927
ip->status = status;
928
messagef((state.main->id, NiL, -9, "csspoll: status=%06o fd=%d actionf=%p", status, fd, ip->actionf));
929
if (!ip->actionf || (n = (*ip->actionf)(css, ip, css->disc)) == 0)
930
{
931
state.fdpending--;
932
state.polling--;
933
return ip;
934
}
935
if (n < 0)
936
goto reject;
937
break;
938
case CS_POLL_AUTH:
939
case CS_POLL_AUTH|CS_POLL_CONNECT:
940
case CS_POLL_CONNECT:
941
break;
942
case 0:
943
continue;
944
default:
945
reject:
946
drop(css, pp);
947
state.fdnext--;
948
break;
949
}
950
state.fdpending--;
951
} while (state.fdpending);
952
}
953
}
954
955