Example #1
0
static void
pseudo_file_close(int *fd, FILE **fp) {
	if (!fp || !fd) {
		pseudo_diag("pseudo_file_close: needs valid pointers.\n");
		return;
	}
	pseudo_antimagic();
	if (*fp) {
#if PSEUDO_PORT_DARWIN
		if (*fp == pseudo_host_etc_passwd_file) {
			endpwent();
		} else if (*fp != pseudo_host_etc_group_file) {
			endgrent();
		} else {
			fclose(*fp);
		}
#else
		fclose(*fp);
#endif
		*fd = -1;
		*fp = 0;
	}
#if PSEUDO_PORT_DARWIN
	if (*fd == pseudo_host_etc_passwd_fd ||
	    *fd == pseudo_host_etc_group_fd) {
		*fd = -1;
	}
#endif
	/* this should be impossible */
	if (*fd >= 0) {
		close(*fd);
		*fd = -1;
	}
	pseudo_magic();
}
Example #2
0
static FILE *
pseudo_file_open(char *name, int *fd, FILE **fp) {
	if (!fp || !fd || !name) {
		pseudo_diag("pseudo_file_open: needs valid pointers.\n");
		return NULL;
	}
	pseudo_file_close(fd, fp);
	pseudo_antimagic();
	*fd = PSEUDO_ETC_FILE(name, NULL, O_RDONLY);
#if PSEUDO_PORT_DARWIN
	if (*fd == pseudo_host_etc_passwd_fd) {
		*fp = pseudo_host_etc_passwd_file;
		setpwent();
	} else if (*fd == pseudo_host_etc_group_fd) {
		*fp = pseudo_host_etc_group_file;
		setgrent();
	}
#endif
	if (*fd >= 0) {
		*fd = pseudo_fd(*fd, MOVE_FD);
		*fp = fdopen(*fd, "r");
		if (!*fp) {
			close(*fd);
			*fd = -1;
		}
	}
	pseudo_magic();
	return *fp;
}
Example #3
0
mode_t
parse_file_type(char *string) {
	switch (*string) {
	case 'b':
		return S_IFBLK;
		break;
	case 'c':
		return S_IFCHR;
		break;
	case 'd':
		return S_IFDIR;
		break;
	case '-':	/* FALLTHROUGH */
	case 'f':
		return S_IFREG;
		break;
	case 'l':
		return S_IFLNK;
		break;
	case 'p':
		return S_IFIFO;
		break;
	case 's':
		return S_IFSOCK;
		break;
	default:
		pseudo_diag("unknown file type %c; should be one of [-bcdflps]\n",
			isprint(*string) ? *string : '?');
		return -1;
		break;
	}
}
int
pseudo_client_chroot(const char *path) {
	/* free old value */
	free(pseudo_chroot);

	pseudo_debug(2, "client chroot: %s\n", path);
	if (!strcmp(path, "/")) {
		pseudo_chroot_len = 0;
		pseudo_chroot = 0;
		pseudo_set_value("PSEUDO_CHROOT", NULL);
		return 0;
	}
	/* allocate new value */
	pseudo_chroot_len = strlen(path);
	pseudo_chroot = malloc(pseudo_chroot_len + 1);
	if (!pseudo_chroot) {
		pseudo_diag("Couldn't allocate chroot directory buffer.\n");
		pseudo_chroot_len = 0;
		errno = ENOMEM;
		return -1;
	}
	memcpy(pseudo_chroot, path, pseudo_chroot_len + 1);
	pseudo_set_value("PSEUDO_CHROOT", pseudo_chroot);
	return 0;
}
Example #5
0
mode_t
parse_mode_string(char *string) {
	size_t len = strlen(string);
	mode_t mode = 0;
	mode_t bits = 0;

	if (len != 9 && len != 10) {
		pseudo_diag("mode strings must be of the form [-]rwxr-xr-x\n");
		return -1;
	}
	if (len == 10) {
		mode |= parse_file_type(string);
		++string;
		if (mode == (mode_t) -1) {
			pseudo_diag("mode strings with a file type must use a valid type [-bcdflps]\n");
			return -1;
		}
	}
	bits = parse_partial_mode(string);
	if (bits == (mode_t) -1)
		return -1;
	if (bits & 010) {
		mode |= S_ISUID;
		bits &= ~010;
	}
	mode |= bits << 6;
	string += 3;
	bits = parse_partial_mode(string);
	if (bits == (mode_t) -1)
		return -1;
	if (bits & 010) {
		mode |= S_ISGID;
		bits &= ~010;
	}
	mode |= bits << 3;
	string += 3;
	bits = parse_partial_mode(string);
	if (bits == (mode_t) -1)
		return -1;
	if (bits & 010) {
		mode |= S_ISVTX;
		bits &= ~010;
	}
	mode |= bits;
	return mode;
}
Example #6
0
mode_t
parse_partial_mode(char *string) {
	mode_t mode = 0;
	switch (string[0]) {
	case 'r':
		mode |= 04;
		break;
	case '-':
		break;
	default:
		pseudo_diag("unknown mode character: %c\n", string[0]);
		return -1;
		break;
	}
	switch (string[1]) {
	case 'w':
		mode |= 02;
		break;
	case '-':
		break;
	default:
		pseudo_diag("unknown mode character: %c\n", string[1]);
		return -1;
		break;
	}
	switch (string[2]) {
	case 'x':
		mode |= 01;
		break;
	case 't':	/* FALLTHROUGH */
	case 's':
		mode |= 011;
		break;
	case 'T':	/* FALLTHROUGH */
	case 'S':
		mode |= 010;
		break;
	case '-':
		break;
	default:
		pseudo_diag("unknown mode character: %c\n", string[2]);
		return -1;
		break;
	}
	return mode;
}
Example #7
0
static time_t
parse_timestamp(char *string) {
	time_t stamp_sec;
	struct tm stamp_tm;
	int i;
	char *s;
	char timebuf[4096];

	stamp_sec = time(0);

	/* try the user's provided time format first, if there is one: */
	localtime_r(&stamp_sec, &stamp_tm);
	s = strptime(string, timeformat, &stamp_tm);
	if (s && !*s) {
		return mktime(&stamp_tm);
	}

	for (i = 0; time_formats[i]; ++i) {
		char *s;
		localtime_r(&stamp_sec, &stamp_tm);
		s = strptime(string, time_formats[i], &stamp_tm);
		if (s && !*s) {
			break;
		}
	}
	if (!time_formats[i]) {
		pseudo_diag("Couldn't parse <%s> as a time.  Current time in known formats is:\n",
			string);
		localtime_r(&stamp_sec, &stamp_tm);
		for (i = 0; time_formats[i]; ++i) {
			strftime(timebuf, sizeof(timebuf), time_formats[i], &stamp_tm);
			pseudo_diag("\t%s\n", timebuf);
		}
		pseudo_diag("Or, specify your own with -E; see strptime(3).\n");
		return -1;
	}
	return mktime(&stamp_tm);
}
Example #8
0
/* there is no spec I know of requiring us to defend this fd
 * against being closed by the user.
 */
