Пример #1
0
static void
update(char* data, unsigned long now, int delay, CSSTAT* ss)
{
	unsigned long		tm;
	struct stat		st;

	static unsigned long	idle;
	static unsigned long	next;
	static unsigned long	down;
	static char		flush[] = ".flush.";

	if (ss->up < 0) 
	{
		tm = CSTIME();
		if (down) ss->up -= (long)(tm - down);
		down = tm;
	}
	if (now)
	{
		if (now > next || ss->idle < idle)
		{
			next = now + delay;
			now = 0;
		}
		if (delay > 10) delay = 10;
	}
	if (!now && csnote(data, ss) || stat(data, &st)) finish(1);
	idle = ss->idle;
	if (delay)
	{
		sleep(delay);
		if (remote && remove(flush)) close(open(flush, O_WRONLY|O_CREAT|O_TRUNC, 0));
		tm = st.st_ctime;
		if (stat(data, &st)) finish(1);
		if (tm != (unsigned long)st.st_ctime) finish(0);
	}
}
Пример #2
0
int
main(int argc, char** argv)
{
	register int	n;
	register int	i;
	register long	v;
	char*		s;
	char*		e;
	char*		data;
	int		uf;
	int		wf;
	int		idlecmd;
	int		usercount;
	unsigned long	t;
	unsigned long	toss;
	unsigned long	usertime;
	unsigned long	now;
	unsigned long	then;
	Proc_t*		proc;
	CSSTAT		ss;
	struct stat	st;
	char		cmd[PATH_MAX];
	char		buf[PATH_MAX];
	char		tmp[PATH_MAX / 4];
	char*		av[4];
	char*		iv[3];
#if NAMELIST
	DIR*		root;
	struct dirent*	entry;
	int		kf;
#endif

	NoP(argc);
	error_info.id = CS_STAT_DAEMON;
	if (!pathpath(error_info.id, argv[0], PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, cmd, sizeof(cmd)))
		error(ERROR_SYSTEM|3, "cannot locate daemon executable");
	if (!pathpath(CS_STAT_DIR, argv[0], PATH_EXECUTE, buf, sizeof(buf)))
		error(3, "%s: cannot locate data directory", CS_STAT_DIR);
	if (stat(buf, &st))
		error(ERROR_SYSTEM|3, "%s: stat error", buf);
	if (st.st_uid != geteuid())
		error(3, "%s: effective uid mismatch", buf);
	if (chdir(buf))
		error(ERROR_SYSTEM|3, "%s: chdir error", buf);
	data = csname(0);
	if (argv[1] && strcmp(argv[1], data))
	{
		/*
		 * start remote status daemon
		 */

		data = argv[1];
		if (!csaddr(data))
			error(3, "%s: unknown host", data);
		if (!stat(data, &st) && (long)(CSTIME() - (unsigned long)st.st_ctime) < CS_STAT_DOWN)
			exit(0);
		sfsprintf(buf, sizeof(buf), "./%s", data);
		csstat(buf, &ss);
		if (s = csattr(CS_HOST_LOCAL, "type"))
		{
			strcpy(tmp, s);
			if (s = csattr(data, "type"))
				pathrepl(cmd, sizeof(cmd), tmp, s);
		}

		/*
		 * loop until remote status daemon starts
		 * check for competing startup daemon
		 */

		if (csdaemon(0))
			exit(1);
		umask(S_IRWXU|S_IRWXG|S_IRWXO);
		av[0] = CS_REMOTE_SHELL;
		av[1] = data;
		av[2] = cmd;
		av[3] = 0;
		for (;;)
		{
			update(data, 0, 0, &ss);
			if (!(remote = procopen(av[0], av, NiL, NiL, PROC_UID|PROC_GID)))
				break;
			while (!kill(remote->pid, 0))
				update(data, 0, CS_STAT_FREQ + (CS_STAT_DOWN - CS_STAT_FREQ) / 2, &ss);
			procclose(remote);
			remote = 0;
			if (ss.up > 0)
				ss.up = -ss.up;
		}
		for (;;) update(data, 0, CS_STAT_FREQ + (CS_STAT_DOWN - CS_STAT_FREQ) / 2, &ss);
	}
	remove(data);
	if ((n = open(data, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0)) < 0)
		error(ERROR_SYSTEM|3, "%s: cannot update", data);
	for (i = 0; i < elementsof(usrfiles); i++)
		if ((uf = open(usrfile = usrfiles[i], O_RDONLY)) >= 0) break;
	if (uf < 0)
		error(ERROR_SYSTEM|3, "%s: cannot read", usrfiles[0]);

	/*
	 * final initialization
	 */

	if (csdaemon((1<<2)|(1<<n)|(1<<uf)))
		error(ERROR_SYSTEM|3, "cannot dive into background");
	umask(S_IRWXU|S_IRWXG|S_IRWXO);
	close(2);
	dup(n);
	close(n);
	error_info.id = data;
	av[0] = "uptime";
	av[1] = 0;
	toss = getpid();
	for (s = data; *s; s++)
		CSTOSS(toss, *s);
	usertime = 0;
#if NAMELIST
	for (n = 0; n < elementsof(symbols); n++)
		names[n].n_name = symbols[n].name;
	if ((kf = open(memfile, O_RDONLY)) >= 0)
	{
		if (chdir("/"))
			error(ERROR_SYSTEM|3, "/: chdir error");
		s = 0;
		for (i = 0; i < elementsof(sysfiles); i++)
			if (!access(sysfiles[i], F_OK))
			{
				s = sysfiles[i];
				break;
			}
		if (!s)
		{
			if (!(root = opendir(".")))
				error(ERROR_SYSTEM|3, "/: cannot read");
			while (entry = readdir(root))
			{
				if ((i = strlen(entry->d_name) - 2) > 0 && entry->d_name[i] == 'i' && entry->d_name[i + 1] == 'x' && !stat(entry->d_name, &st) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
				{
					s = entry->d_name;
					break;
				}
			}
			closedir(root);
		}
		nlist(s, names);
		for (n = 0; n < elementsof(symbols); n++)
			if (!names[n].n_type)
			{
				error(1, "%s: %s not in nlist", s, names[n].n_name);
				close(kf);
				kf = -1;
			}
		if (chdir(buf))
			error(ERROR_SYSTEM|3, "%s: chdir error", buf);
	}
	if (kf < 0)
#endif
	{
		sfsprintf(buf, sizeof(buf), "%s/%s%s%s", WHODIR, WHOPRE, data, WHOSUF);
		if ((wf = open(buf, O_RDONLY)) >= 0)
		{
			if (read(wf, &who, sizeof(who)) != sizeof(who) || who.wd_vers != WHOVERS || who.wd_type != WHOTYPE)
			{
				error(1, "%s: rwhod protocol mismatch", buf);
				close(wf);
				wf = -1;
			}
			else whofile = strdup(buf);
		}
	}
	strcpy(cmd + strlen(cmd), ".idle");
	if (eaccess(cmd, X_OK)) idlecmd = 0;
	else
	{
		idlecmd = 1;
		iv[0] = cmd;
		iv[1] = data;
		iv[2] = 0;
	}

	/*
	 * the daemon loop
	 */

	ss.idle = 4 * 60 * 60;
	now = CSTIME();
	for (;;)
	{
		then = now;
		now = CSTIME();

		/*
		 * update logged in user stats
		 */

		if (fstat(uf, &st))
			error(ERROR_SYSTEM|3, "%s: stat error", usrfile);
		if (usertime != (unsigned long)st.st_mtime)
		{
			usertime = st.st_mtime;
			if (lseek(uf, 0L, 0))
				error(ERROR_SYSTEM|3, "%s: seek error", usrfile);
			if ((n = read(uf, usrs, sizeof(usrs))) < 0)
				error(ERROR_SYSTEM|3, "%s: read error", usrfile);
			usercount = n / sizeof(struct utmp);
		}

		/*
		 * count the interesting users
		 * find the min user idle time
		 */

		if (idlecmd)
		{
			/*
			 * check idle command
			 */

			if (!(proc = procopen(iv[0], iv, NiL, NiL, PROC_READ|PROC_UID|PROC_GID)))
				idlecmd = 0;
			else
			{
				idlecmd = 1;
				n = read(proc->rfd, buf, sizeof(buf));
				if (procclose(proc) || n < 0)
					idlecmd = 0;
				else
				{
					if (n > 0)
						n--;
					buf[n] = 0;
					if (isdigit(buf[0]))
						ss.idle = strtol(buf, NiL, 10);
					else if (streq(buf, "busy"))
						ss.idle = 0;
					else if (streq(buf, "free"))
						ss.idle = ~0;
					else if (streq(buf, "idle"))
					{
						n = since(then);
						if ((ss.idle + n) < ss.idle) ss.idle = ~0;
						else ss.idle += n;
					}
					else idlecmd = -1;
				}
			}
		}
		if (idlecmd <= 0)
			ss.idle = ~0;
		ss.users = 0;
		for (i = 0; i < usercount; i++)
			if (usrs[i].ut_name[0] && usrs[i].ut_line[0])
			{
				sfsprintf(buf, sizeof(buf), "/dev/%s", usrs[i].ut_line);
				if (stat(buf, &st)) usrs[i].ut_name[0] = 0;
				else
				{
					v = since(st.st_atime);
					if (v < CS_STAT_IGNORE)
						ss.users++;
					if (idlecmd <= 0 && v < ss.idle)
						ss.idle = v;
				}
			}
		if (idlecmd <= 0 || !ss.users)
		{
			/*
			 * check devices for min idle time
			 */

			for (i = 0; i < elementsof(devfiles); i++)
				if (devfiles[i])
				{
					if (stat(devfiles[i], &st)) devfiles[i] = 0;
					else
					{
						v = since(st.st_atime);
						if (!ss.users && v < CS_STAT_IGNORE)
							ss.users++;
						if (idlecmd <= 0 && v < ss.idle)
							ss.idle = v;
					}
				}
		}

		/*
		 * get the hard stuff
		 */

#if NAMELIST
		if (kf >= 0)
		{
			/*
			 * update memfile symbol values
			 */

			for (n = 0; n < elementsof(symbols); n++)
				if (symbols[n].once >= 0)
				{
					if (lseek(kf, (long)names[n].n_value, 0) != (long)names[n].n_value)
						error(ERROR_SYSTEM|3, "%s: %s seek error", memfile, names[n].n_name);
					if (read(kf, symbols[n].addr, symbols[n].size) != symbols[n].size)
						error(ERROR_SYSTEM|3, "%s: %s read error", memfile, names[n].n_name);
					if (symbols[n].once) symbols[n].once = -1;
				}
#ifdef CP_TIME
			for (i = 0; i < CPUSTATES; i++)
				cp_time[i] = 0;
			for (n = 0; n <= maxcpu; n++)
				if (CPUFOUND(n))
					for (i = 0; i < CPUSTATES; i++)
						cp_time[i] += CP_TIME(n)[i];
#endif
			ss.load = (avenrun * 100) / FSCALE;
		}
		else
#endif
		if (wf >= 0)
		{
			if (lseek(wf, 0L, 0))
				error(ERROR_SYSTEM|3, "%s: seek error", whofile);
			read(wf, &who, sizeof(who));
			ss.load = who.wd_loadav[0];
			boottime = who.wd_boottime;
			for (i = 0; i < elementsof(cp_time); i++)
				cp_time[i] = 100;
		}
		else if (!(proc = procopen(av[0], av, NiL, NiL, PROC_READ|PROC_UID|PROC_GID)))
			error(ERROR_SYSTEM|3, "%s: exec error", av[0]);
		else
		{
			/*
			 * defer to process with memfile access
			 */

			n = read(proc->rfd, buf, sizeof(buf) - 1);
			if (procclose(proc) || n <= 0)
				error(3, "%s: invalid", av[0]);
			buf[n] = 0;
			if (!(s = strrchr(buf, ':')))
				error(3, "%s: invalid output", av[0]);
			ss.load = strton(s + 1, NiL, NiL, 100);
			n = 0;
			if ((s = strchr(buf, 'u')) && *++s == 'p')
			{
				n = strtol(s + 1, &e, 10) * 60 * 60;
				s = e;
				while (isspace(*s)) s++;
				if (*s == 'd')
				{
					n *= 24;
					while (*s && !isdigit(*s)) s++;
					n += strtol(s, &e, 10) * 60 * 60;
					s = e;
				}
				if (*s == ':') n += strtol(s + 1, NiL, 10) * 60;
			}
			boottime = since(n);
			for (i = 0; i < elementsof(cp_time); i++)
				cp_time[i] = 0;
		}

		/*
		 * finalize the new stat info
		 */

		t = 0;
		for (i = 0; i < elementsof(cp_time); i++)
		{
			if ((cp_diff[i] = cp_time[i] - cp_prev[i]) < 0) cp_diff[i] = -cp_diff[i];
			t += cp_diff[i];
			cp_prev[i] = cp_time[i];
		}
		if (!t) t = 1;
		ss.pctsys = (cp_diff[CP_SYS] * 100) / t;
		ss.pctusr = ((cp_diff[CP_USER] + cp_diff[CP_NICE]) * 100) / t;
		ss.up = since(boottime);
		update(data, now, (4 * CS_STAT_FREQ + 2 * (CSTOSS(toss, 0) % (CS_STAT_FREQ + 1))) / 5, &ss);
	}
}
Пример #3
0
int
csopen(register Cs_t* state, const char* apath, int op)
{
	register char*	path = (char*)apath;
	register char*	b;
	register char*	s;
	register int	n;
	int		fd;
	char*		t;
	char*		u;
	char*		type;
	char*		endtype;
	char*		host;
	char*		endhost;
	char*		serv;
	char*		endserv;
	char*		qual;
	char*		endqual;
	char*		opath;
	char*		user = 0;
	char*		group = 0;
	char*		trust = 0;
	char*		arg = 0;
	int		nfd = -1;
	int		uid = -1;
	int		gid = -1;
	int		sid = -1;
	int		auth = 1;
	int		mode;
	unsigned long	addr;
	unsigned long	port = 0;
	struct stat	st;
	char		buf[PATH_MAX];
	char		tmp[PATH_MAX];

	if (!path)
	{
		errno = EFAULT;
		return -1;
	}
	csprotect(&cs);
	if (op < 0)
		op = CS_OPEN_TEST;
	messagef((state->id, NiL, -8, "open(%s,%o) call", path, op));

	/*
	 * blast out the parts
	 */

	opath = path;
	if (pathgetlink(path, buf, sizeof(buf)) <= 0)
	{
		if (strlen(path) >= sizeof(buf))
			return -1;
		strcpy(buf, path);
	}
	else if ((state->flags & CS_ADDR_LOCAL) && (s = strrchr(buf, '/')))
	{
		/*
		 * dynamic ip assignment can change the addr
		 * underfoot in some implementations so we
		 * double check the local ip here
		 */

		strcpy(tmp, buf);
		if (tokscan(tmp, NiL, "/dev/%s/%s/%s", &type, NiL, &serv) == 3)
			sfsprintf(buf, sizeof(buf), "/dev/%s/%s/%s", type, csntoa(state, 0), serv);
	}
	path = buf;
	pathcanon(path, 0, 0);
	errno = ENOENT;
	strcpy(state->path, path);
	b = path;
	if ((*b++ != '/') || !(s = strchr(b, '/')))
		return -1;
	*s++ = 0;
	if (!streq(b, "dev"))
		return -1;
	if (b = strchr(s, '/'))
		*b++ = 0;
	if (streq(s, "fdp"))
	{
#if !( CS_LIB_SOCKET_UN || CS_LIB_STREAM || CS_LIB_V10 )
		if (access(CS_PROC_FD_TST, F_OK))
		{
			errno = ENODEV;
			messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, s));
			return -1;
		}
#endif
	}
	else if (!streq(s, "tcp") && !streq(s, "udp"))
	{
		messagef((state->id, NiL, -1, "open: %s: %s: invalid type", state->path, s));
		return -1;
	}
