From nobody Tue May 27 20:27:29 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4b6PM52kgMz5xs20; Tue, 27 May 2025 20:27:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4b6PM521fPz4PDl; Tue, 27 May 2025 20:27:29 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1748377649; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=kPnzE1yJdmie9H5Mi4hAib8fhAGXM5VHLJmIHJ/rBBc=; b=STeLkfVcVJArEsKckWgZHEdyVmAeBX4JpFwwoUH1l4td2lvO4iO6vYSVKYcj85a0I6yt2u IJhe1W2scbp/1Zi1W0mFt78X8f52l640j1nT0vzTu6Jw2b3R8Joiliolzo6S210Sg2gVNN MQgqvxL9cNpyBZ2TE69O5T3GYMyeVtrGxUzw/Id+HkL8o81DKkDLm0Ym5qrFSi2qfhLHqT gcI6xo4I36u1e5+W3gjllr+l1UHAzvdI3CE72ssWTcWxDIKlRkqiSyyC/s49Qo1MFL+eKq EWalnIMA1w25cyLDvffTrZ0LVsW9XazKtOBQSKcVP4GUs07aMP9sPK4DgP/HBQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1748377649; a=rsa-sha256; cv=none; b=vApTqDQMHuDJDyLk4fqA6211fmMyABJOKy4cH+Z47Eg9eHNZLeIMhWI4nQUpDg5KK0adc9 BCtO+drfvXQ2S/iJDFMJQqw6fRaXds9OUvBjk6wiSFFFwG04c9X6AFRlJjj40Ff7400mxs iqpDKwgCCGY8jrJEFpxkWfMxlCJXhanZtVkBunTzIf3YjgKbT5kgyWITpFyr5kKh0FlB+R q0GV02PXu2u84KagQX9y/zv5ZF0s3f01A+5kyqATk+PT45+0tFWTreIBOhamiehlLgQJ4K 8KV1jAP5uPeXJ1xh51gfEop5lN21fyowsek9HBZQ72t48BXG6oB3FT/1T4bG+w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1748377649; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=kPnzE1yJdmie9H5Mi4hAib8fhAGXM5VHLJmIHJ/rBBc=; b=ERKXodn9taOw5v/iOV484jUtd7rJc2GTbeN1l8XAkhD2XfLGUntWl0erv/yrri4VqLRw1p u+Lhq4/TEmrd/Nl6FClEIOL0Fb7OmOT8HAtmlH8j8HP93wBmQLVNpA7oQFX6W4lTz8jE8s QgLLbgYhE0Sj1RIssErBeRGL1C/wiUuAcI66lXJeH3r+bOjTPvRMXM17UzjNrcx3a0H+bL o9A9c0TgVV+eACZP9LS4McX62TxXkg5d7Yc1QQIBHthfDNScTcrcPmMzSnLM7wB3BqZhxH 7XTRWMWAK0b7L0st67A2L6vq35ZaBLzIl7g7C+ZS4NpdF/uO957dG9xz5Q7r5A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4b6PM51bStz16R1; Tue, 27 May 2025 20:27:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 54RKRTi9085984; Tue, 27 May 2025 20:27:29 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 54RKRTqj085981; Tue, 27 May 2025 20:27:29 GMT (envelope-from git) Date: Tue, 27 May 2025 20:27:29 GMT Message-Id: <202505272027.54RKRTqj085981@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Juraj Lutter Subject: git: 3d516b853179 - main - Add ts(1) command List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: otis X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 3d516b853179b9cc02d358410ef9b64c593022ce Auto-Submitted: auto-generated The branch main has been updated by otis: URL: https://cgit.FreeBSD.org/src/commit/?id=3d516b853179b9cc02d358410ef9b64c593022ce commit 3d516b853179b9cc02d358410ef9b64c593022ce Author: Juraj Lutter AuthorDate: 2022-07-02 15:26:42 +0000 Commit: Juraj Lutter CommitDate: 2025-05-27 20:24:22 +0000 Add ts(1) command Add /usr/bin/ts, a command that timestamps each line of its stdin before it is being printed to stdout. A typical use case is to profile shell scripts. Obtained from: OpenBSD 7.2 Relnotes: yes Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D35694 --- contrib/ts/ts.1 | 112 ++++++++++++++++++++++++++++++++++ contrib/ts/ts.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++ usr.bin/Makefile | 1 + usr.bin/ts/Makefile | 7 +++ 4 files changed, 291 insertions(+) diff --git a/contrib/ts/ts.1 b/contrib/ts/ts.1 new file mode 100644 index 000000000000..3406bdae9bab --- /dev/null +++ b/contrib/ts/ts.1 @@ -0,0 +1,112 @@ +.\" $OpenBSD: ts.1,v 1.6 2022/06/30 21:40:41 jmc Exp $ +.\" +.\" Copyright (c) 2022 Job Snijders +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd June 30, 2022 +.Dt TS 1 +.Os +.Sh NAME +.Nm ts +.Nd timestamp input +.Sh SYNOPSIS +.Nm +.Op Fl i | s +.Op Fl m +.Op Ar format +.Sh DESCRIPTION +The +.Nm +utility prepends a timestamp to each line of standard input and writes +it to standard output. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl i +Display time elapsed since the last timestamp. +.It Fl m +Display timestamps derived from a strictly linearly increasing clock. +Without +.Fl m , +timestamps reflect the current date and time, including time jumps if the +system time is changed. +.It Fl s +Display time elapsed since the start of the program. +.El +.Pp +The optional +.Ar format +argument controls how the timestamp is displayed, according to the conversion +specifications described in the +.Xr strftime 3 +manual page. +The default format is +.Qq %b %d %H:%M:%S ; +or +.Qq %H:%M:%S +if one of the +.Fl i +or +.Fl s +options is used. +.Pp +Some additional conversion specifications are also supported +to append microsecond resolution: +.Cm %.S , +.Cm %.s , +and +.Cm %.T ; +which are similar to +.Cm %S , +.Cm %s , +and +.Cm \&%T . +Examples: +.Qq 10.00001 , +.Qq 1656427781.00001 , +and +.Qq 4:20:00.00001 . +.Sh EXAMPLES +.Bd -literal -offset indent +$ (echo foo; sleep 2; echo bar) | ts +Jun 28 12:13:38 foo +Jun 28 12:13:40 bar + +$ ls | ts -i %.S +00.000452 CVS +00.000595 Makefile +00.000004 ts.1 +00.000004 ts.c +.Ed +.Sh SEE ALSO +.Xr strftime 3 +.Sh HISTORY +A +.Nm +utility first appeared in the moreutils collection by Joey Hess, and was +rewritten from scratch for +.Ox 7.2 . +.Pp +It was imported to +.Fx +by +.An -nosplit +.An Juraj Lutter Aq Mt otis@FreeBSD.org . +.Sh AUTHORS +This +.Nm +utility was written by +.An Job Snijders Aq Mt job@openbsd.org +and +.An Claudio Jeker Aq Mt claudio@openbsd.org . diff --git a/contrib/ts/ts.c b/contrib/ts/ts.c new file mode 100644 index 000000000000..f20826176229 --- /dev/null +++ b/contrib/ts/ts.c @@ -0,0 +1,171 @@ +/* $OpenBSD: ts.c,v 1.7 2022/07/06 07:59:03 claudio Exp $ */ +/* + * Copyright (c) 2022 Job Snijders + * Copyright (c) 2022 Claudio Jeker + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static const char *format = "%b %d %H:%M:%S"; +static char *buf; +static char *outbuf; +static size_t bufsize; + +static void fmtfmt(const struct timespec *); +static void __dead2 usage(void); + +int +main(int argc, char *argv[]) +{ + int iflag, mflag, sflag; + int ch, prev; + struct timespec start, now, utc_offset, ts; + clockid_t clock = CLOCK_REALTIME; + + iflag = mflag = sflag = 0; + + while ((ch = getopt(argc, argv, "ims")) != -1) { + switch (ch) { + case 'i': + iflag = 1; + format = "%H:%M:%S"; + clock = CLOCK_MONOTONIC; + break; + case 'm': + mflag = 1; + clock = CLOCK_MONOTONIC; + break; + case 's': + sflag = 1; + format = "%H:%M:%S"; + clock = CLOCK_MONOTONIC; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if ((iflag && sflag) || argc > 1) + usage(); + + if (argc == 1) + format = *argv; + + bufsize = strlen(format); + if (bufsize > SIZE_MAX / 10) + errx(1, "format string too big"); + + bufsize *= 10; + if ((buf = calloc(1, bufsize)) == NULL) + err(1, NULL); + if ((outbuf = calloc(1, bufsize)) == NULL) + err(1, NULL); + + /* force UTC for interval calculations */ + if (iflag || sflag) + if (setenv("TZ", "UTC", 1) == -1) + err(1, "setenv UTC"); + + clock_gettime(clock, &start); + clock_gettime(CLOCK_REALTIME, &utc_offset); + timespecsub(&utc_offset, &start, &utc_offset); + + for (prev = '\n'; (ch = getchar()) != EOF; prev = ch) { + if (prev == '\n') { + clock_gettime(clock, &now); + if (iflag || sflag) + timespecsub(&now, &start, &ts); + else if (mflag) + timespecadd(&now, &utc_offset, &ts); + else + ts = now; + fmtfmt(&ts); + if (iflag) + start = now; + } + if (putchar(ch) == EOF) + break; + } + + if (fclose(stdout)) + err(1, "stdout"); + return 0; +} + +static void __dead2 +usage(void) +{ + fprintf(stderr, "usage: %s [-i | -s] [-m] [format]\n", getprogname()); + exit(1); +} + +/* + * yo dawg, i heard you like format strings + * so i put format strings in your user supplied input + * so you can format while you format + */ +static void +fmtfmt(const struct timespec *ts) +{ + struct tm *tm; + char *f, us[7]; + + if ((tm = localtime(&ts->tv_sec)) == NULL) + err(1, "localtime"); + + snprintf(us, sizeof(us), "%06ld", ts->tv_nsec / 1000); + strlcpy(buf, format, bufsize); + f = buf; + + do { + while ((f = strchr(f, '%')) != NULL && f[1] == '%') + f += 2; + + if (f == NULL) + break; + + f++; + if (f[0] == '.' && + (f[1] == 'S' || f[1] == 's' || f[1] == 'T')) { + size_t l; + + f[0] = f[1]; + f[1] = '.'; + f += 2; + l = strlen(f); + memmove(f + 6, f, l + 1); + memcpy(f, us, 6); + f += 6; + } + } while (*f != '\0'); + + if (strftime(outbuf, bufsize, buf, tm) == 0) + errx(1, "strftime"); + + fprintf(stdout, "%s ", outbuf); + if (ferror(stdout)) + exit(1); +} diff --git a/usr.bin/Makefile b/usr.bin/Makefile index e99670ec2d3e..787cbc0cbd78 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -155,6 +155,7 @@ SUBDIR= alias \ tr \ true \ truncate \ + ts \ tsort \ tty \ uname \ diff --git a/usr.bin/ts/Makefile b/usr.bin/ts/Makefile new file mode 100644 index 000000000000..4a74927fcede --- /dev/null +++ b/usr.bin/ts/Makefile @@ -0,0 +1,7 @@ +.PATH: ${SRCTOP}/contrib/ts + +PROG= ts +SRCS= ts.c +MAN= ts.1 + +.include