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