aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2025-04-20 16:34:52 +0000
committerKyle Evans <kevans@FreeBSD.org>2025-04-20 16:35:34 +0000
commit1b3748977f28c70e0b161fb476bf4e075bcc5940 (patch)
tree0bb4789ebdfe29ba5e0297d01cc9926a7d5e5ab6
parent414c2b8d1e5abe7186c1aa4dc3ab28147ce46f47 (diff)
-rw-r--r--usr.bin/tee/tee.18
-rw-r--r--usr.bin/tee/tee.c46
-rw-r--r--usr.bin/tee/tests/tee_test.sh32
3 files changed, 83 insertions, 3 deletions
diff --git a/usr.bin/tee/tee.1 b/usr.bin/tee/tee.1
index 9497a2aa921e..9884dcf37919 100644
--- a/usr.bin/tee/tee.1
+++ b/usr.bin/tee/tee.1
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 30, 2022
+.Dd December 25, 2024
.Dt TEE 1
.Os
.Sh NAME
@@ -69,6 +69,12 @@ utility takes the default action for all signals,
except in the event of the
.Fl i
option.
+.Pp
+This implementation of the
+.Nm
+utility may also write to
+.Xr unix 4
+sockets.
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
diff --git a/usr.bin/tee/tee.c b/usr.bin/tee/tee.c
index f1d192ff315f..fb73b311a31b 100644
--- a/usr.bin/tee/tee.c
+++ b/usr.bin/tee/tee.c
@@ -29,10 +29,12 @@
* SUCH DAMAGE.
*/
+#include <sys/types.h>
#include <sys/capsicum.h>
#include <sys/queue.h>
+#include <sys/socket.h>
#include <sys/stat.h>
-#include <sys/types.h>
+#include <sys/un.h>
#include <capsicum_helpers.h>
#include <err.h>
@@ -52,6 +54,7 @@ struct entry {
static STAILQ_HEAD(, entry) head = STAILQ_HEAD_INITIALIZER(head);
static void add(int, const char *);
+static int tee_open(const char *, int);
static void usage(void) __dead2;
int
@@ -93,7 +96,7 @@ main(int argc, char *argv[])
oflags |= O_TRUNC;
for (exitval = 0; *argv; ++argv) {
- if ((fd = open(*argv, oflags, DEFFILEMODE)) < 0) {
+ if ((fd = tee_open(*argv, oflags)) < 0) {
warn("%s", *argv);
exitval = 1;
} else {
@@ -149,3 +152,42 @@ add(int fd, const char *name)
p->name = name;
STAILQ_INSERT_HEAD(&head, p, entries);
}
+
+static int
+tee_open(const char *path, int oflags)
+{
+ struct sockaddr_un sun = { .sun_family = AF_UNIX };
+ size_t pathlen;
+ int fd;
+
+ if ((fd = open(path, oflags, DEFFILEMODE)) >= 0)
+ return (fd);
+
+ if (errno != EOPNOTSUPP)
+ return (-1);
+
+ pathlen = strnlen(path, sizeof(sun.sun_path));
+ if (pathlen >= sizeof(sun.sun_path))
+ goto failed;
+
+ /*
+ * For EOPNOTSUPP, we'll try again as a unix(4) socket. Any errors here
+ * we'll just surface as the original EOPNOTSUPP since they may not have
+ * intended for this.
+ */
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ goto failed;
+
+ (void)strlcpy(&sun.sun_path[0], path, sizeof(sun.sun_path));
+ sun.sun_len = SUN_LEN(&sun);
+
+ if (connect(fd, (const struct sockaddr *)&sun, sun.sun_len) == 0)
+ return (fd);
+
+failed:
+ if (fd >= 0)
+ close(fd);
+ errno = EOPNOTSUPP;
+ return (-1);
+}
diff --git a/usr.bin/tee/tests/tee_test.sh b/usr.bin/tee/tests/tee_test.sh
index 6ac733f2e58f..cf8e74dd47e7 100644
--- a/usr.bin/tee/tests/tee_test.sh
+++ b/usr.bin/tee/tests/tee_test.sh
@@ -64,6 +64,37 @@ sigint_ignored_body()
atf_check -o inline:"text\ntext\n" cat file
}
+atf_test_case unixsock "cleanup"
+unixsock_pidfile="nc.pid"
+
+unixsock_body()
+{
+ outfile=out.log
+
+ nc -lU logger.sock > "$outfile" &
+ npid=$!
+
+ atf_check -o save:"$unixsock_pidfile" echo "$npid"
+
+ # Wait for the socket to come online, just in case.
+ while [ ! -S logger.sock ]; do
+ sleep 0.1
+ done
+
+ atf_check -o inline:"text over socket\n" -x \
+ 'echo "text over socket" | tee logger.sock'
+
+ atf_check rm "$unixsock_pidfile"
+ atf_check -o inline:"text over socket\n" cat "$outfile"
+}
+unixsock_cleanup()
+{
+ if [ -s "$unixsock_pidfile" ]; then
+ read npid < "$unixsock_pidfile"
+ kill "$npid"
+ fi
+}
+
atf_init_test_cases()
{
atf_add_test_case single_file
@@ -71,4 +102,5 @@ atf_init_test_cases()
atf_add_test_case multiple_file
atf_add_test_case append
atf_add_test_case sigint_ignored
+ atf_add_test_case unixsock
}