int
pseudo_pwd_lck_open(void) {
	if (!pseudo_pwd_lck_name) {
		pseudo_pwd_lck_name = malloc(pseudo_path_max());
		if (!pseudo_pwd_lck_name) {
			pseudo_diag("couldn't allocate space for passwd lockfile path.\n");
			return -1;
		}
	}
	pseudo_pwd_lck_close();
	pseudo_pwd_lck_fd = PSEUDO_ETC_FILE(".pwd.lock",
					pseudo_pwd_lck_name, O_RDWR | O_CREAT);
	return pseudo_pwd_lck_fd;
}
Example #9
0
char *
pseudo_root_path(const char *func, int line, int dirfd, const char *path, int leave_last) {
	char *rc;
	pseudo_antimagic();
	rc = base_path(dirfd, path, leave_last);
	pseudo_magic();
	if (!rc) {
		pseudo_diag("couldn't allocate absolute path for '%s'.\n",
			path);
	}
	pseudo_debug(3, "root_path [%s, %d]: '%s' from '%s'\n",
		func, line,
		rc ? rc : "<nil>",
		path ? path : "<nil>");
	return rc;
}
Example #10
0
int
pseudo_fd(int fd, int how) {
	int newfd;

	if (fd < 0)
		return(-1);

	/* If already above PSEUDO_MIN_FD, no need to move */
	if ((how == MOVE_FD) && (fd >= PSEUDO_MIN_FD)) {
		newfd = fd;
	} else {
		newfd = fcntl(fd, F_DUPFD, PSEUDO_MIN_FD);

		if (how == MOVE_FD)
			close(fd);
	}

	/* Set close on exec, even if we didn't move it. */
	if ((newfd >= 0) && (fcntl(newfd, F_SETFD, FD_CLOEXEC) < 0))
		pseudo_diag("can't set close on exec flag: %s\n",
			strerror(errno));

	return(newfd);
}
Example #11
0
int
pseudo_client_shutdown(void) {
	pseudo_msg_t msg;
	pseudo_msg_t *ack;
	char *pseudo_path;

	pseudo_path = pseudo_prefix_path(NULL);
	if (pseudo_prefix_dir_fd == -1) {
		if (pseudo_path) {
			pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
			/* directory is missing? */
			if (pseudo_prefix_dir_fd == -1 && errno == ENOENT) {
				pseudo_debug(1, "prefix directory doesn't exist, trying to create\n");
				mkdir_p(pseudo_path);
				pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
			}
			pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, COPY_FD);
			free(pseudo_path);
		} else {
			pseudo_diag("No prefix available to to find server.\n");
			exit(1);
		}
		if (pseudo_prefix_dir_fd == -1) {
			pseudo_diag("Can't open prefix path (%s) for server. (%s)\n",
				pseudo_prefix_path(NULL),
				strerror(errno));
			exit(1);
		}
	}
	pseudo_path = pseudo_localstatedir_path(NULL);
	mkdir_p(pseudo_path);
	if (pseudo_localstate_dir_fd == -1) {
		if (pseudo_path) {
			pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
			/* directory is missing? */
			if (pseudo_localstate_dir_fd == -1 && errno == ENOENT) {
				pseudo_debug(1, "local state dir doesn't exist, trying to create\n");
				mkdir_p(pseudo_path);
				pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
			}
			pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, COPY_FD);
			free(pseudo_path);
		} else {
			pseudo_diag("No prefix available to to find server.\n");
			exit(1);
		}
		if (pseudo_localstate_dir_fd == -1) {
			pseudo_diag("Can't open local state path (%s) for server. (%s)\n",
				pseudo_localstatedir_path(NULL),
				strerror(errno));
			exit(1);
		}
	}
	if (client_connect()) {
		pseudo_diag("Pseudo server seems to be already offline.\n");
		return 0;
	}
	memset(&msg, 0, sizeof(pseudo_msg_t));
	msg.type = PSEUDO_MSG_SHUTDOWN;
	msg.op = OP_NONE;
	msg.client = getpid();
	pseudo_debug(2, "sending shutdown request\n");
	if (pseudo_msg_send(connect_fd, &msg, 0, NULL)) {
		pseudo_debug(1, "error requesting shutdown: %s\n", strerror(errno));
		return 1;
	}
	ack = pseudo_msg_receive(connect_fd);
	if (!ack) {
		pseudo_diag("server did not respond to shutdown query.\n");
		return 1;
	}
	if (ack->type == PSEUDO_MSG_ACK) {
		return 0;
	}
	pseudo_diag("Server refused shutdown.  Remaining client fds: %d\n", ack->fd);
	pseudo_diag("Client pids: %s\n", ack->path);
	pseudo_diag("Server will shut down after all clients exit.\n");
	return 0;
}
Example #12
0
/* spawn server */
static int
client_spawn_server(void) {
	int status;
	FILE *fp;
	char * pseudo_pidfile;

	if ((server_pid = fork()) != 0) {
		if (server_pid == -1) {
			pseudo_diag("couldn't fork server: %s\n", strerror(errno));
			return 1;
		}
		pseudo_debug(4, "spawned server, pid %d\n", server_pid);
		/* wait for the child process to terminate, indicating server
		 * is ready
		 */
		waitpid(server_pid, &status, 0);
		server_pid = -2;
		pseudo_pidfile = pseudo_localstatedir_path(PSEUDO_PIDFILE);
		fp = fopen(pseudo_pidfile, "r");
		if (fp) {
			if (fscanf(fp, "%d", &server_pid) != 1) {
				pseudo_debug(1, "Opened server PID file, but didn't get a pid.\n");
			}
			fclose(fp);
		} else {
			pseudo_debug(1, "no pid file (%s): %s\n",
				pseudo_pidfile, strerror(errno));
		}
		pseudo_debug(2, "read new pid file: %d\n", server_pid);
		free(pseudo_pidfile);
		/* at this point, we should have a new server_pid */
		return 0;
	} else {
		char *base_args[] = { NULL, NULL, NULL };
		char **argv;
		char *option_string = pseudo_get_value("PSEUDO_OPTS");
		int args;
		int fd;

		pseudo_new_pid();
		base_args[0] = pseudo_bindir_path("pseudo");
		base_args[1] = "-d";
		if (option_string) {
			char *s;
			int arg;

			/* count arguments in PSEUDO_OPTS, starting at 2
			 * for pseudo/-d/NULL, plus one for the option string.
			 * The number of additional arguments may be less
			 * than the number of spaces, but can't be more.
			 */
			args = 4;
			for (s = option_string; *s; ++s)
				if (*s == ' ')
					++args;

			argv = malloc(args * sizeof(char *));
			argv[0] = base_args[0];
			argv[1] = base_args[1];
			arg = 2;
			while ((s = strsep(&option_string, " ")) != NULL) {
				if (*s) {
					argv[arg++] = strdup(s);
				}
			}
			argv[arg] = 0;
		} else {
			argv = base_args;
		}

		/* close any higher-numbered fds which might be open,
		 * such as sockets.  We don't have to worry about 0 and 1;
		 * the server closes them already, and more importantly,
		 * they can't have been opened or closed without us already
		 * having spawned a server... The issue is just socket()
		 * calls which could result in fds being left open, and those
		 * can't overwrite fds 0-2 unless we closed them...
		 * 
		 * No, really.  It works.
		 */
		for (fd = 3; fd < 1024; ++fd) {
			if (fd != pseudo_util_debug_fd)
				close(fd);
		}
		/* and now, execute the server */

		pseudo_set_value("PSEUDO_RELOADED", "YES");
		pseudo_setupenv();
		pseudo_dropenv(); /* drop PRELINK_LIBRARIES */

		pseudo_debug(4, "calling execv on %s\n", argv[0]);

		execv(argv[0], argv);
		pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno));
		exit(1);
	}
}
Example #13
0
void
pseudo_init_client(void) {
	char *env;

	pseudo_antimagic();
	pseudo_new_pid();
	if (connect_fd != -1) {
		close(connect_fd);
		connect_fd = -1;
	}

	/* in child processes, PSEUDO_DISABLED may have become set to
	 * some truthy value, in which case we'd disable pseudo,
	 * or it may have gone away, in which case we'd enable
	 * pseudo (and cause it to reinit the defaults).
	 */
	env = getenv("PSEUDO_DISABLED");
	if (!env) {
		env = pseudo_get_value("PSEUDO_DISABLED");
	}
	if (env) {
		int actually_disabled = 1;
		switch (*env) {
		case '0':
		case 'f':
		case 'F':
		case 'n':
		case 'N':
			actually_disabled = 0;
			break;
		case 's':
		case 'S':
			actually_disabled = 0;
			pseudo_local_only = 1;
			break;
		}
		if (actually_disabled) {
			if (!pseudo_disabled) {
				pseudo_antimagic();
				pseudo_disabled = 1;
			}
			pseudo_set_value("PSEUDO_DISABLED", "1");
		} else {
			if (pseudo_disabled) {
				pseudo_magic();
				pseudo_disabled = 0;
				pseudo_inited = 0; /* Re-read the initial values! */
			}
			pseudo_set_value("PSEUDO_DISABLED", "0");
		}
	} else {
		pseudo_set_value("PSEUDO_DISABLED", "0");
	}

	/* Setup global items needed for pseudo to function... */
	if (!pseudo_inited) {
		/* Ensure that all of the values are reset */
		server_pid = 0;
		pseudo_prefix_dir_fd = -1;
		pseudo_localstate_dir_fd = -1;
		pseudo_pwd_fd = -1;
		pseudo_pwd_lck_fd = -1;
		pseudo_pwd_lck_name = NULL;
		pseudo_pwd = NULL;
		pseudo_grp_fd = -1;
		pseudo_grp = NULL;
		pseudo_cwd = NULL;
		pseudo_cwd_len = 0;
		pseudo_chroot = NULL;
		pseudo_passwd = NULL;
		pseudo_chroot_len = 0;
		pseudo_cwd_rel = NULL;
		pseudo_nosymlinkexp = 0;
	}

	if (!pseudo_disabled && !pseudo_inited) {
		char *pseudo_path = 0;

		pseudo_path = pseudo_prefix_path(NULL);
		if (pseudo_prefix_dir_fd == -1) {
			if (pseudo_path) {
				pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
				/* directory is missing? */
				if (pseudo_prefix_dir_fd == -1 && errno == ENOENT) {
					pseudo_debug(1, "prefix directory doesn't exist, trying to create\n");
					mkdir_p(pseudo_path);
					pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY);
				}
				pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, MOVE_FD);
			} else {
				pseudo_diag("No prefix available to to find server.\n");
				exit(1);
			}
			if (pseudo_prefix_dir_fd == -1) {
				pseudo_diag("Can't open prefix path (%s) for server: %s\n",
					pseudo_path,
					strerror(errno));
				exit(1);
			}
		}
		free(pseudo_path);
		pseudo_path = pseudo_localstatedir_path(NULL);
		if (pseudo_localstate_dir_fd == -1) {
			if (pseudo_path) {
				pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
				/* directory is missing? */
				if (pseudo_localstate_dir_fd == -1 && errno == ENOENT) {
					pseudo_debug(1, "local state directory doesn't exist, trying to create\n");
					mkdir_p(pseudo_path);
					pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY);
				}
				pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, MOVE_FD);
			} else {
				pseudo_diag("No prefix available to to find server.\n");
				exit(1);
			}
			if (pseudo_localstate_dir_fd == -1) {
				pseudo_diag("Can't open local state path (%s) for server: %s\n",
					pseudo_path,
					strerror(errno));
				exit(1);
			}
		}
		free(pseudo_path);

		env = pseudo_get_value("PSEUDO_NOSYMLINKEXP");
		if (env) {
			char *endptr;
			/* if the environment variable is not an empty string,
			 * parse it; "0" means turn NOSYMLINKEXP off, "1" means
			 * turn it on (disabling the feature).  An empty string
			 * or something we can't parse means to set the flag; this
			 * is a safe default because if you didn't want the flag
			 * set, you normally wouldn't set the environment variable
			 * at all.
			 */
			if (*env) {
				pseudo_nosymlinkexp = strtol(env, &endptr, 10);
				if (*endptr)
					pseudo_nosymlinkexp = 1;
			} else {
				pseudo_nosymlinkexp = 1;
			}
		} else {
			pseudo_nosymlinkexp = 0;
		}
		free(env);
		env = pseudo_get_value("PSEUDO_UIDS");
		if (env)
			sscanf(env, "%d,%d,%d,%d",
				&pseudo_ruid, &pseudo_euid,
				&pseudo_suid, &pseudo_fuid);
		free(env);

		env = pseudo_get_value("PSEUDO_GIDS");
		if (env)
			sscanf(env, "%d,%d,%d,%d",
				&pseudo_rgid, &pseudo_egid,
				&pseudo_sgid, &pseudo_fuid);
		free(env);

		env = pseudo_get_value("PSEUDO_CHROOT");
		if (env) {
			pseudo_chroot = strdup(env);
			if (pseudo_chroot) {
				pseudo_chroot_len = strlen(pseudo_chroot);
			} else {
				pseudo_diag("can't store chroot path (%s)\n", env);
			}
		}
		free(env);

		env = pseudo_get_value("PSEUDO_PASSWD");
		if (env) {
			pseudo_passwd = strdup(env);
		}
		free(env);

		pseudo_inited = 1;
	}
	if (!pseudo_disabled)
		pseudo_client_getcwd();

	pseudo_magic();
}
Example #14
0
/* print a single member of log, based on a single format specifier;
 * returns the address of the last character of the format specifier.
 */
