brintos

brintos / linux-shallow public Read only

0
0
Text · 31.4 KiB · f056843 Raw
1546 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <internal/lib.h>3#include <inttypes.h>4#include <subcmd/parse-options.h>5#include <api/fd/array.h>6#include <api/fs/fs.h>7#include <linux/zalloc.h>8#include <linux/string.h>9#include <linux/limits.h>10#include <string.h>11#include <sys/file.h>12#include <signal.h>13#include <stdlib.h>14#include <time.h>15#include <stdio.h>16#include <unistd.h>17#include <errno.h>18#include <sys/inotify.h>19#include <libgen.h>20#include <sys/types.h>21#include <sys/socket.h>22#include <sys/un.h>23#include <sys/stat.h>24#include <sys/signalfd.h>25#include <sys/wait.h>26#include <poll.h>27#include "builtin.h"28#include "perf.h"29#include "debug.h"30#include "config.h"31#include "util.h"32 33#define SESSION_OUTPUT  "output"34#define SESSION_CONTROL "control"35#define SESSION_ACK     "ack"36 37/*38 * Session states:39 *40 *   OK       - session is up and running41 *   RECONFIG - session is pending for reconfiguration,42 *              new values are already loaded in session object43 *   KILL     - session is pending to be killed44 *45 * Session object life and its state is maintained by46 * following functions:47 *48 *  setup_server_config49 *    - reads config file and setup session objects50 *      with following states:51 *52 *      OK       - no change needed53 *      RECONFIG - session needs to be changed54 *                 (run variable changed)55 *      KILL     - session needs to be killed56 *                 (session is no longer in config file)57 *58 *  daemon__reconfig59 *    - scans session objects and does following actions60 *      for states:61 *62 *      OK       - skip63 *      RECONFIG - session is killed and re-run with new config64 *      KILL     - session is killed65 *66 *    - all sessions have OK state on the function exit67 */68enum daemon_session_state {69	OK,70	RECONFIG,71	KILL,72};73 74struct daemon_session {75	char				*base;76	char				*name;77	char				*run;78	char				*control;79	int				 pid;80	struct list_head		 list;81	enum daemon_session_state	 state;82	time_t				 start;83};84 85struct daemon {86	const char		*config;87	char			*config_real;88	char			*config_base;89	const char		*csv_sep;90	const char		*base_user;91	char			*base;92	struct list_head	 sessions;93	FILE			*out;94	char			*perf;95	int			 signal_fd;96	time_t			 start;97};98 99static struct daemon __daemon = {100	.sessions = LIST_HEAD_INIT(__daemon.sessions),101};102 103static const char * const daemon_usage[] = {104	"perf daemon {start|signal|stop|ping} [<options>]",105	"perf daemon [<options>]",106	NULL107};108 109static volatile sig_atomic_t done;110 111static void sig_handler(int sig __maybe_unused)112{113	done = true;114}115 116static struct daemon_session *daemon__add_session(struct daemon *config, char *name)117{118	struct daemon_session *session = zalloc(sizeof(*session));119 120	if (!session)121		return NULL;122 123	session->name = strdup(name);124	if (!session->name) {125		free(session);126		return NULL;127	}128 129	session->pid = -1;130	list_add_tail(&session->list, &config->sessions);131	return session;132}133 134static struct daemon_session *daemon__find_session(struct daemon *daemon, char *name)135{136	struct daemon_session *session;137 138	list_for_each_entry(session, &daemon->sessions, list) {139		if (!strcmp(session->name, name))140			return session;141	}142 143	return NULL;144}145 146static int get_session_name(const char *var, char *session, int len)147{148	const char *p = var + sizeof("session-") - 1;149 150	while (*p != '.' && *p != 0x0 && len--)151		*session++ = *p++;152 153	*session = 0;154	return *p == '.' ? 0 : -EINVAL;155}156 157static int session_config(struct daemon *daemon, const char *var, const char *value)158{159	struct daemon_session *session;160	char name[100];161 162	if (get_session_name(var, name, sizeof(name) - 1))163		return -EINVAL;164 165	var = strchr(var, '.');166	if (!var)167		return -EINVAL;168 169	var++;170 171	session = daemon__find_session(daemon, name);172 173	if (!session) {174		/* New session is defined. */175		session = daemon__add_session(daemon, name);176		if (!session)177			return -ENOMEM;178 179		pr_debug("reconfig: found new session %s\n", name);180 181		/* Trigger reconfig to start it. */182		session->state = RECONFIG;183	} else if (session->state == KILL) {184		/* Current session is defined, no action needed. */185		pr_debug("reconfig: found current session %s\n", name);186		session->state = OK;187	}188 189	if (!strcmp(var, "run")) {190		bool same = false;191 192		if (session->run)193			same = !strcmp(session->run, value);194 195		if (!same) {196			if (session->run) {197				zfree(&session->run);198				pr_debug("reconfig: session %s is changed\n", name);199			}200 201			session->run = strdup(value);202			if (!session->run)203				return -ENOMEM;204 205			/*206			 * Either new or changed run value is defined,207			 * trigger reconfig for the session.208			 */209			session->state = RECONFIG;210		}211	}212 213	return 0;214}215 216static int server_config(const char *var, const char *value, void *cb)217{218	struct daemon *daemon = cb;219 220	if (strstarts(var, "session-")) {221		return session_config(daemon, var, value);222	} else if (!strcmp(var, "daemon.base") && !daemon->base_user) {223		if (daemon->base && strcmp(daemon->base, value)) {224			pr_err("failed: can't redefine base, bailing out\n");225			return -EINVAL;226		}227		daemon->base = strdup(value);228		if (!daemon->base)229			return -ENOMEM;230	}231 232	return 0;233}234 235static int client_config(const char *var, const char *value, void *cb)236{237	struct daemon *daemon = cb;238 239	if (!strcmp(var, "daemon.base") && !daemon->base_user) {240		daemon->base = strdup(value);241		if (!daemon->base)242			return -ENOMEM;243	}244 245	return 0;246}247 248static int check_base(struct daemon *daemon)249{250	struct stat st;251 252	if (!daemon->base) {253		pr_err("failed: base not defined\n");254		return -EINVAL;255	}256 257	if (stat(daemon->base, &st)) {258		switch (errno) {259		case EACCES:260			pr_err("failed: permission denied for '%s' base\n",261			       daemon->base);262			return -EACCES;263		case ENOENT:264			pr_err("failed: base '%s' does not exists\n",265			       daemon->base);266			return -EACCES;267		default:268			pr_err("failed: can't access base '%s': %s\n",269			       daemon->base, strerror(errno));270			return -errno;271		}272	}273 274	if ((st.st_mode & S_IFMT) != S_IFDIR) {275		pr_err("failed: base '%s' is not directory\n",276		       daemon->base);277		return -EINVAL;278	}279 280	return 0;281}282 283static int setup_client_config(struct daemon *daemon)284{285	struct perf_config_set *set = perf_config_set__load_file(daemon->config_real);286	int err = -ENOMEM;287 288	if (set) {289		err = perf_config_set(set, client_config, daemon);290		perf_config_set__delete(set);291	}292 293	return err ?: check_base(daemon);294}295 296static int setup_server_config(struct daemon *daemon)297{298	struct perf_config_set *set;299	struct daemon_session *session;300	int err = -ENOMEM;301 302	pr_debug("reconfig: started\n");303 304	/*305	 * Mark all sessions for kill, the server config306	 * will set following states, see explanation at307	 * enum daemon_session_state declaration.308	 */309	list_for_each_entry(session, &daemon->sessions, list)310		session->state = KILL;311 312	set = perf_config_set__load_file(daemon->config_real);313	if (set) {314		err = perf_config_set(set, server_config, daemon);315		perf_config_set__delete(set);316	}317 318	return err ?: check_base(daemon);319}320 321static int daemon_session__run(struct daemon_session *session,322			       struct daemon *daemon)323{324	char buf[PATH_MAX];325	char **argv;326	int argc, fd;327 328	if (asprintf(&session->base, "%s/session-%s",329		     daemon->base, session->name) < 0) {330		perror("failed: asprintf");331		return -1;332	}333 334	if (mkdir(session->base, 0755) && errno != EEXIST) {335		perror("failed: mkdir");336		return -1;337	}338 339	session->start = time(NULL);340 341	session->pid = fork();342	if (session->pid < 0)343		return -1;344	if (session->pid > 0) {345		pr_info("reconfig: ruining session [%s:%d]: %s\n",346			session->name, session->pid, session->run);347		return 0;348	}349 350	if (chdir(session->base)) {351		perror("failed: chdir");352		return -1;353	}354 355	fd = open("/dev/null", O_RDONLY);356	if (fd < 0) {357		perror("failed: open /dev/null");358		return -1;359	}360 361	dup2(fd, 0);362	close(fd);363 364	fd = open(SESSION_OUTPUT, O_RDWR|O_CREAT|O_TRUNC, 0644);365	if (fd < 0) {366		perror("failed: open session output");367		return -1;368	}369 370	dup2(fd, 1);371	dup2(fd, 2);372	close(fd);373 374	if (mkfifo(SESSION_CONTROL, 0600) && errno != EEXIST) {375		perror("failed: create control fifo");376		return -1;377	}378 379	if (mkfifo(SESSION_ACK, 0600) && errno != EEXIST) {380		perror("failed: create ack fifo");381		return -1;382	}383 384	scnprintf(buf, sizeof(buf), "%s record --control=fifo:%s,%s %s",385		  daemon->perf, SESSION_CONTROL, SESSION_ACK, session->run);386 387	argv = argv_split(buf, &argc);388	if (!argv)389		exit(-1);390 391	exit(execve(daemon->perf, argv, NULL));392	return -1;393}394 395static pid_t handle_signalfd(struct daemon *daemon)396{397	struct daemon_session *session;398	struct signalfd_siginfo si;399	ssize_t err;400	int status;401	pid_t pid;402 403	/*404	 * Take signal fd data as pure signal notification and check all405	 * the sessions state. The reason is that multiple signals can get406	 * coalesced in kernel and we can receive only single signal even407	 * if multiple SIGCHLD were generated.408	 */409	err = read(daemon->signal_fd, &si, sizeof(struct signalfd_siginfo));410	if (err != sizeof(struct signalfd_siginfo)) {411		pr_err("failed to read signal fd\n");412		return -1;413	}414 415	list_for_each_entry(session, &daemon->sessions, list) {416		if (session->pid == -1)417			continue;418 419		pid = waitpid(session->pid, &status, WNOHANG);420		if (pid <= 0)421			continue;422 423		if (WIFEXITED(status)) {424			pr_info("session '%s' exited, status=%d\n",425				session->name, WEXITSTATUS(status));426		} else if (WIFSIGNALED(status)) {427			pr_info("session '%s' killed (signal %d)\n",428				session->name, WTERMSIG(status));429		} else if (WIFSTOPPED(status)) {430			pr_info("session '%s' stopped (signal %d)\n",431				session->name, WSTOPSIG(status));432		} else {433			pr_info("session '%s' Unexpected status (0x%x)\n",434				session->name, status);435		}436 437		session->state = KILL;438		session->pid = -1;439	}440 441	return 0;442}443 444static int daemon_session__wait(struct daemon_session *session, struct daemon *daemon,445				int secs)446{447	struct pollfd pollfd = {448		.fd	= daemon->signal_fd,449		.events	= POLLIN,450	};451	time_t start;452 453	start = time(NULL);454 455	do {456		int err = poll(&pollfd, 1, 1000);457 458		if (err > 0) {459			handle_signalfd(daemon);460		} else if (err < 0) {461			perror("failed: poll\n");462			return -1;463		}464 465		if (start + secs < time(NULL))466			return -1;467	} while (session->pid != -1);468 469	return 0;470}471 472static bool daemon__has_alive_session(struct daemon *daemon)473{474	struct daemon_session *session;475 476	list_for_each_entry(session, &daemon->sessions, list) {477		if (session->pid != -1)478			return true;479	}480 481	return false;482}483 484static int daemon__wait(struct daemon *daemon, int secs)485{486	struct pollfd pollfd = {487		.fd	= daemon->signal_fd,488		.events	= POLLIN,489	};490	time_t start;491 492	start = time(NULL);493 494	do {495		int err = poll(&pollfd, 1, 1000);496 497		if (err > 0) {498			handle_signalfd(daemon);499		} else if (err < 0) {500			perror("failed: poll\n");501			return -1;502		}503 504		if (start + secs < time(NULL))505			return -1;506	} while (daemon__has_alive_session(daemon));507 508	return 0;509}510 511static int daemon_session__control(struct daemon_session *session,512				   const char *msg, bool do_ack)513{514	struct pollfd pollfd = { .events = POLLIN, };515	char control_path[PATH_MAX];516	char ack_path[PATH_MAX];517	int control, ack = -1, len;518	char buf[20];519	int ret = -1;520	ssize_t err;521 522	/* open the control file */523	scnprintf(control_path, sizeof(control_path), "%s/%s",524		  session->base, SESSION_CONTROL);525 526	control = open(control_path, O_WRONLY|O_NONBLOCK);527	if (control < 0)528		return -1;529 530	if (do_ack) {531		/* open the ack file */532		scnprintf(ack_path, sizeof(ack_path), "%s/%s",533			  session->base, SESSION_ACK);534 535		ack = open(ack_path, O_RDONLY, O_NONBLOCK);536		if (ack < 0) {537			close(control);538			return -1;539		}540	}541 542	/* write the command */543	len = strlen(msg);544 545	err = writen(control, msg, len);546	if (err != len) {547		pr_err("failed: write to control pipe: %d (%s)\n",548		       errno, control_path);549		goto out;550	}551 552	if (!do_ack)553		goto out;554 555	/* wait for an ack */556	pollfd.fd = ack;557 558	if (!poll(&pollfd, 1, 2000)) {559		pr_err("failed: control ack timeout\n");560		goto out;561	}562 563	if (!(pollfd.revents & POLLIN)) {564		pr_err("failed: did not received an ack\n");565		goto out;566	}567 568	err = read(ack, buf, sizeof(buf));569	if (err > 0)570		ret = strcmp(buf, "ack\n");571	else572		perror("failed: read ack %d\n");573 574out:575	if (ack != -1)576		close(ack);577 578	close(control);579	return ret;580}581 582static int setup_server_socket(struct daemon *daemon)583{584	struct sockaddr_un addr;585	char path[PATH_MAX];586	int fd = socket(AF_UNIX, SOCK_STREAM, 0);587 588	if (fd < 0) {589		fprintf(stderr, "socket: %s\n", strerror(errno));590		return -1;591	}592 593	if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {594		perror("failed: fcntl FD_CLOEXEC");595		close(fd);596		return -1;597	}598 599	scnprintf(path, sizeof(path), "%s/control", daemon->base);600 601	if (strlen(path) + 1 >= sizeof(addr.sun_path)) {602		pr_err("failed: control path too long '%s'\n", path);603		close(fd);604		return -1;605	}606 607	memset(&addr, 0, sizeof(addr));608	addr.sun_family = AF_UNIX;609 610	strlcpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);611	unlink(path);612 613	if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {614		perror("failed: bind");615		close(fd);616		return -1;617	}618 619	if (listen(fd, 1) == -1) {620		perror("failed: listen");621		close(fd);622		return -1;623	}624 625	return fd;626}627 628enum {629	CMD_LIST   = 0,630	CMD_SIGNAL = 1,631	CMD_STOP   = 2,632	CMD_PING   = 3,633	CMD_MAX,634};635 636#define SESSION_MAX 64637 638union cmd {639	int cmd;640 641	/* CMD_LIST */642	struct {643		int	cmd;644		int	verbose;645		char	csv_sep;646	} list;647 648	/* CMD_SIGNAL */649	struct {650		int	cmd;651		int	sig;652		char	name[SESSION_MAX];653	} signal;654 655	/* CMD_PING */656	struct {657		int	cmd;658		char	name[SESSION_MAX];659	} ping;660};661 662enum {663	PING_OK	  = 0,664	PING_FAIL = 1,665	PING_MAX,666};667 668static int daemon_session__ping(struct daemon_session *session)669{670	return daemon_session__control(session, "ping", true) ?  PING_FAIL : PING_OK;671}672 673static int cmd_session_list(struct daemon *daemon, union cmd *cmd, FILE *out)674{675	char csv_sep = cmd->list.csv_sep;676	struct daemon_session *session;677	time_t curr = time(NULL);678 679	if (csv_sep) {680		fprintf(out, "%d%c%s%c%s%c%s/%s",681			/* pid daemon  */682			getpid(), csv_sep, "daemon",683			/* base */684			csv_sep, daemon->base,685			/* output */686			csv_sep, daemon->base, SESSION_OUTPUT);687 688		fprintf(out, "%c%s/%s",689			/* lock */690			csv_sep, daemon->base, "lock");691 692		fprintf(out, "%c%" PRIu64,693			/* session up time */694			csv_sep, (uint64_t)((curr - daemon->start) / 60));695 696		fprintf(out, "\n");697	} else {698		fprintf(out, "[%d:daemon] base: %s\n", getpid(), daemon->base);699		if (cmd->list.verbose) {700			fprintf(out, "  output:  %s/%s\n",701				daemon->base, SESSION_OUTPUT);702			fprintf(out, "  lock:    %s/lock\n",703				daemon->base);704			fprintf(out, "  up:      %" PRIu64 " minutes\n",705				(uint64_t)((curr - daemon->start) / 60));706		}707	}708 709	list_for_each_entry(session, &daemon->sessions, list) {710		if (csv_sep) {711			fprintf(out, "%d%c%s%c%s",712				/* pid */713				session->pid,714				/* name */715				csv_sep, session->name,716				/* base */717				csv_sep, session->run);718 719			fprintf(out, "%c%s%c%s/%s",720				/* session dir */721				csv_sep, session->base,722				/* session output */723				csv_sep, session->base, SESSION_OUTPUT);724 725			fprintf(out, "%c%s/%s%c%s/%s",726				/* session control */727				csv_sep, session->base, SESSION_CONTROL,728				/* session ack */729				csv_sep, session->base, SESSION_ACK);730 731			fprintf(out, "%c%" PRIu64,732				/* session up time */733				csv_sep, (uint64_t)((curr - session->start) / 60));734 735			fprintf(out, "\n");736		} else {737			fprintf(out, "[%d:%s] perf record %s\n",738				session->pid, session->name, session->run);739			if (!cmd->list.verbose)740				continue;741			fprintf(out, "  base:    %s\n",742				session->base);743			fprintf(out, "  output:  %s/%s\n",744				session->base, SESSION_OUTPUT);745			fprintf(out, "  control: %s/%s\n",746				session->base, SESSION_CONTROL);747			fprintf(out, "  ack:     %s/%s\n",748				session->base, SESSION_ACK);749			fprintf(out, "  up:      %" PRIu64 " minutes\n",750				(uint64_t)((curr - session->start) / 60));751		}752	}753 754	return 0;755}756 757static int daemon_session__signal(struct daemon_session *session, int sig)758{759	if (session->pid < 0)760		return -1;761	return kill(session->pid, sig);762}763 764static int cmd_session_kill(struct daemon *daemon, union cmd *cmd, FILE *out)765{766	struct daemon_session *session;767	bool all = false;768 769	all = !strcmp(cmd->signal.name, "all");770 771	list_for_each_entry(session, &daemon->sessions, list) {772		if (all || !strcmp(cmd->signal.name, session->name)) {773			daemon_session__signal(session, cmd->signal.sig);774			fprintf(out, "signal %d sent to session '%s [%d]'\n",775				cmd->signal.sig, session->name, session->pid);776		}777	}778 779	return 0;780}781 782static const char *ping_str[PING_MAX] = {783	[PING_OK]   = "OK",784	[PING_FAIL] = "FAIL",785};786 787static int cmd_session_ping(struct daemon *daemon, union cmd *cmd, FILE *out)788{789	struct daemon_session *session;790	bool all = false, found = false;791 792	all = !strcmp(cmd->ping.name, "all");793 794	list_for_each_entry(session, &daemon->sessions, list) {795		if (all || !strcmp(cmd->ping.name, session->name)) {796			int state = daemon_session__ping(session);797 798			fprintf(out, "%-4s %s\n", ping_str[state], session->name);799			found = true;800		}801	}802 803	if (!found && !all) {804		fprintf(out, "%-4s %s (not found)\n",805			ping_str[PING_FAIL], cmd->ping.name);806	}807	return 0;808}809 810static int handle_server_socket(struct daemon *daemon, int sock_fd)811{812	int ret = -1, fd;813	FILE *out = NULL;814	union cmd cmd;815 816	fd = accept(sock_fd, NULL, NULL);817	if (fd < 0) {818		perror("failed: accept");819		return -1;820	}821 822	if (sizeof(cmd) != readn(fd, &cmd, sizeof(cmd))) {823		perror("failed: read");824		goto out;825	}826 827	out = fdopen(fd, "w");828	if (!out) {829		perror("failed: fdopen");830		goto out;831	}832 833	switch (cmd.cmd) {834	case CMD_LIST:835		ret = cmd_session_list(daemon, &cmd, out);836		break;837	case CMD_SIGNAL:838		ret = cmd_session_kill(daemon, &cmd, out);839		break;840	case CMD_STOP:841		done = 1;842		ret = 0;843		pr_debug("perf daemon is exciting\n");844		break;845	case CMD_PING:846		ret = cmd_session_ping(daemon, &cmd, out);847		break;848	default:849		break;850	}851 852	fclose(out);853out:854	/* If out is defined, then fd is closed via fclose. */855	if (!out)856		close(fd);857	return ret;858}859 860static int setup_client_socket(struct daemon *daemon)861{862	struct sockaddr_un addr;863	char path[PATH_MAX];864	int fd = socket(AF_UNIX, SOCK_STREAM, 0);865 866	if (fd == -1) {867		perror("failed: socket");868		return -1;869	}870 871	scnprintf(path, sizeof(path), "%s/control", daemon->base);872 873	if (strlen(path) + 1 >= sizeof(addr.sun_path)) {874		pr_err("failed: control path too long '%s'\n", path);875		close(fd);876		return -1;877	}878 879	memset(&addr, 0, sizeof(addr));880	addr.sun_family = AF_UNIX;881	strlcpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);882 883	if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {884		perror("failed: connect");885		close(fd);886		return -1;887	}888 889	return fd;890}891 892static void daemon_session__kill(struct daemon_session *session,893				 struct daemon *daemon)894{895	int how = 0;896 897	do {898		switch (how) {899		case 0:900			daemon_session__control(session, "stop", false);901			break;902		case 1:903			daemon_session__signal(session, SIGTERM);904			break;905		case 2:906			daemon_session__signal(session, SIGKILL);907			break;908		default:909			pr_err("failed to wait for session %s\n",910			       session->name);911			return;912		}913		how++;914 915	} while (daemon_session__wait(session, daemon, 10));916}917 918static void daemon__signal(struct daemon *daemon, int sig)919{920	struct daemon_session *session;921 922	list_for_each_entry(session, &daemon->sessions, list)923		daemon_session__signal(session, sig);924}925 926static void daemon_session__delete(struct daemon_session *session)927{928	zfree(&session->base);929	zfree(&session->name);930	zfree(&session->run);931	free(session);932}933 934static void daemon_session__remove(struct daemon_session *session)935{936	list_del(&session->list);937	daemon_session__delete(session);938}939 940static void daemon__stop(struct daemon *daemon)941{942	struct daemon_session *session;943 944	list_for_each_entry(session, &daemon->sessions, list)945		daemon_session__control(session, "stop", false);946}947 948static void daemon__kill(struct daemon *daemon)949{950	int how = 0;951 952	do {953		switch (how) {954		case 0:955			daemon__stop(daemon);956			break;957		case 1:958			daemon__signal(daemon, SIGTERM);959			break;960		case 2:961			daemon__signal(daemon, SIGKILL);962			break;963		default:964			pr_err("failed to wait for sessions\n");965			return;966		}967		how++;968 969	} while (daemon__wait(daemon, 10));970}971 972static void daemon__exit(struct daemon *daemon)973{974	struct daemon_session *session, *h;975 976	list_for_each_entry_safe(session, h, &daemon->sessions, list)977		daemon_session__remove(session);978 979	zfree(&daemon->config_real);980	zfree(&daemon->config_base);981	zfree(&daemon->base);982}983 984static int daemon__reconfig(struct daemon *daemon)985{986	struct daemon_session *session, *n;987 988	list_for_each_entry_safe(session, n, &daemon->sessions, list) {989		/* No change. */990		if (session->state == OK)991			continue;992 993		/* Remove session. */994		if (session->state == KILL) {995			if (session->pid > 0) {996				daemon_session__kill(session, daemon);997				pr_info("reconfig: session '%s' killed\n", session->name);998			}999			daemon_session__remove(session);1000			continue;1001		}1002 1003		/* Reconfig session. */1004		if (session->pid > 0) {1005			daemon_session__kill(session, daemon);1006			pr_info("reconfig: session '%s' killed\n", session->name);1007		}1008		if (daemon_session__run(session, daemon))1009			return -1;1010 1011		session->state = OK;1012	}1013 1014	return 0;1015}1016 1017static int setup_config_changes(struct daemon *daemon)1018{1019	char *basen = strdup(daemon->config_real);1020	char *dirn  = strdup(daemon->config_real);1021	char *base, *dir;1022	int fd, wd = -1;1023 1024	if (!dirn || !basen)1025		goto out;1026 1027	fd = inotify_init1(IN_NONBLOCK|O_CLOEXEC);1028	if (fd < 0) {1029		perror("failed: inotify_init");1030		goto out;1031	}1032 1033	dir = dirname(dirn);1034	base = basename(basen);1035	pr_debug("config file: %s, dir: %s\n", base, dir);1036 1037	wd = inotify_add_watch(fd, dir, IN_CLOSE_WRITE);1038	if (wd >= 0) {1039		daemon->config_base = strdup(base);1040		if (!daemon->config_base) {1041			close(fd);1042			wd = -1;1043		}1044	} else {1045		perror("failed: inotify_add_watch");1046	}1047 1048out:1049	free(basen);1050	free(dirn);1051	return wd < 0 ? -1 : fd;1052}1053 1054static bool process_inotify_event(struct daemon *daemon, char *buf, ssize_t len)1055{1056	char *p = buf;1057 1058	while (p < (buf + len)) {1059		struct inotify_event *event = (struct inotify_event *) p;1060 1061		/*1062		 * We monitor config directory, check if our1063		 * config file was changes.1064		 */1065		if ((event->mask & IN_CLOSE_WRITE) &&1066		    !(event->mask & IN_ISDIR)) {1067			if (!strcmp(event->name, daemon->config_base))1068				return true;1069		}1070		p += sizeof(*event) + event->len;1071	}1072	return false;1073}1074 1075static int handle_config_changes(struct daemon *daemon, int conf_fd,1076				 bool *config_changed)1077{1078	char buf[4096];1079	ssize_t len;1080 1081	while (!(*config_changed)) {1082		len = read(conf_fd, buf, sizeof(buf));1083		if (len == -1) {1084			if (errno != EAGAIN) {1085				perror("failed: read");1086				return -1;1087			}1088			return 0;1089		}1090		*config_changed = process_inotify_event(daemon, buf, len);1091	}1092	return 0;1093}1094 1095static int setup_config(struct daemon *daemon)1096{1097	if (daemon->base_user) {1098		daemon->base = strdup(daemon->base_user);1099		if (!daemon->base)1100			return -ENOMEM;1101	}1102 1103	if (daemon->config) {1104		char *real = realpath(daemon->config, NULL);1105 1106		if (!real) {1107			perror("failed: realpath");1108			return -1;1109		}1110		daemon->config_real = real;1111		return 0;1112	}1113 1114	if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK))1115		daemon->config_real = strdup(perf_etc_perfconfig());1116	else if (perf_config_global() && perf_home_perfconfig())1117		daemon->config_real = strdup(perf_home_perfconfig());1118 1119	return daemon->config_real ? 0 : -1;1120}1121 1122#ifndef F_TLOCK1123#define F_TLOCK 21124 1125static int lockf(int fd, int cmd, off_t len)1126{1127	if (cmd != F_TLOCK || len != 0)1128		return -1;1129 1130	return flock(fd, LOCK_EX | LOCK_NB);1131}1132#endif // F_TLOCK1133 1134/*1135 * Each daemon tries to create and lock BASE/lock file,1136 * if it's successful we are sure we're the only daemon1137 * running over the BASE.1138 *1139 * Once daemon is finished, file descriptor to lock file1140 * is closed and lock is released.1141 */1142static int check_lock(struct daemon *daemon)1143{1144	char path[PATH_MAX];1145	char buf[20];1146	int fd, pid;1147	ssize_t len;1148 1149	scnprintf(path, sizeof(path), "%s/lock", daemon->base);1150 1151	fd = open(path, O_RDWR|O_CREAT|O_CLOEXEC, 0640);1152	if (fd < 0)1153		return -1;1154 1155	if (lockf(fd, F_TLOCK, 0) < 0) {1156		filename__read_int(path, &pid);1157		fprintf(stderr, "failed: another perf daemon (pid %d) owns %s\n",1158			pid, daemon->base);1159		close(fd);1160		return -1;1161	}1162 1163	scnprintf(buf, sizeof(buf), "%d", getpid());1164	len = strlen(buf);1165 1166	if (write(fd, buf, len) != len) {1167		perror("failed: write");1168		close(fd);1169		return -1;1170	}1171 1172	if (ftruncate(fd, len)) {1173		perror("failed: ftruncate");1174		close(fd);1175		return -1;1176	}1177 1178	return 0;1179}1180 1181static int go_background(struct daemon *daemon)1182{1183	int pid, fd;1184 1185	pid = fork();1186	if (pid < 0)1187		return -1;1188 1189	if (pid > 0)1190		return 1;1191 1192	if (setsid() < 0)1193		return -1;1194 1195	if (check_lock(daemon))1196		return -1;1197 1198	umask(0);1199 1200	if (chdir(daemon->base)) {1201		perror("failed: chdir");1202		return -1;1203	}1204 1205	fd = open("output", O_RDWR|O_CREAT|O_TRUNC, 0644);1206	if (fd < 0) {1207		perror("failed: open");1208		return -1;1209	}1210 1211	if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {1212		perror("failed: fcntl FD_CLOEXEC");1213		close(fd);1214		return -1;1215	}1216 1217	close(0);1218	dup2(fd, 1);1219	dup2(fd, 2);1220	close(fd);1221 1222	daemon->out = fdopen(1, "w");1223	if (!daemon->out) {1224		close(1);1225		close(2);1226		return -1;1227	}1228 1229	setbuf(daemon->out, NULL);1230	return 0;1231}1232 1233static int setup_signalfd(struct daemon *daemon)1234{1235	sigset_t mask;1236 1237	sigemptyset(&mask);1238	sigaddset(&mask, SIGCHLD);1239 1240	if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)1241		return -1;1242 1243	daemon->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);1244	return daemon->signal_fd;1245}1246 1247static int __cmd_start(struct daemon *daemon, struct option parent_options[],1248		       int argc, const char **argv)1249{1250	bool foreground = false;1251	struct option start_options[] = {1252		OPT_BOOLEAN('f', "foreground", &foreground, "stay on console"),1253		OPT_PARENT(parent_options),1254		OPT_END()1255	};1256	int sock_fd = -1, conf_fd = -1, signal_fd = -1;1257	int sock_pos, file_pos, signal_pos;1258	struct fdarray fda;1259	int err = 0;1260 1261	argc = parse_options(argc, argv, start_options, daemon_usage, 0);1262	if (argc)1263		usage_with_options(daemon_usage, start_options);1264 1265	daemon->start = time(NULL);1266 1267	if (setup_config(daemon)) {1268		pr_err("failed: config not found\n");1269		return -1;1270	}1271 1272	if (setup_server_config(daemon))1273		return -1;1274 1275	if (foreground && check_lock(daemon))1276		return -1;1277 1278	if (!foreground) {1279		err = go_background(daemon);1280		if (err) {1281			/* original process, exit normally */1282			if (err == 1)1283				err = 0;1284			daemon__exit(daemon);1285			return err;1286		}1287	}1288 1289	debug_set_file(daemon->out);1290	debug_set_display_time(true);1291 1292	pr_info("daemon started (pid %d)\n", getpid());1293 1294	fdarray__init(&fda, 3);1295 1296	sock_fd = setup_server_socket(daemon);1297	if (sock_fd < 0)1298		goto out;1299 1300	conf_fd = setup_config_changes(daemon);1301	if (conf_fd < 0)1302		goto out;1303 1304	signal_fd = setup_signalfd(daemon);1305	if (signal_fd < 0)1306		goto out;1307 1308	sock_pos = fdarray__add(&fda, sock_fd, POLLIN|POLLERR|POLLHUP, 0);1309	if (sock_pos < 0)1310		goto out;1311 1312	file_pos = fdarray__add(&fda, conf_fd, POLLIN|POLLERR|POLLHUP, 0);1313	if (file_pos < 0)1314		goto out;1315 1316	signal_pos = fdarray__add(&fda, signal_fd, POLLIN|POLLERR|POLLHUP, 0);1317	if (signal_pos < 0)1318		goto out;1319 1320	signal(SIGINT, sig_handler);1321	signal(SIGTERM, sig_handler);1322	signal(SIGPIPE, SIG_IGN);1323 1324	while (!done && !err) {1325		err = daemon__reconfig(daemon);1326 1327		if (!err && fdarray__poll(&fda, -1)) {1328			bool reconfig = false;1329 1330			if (fda.entries[sock_pos].revents & POLLIN)1331				err = handle_server_socket(daemon, sock_fd);1332			if (fda.entries[file_pos].revents & POLLIN)1333				err = handle_config_changes(daemon, conf_fd, &reconfig);1334			if (fda.entries[signal_pos].revents & POLLIN)1335				err = handle_signalfd(daemon) < 0;1336 1337			if (reconfig)1338				err = setup_server_config(daemon);1339		}1340	}1341 1342out:1343	fdarray__exit(&fda);1344 1345	daemon__kill(daemon);1346	daemon__exit(daemon);1347 1348	if (sock_fd != -1)1349		close(sock_fd);1350	if (conf_fd != -1)1351		close(conf_fd);1352	if (signal_fd != -1)1353		close(signal_fd);1354 1355	pr_info("daemon exited\n");1356	fclose(daemon->out);1357	return err;1358}1359 1360static int send_cmd(struct daemon *daemon, union cmd *cmd)1361{1362	int ret = -1, fd;1363	char *line = NULL;1364	size_t len = 0;1365	ssize_t nread;1366	FILE *in = NULL;1367 1368	if (setup_client_config(daemon))1369		return -1;1370 1371	fd = setup_client_socket(daemon);1372	if (fd < 0)1373		return -1;1374 1375	if (sizeof(*cmd) != writen(fd, cmd, sizeof(*cmd))) {1376		perror("failed: write");1377		goto out;1378	}1379 1380	in = fdopen(fd, "r");1381	if (!in) {1382		perror("failed: fdopen");1383		goto out;1384	}1385 1386	while ((nread = getline(&line, &len, in)) != -1) {1387		if (fwrite(line, nread, 1, stdout) != 1)1388			goto out_fclose;1389		fflush(stdout);1390	}1391 1392	ret = 0;1393out_fclose:1394	fclose(in);1395	free(line);1396out:1397	/* If in is defined, then fd is closed via fclose. */1398	if (!in)1399		close(fd);1400	return ret;1401}1402 1403static int send_cmd_list(struct daemon *daemon)1404{1405	union cmd cmd;1406 1407	memset(&cmd, 0, sizeof(cmd));1408	cmd.list.cmd = CMD_LIST;1409	cmd.list.verbose = verbose;1410	cmd.list.csv_sep = daemon->csv_sep ? *daemon->csv_sep : 0;1411 1412	return send_cmd(daemon, &cmd);1413}1414 1415static int __cmd_signal(struct daemon *daemon, struct option parent_options[],1416			int argc, const char **argv)1417{1418	const char *name = "all";1419	struct option start_options[] = {1420		OPT_STRING(0, "session", &name, "session",1421			"Sent signal to specific session"),1422		OPT_PARENT(parent_options),1423		OPT_END()1424	};1425	union cmd cmd;1426 1427	argc = parse_options(argc, argv, start_options, daemon_usage, 0);1428	if (argc)1429		usage_with_options(daemon_usage, start_options);1430 1431	if (setup_config(daemon)) {1432		pr_err("failed: config not found\n");1433		return -1;1434	}1435 1436	memset(&cmd, 0, sizeof(cmd));1437	cmd.signal.cmd = CMD_SIGNAL;1438	cmd.signal.sig = SIGUSR2;1439	strncpy(cmd.signal.name, name, sizeof(cmd.signal.name) - 1);1440 1441	return send_cmd(daemon, &cmd);1442}1443 1444static int __cmd_stop(struct daemon *daemon, struct option parent_options[],1445			int argc, const char **argv)1446{1447	struct option start_options[] = {1448		OPT_PARENT(parent_options),1449		OPT_END()1450	};1451	union cmd cmd;1452 1453	argc = parse_options(argc, argv, start_options, daemon_usage, 0);1454	if (argc)1455		usage_with_options(daemon_usage, start_options);1456 1457	if (setup_config(daemon)) {1458		pr_err("failed: config not found\n");1459		return -1;1460	}1461 1462	memset(&cmd, 0, sizeof(cmd));1463	cmd.cmd = CMD_STOP;1464	return send_cmd(daemon, &cmd);1465}1466 1467static int __cmd_ping(struct daemon *daemon, struct option parent_options[],1468		      int argc, const char **argv)1469{1470	const char *name = "all";1471	struct option ping_options[] = {1472		OPT_STRING(0, "session", &name, "session",1473			"Ping to specific session"),1474		OPT_PARENT(parent_options),1475		OPT_END()1476	};1477	union cmd cmd;1478 1479	argc = parse_options(argc, argv, ping_options, daemon_usage, 0);1480	if (argc)1481		usage_with_options(daemon_usage, ping_options);1482 1483	if (setup_config(daemon)) {1484		pr_err("failed: config not found\n");1485		return -1;1486	}1487 1488	memset(&cmd, 0, sizeof(cmd));1489	cmd.cmd = CMD_PING;1490	scnprintf(cmd.ping.name, sizeof(cmd.ping.name), "%s", name);1491	return send_cmd(daemon, &cmd);1492}1493 1494static char *alloc_perf_exe_path(void)1495{1496	char path[PATH_MAX];1497 1498	perf_exe(path, sizeof(path));1499	return strdup(path);1500}1501 1502int cmd_daemon(int argc, const char **argv)1503{1504	struct option daemon_options[] = {1505		OPT_INCR('v', "verbose", &verbose, "be more verbose"),1506		OPT_STRING(0, "config", &__daemon.config,1507			"config file", "config file path"),1508		OPT_STRING(0, "base", &__daemon.base_user,1509			"directory", "base directory"),1510		OPT_STRING_OPTARG('x', "field-separator", &__daemon.csv_sep,1511			"field separator", "print counts with custom separator", ","),1512		OPT_END()1513	};1514	int ret = -1;1515 1516	__daemon.perf = alloc_perf_exe_path();1517	if (!__daemon.perf)1518		return -ENOMEM;1519 1520	__daemon.out = stdout;1521 1522	argc = parse_options(argc, argv, daemon_options, daemon_usage,1523			     PARSE_OPT_STOP_AT_NON_OPTION);1524 1525	if (argc) {1526		if (!strcmp(argv[0], "start"))1527			ret = __cmd_start(&__daemon, daemon_options, argc, argv);1528		else if (!strcmp(argv[0], "signal"))1529			ret = __cmd_signal(&__daemon, daemon_options, argc, argv);1530		else if (!strcmp(argv[0], "stop"))1531			ret = __cmd_stop(&__daemon, daemon_options, argc, argv);1532		else if (!strcmp(argv[0], "ping"))1533			ret = __cmd_ping(&__daemon, daemon_options, argc, argv);1534		else1535			pr_err("failed: unknown command '%s'\n", argv[0]);1536	} else {1537		ret = setup_config(&__daemon);1538		if (ret)1539			pr_err("failed: config not found\n");1540		else1541			ret = send_cmd_list(&__daemon);1542	}1543	zfree(&__daemon.perf);1544	return ret;1545}1546