#if !( CS_LIB_SOCKET || CS_LIB_STREAM || CS_LIB_V10 )
	else
	{
		errno = ENODEV;
		messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, s));
		return -1;
	}
#endif
	type = s;
	qual = state->qual;
	if (!b)
		host = serv = 0;
	else
	{
		host = b;
		if (!(s = strchr(b, '/')))
			serv = 0;
		else
		{
			*s++ = 0;
			serv = s;

			/*
			 * grab the next fd to preserve open semantics
			 */

			for (n = 0; n < 10; n++)
				if ((nfd = dup(n)) >= 0)
					break;

			/*
			 * get qual, perm and arg
			 */

			mode = S_IRWXU|S_IRWXG|S_IRWXO;
			if (b = strchr(s, '/'))
			{
				*b++ = 0;
				do
				{
					if (*b == '#')
					{
						arg = b + 1;
						break;
					}
					if (u = strchr(b, '/'))
						*u++ = 0;
					if (s = strchr(b, '='))
						*s++ = 0;
					for (n = 0, t = b; *t; n = HASHKEYPART(n, *t++));
					switch (n)
					{
					case HASHKEY5('g','r','o','u','p'):
						group = s ? s : "";
						break;
					case HASHKEY5('l','o','c','a','l'):
						op |= CS_OPEN_LOCAL;
						break;
					case HASHKEY3('n','o','w'):
						op |= CS_OPEN_NOW;
						break;
					case HASHKEY5('o','t','h','e','r'):
						auth = 0;
						break;
					case HASHKEY6('r','e','m','o','t','e'):
						op |= CS_OPEN_REMOTE;
						break;
					case HASHKEY5('s','h','a','r','e'):
						op |= CS_OPEN_SHARE;
						break;
					case HASHKEY5('s','l','a','v','e'):
						op |= CS_OPEN_SLAVE;
						break;
					case HASHKEY4('t','e','s','t'):
						op |= CS_OPEN_TEST;
						break;
					case HASHKEY5('t','r','u','s','t'):
						op |= CS_OPEN_TRUST;
						trust = s;
						break;
					case HASHKEY4('u','s','e','r'):
						user = s ? s : "";
						break;
					default:
						qual += sfsprintf(qual, sizeof(state->qual) - (qual - state->qual) - 1, "%s%s", qual == state->qual ? "" : "-", b);
						if (s)
							*(s - 1) = '=';
						break;
					}
				} while (b = u);
			}
		}
	}
	if (*type != 't')
		auth = 0;
	strncpy(state->type, type, sizeof(state->type) - 1);
	qual = (qual == state->qual) ? (char*)0 : state->qual;
	messagef((state->id, NiL, -8, "open: type=%s host=%s serv=%s qual=%s", type, host, serv, qual));
	if (host)
	{
		/*
		 * validate host
		 */

		if (!(state->addr = addr = csaddr(state, host)))
		{
			if (serv && !(op & CS_OPEN_CREATE) && *type == 't' && (port = csport(state, type, serv)) >= CS_PORT_MIN && port <= CS_PORT_MAX)
			{
				/*
				 * attempt proxy connection
				 */

				if (nfd >= 0)
				{
					close(nfd);
					nfd = -1;
				}
				if ((fd = state->proxy.addr ? csbind(state, type, state->proxy.addr, state->proxy.port, 0L) : reopen(state, csvar(state, CS_VAR_PROXY, 0))) >= 0)
				{
					state->proxy.addr = state->addr;
					state->proxy.port = state->port;
					n = sfsprintf(tmp, sizeof(tmp), "\n%s!%s!%d\n\n%s\n%s\n0\n-1\n-1\n", type, host, port, csname(state, 0), error_info.id ? error_info.id : state->id);
					if (cswrite(state, fd, tmp, n) == n && (n = csread(state, fd, tmp, sizeof(tmp), CS_LINE)) >= 2)
					{
						if (tmp[0] == '0' && tmp[1] == '\n')
							return fd;
						if (error_info.trace <= -4 && n > 2)
						{
							s = tmp;
							s[n - 1] = 0;
							while (*s && *s++ != '\n');
							messagef((state->id, NiL, -4, "%s error message `%s'", csvar(state, CS_VAR_PROXY, 0), s));
						}
					}
					close(fd);
				}
			}
#ifdef EADDRNOTAVAIL
			errno = EADDRNOTAVAIL;
#else
			errno = ENOENT;
#endif
			goto bad;
		}
		if (op & CS_OPEN_LOCAL)
		{
			state->flags |= CS_ADDR_LOCAL;
			state->flags &= ~CS_ADDR_REMOTE;
		}
		if (op & CS_OPEN_NOW)
			state->flags |= CS_ADDR_NOW;
		if ((op & (CS_OPEN_AGENT|CS_OPEN_REMOTE)) == CS_OPEN_REMOTE)
		{
			state->flags |= CS_ADDR_REMOTE;
			state->flags &= ~CS_ADDR_LOCAL;
		}
		if (op & CS_OPEN_SHARE)
			state->flags |= CS_ADDR_SHARE;
		if (op & CS_OPEN_SLAVE)
			state->flags |= CS_DAEMON_SLAVE;
		if (op & CS_OPEN_TEST)
			state->flags |= CS_ADDR_TEST;
		if (op & CS_OPEN_TRUST)
			state->flags |= CS_ADDR_TRUST;
		if ((state->flags & CS_ADDR_REMOTE) && (!serv || !strneq(serv, CS_SVC_INET, sizeof(CS_SVC_INET) - 1) && (strtol(serv, &t, 0), *t)))
			return agent(state, state->host, state->user, state->path);
		if (s = user)
		{
			n = geteuid();
			if (*s)
			{
				if ((uid = struid(s)) < 0)
				{
					uid = strtol(s, &t, 0);
					if (*t)
					{
						errno = EACCES;
						goto bad;
					}
				}
				if (n && uid != n)
				{
					errno = EACCES;
					goto bad;
				}
			}
			else
				uid = n;
			mode &= ~(S_IRWXG|S_IRWXO);
		}
		if (s = group)
		{
			n = getegid();
			if (*s)
			{
				if ((gid = strgid(s)) < 0)
				{
					gid = strtol(s, &t, 0);
					if (*t)
					{
						errno = EACCES;
						goto bad;
					}
				}
				if (geteuid() && gid != n)
				{
					gid_t*	groups;
					int	g;

					if ((g = getgroups(0, NiL)) <= 0)
						g = getconf("NGROUPS_MAX");
					if (groups = newof(0, gid_t, g, 0))
					{
						for (n = getgroups(g, groups); n >= 0; n--)
							if (gid == groups[n])
								break;
						free(groups);
					}
					else
						n = -1;
					if (n < 0)
					{
						errno = EACCES;
						goto bad;
					}
				}
			}
			else
				gid = n;
			mode &= ~S_IRWXO;
		}
		if (s = trust)
		{
			if (!*s)
				sid = geteuid();
			else if ((sid = struid(s)) < 0)
			{
				sid = strtol(s, &t, 0);
				if (*t)
				{
					errno = EACCES;
					goto bad;
				}
			}
		}
		if (state->flags & CS_ADDR_SHARE)
			host = CS_HOST_SHARE;
		else
		{
			host = state->host;
			if (!(state->flags & CS_ADDR_LOCAL))
			{
				if (*type == 'f')
				{
					errno = ENODEV;
					goto bad;
				}
				if (op & CS_OPEN_CREATE)
				{
					errno = EROFS;
					goto bad;
				}
			}
			if (serv && !qual && *type != 'f' && (port = csport(state, type, serv)) != CS_PORT_INVALID)
			{
				if (op & CS_OPEN_CREATE)
					addr = 0;
				else if (port == CS_PORT_RESERVED || port == CS_PORT_NORMAL)
					goto bad;
				if (nfd >= 0)
				{
					close(nfd);
					nfd = -1;
				}
				state->control = 0;
				if ((fd = csbind(state, type, addr, port, 0L)) >= 0)
				{
					if (mode != (S_IRWXU|S_IRWXG|S_IRWXO) && csauth(state, fd, NiL, NiL))
					{
						close(fd);
						return -1;
					}
					return fd;
				}
			}
		}
	}

	/*
	 * get the mount dir prefix
	 */

	if (opath == (b = path = state->mount))
	{
#ifdef ELOOP
		errno = ELOOP;
#else
		errno = EINVAL;
#endif
		goto bad;
	}
	if (*type == 'f')
	{
		if (host && !(state->flags & CS_ADDR_LOCAL))
		{
			errno = ENODEV;
			goto bad;
		}
		b += sfsprintf(b, sizeof(state->mount) - (b - path), "%s", csvar(state, CS_VAR_LOCAL, 0));
		if ((op & CS_OPEN_CREATE) && eaccess(path, X_OK) && (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO) || chmod(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)))
			goto bad;
	}
	else
	{
		if (op & CS_OPEN_TRUST)
		{
			if (!pathaccess(csvar(state, CS_VAR_TRUST, 1), csvar(state, CS_VAR_SHARE, 1), NiL, PATH_EXECUTE, b, sizeof(state->mount) - (b - state->mount)))
				goto bad;
		}
		else if (!pathpath(csvar(state, CS_VAR_SHARE, 0), "", PATH_EXECUTE, b, sizeof(state->mount) - (b - state->mount)))
			goto bad;
		b += strlen(b);
	}

	/*
	 * add the type
	 */

	b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", type);
	if (!host)
	{
		*(state->control = b + 1) = 0;
		if (nfd >= 0)
			close(nfd);
		if ((fd = open(path, O_RDONLY)) < 0)
		{
			mkmount(state, S_IRWXU|S_IRWXG|S_IRWXO, -1, -1, NiL, NiL, NiL);
			fd = open(path, O_RDONLY);
		}
		if (fd < 0)
			messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path));
		return fd;
	}
	endtype = b;

	/*
	 * add the host
	 */

	if (strlen(host) <= CS_MNT_MAX)
		b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", host);
	else
	{
		s = csntoa(state, addr);
		if (strlen(s) <= CS_MNT_MAX)
			b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", s);
		else
		{
			unsigned char*	a = (unsigned char*)&addr;

			b += sfsprintf(b, sizeof(state->mount) - (b - path), "/0x%X.%X.%X.%X", a[0], a[1], a[2], a[3]);
		}
	}
	messagef((state->id, NiL, -8, "%s:%d host=`%s' path=`%s'", __FILE__, __LINE__, host, path));
	if (!serv)
	{
		*(state->control = b + 1) = 0;
		if (nfd >= 0)
			close(nfd);
		if ((fd = open(path, O_RDONLY)) < 0)
			messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path));
		return fd;
	}
	endhost = b;

	/*
	 * add the service
	 */

	sfsprintf(b, sizeof(state->mount) - (b - path), "%s/%s/%s/%s%s", CS_SVC_DIR, type, serv, serv, CS_SVC_SUFFIX);
	if (!pathpath(b, "", PATH_ABSOLUTE|PATH_EXECUTE, tmp, sizeof(tmp)) || stat(tmp, &st))
		op |= CS_OPEN_TEST;
	else
	{
		*strrchr(tmp, '/') = 0;
		if (!(op & CS_OPEN_TRUST))
			sid = st.st_uid;
		if (!st.st_size)
			op |= CS_OPEN_TEST;
	}
	b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", serv);
	endserv = b;

	/*
	 * add the qualifier and perm
	 */

	if (sid >= 0)
		b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%d-", sid);
	else
		b += sfsprintf(b, sizeof(state->mount) - (b - path), "/-");
	if (uid >= 0)
		b += sfsprintf(b, sizeof(state->mount) - (b - path), "%d-", uid);
	else if (gid >= 0)
		b += sfsprintf(b, sizeof(state->mount) - (b - path), "-%d", gid);
	else
		b += sfsprintf(b, sizeof(state->mount) - (b - path), "-");
