static int doattach(register Cs_t* state, const char* path, int op, int mode, char* user, char* opath, char* tmp, char* serv, char*b) { register int n; int fd; char* s; #if CS_LIB_STREAM || CS_LIB_V10 int fds[2]; struct stat st; if (op & CS_OPEN_CREATE) { n = errno; if (chmod(path, mode)) { remove(path); if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) { messagef((state->id, NiL, -1, "open: %s: %s: creat %o error", state->path, path, mode)); return -1; } close(fd); chmod(path, mode); } errno = n; if (pipe(fds)) { messagef((state->id, NiL, -1, "open: %s: pipe error", state->path, path)); return -1; } #if CS_LIB_V10 if ((n = ioctl(fds[1], FIOPUSHLD, &conn_ld)) || fmount(3, fds[1], path, 0)) #else if ((n = ioctl(fds[1], I_PUSH, "connld")) || fattach(fds[1], path)) #endif { messagef((state->id, NiL, -1, "open: %s: %s: %s error", state->path, path, n ? "connld" : "fattach")); close(fds[0]); close(fds[1]); errno = ENXIO; return -1; } close(fds[1]); fd = fds[0]; } else for (;;) { if ((fd = open(path, O_RDWR)) >= 0) { if (!fstat(fd, &st) && !S_ISREG(st.st_mode)) break; close(fd); remove(path); } else if ((op & CS_OPEN_TEST) || errno == EACCES) { messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path)); return -1; } if (initiate(state, user, opath, tmp, serv)) { messagef((state->id, NiL, -1, "open: %s: %s: service initiate error", state->path, path)); return -1; } op = CS_OPEN_TEST; } #else #if CS_LIB_SOCKET_UN int pid; int namlen; char c; struct sockaddr_un nam; messagef((state->id, NiL, -8, "%s:%d state.path=`%s' state.mount=`%s' path=`%s' opath=`%s' user=`%s' serv=`%s'", __FILE__, __LINE__, state->path, state->mount, path, opath, user, serv)); nam.sun_family = AF_UNIX; strcpy(nam.sun_path, path); namlen = sizeof(nam.sun_family) + strlen(path) + 1; for (n = 0;; n++) { if (n >= 10) { errno = ENXIO; badcon: close(fd); return -1; } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { messagef((state->id, NiL, -1, "open: %s: %s: AF_UNIX socket error", state->path, path)); return -1; } if (!connect(fd, (struct sockaddr*)&nam, namlen)) { if (op & CS_OPEN_CREATE) { errno = EEXIST; goto badcon; } #if CS_LIB_SOCKET_RIGHTS if (read(fd, &c, 1) == 1 && !cssend(state, fd, NiL, 0)) break; #else break; #endif } else { messagef((state->id, NiL, -1, "open: %s: %s: connect error", state->path, path)); if (errno == EACCES) goto badcon; else if (errno == EADDRNOTAVAIL || errno == ECONNREFUSED) { c = 0; for (;;) { *b = CS_MNT_PROCESS; pid = pathgetlink(path, state->temp, sizeof(state->temp)); *b = CS_MNT_STREAM; if (pid > 0 || ++c >= 5) break; sleep(1); } if (pid > 0 && (s = strrchr(state->temp, '/')) && (pid = strtol(s + 1, NiL, 0)) > 0) { if (!kill(pid, 0) || errno != ESRCH) { if (op & CS_OPEN_CREATE) { errno = EEXIST; goto badcon; } close(fd); if (n) sleep(1); continue; } *b = CS_MNT_PROCESS; remove(path); *b = CS_MNT_STREAM; } } } close(fd); errno = ENOENT; if (op & CS_OPEN_CREATE) { if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { messagef((state->id, NiL, -1, "open: %s: %s: AF_UNIX socket error", state->path, path)); return -1; } if (!bind(fd, (struct sockaddr*)&nam, namlen)) { chmod(path, mode); if (listen(fd, 32)) { messagef((state->id, NiL, -1, "open: %s: %s: listen error", state->path, path)); n = errno; remove(path); errno = n; goto badcon; } break; } else messagef((state->id, NiL, -1, "open: %s: %s: bind error", state->path, path)); if (errno != EADDRINUSE || n && remove(path) && errno != ENOENT) goto badcon; close(fd); } else if (op & CS_OPEN_TEST) return -1; else if (!n && initiate(state, user, opath, tmp, serv)) { messagef((state->id, NiL, -1, "open: %s: %s: service initiate error", state->path, path)); return -1; } else sleep(2); } #else errno = (op & CS_OPEN_CREATE) ? ENXIO : ENOENT; messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, path)); fd = -1; #endif #endif #if CS_LIB_SOCKET_UN || CS_LIB_STREAM || CS_LIB_V10 touch(path, (time_t)0, (time_t)0, 0); strcpy(state->path, path); #endif return fd; }
int cslocal(register Cs_t* state, const char* path) { register char* s; register char* p; register char* t; register char* v; struct stat st; char cmd[PATH_MAX / 8]; char exe[PATH_MAX + 1]; char tmp[PATH_MAX + 1]; #if CS_LIB_STREAM || CS_LIB_V10 || CS_LIB_SOCKET_UN int fd; int n; #endif messagef((state->id, NiL, -8, "local(%s) call", path)); /* * validate the path */ p = (char*)path; if (strncmp(p, DEVLOCAL, sizeof(DEVLOCAL) - 1)) { messagef((state->id, NiL, -1, "local: %s: %s* expected", path, DEVLOCAL)); goto sorry; } p += sizeof(DEVLOCAL) - 1; for (t = p; *t && *t != '/'; t++); if (!streq(t + 1, "user")) { messagef((state->id, NiL, -1, "local: %s: %s*/user expected", path, DEVLOCAL)); goto sorry; } /* * locate the service */ s = cmd; for (v = p; p <= t; *s++ = *p++); t = s - 1; for (p = v; p <= t; *s++ = *p++); for (p = CS_SVC_SUFFIX; *s++ = *p++;); p = pathbin(); for (;;) { p = pathcat(p, ':', "../lib/cs/fdp", cmd, exe, PATH_MAX + 1); if (!eaccess(exe, X_OK) && !stat(exe, &st)) break; if (!p) { messagef((state->id, NiL, -1, "local: %s: %s: cannot locate service on ../lib/cs/fdp", path, cmd)); goto sorry; } } *t = 0; sfsprintf(tmp, sizeof(tmp), "%s/fdp/%s/%s/%d-%d-/%c%s", csvar(state, CS_VAR_LOCAL, 0), csname(state, 0), cmd, st.st_uid, geteuid(), CS_MNT_STREAM, CS_MNT_TAIL); #if CS_LIB_STREAM || CS_LIB_V10 for (n = 0; (fd = open(tmp, O_RDWR)) < 0; n++) if (n || errno == EACCES) { messagef((state->id, NiL, -1, "local: %s: %s: cannot open service", path, tmp)); return -1; } else if (initiate(state, path, exe) < 0) { messagef((state->id, NiL, -1, "local: %s: %s: cannot initiate service %s", path, tmp, exe)); return -1; } messagef((state->id, NiL, -8, "local(%s) fd=%d server=%s stream=%s", path, fd, exe, tmp)); return fd; #else #if CS_LIB_SOCKET_UN { int namlen; struct sockaddr_un nam; nam.sun_family = AF_UNIX; strcpy(nam.sun_path, tmp); namlen = sizeof(nam.sun_family) + strlen(tmp); n = 0; fd = -1; for (;;) { if (fd < 0 && (fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { messagef((state->id, NiL, -1, "local: %s: AF_UNIX socket error", path)); return -1; } if (!connect(fd, (struct sockaddr*)&nam, namlen)) { #if CS_LIB_SOCKET_RIGHTS if (read(fd, cmd, 1) != 1) messagef((state->id, NiL, -1, "local: %s: connect ack read error", path)); else if (cssend(state, fd, NiL, 0)) messagef((state->id, NiL, -1, "local: %s: connect authentication send error", path)); else #endif return fd; #if CS_LIB_SOCKET_RIGHTS close(fd); fd = -1; #endif } else messagef((state->id, NiL, -1, "local: %s: connect error", path)); if (errno != EACCES) errno = ENOENT; if (n || errno == EACCES || initiate(state, path, exe) < 0) { if (fd >= 0) close(fd); return -1; } n = 1; messagef((state->id, NiL, -1, "local: %s: connect retry", path)); } } #endif #endif sorry: errno = ENOENT; return -1; }