static char *
format_one(log_entry *e, char *format) {
	char fmtbuf[256];
	size_t len = strcspn(format, "acdfgGimMoprRsStTuy"), real_len;
	char scratch[4096];
	time_t stamp_sec;
	struct tm stamp_tm;
	char *s;

	if (!e || !format) {
		pseudo_diag("invalid log entry or format specifier.\n");
		return 0;
	}
	real_len = snprintf(fmtbuf, sizeof(fmtbuf), "%.*s", (int) len + 1, format);
	if (real_len >= sizeof(fmtbuf) - 1) {
		pseudo_diag("Format string way too long starting at %.10s",
			format - 1);
		return 0;
	}
	/* point to the last character */
	s = fmtbuf + real_len - 1;

	/* The * modifier for width or precision requires additional
	 * parameters -- this doesn't make sense here.
	 */
	if (strchr(fmtbuf, '*') || strchr(fmtbuf, 'l') || strchr(fmtbuf, 'h')) {
		pseudo_diag("Sorry, you can't use *, h, or l format modifiers.\n");
		return 0;
	}

	switch (*s) {
	case 'a':		/* PSQF_ACCESS */
		*scratch = '\0';
		if (e->access == -1) {
			strcpy(scratch, "invalid");
		} else if (e->access != 0) {
			if (e->access & PSA_READ) {
				strcpy(scratch, "r");
				if (e->access & PSA_WRITE)
					strcat(scratch, "+");
			} else if (e->access & PSA_WRITE) {
				if (e->access & PSA_APPEND) {
					strcpy(scratch, "a");
				} else {
					strcpy(scratch, "w");
				}
				if (e->access & PSA_READ)
					strcat(scratch, "+");
			} else if (e->access & PSA_EXEC) {
				strcpy(scratch, "x");
			}
			/* this should be impossible... should. */
			if (e->access & PSA_APPEND && !(e->access & PSA_WRITE)) {
				strcat(scratch, "?a");
			}
		} else {
			strcpy(scratch, "-");
		}
		strcpy(s, "s");
		printf(fmtbuf, scratch);
		break;
	case 'c':		/* PSQF_CLIENT */
		strcpy(s, "d");
		printf(fmtbuf, (int) e->client);
		break;
	case 'd':		/* PSQF_DEV */
		strcpy(s, "d");
		printf(fmtbuf, (int) e->dev);
		break;
	case 'f':		/* PSQF_FD */
		strcpy(s, "d");
		printf(fmtbuf, (int) e->fd);
		break;
	case 'g':		/* PSQF_GID */
		strcpy(s, "d");
		printf(fmtbuf, (int) e->gid);
		break;
	case 'G':		/* PSQF_TAG */
		strcpy(s, "s");
		printf(fmtbuf, e->tag ? e->tag : "");
		break;
	case 'i':		/* PSQF_INODE */
		strcpy(s, "llu");
		printf(fmtbuf, (unsigned long long) e->ino);
		break;
	case 'm':		/* PSQF_PERM */
		strcpy(s, "o");
		printf(fmtbuf, (unsigned int) e->mode & ALLPERMS);
		break;
	case 'M':		/* PSQF_MODE */
		strcpy(s, "o");
		printf(fmtbuf, (unsigned int) e->mode);
		break;
	case 'o':		/* PSQF_OP */
		strcpy(s, "s");
		printf(fmtbuf, pseudo_op_name(e->op));
		break;
	case 'p':		/* PSQF_PATH */
		strcpy(s, "s");
		printf(fmtbuf, e->path ? e->path : "");
		break;
	case 'r':		/* PSQF_RESULT */
		strcpy(s, "s");
		printf(fmtbuf, pseudo_res_name(e->result));
		break;
	case 'R':		/* PSQF_PROGRAM */
		strcpy(s, "s");
		printf(fmtbuf, e->program ? e->program : "");
		break;
	case 's':		/* PSQF_STAMP */
		strcpy(s, "s");
		stamp_sec = e->stamp;
		localtime_r(&stamp_sec, &stamp_tm);
		strftime(scratch, sizeof(scratch), timeformat, &stamp_tm);
		printf(fmtbuf, scratch);
		break;
	case 'S':		/* PSQF_SEVERITY */
		strcpy(s, "s");
		printf(fmtbuf, pseudo_sev_name(e->severity));
		break;
	case 't':		/* PSQF_FTYPE */
	strcpy(s, "s");
		if (S_ISREG(e->mode)) {
			strcpy(scratch, "file");
		} if (S_ISLNK(e->mode)) {
			strcpy(scratch, "link");
		} else if (S_ISDIR(e->mode)) {
			strcpy(scratch, "dir");
		} else if (S_ISFIFO(e->mode)) {
			strcpy(scratch, "fifo");
		} else if (S_ISBLK(e->mode)) {
			strcpy(scratch, "block");
		} else if (S_ISCHR(e->mode)) {
			strcpy(scratch, "char");
		} else {
			snprintf(scratch, sizeof(scratch), "?%o", (unsigned int) e->mode & S_IFMT);
		}
		printf(fmtbuf, scratch);
		break;
	case 'T':		/* PSQF_TEXT */
		strcpy(s, "s");
		printf(fmtbuf, e->text ? e->text : "");
		break;
	case 'u':		/* PSQF_UID */
		strcpy(s, "d");
		printf(fmtbuf, (int) e->uid);
		break;
	case 'y':		/* PSQF_TYPE */
		strcpy(s, "s");
		printf(fmtbuf, pseudo_msg_type_name(e->type));
		break;
	}
	return format + len;
}
Example #15
0
/* You can either create a query or create a log entry.  They use very
 * similar syntax, but:
 * - if you're making a query, you can use >, <, etc.
 * - if you're logging, you can't.
 * This is tracked by recording whether any non-exact relations
 * have been requested ("query_only"), and refusing to set the -l
 * flag if they have, and refusing to accept any such relation
 * if the -l flag is already set.
 */