#if limit_qualifier_length
	endqual = endserv + CS_MNT_MAX + 1;
#else
	endqual = state->mount + sizeof(state->mount) - 1;
#endif
	if (qual)
	{
		if (b < endqual)
			*b++ = '-';
		while (b < endqual && *qual)
			*b++ = *qual++;
	}
	if (*type == 't' && !auth)
	{
		if (b >= endqual)
			b--;
		*b++ = CS_MNT_OTHER;
	}

	/*
	 * add in the connect stream control
	 */

	*b++ = '/';
	*b = CS_MNT_STREAM;
	strcpy(b + 1, CS_MNT_TAIL);
	messagef((state->id, NiL, -8, "%s:%d %s", __FILE__, __LINE__, state->mount));
	state->control = b;

	/*
	 * create the mount subdirs if necessary
	 */

	if ((op & CS_OPEN_CREATE) && mkmount(state, mode, uid, gid, endserv, endhost, endtype))
		goto bad;
	mode &= S_IRWXU|S_IRWXG|S_IRWXO;
	if (nfd >= 0)
	{
		close(nfd);
		nfd = -1;
	}
	if (op & CS_OPEN_MOUNT)
	{
		messagef((state->id, NiL, -1, "open(%s,%o) = %d, mount = %s", state->path, op, state->mount));
		return 0;
	}
	if (*type == 'f')
	{
		/*
		 * {fdp}
		 */

		if ((fd = doattach(state, path, op, mode, user, opath, tmp, serv, b)) < 0)
			return -1;
	}
	else
	{
		/*
		 * {tcp,udp}
		 */

		messagef((state->id, NiL, -8, "%s:%d %s", __FILE__, __LINE__, state->mount));
		if ((fd = reopen(state, path)) < 0)
		{
			/*
			 * check for old single char cs mount
			 */

			*(state->control + 1) = 0;
			if ((fd = reopen(state, path)) < 0)
				messagef((state->id, NiL, -1, "open: %s: %s: reopen error", state->path, path));
			*(state->control + 1) = CS_MNT_TAIL[0];
		}
		if (op & CS_OPEN_CREATE)
		{
			if (fd >= 0)
			{
				close(fd);
				errno = EEXIST;
				return -1;
			}
			if (errno != ENOENT && errno != ENOTDIR)
				return -1;
			sigcritical(1);
			*state->control = CS_MNT_LOCK;
			if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0)) < 0)
			{
				if (stat(path, &st))
				{
					messagef((state->id, NiL, -1, "open: %s: %s: creat error", state->path, path));
					goto unblock;
				}
				if ((CSTIME() - (unsigned long)st.st_ctime) < 2 * 60)
				{
					errno = EEXIST;
					messagef((state->id, NiL, -1, "open: %s: %s: another server won the race", state->path, path));
					goto unblock;
				}
				if (remove(path))
				{
					messagef((state->id, NiL, -1, "open: %s: %s: remove error", state->path, path));
					goto unblock;
				}
				if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0)) < 0)
				{
					messagef((state->id, NiL, -1, "open: %s: %s: creat error", state->path, path));
					goto unblock;
				}
			}
			close(fd);
			if (!port && (n = strtol(serv, &t, 0)) && t > serv && !*t)
				port = n;
			else if (geteuid())
				port = CS_NORMAL;
			else
				port = CS_RESERVED;
			if ((fd = csbind(state, type, 0L, port, 0L)) >= 0)
			{
				*state->control = CS_MNT_STREAM;
				remove(path);
				if (pathsetlink(cspath(state, fd, 0), path))
				{
					messagef((state->id, NiL, -1, "open: %s: %s: link error", cspath(state, fd, 0), path));
					close(fd);
					fd = -1;
				}
			}
		unblock:
			*state->control = CS_MNT_LOCK;
			remove(path);
			sigcritical(0);
			*state->control = CS_MNT_STREAM;
			if (fd < 0)
				return -1;
		}
		else if (fd < 0 && ((op & CS_OPEN_TEST) || initiate(state, user, opath, tmp, serv) || (fd = reopen(state, path)) < 0))
		{
			messagef((state->id, NiL, -1, "open: %s: %s: reopen/initiate error", state->path, path));
			return -1;
		}
		else if (!(op & CS_OPEN_AGENT))
		{
			*state->control = CS_MNT_AUTH;
			n = csauth(state, fd, path, arg);
			*state->control = CS_MNT_STREAM;
			if (n)
			{
				close(fd);
				messagef((state->id, NiL, -1, "open: %s: %s: authentication error", state->path, path));
				return -1;
			}
		}
	}

	/*
	 * fd is open at this point
	 * make sure its not a bogus mount
	 */

	if (mode != (S_IRWXU|S_IRWXG|S_IRWXO))
	{
		*state->control = 0;
		n = stat(path, &st);
		*state->control = CS_MNT_STREAM;
		if (n)
		{
			messagef((state->id, NiL, -1, "open: %s: %s: stat error", state->path, path));
			close(fd);
			return -1;
		}
		if (uid >= 0 && st.st_uid != uid || gid >= 0 && st.st_gid != gid)
		{
			close(fd);
			errno = EPERM;
			messagef((state->id, NiL, -1, "open: %s: %s: uid/gid error", state->path, path));
			return -1;
		}
	}
	return fd;
 bad:
	if (nfd >= 0)
		close(nfd);
	return -1;
}
Пример #4
0
int
cspoll(Cs_t* state, Cspoll_t* fds, int num, int ms)
{
	register Cspoll_t*	pp;
	register Cspoll_t*	mp;

#if CS_LIB_SOCKET || CS_LIB_V10
	register int		events;
	register int		width;
	fd_set			rd;
	register fd_set*	rp = &rd;
	fd_set			wr;
	register fd_set*	wp = &wr;
#if CS_LIB_SOCKET
	fd_set			ex;
	register fd_set*	ep = &ex;
	struct timeval*		tp;
	struct timeval		tv;

	if (ms >= 0)
	{
		tv.tv_sec = ms / 1000;
		tv.tv_usec = (ms % 1000) * 1000;
		tp = &tv;
	}
	else tp = 0;
	FD_ZERO(ep);
#endif
	FD_ZERO(rp);
	FD_ZERO(wp);
	events = width = 0;
	for (mp = (pp = fds) + num; pp < mp; pp++)
		if (pp->fd >= 0)
		{
			if (pp->fd > width)
				width = pp->fd;
			if (pp->events & CS_POLL_READ)
			{
				events |= CS_POLL_READ;
				FD_SET(pp->fd, rp);
			}
			if (pp->events & CS_POLL_WRITE)
			{
				events |= CS_POLL_WRITE;
				FD_SET(pp->fd, wp);
			}
			if (pp->events & CS_POLL_CONTROL)
			{
				events |= CS_POLL_CONTROL;
#if CS_LIB_SOCKET
				FD_SET(pp->fd, ep);
#endif
			}
		}
	if (!(events & CS_POLL_WRITE))
		wp = 0;
#if CS_LIB_SOCKET
	if (!(events & CS_POLL_READ))
		rp = 0;
	if (!(events & CS_POLL_CONTROL))
		ep = 0;
	messagef((state->id, NiL, -6, "poll: %s num=%d ms=%d sec=%d usec=%d", fmttime("%K", CSTIME()), num, ms, tp ? tp->tv_sec : 0, tp ? tp->tv_usec : 0));
	num = select(width + 1, rp, wp, ep, tp);
#else
	if (!(events & (CS_POLL_READ|CS_POLL_CONTROL)))
		rp = 0;
	messagef((state->id, NiL, -6, "poll: %s num=%d ms=%d", fmttime("%K", CSTIME()), num, ms);
	num = select(width + 1, rp, wp, ms);
#endif
	messagef((state->id, NiL, -6, "poll: %s num=%d", fmttime("%K", CSTIME()), num));
	if (num < 0)
		messagef((state->id, NiL, -1, "poll: select error"));
	else
		for (num = 0, pp = fds; pp < mp; pp++)
		{
			pp->status = 0;
			if (pp->fd >= 0)
			{
				if (rp && FD_ISSET(pp->fd, rp))
				{
#if CS_LIB_V10
					long	n;

					if ((pp->event & CS_POLL_CONTROL) && ioctl(fd, FIONREAD, &n))
						pp->status |= CS_POLL_CLOSE;
					else if (!n)
						pp->status |= CS_POLL_CONTROL;
					else
#endif
					pp->status |= CS_POLL_READ;
				}
				if (wp && FD_ISSET(pp->fd, wp))
					pp->status |= CS_POLL_WRITE;
#if CS_LIB_SOCKET
				if (ep && FD_ISSET(pp->fd, ep))
					pp->status |= CS_POLL_CONTROL;
#endif
				if (pp->status)
				{
					pp->status |= pp->events & (CS_POLL_AUTH|CS_POLL_CONNECT|CS_POLL_USER);
					num++;
				}
			}
		}
	return num;
	
#else

#if CS_LIB_STREAM

	int	n;

#if _lib_poll_fd_2
	n = poll(num, fds, ms);
#else
	n = poll(fds, num, ms);
#endif
	if (n < 0)
		messagef((state->id, NiL, -1, "poll: poll error"));
	else if (n > 0)
	{
		int		i;
#ifdef RS_HIPRI
		struct strbuf	buf;

		buf.maxlen = 0;
#endif
		for (mp = (pp = fds) + num, i = n; pp < mp; pp++)
		{
			if (pp->status)
			{
				pp->status |= pp->events & (CS_POLL_AUTH|CS_POLL_CONNECT|CS_POLL_USER);
#ifdef RS_HIPRI
				if (pp->status & CS_POLL_CONTROL)
				{
					int	f = RS_HIPRI;

					if (getmsg(pp->fd, NiL, &buf, &f))
						pp->status &= ~CS_POLL_CONTROL;
				}
#endif
				if (--i <= 0)
					break;
			}
		}
	}
	return n;

#else

	errno = EINVAL;
	messagef((state->id, NiL, -1, "poll: not supported"));
	return -1;

#endif

#endif

}