obmc-console: switch to use forked repo switch to use forked google owned repo and remove the patch Tested: All build Fusion: http://fusion2/2d1e92f6-f77b-3088-baf8-15095536d26f http://fusion2/ed562648-9715-3fe0-b8c2-05525bbd7ae4 http://fusion2/8b276b1b-4b2b-3b86-9d17-513197696d31 http://fusion2/3d123260-2768-3e32-aae5-44fa73bc18ee Platforms-Affected: platform31, platform24 Google-Bug-Id: 448789715 Google-Bug-Id: 431856114 Change-Id: I1d5818c5b3e0b8ce3b36c0510b8161dd3ce48c89 Signed-off-by: Dan Zhang <zhdaniel@google.com> (cherry picked from commit 250abe4fe99bf86b5ca441ff422781ecb3f8a688)
diff --git a/recipes-phosphor/console/obmc-console/0001-Add-syslog-handler.patch b/recipes-phosphor/console/obmc-console/0001-Add-syslog-handler.patch deleted file mode 100644 index 627ca81..0000000 --- a/recipes-phosphor/console/obmc-console/0001-Add-syslog-handler.patch +++ /dev/null
@@ -1,269 +0,0 @@ -From 519776d4d291dd5655bd648ebfd0a5a48f08a82b Mon Sep 17 00:00:00 2001 -From: Dan Zhang <zhdaniel@google.com> -Date: Mon, 20 May 2024 22:02:21 +0000 -Subject: [PATCH 1/5] Add syslog-handler - -Log the console data to syslog when syslogid configured. -Will buffer small piece of data to avoid overwhelming the syslog with -small message. The buffer delay threshold set to 1 second. log threshold -is 1KB. - -The data will be logged line by line, line longer than 1K will be -breaked into multiple log messages. Filter out non-printable characters. - -Change-Id: I21698a36b11b064d75b9846e54bb12848e2d8bfa -Signed-off-by: Dan Zhang <zhdaniel@google.com> ---- - meson.build | 1 + - syslog-handler.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 228 insertions(+) - create mode 100644 syslog-handler.c - -diff --git a/meson.build b/meson.build -index 06a7200..a604223 100644 ---- a/meson.build -+++ b/meson.build -@@ -60,6 +60,7 @@ executable('obmc-console-server', - 'log-handler.c', - 'ringbuffer.c', - 'socket-handler.c', -+ 'syslog-handler.c', - 'tty-handler.c', - 'util.c', - c_args: [ -diff --git a/syslog-handler.c b/syslog-handler.c -new file mode 100644 -index 0000000..b374683 ---- /dev/null -+++ b/syslog-handler.c -@@ -0,0 +1,227 @@ -+/** -+ * Copyright © 2024 Google -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#include <ctype.h> -+#include <endian.h> -+#include <err.h> -+#include <fcntl.h> -+#include <stdbool.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <sys/syslog.h> -+#include <unistd.h> -+#include <syslog.h> -+ -+#include <sys/mman.h> -+ -+#include <linux/types.h> -+ -+#include "console-server.h" -+ -+/* syslog data buffering size threshold 1KB */ -+#define SYSLOG_HANDLER_BUF_SIZE_THRESHOLD 1024 -+ -+#define min(a, b) ((a) < (b) ? (a) : (b)) -+ -+static struct timeval const syslog_ts_low_precision = { -+ .tv_sec = 1, -+ .tv_usec = 0, -+}; -+static struct timeval const syslog_ts_high_precision = { -+ .tv_sec = 0, -+ .tv_usec = 100000, /* 100 ms */ -+}; -+static struct timeval const *syslog_handler_timeout = &syslog_ts_low_precision; -+ -+struct syslog_handler { -+ struct handler handler; -+ struct console *console; -+ struct poller *poller; -+ struct ringbuffer_consumer *rbc; -+ char *syslogid; -+ int pipefd[2]; -+ size_t curser; -+ char line[SYSLOG_HANDLER_BUF_SIZE_THRESHOLD + 1]; -+}; -+ -+static struct syslog_handler *to_syslog_handler(struct handler *handler) -+{ -+ return container_of(handler, struct syslog_handler, handler); -+} -+ -+/* -+ * Log the data line by line, line longer than 1K will be break into multiple lines. -+ * Take '\n','\r' or '\0' as line break, filter out non-printable characters. -+ */ -+static void syslog_data_as_canonical_line(struct syslog_handler *lh, -+ const uint8_t *data, -+ size_t to_log_len) -+{ -+ const char *p = (const char *)data; -+ const char *end = p + to_log_len; -+ char *line = lh->line; -+ size_t wi = lh->curser; -+ while (p < end) { -+ if (isprint(*p)) { -+ line[wi++] = *p; -+ } else { -+ if ((*p == '\0' || *p == '\n' || *p == '\r') && wi) { -+ /* log non-empty line */ -+ line[wi] = '\0'; -+ syslog(LOG_INFO, "%s", line); -+ wi = 0; -+ } -+ } -+ p++; -+ /* force line break */ -+ if (wi == SYSLOG_HANDLER_BUF_SIZE_THRESHOLD) { -+ line[wi] = '\0'; -+ syslog(LOG_INFO, "%s", line); -+ wi = 0; -+ } -+ } -+ lh->curser = wi; -+} -+ -+static void syslog_drain_queue(struct syslog_handler *lh, size_t to_drain_len) -+{ -+ uint8_t *buf; -+ size_t drained_len = 0; -+ -+ while (to_drain_len) { -+ size_t len = -+ ringbuffer_dequeue_peek(lh->rbc, drained_len, &buf); -+ if (len == 0) { -+ break; -+ } -+ len = min(to_drain_len, len); -+ syslog_data_as_canonical_line(lh, buf, len); -+ ringbuffer_dequeue_commit(lh->rbc, len); -+ drained_len += len; -+ to_drain_len -= len; -+ } -+} -+ -+static enum ringbuffer_poll_ret syslog_ringbuffer_poll(void *arg, -+ size_t force_len) -+{ -+ struct syslog_handler *lh = arg; -+ size_t len; -+ -+ if (force_len) { -+ /* Drain only force_len when blocking ringbuf enque console input */ -+ syslog_drain_queue(lh, force_len); -+ return RINGBUFFER_POLL_OK; -+ } -+ -+ len = ringbuffer_len(lh->rbc); -+ if (len < SYSLOG_HANDLER_BUF_SIZE_THRESHOLD) { -+ /* Buffer the console data unitl more than 1K or idle 1 second -+ to push the data to syslog */ -+ console_poller_set_timeout(lh->console, lh->poller, -+ syslog_handler_timeout); -+ return RINGBUFFER_POLL_OK; -+ } -+ syslog_drain_queue(lh, len); -+ return RINGBUFFER_POLL_OK; -+} -+ -+static enum poller_ret dummy_poll(struct handler *handler, int events, -+ void *data) -+{ -+ /* shall not get called */ -+ warn("Unexpected dummy_poll call handler = %p, event = 0x%8X, data = %p", -+ (void *)handler, events, data); -+ return POLLER_EXIT; -+} -+ -+static enum poller_ret accum_timeout(struct handler *handler, -+ void *data __attribute__((unused))) -+{ -+ struct syslog_handler *lh = to_syslog_handler(handler); -+ size_t len = ringbuffer_len(lh->rbc); -+ -+ syslog_drain_queue(lh, len); -+ return POLLER_OK; -+} -+ -+static int syslog_init(struct handler *handler, struct console *console, -+ struct config *config) -+{ -+ struct syslog_handler *lh = to_syslog_handler(handler); -+ const char *syslogid; -+ const char *ts_high_precision; -+ -+ lh->console = console; -+ lh->poller = NULL; -+ lh->rbc = NULL; -+ lh->syslogid = NULL; -+ lh->curser = 0; -+ -+ syslogid = config_get_value(config, "syslogid"); -+ if (syslogid == NULL) { -+ warnx("syslogid is not configured, not emit console log to syslog"); -+ return -1; -+ } -+ -+ syslog_handler_timeout = &syslog_ts_low_precision; -+ ts_high_precision = -+ config_get_value(config, "syslog_ts_high_precision"); -+ if (ts_high_precision && !strcasecmp(ts_high_precision, "true")) { -+ syslog_handler_timeout = &syslog_ts_high_precision; -+ } -+ -+ /* regsiter console_poller used for timeout only so create a dummy pipe */ -+ if (pipe(lh->pipefd) == -1) { -+ warn("syslog handler create pipe failed"); -+ return -1; -+ } -+ -+ lh->syslogid = strdup(syslogid); -+ openlog(lh->syslogid, LOG_NOWAIT, LOG_USER); -+ -+ lh->poller = console_poller_register(console, handler, dummy_poll, -+ accum_timeout, lh->pipefd[0], 0, -+ NULL); -+ -+ lh->rbc = console_ringbuffer_consumer_register( -+ console, syslog_ringbuffer_poll, lh); -+ -+ return 0; -+} -+ -+static void syslog_fini(struct handler *handler) -+{ -+ struct syslog_handler *lh = to_syslog_handler(handler); -+ -+ ringbuffer_consumer_unregister(lh->rbc); -+ console_poller_unregister(lh->console, lh->poller); -+ closelog(); -+ close(lh->pipefd[0]); -+ close(lh->pipefd[1]); -+ free(lh->syslogid); -+} -+ -+static struct syslog_handler syslog_handler = { -+ .handler = { -+ .name = "syslog", -+ .init = syslog_init, -+ .fini = syslog_fini, -+ }, -+}; -+ -+console_handler_register(&syslog_handler.handler); --- -2.48.1.502.g6dc24dfdaf-goog -
diff --git a/recipes-phosphor/console/obmc-console/0004-Fix-unexpected-behavior-in-client-timeout-callback.patch b/recipes-phosphor/console/obmc-console/0004-Fix-unexpected-behavior-in-client-timeout-callback.patch deleted file mode 100644 index 9e5f6a1..0000000 --- a/recipes-phosphor/console/obmc-console/0004-Fix-unexpected-behavior-in-client-timeout-callback.patch +++ /dev/null
@@ -1,31 +0,0 @@ -From a3ca446f78f728a1ead81cb622e709d16da3ed36 Mon Sep 17 00:00:00 2001 -From: Dan Zhang <zhdaniel@google.com> -Date: Sun, 9 Feb 2025 16:58:26 +0000 -Subject: [PATCH 4/5] Fix unexpected behavior in client timeout callback - -Avoid calling console_poller_unregister within the poller timeout -callback to prevent reallocation of the poller array during iteration, -which causes unexpected behavior. This ensures client_close does not -unregister pollers in the callback context. - -Change-Id: If723a476d4142a42aa62e97ed0d2e2abca5e00c6 -Signed-off-by: Dan Zhang <zhdaniel@google.com> ---- - socket-handler.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/socket-handler.c b/socket-handler.c -index 5f9d383..4906569 100644 ---- a/socket-handler.c -+++ b/socket-handler.c -@@ -253,6 +253,7 @@ client_timeout(struct handler *handler __attribute__((unused)), void *data) - - rc = client_drain_queue(client, 0); - if (rc) { -+ client->poller = NULL; - client_close(client); - return POLLER_REMOVE; - } --- -2.48.1.502.g6dc24dfdaf-goog -
diff --git a/recipes-phosphor/console/obmc-console/0005-Add-pii-handler.patch b/recipes-phosphor/console/obmc-console/0005-Add-pii-handler.patch deleted file mode 100644 index 2414210..0000000 --- a/recipes-phosphor/console/obmc-console/0005-Add-pii-handler.patch +++ /dev/null
@@ -1,1148 +0,0 @@ -From 82d7154f4377447ba5597f5f6c7b53493aa28cc9 Mon Sep 17 00:00:00 2001 -From: Dan Zhang <zhdaniel@google.com> -Date: Tue, 4 Feb 2025 01:23:09 +0000 -Subject: [PATCH] Add pii-handler - -pii-handler listen on two extra unix socket - @obmc-console-pii-machine.{console-id} => machine socket - @obmc-console-pii-user.{console-id} => user socket -And subscribe to pii notifier systemd target's ActiveState change -singal. The pii notifier can be configed in configuration file with -configuration `pii_notifier`. - -When the pii notifier target is active, all clients connect to -machine socket will get masked off. - -When the pii notifier target inactive, all clients connect to -user socket will get masked off. - -All the user clients (i.e. HISC and host-logger) shall connect -to user socket to only get serial console data when user's OS is booting. - -All machine clients (i.e. megapede-nemora megapede-ttf_console) shall -connect to machine socket to only get serial console data emit from -machine components i.e. UEFI f/w. - -Remove the pii_notifier configuration or uninstall the pii_notifier -target make user socket the same as normal obmc-console.{console-id} -socket, while the machine socket will be disabled. The rationale is -when bare metal state is invalid (unknown), fail open for user stream, -make it resilient, while fail close for machine stream to keep it safe -from user guest os serial console data leak. - -Change-Id: I0f53fac46c51cd781e5a5dcb0c55f8840420f265 -Signed-off-by: Dan Zhang <zhdaniel@google.com> ---- - console-client.c | 30 +- - console-server.h | 10 +- - meson.build | 3 + - pii-handler.c | 877 ++++++++++++++++++++++++++++++++++++++ - pii-socket.c | 68 +++ - test/test-client-escape.c | 1 + - 6 files changed, 982 insertions(+), 7 deletions(-) - create mode 100644 pii-handler.c - create mode 100644 pii-socket.c - -diff --git a/console-client.c b/console-client.c -index 3dc3190..434ce10 100644 ---- a/console-client.c -+++ b/console-client.c -@@ -213,7 +213,7 @@ static int client_tty_init(struct console_client *client) - } - - static int client_init(struct console_client *client, struct config *config, -- const char *console_id) -+ const char *console_id, enum pii_data_t pii_type) - { - const char *resolved_id = NULL; - struct sockaddr_un addr; -@@ -232,12 +232,16 @@ static int client_init(struct console_client *client, struct config *config, - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; -- len = console_socket_path(addr.sun_path, resolved_id); -+ if (pii_type == PII_DATA_MACHINE || pii_type == PII_DATA_USER) { -+ len = console_pii_socket_path(addr.sun_path, resolved_id, pii_type); -+ } else { -+ len = console_socket_path(addr.sun_path, resolved_id); -+ } - if (len < 0) { - if (errno) { -- warn("Failed to configure socket: %s", strerror(errno)); -+ warn("Failed to configure socket"); - } else { -- warn("Socket name length exceeds buffer limits"); -+ warnx("Socket name length exceeds buffer limits"); - } - goto cleanup; - } -@@ -273,6 +277,7 @@ int main(int argc, char *argv[]) - struct config *config = NULL; - const char *console_id = NULL; - const uint8_t *esc = NULL; -+ enum pii_data_t pii_type = PII_DATA_UNKNOWN; - int rc; - - client = &_client; -@@ -280,7 +285,7 @@ int main(int argc, char *argv[]) - client->esc_type = ESC_TYPE_SSH; - - for (;;) { -- rc = getopt(argc, argv, "c:e:i:"); -+ rc = getopt(argc, argv, "c:e:i:p:"); - if (rc == -1) { - break; - } -@@ -308,9 +313,22 @@ int main(int argc, char *argv[]) - } - console_id = optarg; - break; -+ case 'p': -+ if (strcasecmp(optarg, "machine") == 0) { -+ pii_type = PII_DATA_MACHINE; -+ break; -+ } -+ if (strcasecmp(optarg, "user") == 0) { -+ pii_type = PII_DATA_USER; -+ break; -+ } -+ fprintf(stderr, -+ "Console PII type shall be specified as machine or user\n"); -+ return EXIT_FAILURE; - default: - fprintf(stderr, - "Usage: %s " -+ "[-p <(machine|user)>]" - "[-e <escape sequence>]" - "[-i <console ID>]" - "[-c <config>]\n", -@@ -337,7 +355,7 @@ int main(int argc, char *argv[]) - client->esc_state.str.str = esc; - } - -- rc = client_init(client, config, console_id); -+ rc = client_init(client, config, console_id, pii_type); - if (rc) { - goto out_config_fini; - } -diff --git a/console-server.h b/console-server.h -index 3de3ece..646815a 100644 ---- a/console-server.h -+++ b/console-server.h -@@ -223,6 +223,14 @@ ssize_t console_socket_path(socket_path_t path, const char *id); - ssize_t console_socket_path_readable(const struct sockaddr_un *addr, - size_t addrlen, socket_path_t path); - -+enum pii_data_t { -+ PII_DATA_UNKNOWN = 0, -+ PII_DATA_MACHINE = 1, -+ PII_DATA_USER = 2, -+}; -+ssize_t console_pii_socket_path(socket_path_t sun_path, const char *id, -+ enum pii_data_t pii_data); -+ - /* utils */ - int write_buf_to_fd(int fd, const uint8_t *buf, size_t len); - -@@ -240,7 +248,7 @@ int dbus_create_socket_consumer(struct console *console); - #endif - - #define container_of(ptr, type, member) \ -- ((type *)((void *)((ptr)-offsetof(type, member)))) -+ ((type *)((void *)((ptr) - offsetof(type, member)))) - - #define BUILD_ASSERT(c) \ - do { \ -diff --git a/meson.build b/meson.build -index a604223..0db0e6f 100644 ---- a/meson.build -+++ b/meson.build -@@ -62,6 +62,8 @@ executable('obmc-console-server', - 'socket-handler.c', - 'syslog-handler.c', - 'tty-handler.c', -+ 'pii-handler.c', -+ 'pii-socket.c', - 'util.c', - c_args: [ - '-DLOCALSTATEDIR="@0@"'.format(get_option('localstatedir')), -@@ -78,6 +80,7 @@ executable('obmc-console-client', - 'config.c', - 'console-client.c', - 'console-socket.c', -+ 'pii-socket.c', - 'util.c', - c_args: [ - '-DSYSCONFDIR="@0@"'.format(get_option('sysconfdir')) -diff --git a/pii-handler.c b/pii-handler.c -new file mode 100644 -index 0000000..e5dcb1d ---- /dev/null -+++ b/pii-handler.c -@@ -0,0 +1,877 @@ -+/** -+ * Copyright © 2016 IBM Corporation -+ * Copyright © 2025 Google Corporation -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#include <asm-generic/errno-base.h> -+#include <assert.h> -+#include <err.h> -+#include <errno.h> -+#include <limits.h> -+#include <stdbool.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <termios.h> -+#include <unistd.h> -+#include <endian.h> -+ -+#include <sys/socket.h> -+#include <sys/un.h> -+#include <systemd/sd-daemon.h> -+ -+#include "console-server.h" -+ -+#define PII_HANDLER_PKT_SIZE 512 -+/* Set poll() timeout to 4000 uS, or 4 mS */ -+#define PII_HANDLER_PKT_US_TIMEOUT 4000 -+ -+struct pii_client_list { -+ struct pii_client_list *prev; -+ struct pii_client_list *next; -+}; -+ -+static void pii_client_list_init(struct pii_client_list *node) -+{ -+ node->next = node; -+ node->prev = node; -+} -+ -+struct pii_client { -+ struct pii_client_list list; -+ struct pii_handler *ph; -+ struct poller *poller; -+ struct ringbuffer_consumer *rbc; -+ int fd; -+ bool blocked; -+ enum pii_data_t client_role; -+ bool enabled; -+ uint8_t *pending_data; -+ uint8_t *pending_data_ptr; -+ size_t pending_len; -+}; -+ -+struct pii_handler { -+ struct handler handler; -+ struct console *console; -+ struct pii_client_list client_list; -+ -+ sd_bus_slot *pii_watcher; -+ enum pii_data_t pii_state; -+ -+ int machine_sd; -+ struct poller *machine_sd_poller; -+ -+ int user_sd; -+ struct poller *user_sd_poller; -+}; -+ -+static struct timeval const socket_handler_timeout = { -+ .tv_sec = 0, -+ .tv_usec = PII_HANDLER_PKT_US_TIMEOUT -+}; -+ -+static struct pii_client *to_pii_client(struct pii_client_list *list) -+{ -+ return container_of(list, struct pii_client, list); -+} -+ -+static void pii_client_list_insert_after(struct pii_client_list *pos, -+ struct pii_client_list *new) -+{ -+ struct pii_client_list *next = pos->next; -+ pos->next = new; -+ new->next = next; -+ next->prev = new; -+ new->prev = pos; -+} -+ -+static void pii_client_list_remove(struct pii_client_list *node) -+{ -+ node->prev->next = node->next; -+ node->next->prev = node->prev; -+} -+ -+static struct pii_handler *to_pii_handler(struct handler *handler) -+{ -+ return container_of(handler, struct pii_handler, handler); -+} -+ -+static void pii_client_close(struct pii_client *client) -+{ -+ struct pii_handler *ph = client->ph; -+ -+ pii_client_list_remove(&client->list); -+ close(client->fd); -+ if (client->poller) { -+ console_poller_unregister(ph->console, client->poller); -+ } -+ -+ if (client->rbc) { -+ ringbuffer_consumer_unregister(client->rbc); -+ } -+ -+ free(client); -+} -+ -+static void pii_client_set_blocked(struct pii_client *client, bool blocked) -+{ -+ int events; -+ -+ if (client->blocked == blocked) { -+ return; -+ } -+ -+ client->blocked = blocked; -+ -+ events = POLLIN; -+ if (client->blocked) { -+ events |= POLLOUT; -+ } -+ -+ console_poller_set_events(client->ph->console, client->poller, events); -+} -+ -+static ssize_t pii_client_send_all(struct pii_client *client, void *buf, -+ size_t len, bool block) -+{ -+ int fd; -+ int flags; -+ ssize_t rc; -+ size_t pos; -+ -+ if (len > SSIZE_MAX) { -+ return -EINVAL; -+ } -+ -+ fd = client->fd; -+ -+ flags = MSG_NOSIGNAL; -+ if (!block) { -+ flags |= MSG_DONTWAIT; -+ } -+ -+ for (pos = 0; pos < len; pos += rc) { -+ rc = send(fd, (char *)buf + pos, len - pos, flags); -+ if (rc < 0) { -+ if (!block && -+ (errno == EAGAIN || errno == EWOULDBLOCK)) { -+ pii_client_set_blocked(client, true); -+ break; -+ } -+ -+ if (errno == EINTR) { -+ continue; -+ } -+ -+ return -1; -+ } -+ if (rc == 0) { -+ return -1; -+ } -+ } -+ -+ return (ssize_t)pos; -+} -+ -+static int pii_client_send_pending_data(struct pii_client *client) -+{ -+ ssize_t wlen = 0; -+ -+ while (client->pending_len) { -+ wlen = pii_client_send_all(client, client->pending_data_ptr, -+ client->pending_len, false); -+ if (wlen <= 0) { -+ break; -+ } -+ client->pending_data_ptr += wlen; -+ client->pending_len -= wlen; -+ } -+ -+ if (wlen < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/* Drain the queue to the socket and update the queue buffer. If force_len is -+ * set, send at least that many bytes from the queue, possibly while blocking -+ */ -+static int pii_client_drain_queue(struct pii_client *client, size_t force_len) -+{ -+ uint8_t *buf; -+ ssize_t wlen; -+ size_t len; -+ size_t total_len; -+ bool block; -+ -+ total_len = 0; -+ wlen = 0; -+ block = (force_len > 0); -+ -+ /* if we're already blocked, no need try unblock write */ -+ if (!block && client->blocked) { -+ return 0; -+ } -+ -+ if (!client->enabled) { -+ if (client->pending_len) { -+ return pii_client_send_pending_data(client); -+ } -+ return 0; -+ } -+ -+ for (;;) { -+ len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf); -+ if (!len) { -+ break; -+ } -+ -+ wlen = pii_client_send_all(client, buf, len, block); -+ if (wlen <= 0) { -+ break; -+ } -+ -+ total_len += wlen; -+ -+ if (force_len && total_len >= force_len) { -+ break; -+ } -+ } -+ -+ if (wlen < 0) { -+ return -1; -+ } -+ -+ if (force_len && total_len < force_len) { -+ return -1; -+ } -+ -+ ringbuffer_dequeue_commit(client->rbc, total_len); -+ return 0; -+} -+ -+static enum ringbuffer_poll_ret pii_client_ringbuffer_poll(void *arg, -+ size_t force_len) -+{ -+ struct pii_client *client = arg; -+ size_t len; -+ int rc; -+ -+ len = ringbuffer_len(client->rbc); -+ if (!force_len && (len < PII_HANDLER_PKT_SIZE)) { -+ /* Do nothing until many small requests have accumulated, or -+ * the UART is idle for awhile (as determined by the timeout -+ * value supplied to the poll function call in console_server.c. */ -+ console_poller_set_timeout(client->ph->console, client->poller, -+ &socket_handler_timeout); -+ return RINGBUFFER_POLL_OK; -+ } -+ -+ rc = pii_client_drain_queue(client, force_len); -+ if (rc) { -+ client->rbc = NULL; -+ pii_client_close(client); -+ return RINGBUFFER_POLL_REMOVE; -+ } -+ -+ return RINGBUFFER_POLL_OK; -+} -+ -+static enum poller_ret -+pii_client_timeout(struct handler *handler __attribute__((unused)), void *data) -+{ -+ struct pii_client *client = data; -+ int rc = 0; -+ -+ if (client->blocked) { -+ /* nothing to do here, we'll call client_drain_queue when -+ * we become unblocked */ -+ return POLLER_OK; -+ } -+ -+ rc = pii_client_drain_queue(client, 0); -+ if (rc) { -+ client->poller = NULL; -+ pii_client_close(client); -+ return POLLER_REMOVE; -+ } -+ -+ return POLLER_OK; -+} -+ -+static enum poller_ret pii_client_poll(struct handler *handler, int events, -+ void *data) -+{ -+ struct pii_handler *ph = to_pii_handler(handler); -+ struct pii_client *client = data; -+ uint8_t buf[4096]; -+ ssize_t rc; -+ -+ if (events & POLLIN) { -+ rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT); -+ if (rc < 0) { -+ if (errno == EAGAIN || errno == EWOULDBLOCK) { -+ return POLLER_OK; -+ } -+ goto err_close; -+ } -+ if (rc == 0) { -+ goto err_close; -+ } -+ -+ if (client->enabled) { -+ console_data_out(ph->console, buf, rc); -+ } -+ } -+ -+ if (events & POLLOUT) { -+ pii_client_set_blocked(client, false); -+ rc = pii_client_drain_queue(client, 0); -+ if (rc) { -+ goto err_close; -+ } -+ } -+ -+ return POLLER_OK; -+ -+err_close: -+ client->poller = NULL; -+ pii_client_close(client); -+ return POLLER_REMOVE; -+} -+ -+static void pii_client_enable(struct pii_client *client) -+{ -+ if (client->enabled) { -+ return; -+ } -+ client->rbc = console_ringbuffer_consumer_register( -+ client->ph->console, pii_client_ringbuffer_poll, client); -+ client->enabled = true; -+} -+ -+static const char pii_client_disabled_message[] = "\n\rPII mask off\n\r"; -+ -+static void pii_client_free_pending_data(struct pii_client *client) -+{ -+ if (client->pending_data) { -+ if ((const char *)client->pending_data != -+ pii_client_disabled_message) { -+ free(client->pending_data); -+ } -+ client->pending_data = NULL; -+ client->pending_data_ptr = NULL; -+ client->pending_len = 0; -+ } -+} -+ -+static void pii_client_save_pending_data(struct pii_client *client) -+{ -+ size_t total_len; -+ size_t len; -+ uint8_t *buf; -+ -+ /* free old pending data */ -+ pii_client_free_pending_data(client); -+ /* allocate a buffer to save pending data and PII_CLIENT_DISABLED_MESSAGE */ -+ len = ringbuffer_len(client->rbc); -+ /* let's be safe to make sure: -+ * len + sizeof(pii_client_disabled_message) - 1 will not overflow -+ * or the pii_client_disable_message is define as an empty string -+ */ -+ assert(len < (len + sizeof(pii_client_disabled_message) - 1)); -+ client->pending_data = -+ malloc(len + sizeof(pii_client_disabled_message) - 1); -+ if (!client->pending_data) { -+ warn("lost pending data %zu", len); -+ return; -+ } -+ -+ total_len = 0; -+ for (;;) { -+ len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf); -+ if (!len) { -+ break; -+ } -+ memcpy(client->pending_data + total_len, buf, len); -+ total_len += len; -+ } -+ ringbuffer_dequeue_commit(client->rbc, total_len); -+ /* and append PII_CLIENT_DISABLED_MESSAGE*/ -+ memcpy(client->pending_data + total_len, pii_client_disabled_message, -+ sizeof(pii_client_disabled_message) - 1); -+ client->pending_data_ptr = client->pending_data; -+ client->pending_len = -+ total_len + sizeof(pii_client_disabled_message) - 1; -+} -+ -+static void pii_client_disable(struct pii_client *client) -+{ -+ if (!client->enabled) { -+ return; -+ } -+ assert(client->rbc); -+ pii_client_save_pending_data(client); -+ ringbuffer_consumer_unregister(client->rbc); -+ client->rbc = NULL; -+ client->enabled = false; -+} -+ -+static int pii_client_show_pii_mask_off(struct pii_client *client) -+{ -+ /* free old pending data */ -+ pii_client_free_pending_data(client); -+ client->pending_data_ptr = client->pending_data = -+ (uint8_t *)pii_client_disabled_message; -+ client->pending_len = sizeof(pii_client_disabled_message) - 1; -+ return pii_client_send_pending_data(client); -+} -+ -+static bool pii_shall_enable_client(struct pii_handler *ph, -+ struct pii_client *client) -+{ -+ if (ph->pii_state == PII_DATA_UNKNOWN) { -+ /* fail open for user client, to let it be resilient */ -+ return client->client_role == PII_DATA_USER; -+ } -+ return ph->pii_state == client->client_role; -+} -+ -+static enum poller_ret pii_socket_poll(struct pii_handler *ph, int events, -+ enum pii_data_t client_role) -+{ -+ struct pii_client *client; -+ int sd; -+ int fd; -+ -+ if (!(events & POLLIN)) { -+ return POLLER_OK; -+ } -+ assert(client_role == PII_DATA_MACHINE || client_role == PII_DATA_USER); -+ sd = (client_role == PII_DATA_MACHINE) ? ph->machine_sd : ph->user_sd; -+ fd = accept(sd, NULL, NULL); -+ if (fd < 0) { -+ return POLLER_OK; -+ } -+ -+ client = malloc(sizeof(*client)); -+ memset(client, 0, sizeof(*client)); -+ client->client_role = client_role; -+ client->ph = ph; -+ client->fd = fd; -+ if (pii_shall_enable_client(ph, client)) { -+ pii_client_enable(client); -+ } else { -+ pii_client_disable(client); -+ } -+ client->poller = console_poller_register(ph->console, &ph->handler, -+ pii_client_poll, -+ pii_client_timeout, client->fd, -+ POLLIN, client); -+ pii_client_list_insert_after(&ph->client_list, &client->list); -+ if (!client->enabled) { -+ if (pii_client_show_pii_mask_off(client) < 0) { -+ warn("show 'pii mask off' initial message failed"); -+ pii_client_close(client); -+ } -+ } -+ return POLLER_OK; -+} -+ -+static enum poller_ret pii_machine_socket_poll(struct handler *handler, -+ int events, -+ void *data -+ __attribute__((unused))) -+{ -+ struct pii_handler *ph = to_pii_handler(handler); -+ return pii_socket_poll(ph, events, PII_DATA_MACHINE); -+} -+ -+static enum poller_ret pii_user_socket_poll(struct handler *handler, int events, -+ void *data __attribute__((unused))) -+{ -+ struct pii_handler *ph = to_pii_handler(handler); -+ return pii_socket_poll(ph, events, PII_DATA_USER); -+} -+ -+static int pii_setup_socket(struct pii_handler *ph, enum pii_data_t pii_data) -+{ -+ struct sockaddr_un addr; -+ size_t addrlen; -+ ssize_t len; -+ int sd; -+ int rc; -+ -+ assert(pii_data == PII_DATA_MACHINE || pii_data == PII_DATA_USER); -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ len = console_pii_socket_path(addr.sun_path, ph->console->console_id, -+ pii_data); -+ if (len < 0) { -+ warn("Failed to configure socket for pii_data(%d)", pii_data); -+ return -1; -+ } -+ -+ sd = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sd < 0) { -+ warn("Can't create socket"); -+ return -1; -+ } -+ -+ addrlen = sizeof(addr) - sizeof(addr.sun_path) + len; -+ -+ rc = bind(sd, (struct sockaddr *)&addr, addrlen); -+ if (rc) { -+ socket_path_t name; -+ console_socket_path_readable(&addr, addrlen, name); -+ warn("Can't bind to socket path %s (terminated at first null)", -+ name); -+ goto error_cleanup; -+ } -+ -+ rc = listen(sd, 1); -+ if (rc) { -+ warn("Can't listen for incoming connections"); -+ goto error_cleanup; -+ } -+ -+ if (pii_data == PII_DATA_MACHINE) { -+ ph->machine_sd = sd; -+ } -+ if (pii_data == PII_DATA_USER) { -+ ph->user_sd = sd; -+ } -+ -+ return 0; -+ -+error_cleanup: -+ close(sd); -+ return -1; -+} -+ -+static const char *pii_data_enum_to_str(enum pii_data_t pii_data) -+{ -+ switch (pii_data) { -+ case PII_DATA_USER: -+ return "PII_DATA_USER"; -+ case PII_DATA_MACHINE: -+ return "PII_DATA_MACHINE"; -+ case PII_DATA_UNKNOWN: -+ return "PII_DATA_UNKNOWN"; -+ default: -+ return "illegal"; -+ } -+} -+ -+static bool pii_set_pii_state(struct pii_handler *ph, enum pii_data_t state) -+{ -+ warnx("pii_state: %s(%d) => %s(%d)", -+ pii_data_enum_to_str(ph->pii_state), ph->pii_state, -+ pii_data_enum_to_str(state), state); -+ if (ph->pii_state != state) { -+ ph->pii_state = state; -+ return true; -+ } -+ return false; -+} -+ -+static const char *systemd_svc = "org.freedesktop.systemd1"; -+static const char *systemd_unit_obj_prefix = "/org/freedesktop/systemd1/unit"; -+static const char *dbus_properties_interface = -+ "org.freedesktop.DBus.Properties"; -+static const char *systemd_unit_interface = "org.freedesktop.systemd1.Unit"; -+static const char *properties_changed_signal = "PropertiesChanged"; -+static const char *active_state_property = "ActiveState"; -+ -+static enum pii_data_t pii_state_from_signal(sd_bus_message *m) -+{ -+ enum pii_data_t ret = PII_DATA_UNKNOWN; -+ -+ int rc; -+ const char *property_name; -+ const char *active_state; -+ /* PropertiesChanged signal has sa{av}as signature */ -+ /* Skip interface name */ -+ sd_bus_message_skip(m, NULL); -+ /* Enter the array of dictionaries a{sv} */ -+ if ((rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}") < -+ 0)) { -+ warnx("Failed to enter a{sv}: %s", strerror(-rc)); -+ return rc; -+ } -+ /* Iterate through the dictionaries */ -+ while (sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv") > -+ 0) { -+ if ((rc = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, -+ &property_name)) < 0) { -+ warnx("Failed to read property name: %s", -+ strerror(-rc)); -+ return ret; -+ } -+ if (strcmp(property_name, active_state_property) == 0) { -+ /* Enter the variant */ -+ if ((rc = sd_bus_message_enter_container( -+ m, SD_BUS_TYPE_VARIANT, "s")) < 0) { -+ warnx("Failed to enter ActiveState variant: %s", -+ strerror(-rc)); -+ return ret; -+ } -+ if ((rc = sd_bus_message_read_basic( -+ m, SD_BUS_TYPE_STRING, &active_state)) < -+ 0) { -+ warnx("Failed read %s value", -+ active_state_property); -+ return ret; -+ }; -+ sd_bus_message_exit_container(m); -+ /* Exit variant container */ -+ if (active_state && -+ strcasecmp(active_state, "active") == 0) { -+ ret = PII_DATA_USER; -+ } -+ if (active_state && -+ strcasecmp(active_state, "inactive") == 0) { -+ ret = PII_DATA_MACHINE; -+ } -+ return ret; -+ } -+ sd_bus_message_skip(m, NULL); -+ sd_bus_message_exit_container(m); -+ } -+ warnx("Not found %s", active_state_property); -+ return ret; -+} -+ -+static int pii_signal_handler(sd_bus_message *message, void *userdata, -+ sd_bus_error *ret_error) -+{ -+ struct pii_handler *ph = userdata; -+ enum pii_data_t new_pii_state; -+ struct pii_client_list *pos; -+ struct pii_client_list *n; -+ -+ assert(ph); -+ -+ if (ret_error && sd_bus_error_is_set(ret_error)) { -+ warnx("Error in pii signal: %s - %s\n", ret_error->name, -+ ret_error->message); -+ return -1; -+ } -+ -+ new_pii_state = pii_state_from_signal(message); -+ if (new_pii_state == PII_DATA_UNKNOWN) { -+ return 0; -+ } -+ -+ if (!pii_set_pii_state(ph, new_pii_state)) { -+ /* pii state not change */ -+ return 0; -+ } -+ /* pii state changed */ -+ for (pos = ph->client_list.next, n = pos->next; pos != &ph->client_list; -+ pos = n, n = pos->next) { -+ struct pii_client *client = to_pii_client(pos); -+ if (pii_shall_enable_client(ph, client)) { -+ pii_client_enable(client); -+ continue; -+ } -+ pii_client_disable(client); -+ if (pii_client_send_pending_data(client) < 0) { -+ warn("Send pending data to client(%p) failed, close it", -+ (void *)client); -+ pii_client_close(client); -+ } -+ } -+ -+ return 0; -+} -+ -+static int pii_setup_watcher(struct pii_handler *ph, const char *unit_obj_path) -+{ -+ int rc; -+ assert(unit_obj_path); -+ -+ rc = sd_bus_match_signal(ph->console->bus, &ph->pii_watcher, -+ systemd_svc, unit_obj_path, -+ dbus_properties_interface, -+ properties_changed_signal, pii_signal_handler, -+ ph); -+ -+ if (rc < 0) { -+ warnx("Failed to subscribe signal %s of %s: %s\n", -+ properties_changed_signal, unit_obj_path, strerror(-rc)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static enum pii_data_t pii_query_pii_state(struct pii_handler *ph, -+ const char *unit_obj_path) -+{ -+ enum pii_data_t ret = PII_DATA_UNKNOWN; -+ char *property_value = NULL; -+ sd_bus_error error = SD_BUS_ERROR_NULL; -+ -+ assert(unit_obj_path); -+ -+ if (sd_bus_get_property_string(ph->console->bus, systemd_svc, -+ unit_obj_path, systemd_unit_interface, -+ active_state_property, &error, -+ &property_value) < 0) { -+ warnx("get property %s of %s failed %s", active_state_property, -+ unit_obj_path, error.message); -+ goto cleanup; -+ } -+ -+ warnx("%s %s = %s", unit_obj_path, active_state_property, -+ property_value); -+ if (property_value && strcasecmp("active", property_value) == 0) { -+ ret = PII_DATA_USER; -+ } -+ if (property_value && strcasecmp("inactive", property_value) == 0) { -+ ret = PII_DATA_MACHINE; -+ } -+ -+cleanup: -+ if (property_value) { -+ free(property_value); -+ } -+ sd_bus_error_free(&error); -+ return ret; -+} -+ -+static void pii_cleanup(struct pii_handler *ph) -+{ -+ struct pii_client_list *pos; -+ -+ if (!ph) { -+ return; -+ } -+ -+ pos = ph->client_list.next; -+ while (pos != &ph->client_list) { -+ struct pii_client *client = to_pii_client(pos); -+ pos = pos->next; -+ pii_client_close(client); -+ } -+ -+ if (ph->user_sd_poller) { -+ console_poller_unregister(ph->console, ph->user_sd_poller); -+ ph->user_sd_poller = NULL; -+ close(ph->user_sd); -+ } -+ -+ if (ph->machine_sd_poller) { -+ console_poller_unregister(ph->console, ph->machine_sd_poller); -+ ph->machine_sd_poller = NULL; -+ close(ph->machine_sd); -+ } -+ -+ if (ph->pii_watcher) { -+ sd_bus_slot_unref(ph->pii_watcher); -+ ph->pii_watcher = NULL; -+ } -+} -+ -+static int pii_init(struct handler *handler, struct console *console, -+ struct config *config __attribute__((unused))) -+{ -+ int rc; -+ const char *pii_notifier; -+ struct pii_handler *ph = to_pii_handler(handler); -+ char *unit_obj_path = NULL; -+ -+ assert(ph); -+ ph->console = console; -+ ph->pii_watcher = NULL; -+ ph->pii_state = PII_DATA_UNKNOWN; -+ ph->machine_sd = 0; -+ ph->machine_sd_poller = NULL; -+ ph->user_sd = 0; -+ ph->user_sd_poller = NULL; -+ pii_client_list_init(&ph->client_list); -+ -+ pii_notifier = config_get_value(config, "pii_notifier"); -+ if (!pii_notifier) { -+ warnx("No PII notifier defined, no PII filtering enforced"); -+ } -+ -+ if (pii_notifier) { -+ rc = sd_bus_path_encode(systemd_unit_obj_prefix, pii_notifier, -+ &unit_obj_path); -+ if (rc < 0) { -+ warnx("Encode %s failed: %s", pii_notifier, -+ strerror(-rc)); -+ goto init_error; -+ } -+ pii_set_pii_state(ph, pii_query_pii_state(ph, unit_obj_path)); -+ -+ rc = pii_setup_watcher(ph, unit_obj_path); -+ if (rc < 0) { -+ goto init_error; -+ } -+ if (unit_obj_path) { -+ free(unit_obj_path); -+ } -+ } -+ -+ rc = pii_setup_socket(ph, PII_DATA_MACHINE); -+ if (rc < 0) { -+ goto init_error; -+ } -+ -+ rc = pii_setup_socket(ph, PII_DATA_USER); -+ if (rc < 0) { -+ goto init_error; -+ } -+ -+ ph->machine_sd_poller = console_poller_register(console, handler, -+ pii_machine_socket_poll, -+ NULL, ph->machine_sd, -+ POLLIN, NULL); -+ -+ ph->user_sd_poller = console_poller_register(console, handler, -+ pii_user_socket_poll, NULL, -+ ph->user_sd, POLLIN, NULL); -+ -+ return 0; -+ -+init_error: -+ if (unit_obj_path) { -+ free(unit_obj_path); -+ } -+ pii_cleanup(ph); -+ return -1; -+} -+ -+static void pii_fini(struct handler *handler) -+{ -+ struct pii_handler *ph = to_pii_handler(handler); -+ pii_cleanup(ph); -+} -+ -+static struct pii_handler pii_handler = { -+ .handler = { -+ .name = "pii", -+ .init = pii_init, -+ .fini = pii_fini, -+ }, -+}; -+ -+console_handler_register(&pii_handler.handler); -diff --git a/pii-socket.c b/pii-socket.c -new file mode 100644 -index 0000000..142b828 ---- /dev/null -+++ b/pii-socket.c -@@ -0,0 +1,68 @@ -+/** -+ * Copyright © 2016 IBM Corporation -+ * Copyright © 2025 Google -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#include "console-server.h" -+ -+#include <err.h> -+#include <errno.h> -+#include <limits.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <sys/socket.h> -+#include <sys/un.h> -+#include <sys/types.h> -+#include <unistd.h> -+ -+#define CONSOLE_PII_PREFIX_MACHINE "obmc-console-pii-machine" -+#define CONSOLE_PII_PREFIX_USER "obmc-console-pii-user" -+ -+/* Build the socket path. */ -+ssize_t console_pii_socket_path(socket_path_t sun_path, const char *id, -+ enum pii_data_t pii_data) -+{ -+ int rc; -+ const char *path_template; -+ -+ if (!id) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ switch (pii_data) { -+ case PII_DATA_MACHINE: -+ path_template = CONSOLE_PII_PREFIX_MACHINE ".%s"; -+ break; -+ case PII_DATA_USER: -+ path_template = CONSOLE_PII_PREFIX_USER ".%s"; -+ break; -+ default: -+ errno = EINVAL; -+ return -1; -+ } -+ rc = snprintf(sun_path + 1, sizeof(socket_path_t) - 1, path_template, -+ id); -+ if (rc < 0) { -+ return rc; -+ } -+ -+ if ((size_t)rc > (sizeof(socket_path_t) - 1)) { -+ errno = ENOSPC; -+ return -1; -+ } -+ -+ return rc + 1 /* Capture NUL prefix */; -+} -diff --git a/test/test-client-escape.c b/test/test-client-escape.c -index b3083b7..e468b93 100644 ---- a/test/test-client-escape.c -+++ b/test/test-client-escape.c -@@ -25,6 +25,7 @@ static ssize_t __read(int fd, void *buf, size_t len); - #define read __read - #include "config.c" - #include "console-socket.c" -+#include "pii-socket.c" - #define main __main - #include "console-client.c" - #undef read --- -2.48.1.658.g4767266eb4-goog -
diff --git a/recipes-phosphor/console/obmc-console_%.bbappend b/recipes-phosphor/console/obmc-console_%.bbappend index 4f0eb27..8d4a45e 100644 --- a/recipes-phosphor/console/obmc-console_%.bbappend +++ b/recipes-phosphor/console/obmc-console_%.bbappend
@@ -4,11 +4,14 @@ file://readonly-obmc-console-client \ file://40-console-client-override.conf \ file://ttf-console.sh \ - file://0001-Add-syslog-handler.patch \ - file://0004-Fix-unexpected-behavior-in-client-timeout-callback.patch \ - file://0005-Add-pii-handler.patch \ file://journal-ratelimit.conf \ " +SRC_URI:remove:gbmc = " \ + git://github.com/openbmc/obmc-console;branch=master;protocol=https \ +" +SRC_URI:append:gbmc = "git://gbmc.googlesource.com/obmc-console;branch=google-dev;protocol=https" +SRCREV = "a501a047d65d70866138b84e796bc05d33a065ad" + do_install:append:gbmc() { install -d -m0644 ${D}${sysconfdir}/systemd/system/serial-to-host@.service.d/ install -m0644 ${WORKDIR}/40-console-client-override.conf \