int
main(int argc, char **argv) {
	pseudo_query_t *traits = 0, *current = 0, *new_trait = 0;
	char *s;
	log_history history;
	int query_only = 0;
	int o;
	int bad_args = 0;
	char *format = "%s %-12.12R %-4y %7o: [mode %04m, %2a] %p %T";

	while ((o = getopt(argc, argv, "vla:c:d:DE:f:F:g:G:hi:I:m:M:o:O:p:P:r:R:s:S:t:T:u:Ux:y:")) != -1) {
		switch (o) {
		case 'P':
			s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW);
			if (!s)
				pseudo_diag("Can't resolve prefix path '%s'\n", optarg);
			pseudo_set_value("PSEUDO_PREFIX", s);
			break;
		case 'v':
			pseudo_debug_verbose();
			break;
		case 'x':
			pseudo_debug_set(optarg);
			break;
		case 'l':
			opt_l = 1;
			break;
		case 'D':
			opt_D = 1;
			query_only = 1;
			break;
		case 'E':
			timeformat = strdup(optarg);
			break;
		case 'F':
			/* disallow specifying -F with -l */
			format = strdup(optarg);
			query_only = 1;
			break;
		case 'U':
			opt_U = 1;
			query_only = 1;
			break;
		case 'I':		/* PSQF_ID */
			query_only = 1;
					/* FALLTHROUGH */
		case 'a':		/* PSQF_ACCESS */
		case 'c':		/* PSQF_CLIENT */
		case 'd':		/* PSQF_DEV */
		case 'f':		/* PSQF_FD */
		case 'g':		/* PSQF_GID */
		case 'G':		/* PSQF_TAG */
		case 'i':		/* PSQF_INODE */
		case 'm':		/* PSQF_PERM */
		case 'M':		/* PSQF_MODE */
		case 'o':		/* PSQF_OP */
		case 'O':		/* PSQF_ORDER */
		case 'p':		/* PSQF_PATH */
		case 'r':		/* PSQF_RESULT */
		case 'R':		/* PSQF_PROGRAM */
		case 's':		/* PSQF_STAMP */
		case 'S':		/* PSQF_SEVERITY */
		case 't':		/* PSQF_FTYPE */
		case 'T':		/* PSQF_TEXT */
		case 'u':		/* PSQF_UID */
		case 'y':		/* PSQF_TYPE */
			new_trait = plog_trait(o, optarg);
			if (!new_trait) {
				bad_args = 1;
			}
			break;
		case 'h':
			usage(EXIT_SUCCESS);
			break;
		case '?':		/* FALLTHROUGH */
		default:
			fprintf(stderr, "unknown option '%c'\n", optopt);
			usage(EXIT_FAILURE);
			break;
		}
		if (new_trait) {
			if (current) {
				current->next = new_trait;
				current = current->next;
			} else {
				traits = new_trait;
				current = new_trait;
			}
			new_trait = 0;
		}
	}
	pseudo_debug_flags_finalize();

	if (optind < argc) {
		pseudo_diag("Error: Extra arguments not associated with any option.\n");
		usage(EXIT_FAILURE);
	}

	if (query_only && opt_l) {
		pseudo_diag("Error: -l cannot be used with query-only options or flags.\n");
		bad_args = 1;
	}

	/* should be set only if we have already diagnosed the bad arguments. */
	if (bad_args)
		exit(EXIT_FAILURE);

	if (!pseudo_get_prefix(argv[0])) {
		pseudo_diag("Can't figure out prefix.  Set PSEUDO_PREFIX or invoke with full path.\n");
		exit(EXIT_FAILURE);
	}

	if (!pseudo_get_bindir()) {
		pseudo_diag("Can't figure out bindir.  Set PSEUDO_BINDIR.\n");
		exit(EXIT_FAILURE);
	}

	if (!pseudo_get_libdir()) {
		pseudo_diag("Can't figure out libdir.  Set PSEUDO_LIBDIR.\n");
		exit(EXIT_FAILURE);
	}

	if (!pseudo_get_localstatedir()) {
		pseudo_diag("Can't figure out localstatedir.  Set PSEUDO_LOCALSTATEDIR.\n");
		exit(EXIT_FAILURE);
	}

	if (opt_l) {
		pdb_log_traits(traits);
	} else {
		int fields;
		fields = format_scan(format);
		if (fields == -1) {
			pseudo_diag("couldn't parse format string (%s).\n", format);
			return EXIT_FAILURE;
		}
		if (opt_D) {
			if (pdb_delete(traits, fields)) {
				pseudo_diag("errors occurred trying to delete entries.\n");
			}
		} else {
			history = pdb_history(traits, fields, opt_U);
			if (history) {
				log_entry *e;
				while ((e = pdb_history_entry(history)) != NULL) {
					display(e, format);
					log_entry_free(e);
				}
				pdb_history_free(history);
			} else {
				pseudo_diag("could not retrieve history.\n");
				return EXIT_FAILURE;
			}
		}
	}
	return 0;
}
Example #16
0
pseudo_query_t *
plog_trait(int opt, char *string) {
	pseudo_query_t *new_trait;
	char *endptr;

	if (opt < 0 || opt > UCHAR_MAX) {
		pseudo_diag("Unknown/invalid option value: %d\n", opt);
		return 0;
	}
	if (!opt_to_field[opt]) {
		if (isprint(opt)) {
			pseudo_diag("Unknown option: -%c\n", opt);
		} else {
			pseudo_diag("Unknown option: 0x%02x\n", opt);
		}
		return 0;
	}
	if (!*string) {
		pseudo_diag("invalid empty string for -%c\n", opt);
		return 0;
	}
	new_trait = calloc(sizeof(*new_trait), 1);
	if (!new_trait) {
		pseudo_diag("Couldn't allocate requested trait (for -%c %s)\n",
			opt, string ? string : "<nil>");
		return 0;
	}
	new_trait->field = opt_to_field[opt];
	new_trait->type = plog_query_type(&string);
	if (new_trait->type == PSQT_UNKNOWN) {
		pseudo_diag("Couldn't comprehend trait type for '%s'\n",
			string ? string : "<nil>");
		free(new_trait);
		return 0;
	}
	switch (new_trait->field) {
	case PSQF_ACCESS:
		new_trait->data.ivalue = pseudo_access_fopen(string);
		if (new_trait->data.ivalue == (unsigned long long) -1) {
			pseudo_diag("access flags should be specified like fopen(3) mode strings (or x for exec).\n");
			free(new_trait);
			return 0;
		}
		break;
	case PSQF_FTYPE:
		/* special magic: allow file types ala find */
		/* This is implemented by additional magic over in the database code */
		/* must not be more than one character.  The test against
		 * the first character is because in theory, if the
		 * first character is the terminating NUL, we may not
		 * access the second. */
		if (string[0] && string[1]) {
			pseudo_diag("file type must be a single character [-bcdflps].\n");
			free(new_trait);
			return 0;
		}
		new_trait->data.ivalue = parse_file_type(string);
		if (new_trait->data.ivalue == (mode_t) -1) {
			free(new_trait);
			return 0;
		}
		break;
	case PSQF_OP:
		new_trait->data.ivalue = pseudo_op_id(string);
		break;
	case PSQF_ORDER:
		if (string[0] && string[1]) {
			pseudo_diag("order type must be a single specifier character.\n");
			free(new_trait);
			return 0;
		}
		new_trait->data.ivalue = opt_to_field[(unsigned char) string[0]];
		if (!new_trait->data.ivalue) {
			pseudo_diag("Unknown field type: %c\n", string[0]);
		}
		break;
	case PSQF_RESULT:
		new_trait->data.ivalue = pseudo_res_id(string);
		break;
	case PSQF_SEVERITY:
		new_trait->data.ivalue = pseudo_sev_id(string);
		break;
	case PSQF_STAMP:
		new_trait->data.ivalue = parse_timestamp(string);
		if ((time_t) new_trait->data.ivalue == (time_t) -1) {
			free(new_trait);
			return 0;
		}
		break;
	case PSQF_TYPE:
		new_trait->data.ivalue = pseudo_msg_type_id(string);
		break;
	case PSQF_CLIENT:
	case PSQF_DEV:
	case PSQF_FD:
	case PSQF_GID:
	case PSQF_INODE:
	case PSQF_UID:
		new_trait->data.ivalue = strtoll(string, &endptr, 0);
		if (*endptr) {
			pseudo_diag("Unexpected garbage after number (%llu): '%s'\n",
				new_trait->data.ivalue, endptr);
			free(new_trait);
			return 0;
		}
		break;
	case PSQF_MODE:
	case PSQF_PERM:
		new_trait->data.ivalue = strtoll(string, &endptr, 8);
		if (!*endptr) {
			break;
		}
		/* maybe it's a mode string? */
		new_trait->data.ivalue = parse_mode_string(string);
		if (new_trait->data.ivalue == (mode_t) -1) {
			free(new_trait);
			return 0;
		}
		if (new_trait->field == PSQF_PERM) {
			/* mask out file type */
			new_trait->data.ivalue &= ~S_IFMT;
		}
		break;
	case PSQF_PATH:		/* FALLTHROUGH */
	case PSQF_PROGRAM:	/* FALLTHROUGH */
	case PSQF_TEXT:		/* FALLTHROUGH */
	case PSQF_TAG:
		/* Plain strings */
		new_trait->data.svalue = strdup(string);
		break;
	default:
		pseudo_diag("I don't know how I got here.  Unknown field type %d.\n",
			new_trait->field);
		free(new_trait);
		return 0;
		break;
	}
	return new_trait;
}