return leader;
}
+static int evlist__parse_control_fifo(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close)
+{
+ char *s, *p;
+ int ret = 0, fd;
+
+ if (strncmp(str, "fifo:", 5))
+ return -EINVAL;
+
+ str += 5;
+ if (!*str || *str == ',')
+ return -EINVAL;
+
+ s = strdup(str);
+ if (!s)
+ return -ENOMEM;
+
+ p = strchr(s, ',');
+ if (p)
+ *p = '\0';
+
+ /*
+ * O_RDWR avoids POLLHUPs which is necessary to allow the other
+ * end of a FIFO to be repeatedly opened and closed.
+ */
+ fd = open(s, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0) {
+ pr_err("Failed to open '%s'\n", s);
+ ret = -errno;
+ goto out_free;
+ }
+ *ctl_fd = fd;
+ *ctl_fd_close = true;
+
+ if (p && *++p) {
+ /* O_RDWR | O_NONBLOCK means the other end need not be open */
+ fd = open(p, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0) {
+ pr_err("Failed to open '%s'\n", p);
+ ret = -errno;
+ goto out_free;
+ }
+ *ctl_fd_ack = fd;
+ }
+
+out_free:
+ free(s);
+ return ret;
+}
+
+int evlist__parse_control(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close)
+{
+ char *comma = NULL, *endptr = NULL;
+
+ *ctl_fd_close = false;
+
+ if (strncmp(str, "fd:", 3))
+ return evlist__parse_control_fifo(str, ctl_fd, ctl_fd_ack, ctl_fd_close);
+
+ *ctl_fd = strtoul(&str[3], &endptr, 0);
+ if (endptr == &str[3])
+ return -EINVAL;
+
+ comma = strchr(str, ',');
+ if (comma) {
+ if (endptr != comma)
+ return -EINVAL;
+
+ *ctl_fd_ack = strtoul(comma + 1, &endptr, 0);
+ if (endptr == comma + 1 || *endptr != '\0')
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int evlist__initialize_ctlfd(struct evlist *evlist, int fd, int ack)
{
if (fd == -1) {
char c;
size_t bytes_read = 0;
+ *cmd = EVLIST_CTL_CMD_UNSUPPORTED;
memset(cmd_data, 0, data_size);
data_size--;
cmd_data[bytes_read++] = c;
if (bytes_read == data_size)
break;
- } else {
- if (err == -1)
+ continue;
+ } else if (err == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ err = 0;
+ else
pr_err("Failed to read from ctlfd %d: %m\n", evlist->ctl_fd.fd);
- break;
}
+ break;
} while (1);
pr_debug("Message from ctl_fd: \"%s%s\"\n", cmd_data,
bytes_read == data_size ? "" : c == '\n' ? "\\n" : "\\0");
- if (err > 0) {
+ if (bytes_read > 0) {
if (!strncmp(cmd_data, EVLIST_CTL_CMD_ENABLE_TAG,
(sizeof(EVLIST_CTL_CMD_ENABLE_TAG)-1))) {
*cmd = EVLIST_CTL_CMD_ENABLE;
}
}
- return err;
+ return bytes_read ? (int)bytes_read : err;
}
static int evlist__ctlfd_ack(struct evlist *evlist)