diff --git a/usr.bin/runat/Makefile.xattr b/usr.bin/runat/Makefile --- a/usr.bin/runat/Makefile.xattr +++ b/usr.bin/runat/Makefile @@ -0,0 +1,3 @@ +PROG= runat + +.include diff --git a/usr.bin/runat/runat.1.xattr b/usr.bin/runat/runat.1 --- a/usr.bin/runat/runat.1.xattr +++ b/usr.bin/runat/runat.1 @@ -0,0 +1,56 @@ +.\" Copyright (c) 2025 Rick Macklem. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.Dd April 15, 2025 +.Dt RUNAT 1 +.Os +.Sh NAME +.Nm runat +.Nd run a shell command on a named attribute directory +.Sh SYNOPSIS +.Nm +.Op Fl create +.Op Fl - +.Op Ar file +.Op Ar shell command +.Sh DESCRIPTION +The +.Nm +utility runs the shell command on the named attribute directory for the +.Ar file +argument. +It does a +.Xr fchdir 2 +system call to change the current working directory into the +named attribute directory for the +.Fa file +argument and then performs the shell command via +.Xr sh 1 . +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl create +Create the named attribute directory if it does not already exist. +.It Fl - +Used if the +.Fa file +argument happens to be called +.Dq -create . +.El +.Sh EXAMPLES +For a file called +.Dq myfile : +.Bd -literal +$ runat myfile ls -l # lists the attributes for myfile +$ runat myfile cp /etc/hosts attrhosts # creates attrhosts +$ runat myfile cat attrhosts # displays contents of attrhosts +.Ed +.Sh SEE ALSO +.Xr sh 1 , +.Xr open 2 , +.Xr named_attribute 7 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 15.0 . diff --git a/usr.bin/runat/runat.c.xattr b/usr.bin/runat/runat.c --- a/usr.bin/runat/runat.c.xattr +++ b/usr.bin/runat/runat.c @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2025 Rick Macklem + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: runat [-create/--] " + "\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int fmode, i, file_fd, nameddir_fd, outsiz; + char *buf; + long named_enabled; + size_t pos, siz; + + fmode = O_NAMEDATTR | O_RDONLY | O_CLOEXEC; + if (argc <= 2) + usage(); + argv++; + argc--; + if (strcmp(argv[0], "-create") == 0) { + fmode |= O_CREAT; + argv++; + argc--; + } else if (strcmp(argv[0], "--") == 0) { + argv++; + argc--; + } + if (argc < 2) + usage(); + + named_enabled = pathconf(argv[0], _PC_NAMEDATTR_ENABLED); + if (named_enabled <= 0) + errx(1, "Named attributes not enabled for %s", argv[0]); + + /* Generate the command string for "sh". */ + siz = 0; + for (i = 1; i < argc; i++) + siz += strlen(argv[i]) + 1; + buf = malloc(siz); + if (buf == NULL) + errx(1, "Cannot malloc"); + pos = 0; + for (i = 1; i < argc; i++) { + outsiz = snprintf(&buf[pos], siz, "%s ", argv[i]); + if ((size_t)outsiz > siz) + errx(1, "Arguments too large"); + pos += outsiz; + siz -= outsiz; + } + buf[pos - 1] = '\0'; + + file_fd = open(argv[0], O_RDONLY | O_CLOEXEC, 0); + if (file_fd < 0) + err(1, "Cannot open %s", argv[0]); + nameddir_fd = openat(file_fd, ".", fmode, 0); + if (nameddir_fd < 0) + err(1, "Cannot open named attribute directory " + "for %s", argv[0]); + + if (fchdir(nameddir_fd) < 0) + err(1, "Cannot fchdir to named attribute dir"); + + execl(_PATH_BSHELL, "sh", "-c", buf, NULL); + err(1, "Could not exec /bin/sh"); +}