File bsc1245199.patch of Package bash.41090
commit 64b2b7c08d427796d75411f5d3ea46e585ad2d4b
Author: Chet Ramey <chet.ramey@case.edu>
Date: Mon Mar 27 09:28:12 2023 -0400
fixes for glibc time/gettimeofday issue; fix issue with history file containing one line too few if saving timestamps; fix for signal arriving while displaying readline completions
---
histfile.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 46 insertions(+), 14 deletions(-)
--- a/lib/readline/histfile.c
+++ b/lib/readline/histfile.c 2025-10-13 13:08:20.544420675 +0000
@@ -466,6 +466,10 @@ histfile_restore (backup, orig)
return (rename (backup, orig));
}
+
+#define SHOULD_CHOWN(finfo, nfinfo) \
+ (finfo.st_uid != nfinfo.st_uid || finfo.st_gid != nfinfo.st_gid)
+
/* Truncate the history file FNAME, leaving only LINES trailing lines.
If FNAME is NULL, then use ~/.history. Writes a new file and renames
it to the original name. Returns 0 on success, errno on failure. */
@@ -476,7 +480,7 @@ history_truncate_file (fname, lines)
{
char *buffer, *filename, *tempname, *bp, *bp1; /* bp1 == bp+1 */
int file, chars_read, rv, orig_lines, exists, r;
- struct stat finfo;
+ struct stat finfo, nfinfo;
size_t file_size;
history_lines_written_to_file = 0;
@@ -497,6 +501,9 @@ history_truncate_file (fname, lines)
}
exists = 1;
+ nfinfo.st_uid = finfo.st_uid;
+ nfinfo.st_gid = finfo.st_gid;
+
if (S_ISREG (finfo.st_mode) == 0)
{
close (file);
@@ -532,6 +539,15 @@ history_truncate_file (fname, lines)
goto truncate_exit;
}
+ /* Don't bother with any of this if we're truncating to zero length. */
+ if (lines == 0)
+ {
+ close (file);
+ buffer[chars_read = 0] = '\0';
+ bp = buffer;
+ goto truncate_write;
+ }
+
chars_read = read (file, buffer, file_size);
close (file);
@@ -540,27 +556,35 @@ history_truncate_file (fname, lines)
rv = (chars_read < 0) ? errno : 0;
goto truncate_exit;
}
+ buffer[chars_read] = '\0'; /* for the initial check of bp1[1] */
orig_lines = lines;
/* Count backwards from the end of buffer until we have passed
LINES lines. bp1 is set funny initially. But since bp[1] can't
be a comment character (since it's off the end) and *bp can't be
- both a newline and the history comment character, it should be OK. */
- for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
+ both a newline and the history comment character, it should be OK.
+ If we are writing history timestamps, we need to add one to LINES
+ because we decrement it one extra time the first time through the loop
+ and we need the final timestamp line. */
+ lines += history_write_timestamps;
+ for (bp1 = bp = buffer + chars_read - 1; lines > 0 && bp > buffer; bp--)
{
if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
lines--;
bp1 = bp;
}
- /* If this is the first line, then the file contains exactly the
+ /* This is the right line, so move to its start. If we're writing history
+ timestamps, we want to go back until *bp == '\n' and bp1 starts a
+ history timestamp. If we're not, just move back to *bp == '\n'.
+ If this is the first line, then the file contains exactly the
number of lines we want to truncate to, so we don't need to do
- anything. It's the first line if we don't find a newline between
- the current value of i and 0. Otherwise, write from the start of
- this line until the end of the buffer. */
+ anything, and we'll end up with bp == buffer.
+ Otherwise, write from the start of this line until the end of the
+ buffer. */
for ( ; bp > buffer; bp--)
{
- if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
+ if (*bp == '\n' && (history_write_timestamps == 0 || HIST_TIMESTAMP_START(bp1)))
{
bp++;
break;
@@ -578,15 +602,23 @@ history_truncate_file (fname, lines)
goto truncate_exit;
}
+truncate_write:
+
tempname = history_tempfile (filename);
- if ((file = open (tempname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1)
+ if ((file = open (tempname, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)
{
if (write (file, bp, chars_read - (bp - buffer)) < 0)
- rv = errno;
-
- if (close (file) < 0 && rv == 0)
- rv = errno;
+ {
+ rv = errno;
+ close (file);
+ }
+
+ if (rv == 0 && fstat (file, &nfinfo) < 0)
+ {
+ rv = errno;
+ close (file);
+ }
}
else
rv = errno;
@@ -610,7 +642,7 @@ history_truncate_file (fname, lines)
user is running this, it's a no-op. If the shell is running after sudo
with a shared history file, we don't want to leave the history file
owned by root. */
- if (rv == 0 && exists)
+ if (rv == 0 && exists && SHOULD_CHOWN (finfo, nfinfo))
r = chown (filename, finfo.st_uid, finfo.st_gid);
xfree (filename);