Skip to content

Commit

Permalink
perf daemon: Add client socket support
Browse files Browse the repository at this point in the history
Add support for client socket side that will be used to send commands to
the daemon server socket.

This patch adds only the core support, all commands using this
functionality are coming in the following patches.

Committer notes:

Hat to patch patch it to deal with this in some systems:

  cc1: warnings being treated as errors
  builtin-daemon.c: In function 'send_cmd':  MKDIR    /tmp/build/perf/bench/

  builtin-daemon.c:1368: error: ignoring return value of 'fwrite', declared with attribute warn_unused_result
    MKDIR    /tmp/build/perf/tests/
  make[3]: *** [/tmp/build/perf/builtin-daemon.o] Error 1

And also to not leak the 'line' buffer allocated by getline(), since you
initialized line to NULL and len to zero, man page says:

  If *lineptr is set to NULL and *n is set 0 before the call,
  then getline() will allocate a buffer for storing the line.
  This buffer should be freed by the user program even if
  getline() failed.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Budankov <abudankov@huawei.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: https://lore.kernel.org/r/20210208200908.1019149-6-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Jiri Olsa authored and Arnaldo Carvalho de Melo committed Feb 11, 2021
1 parent ed36b70 commit 90b0aad
Showing 1 changed file with 138 additions and 0 deletions.
138 changes: 138 additions & 0 deletions tools/perf/builtin-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <poll.h>
#include "builtin.h"
#include "perf.h"
Expand Down Expand Up @@ -44,6 +45,67 @@ static void sig_handler(int sig __maybe_unused)
done = true;
}

static int client_config(const char *var, const char *value, void *cb)
{
struct daemon *daemon = cb;

if (!strcmp(var, "daemon.base") && !daemon->base_user) {
daemon->base = strdup(value);
if (!daemon->base)
return -ENOMEM;
}

return 0;
}

static int check_base(struct daemon *daemon)
{
struct stat st;

if (!daemon->base) {
pr_err("failed: base not defined\n");
return -EINVAL;
}

if (stat(daemon->base, &st)) {
switch (errno) {
case EACCES:
pr_err("failed: permission denied for '%s' base\n",
daemon->base);
return -EACCES;
case ENOENT:
pr_err("failed: base '%s' does not exists\n",
daemon->base);
return -EACCES;
default:
pr_err("failed: can't access base '%s': %s\n",
daemon->base, strerror(errno));
return -errno;
}
}

if ((st.st_mode & S_IFMT) != S_IFDIR) {
pr_err("failed: base '%s' is not directory\n",
daemon->base);
return -EINVAL;
}

return 0;
}

static int setup_client_config(struct daemon *daemon)
{
struct perf_config_set *set = perf_config_set__load_file(daemon->config_real);
int err = -ENOMEM;

if (set) {
err = perf_config_set(set, client_config, daemon);
perf_config_set__delete(set);
}

return err ?: check_base(daemon);
}

static int setup_server_socket(struct daemon *daemon)
{
struct sockaddr_un addr;
Expand Down Expand Up @@ -130,6 +192,38 @@ static int handle_server_socket(struct daemon *daemon __maybe_unused, int sock_f
return ret;
}

static int setup_client_socket(struct daemon *daemon)
{
struct sockaddr_un addr;
char path[PATH_MAX];
int fd = socket(AF_UNIX, SOCK_STREAM, 0);

if (fd == -1) {
perror("failed: socket");
return -1;
}

scnprintf(path, sizeof(path), "%s/control", daemon->base);

if (strlen(path) + 1 >= sizeof(addr.sun_path)) {
pr_err("failed: control path too long '%s'\n", path);
close(fd);
return -1;
}

memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strlcpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);

if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
perror("failed: connect");
close(fd);
return -1;
}

return fd;
}

static void daemon__exit(struct daemon *daemon)
{
free(daemon->config_real);
Expand Down Expand Up @@ -222,6 +316,50 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[],
return err;
}

__maybe_unused
static int send_cmd(struct daemon *daemon, union cmd *cmd)
{
int ret = -1, fd;
char *line = NULL;
size_t len = 0;
ssize_t nread;
FILE *in = NULL;

if (setup_client_config(daemon))
return -1;

fd = setup_client_socket(daemon);
if (fd < 0)
return -1;

if (sizeof(*cmd) != writen(fd, cmd, sizeof(*cmd))) {
perror("failed: write");
goto out;
}

in = fdopen(fd, "r");
if (!in) {
perror("failed: fdopen");
goto out;
}

while ((nread = getline(&line, &len, in)) != -1) {
if (fwrite(line, nread, 1, stdout) != 1)
goto out_fclose;
fflush(stdout);
}

ret = 0;
out_fclose:
fclose(in);
free(line);
out:
/* If in is defined, then fd is closed via fclose. */
if (!in)
close(fd);
return ret;
}

int cmd_daemon(int argc, const char **argv)
{
struct option daemon_options[] = {
Expand Down

0 comments on commit 90b0aad

Please sign in to comment.