From 33ad117166c4b37cc202eaefe5a9a79f0a51d38b Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 5 Apr 2023 17:50:12 +0200 Subject: [PATCH 1/5] Fix purging old log files with absolute file path Removing old timestamp or increment versions of log backup files did not work when the file is an absolute path: only the entry name was provided to the file remove function. The dirname was also bogus, since the file separater was put back too soon. Fix these issues to make log file rotation work when the file is configured to be an absolute path. (cherry picked from commit 70629d73da5b0de709bece2d0ff38ac0b165ef77) --- lib/isc/log.c | 80 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/lib/isc/log.c b/lib/isc/log.c index 4ad9983769..ca9dc8af71 100644 --- a/lib/isc/log.c +++ b/lib/isc/log.c @@ -1044,18 +1044,11 @@ greatest_version(isc_logfile_t *file, int versions, int *greatestp) { isc_dir_init(&dir); result = isc_dir_open(&dir, dirname); - /* - * Replace the file separator if it was taken out. - */ - if (bname != file->name) { - *(bname - 1) = sep; - } - /* * Return if the directory open failed. */ if (result != ISC_R_SUCCESS) { - return (result); + goto out; } while (isc_dir_read(&dir) == ISC_R_SUCCESS) { @@ -1069,14 +1062,25 @@ greatest_version(isc_logfile_t *file, int versions, int *greatestp) { * Remove any backup files that exceed versions. */ if (*digit_end == '\0' && version >= versions) { - result = isc_file_remove(dir.entry.name); + char rmfile[PATH_MAX + 1]; + int n = snprintf(rmfile, sizeof(rmfile), + "%s/%s", dirname, + dir.entry.name); + if (n >= (int)sizeof(rmfile) || n < 0) { + result = ISC_R_NOSPACE; + syslog(LOG_ERR, + "unable to remove log files: %s", + isc_result_totext(result)); + break; + } + result = isc_file_remove(rmfile); if (result != ISC_R_SUCCESS && - result != ISC_R_FILENOTFOUND) + result != ISC_R_NOTFOUND) { syslog(LOG_ERR, - "unable to remove " - "log file '%s': %s", - dir.entry.name, + "unable to remove log file " + "'%s': %s", + rmfile, isc_result_totext(result)); } } else if (*digit_end == '\0' && version > greatest) { @@ -1087,8 +1091,16 @@ greatest_version(isc_logfile_t *file, int versions, int *greatestp) { isc_dir_close(&dir); *greatestp = greatest; + result = ISC_R_SUCCESS; - return (ISC_R_SUCCESS); +out: + /* + * Replace the file separator if it was taken out. + */ + if (bname != file->name) { + *(bname - 1) = sep; + } + return (result); } static void @@ -1176,18 +1188,11 @@ remove_old_tsversions(isc_logfile_t *file, int versions) { isc_dir_init(&dir); result = isc_dir_open(&dir, dirname); - /* - * Replace the file separator if it was taken out. - */ - if (bname != file->name) { - *(bname - 1) = sep; - } - /* * Return if the directory open failed. */ if (result != ISC_R_SUCCESS) { - return (result); + goto out; } last = last_to_keep(versions, &dir, bname, bnamelen); @@ -1206,14 +1211,25 @@ remove_old_tsversions(isc_logfile_t *file, int versions) { * Remove any backup files that exceed versions. */ if (*digit_end == '\0' && version < last) { - result = isc_file_remove(dir.entry.name); + char rmfile[PATH_MAX + 1]; + int n = snprintf(rmfile, sizeof(rmfile), + "%s/%s", dirname, + dir.entry.name); + if (n >= (int)sizeof(rmfile) || n < 0) { + result = ISC_R_NOSPACE; + syslog(LOG_ERR, + "unable to remove log files: %s", + isc_result_totext(result)); + break; + } + result = isc_file_remove(rmfile); if (result != ISC_R_SUCCESS && - result != ISC_R_FILENOTFOUND) + result != ISC_R_NOTFOUND) { syslog(LOG_ERR, - "unable to remove " - "log file '%s': %s", - dir.entry.name, + "unable to remove log file " + "'%s': %s", + rmfile, isc_result_totext(result)); } } @@ -1221,8 +1237,16 @@ remove_old_tsversions(isc_logfile_t *file, int versions) { } isc_dir_close(&dir); + result = ISC_R_SUCCESS; - return (ISC_R_SUCCESS); +out: + /* + * Replace the file separator if it was taken out. + */ + if (bname != file->name) { + *(bname - 1) = sep; + } + return (result); } static isc_result_t From eb37fd2f136afdf0937261aaf4e6066b95ef564d Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 6 Apr 2023 09:21:09 +0200 Subject: [PATCH 2/5] Add more log/tap rotation tests Add more tests to the dnstap system test to roll with different values. Touch some files to make sure the number of existing files exceed the number that we want to keep. Add a test to the logfileconfig system test for the increment suffix. (cherry picked from commit 9fb9670ebcc9d234c95c1c9512211ad6d50feea5) --- bin/tests/system/dnstap/tests.sh | 40 +++++++++----- bin/tests/system/logfileconfig/clean.sh | 2 + .../system/logfileconfig/ns1/named.incconf.in | 52 +++++++++++++++++++ bin/tests/system/logfileconfig/tests.sh | 28 ++++++++++ 4 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 bin/tests/system/logfileconfig/ns1/named.incconf.in diff --git a/bin/tests/system/dnstap/tests.sh b/bin/tests/system/dnstap/tests.sh index 5ed1d94c3c..9e28c95689 100644 --- a/bin/tests/system/dnstap/tests.sh +++ b/bin/tests/system/dnstap/tests.sh @@ -787,28 +787,42 @@ lines=`$DNSTAPREAD -y large-answer.fstrm | grep -c "opcode: QUERY"` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` -test_dnstap_roll() ( +_test_dnstap_roll() ( ip="$1" ns="$2" n="$3" + $RNDCCMD -s "${ip}" dnstap -roll "${n}" | sed "s/^/${ns} /" | cat_i && files=$(find "$ns" -name "dnstap.out.[0-9]" | wc -l) && - test "$files" -le "${n}" && test "$files" -ge "1" + test "$files" -eq "${n}" && test "$files" -ge "1" ) -echo_i "checking 'rndc -roll ' (no versions)" -ret=0 -start_server --noclean --restart --port "${PORT}" ns3 -_repeat 5 test_dnstap_roll 10.53.0.3 ns3 3 || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status+ret)) -echo_i "checking 'rndc -roll ' (versions)" -ret=0 +test_dnstap_roll() { + echo_i "checking 'rndc -roll $4' ($1)" + ret=0 + + try=0 + while test $try -lt 12 + do + touch "$3/dnstap.out.$try" + try=`expr $try + 1` + done + + _repeat 10 _test_dnstap_roll $2 $3 $4 || ret=1 + if [ $ret != 0 ]; then echo_i "failed"; fi + status=$((status+ret)) +} + +start_server --noclean --restart --port "${PORT}" ns3 +test_dnstap_roll "no versions" 10.53.0.3 ns3 6 +test_dnstap_roll "no versions" 10.53.0.3 ns3 3 +test_dnstap_roll "no versions" 10.53.0.3 ns3 1 + start_server --noclean --restart --port "${PORT}" ns2 -_repeat 5 test_dnstap_roll 10.53.0.2 ns2 3 || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status+ret)) +test_dnstap_roll "versions" 10.53.0.2 ns2 6 +test_dnstap_roll "versions" 10.53.0.2 ns2 3 +test_dnstap_roll "versions" 10.53.0.2 ns2 1 echo_i "exit status: $status" [ "$status" -eq 0 ] || exit 1 diff --git a/bin/tests/system/logfileconfig/clean.sh b/bin/tests/system/logfileconfig/clean.sh index 18aa5de2dd..befbcfe84e 100644 --- a/bin/tests/system/logfileconfig/clean.sh +++ b/bin/tests/system/logfileconfig/clean.sh @@ -31,6 +31,8 @@ rm -f ns1/named_vers rm -f ns1/named_vers.* rm -f ns1/named_ts rm -f ns1/named_ts.* +rm -f ns1/named_inc +rm -f ns1/named_inc.* rm -f ns1/named_unlimited rm -f ns1/named_unlimited.* rm -f ns*/managed-keys.bind* diff --git a/bin/tests/system/logfileconfig/ns1/named.incconf.in b/bin/tests/system/logfileconfig/ns1/named.incconf.in new file mode 100644 index 0000000000..d398c330eb --- /dev/null +++ b/bin/tests/system/logfileconfig/ns1/named.incconf.in @@ -0,0 +1,52 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + dnssec-validation no; + recursion no; + notify yes; +}; + +logging { + channel default_log { + buffered no; + file "named_inc" versions 1 size 1k suffix increment; # small size + severity debug 100; + print-time yes; + }; + category default { default_log; default_debug; }; + category lame-servers { null; }; + + channel query_log { + file "query_log"; + print-time yes; + buffered yes; + }; + category queries { query_log; }; +}; + +controls { + inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; +}; + +key rndc-key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; diff --git a/bin/tests/system/logfileconfig/tests.sh b/bin/tests/system/logfileconfig/tests.sh index 397f9aa443..8c433b07f7 100644 --- a/bin/tests/system/logfileconfig/tests.sh +++ b/bin/tests/system/logfileconfig/tests.sh @@ -208,6 +208,34 @@ retry_quiet 5 _found2 || ret=1 if [ "$ret" -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) +n=$((n+1)) +echo_i "testing incremented versions ($n)" +ret=0 +copy_setports ns1/named.incconf.in ns1/named.conf +try=0 +while test $try -lt 12 +do + touch ns1/named_inc.$try + try=`expr $try + 1` +done +rndc_reconfig ns1 10.53.0.1 > rndc.out.test$n +_found2() ( + $DIG version.bind txt ch @10.53.0.1 -p ${PORT} > dig.out.test$n + grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + + try=1 + while test $try -lt 12 + do + [ -f ns1/named_inc.$try ] && return 1 + try=`expr $try + 1` + done + set -- ns1/named_inc.* + [ "$#" -eq 1 ] || return 1 +) +retry_quiet 5 _found2 || ret=1 +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + n=$((n+1)) echo_i "testing unlimited versions ($n)" ret=0 From cf8bf1e0840eeaadc19b3df0fe2466f0f9b15c4e Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 6 Apr 2023 09:24:43 +0200 Subject: [PATCH 3/5] Add log rotation test with absolute file path Add a test to the logfileconfig system test to test log file rotation when using absolute file paths. (cherry picked from commit d9b1df3b5d23ade36dbf8c251f4fb2fb20556a78) --- bin/tests/system/conf.sh.common | 7 ++- .../logfileconfig/ns1/named.abspathconf.in | 52 +++++++++++++++++++ bin/tests/system/logfileconfig/tests.sh | 28 ++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 bin/tests/system/logfileconfig/ns1/named.abspathconf.in diff --git a/bin/tests/system/conf.sh.common b/bin/tests/system/conf.sh.common index 5474332ca5..1f3bb68d3e 100644 --- a/bin/tests/system/conf.sh.common +++ b/bin/tests/system/conf.sh.common @@ -709,9 +709,12 @@ get_named_xfer_stats() { # copy_setports infile outfile # copy_setports() { - sed -e "s/@PORT@/${PORT}/g" \ + dir=$(echo "$TMPDIR" | sed 's/\//\\\//g') + + sed -e "s/@TMPDIR@/${dir}/g" \ + -e "s/@PORT@/${PORT}/g" \ -e "s/@TLSPORT@/${TLSPORT}/g" \ - -e "s/@HTTPPORT@/${HTTPPORT}/g" \ + -e "s/@HTTPPORT@/${HTTPPORT}/g" \ -e "s/@HTTPSPORT@/${HTTPSPORT}/g" \ -e "s/@EXTRAPORT1@/${EXTRAPORT1}/g" \ -e "s/@EXTRAPORT2@/${EXTRAPORT2}/g" \ diff --git a/bin/tests/system/logfileconfig/ns1/named.abspathconf.in b/bin/tests/system/logfileconfig/ns1/named.abspathconf.in new file mode 100644 index 0000000000..fdf8a8ace2 --- /dev/null +++ b/bin/tests/system/logfileconfig/ns1/named.abspathconf.in @@ -0,0 +1,52 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + dnssec-validation no; + recursion no; + notify yes; +}; + +logging { + channel default_log { + buffered no; + file "@TMPDIR@/example.log" versions 1 size 1k suffix increment; # small size + severity debug 100; + print-time yes; + }; + category default { default_log; default_debug; }; + category lame-servers { null; }; + + channel query_log { + file "query_log"; + print-time yes; + buffered yes; + }; + category queries { query_log; }; +}; + +controls { + inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; +}; + +key rndc-key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; diff --git a/bin/tests/system/logfileconfig/tests.sh b/bin/tests/system/logfileconfig/tests.sh index 8c433b07f7..3abf17540a 100644 --- a/bin/tests/system/logfileconfig/tests.sh +++ b/bin/tests/system/logfileconfig/tests.sh @@ -236,6 +236,34 @@ retry_quiet 5 _found2 || ret=1 if [ "$ret" -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) +n=$((n+1)) +echo_i "testing absolute file path versions ($n)" +ret=0 +copy_setports ns1/named.abspathconf.in ns1/named.conf +try=0 +while test $try -lt 12 +do + touch $TMPDIR/example.log.$try + try=`expr $try + 1` +done +rndc_reconfig ns1 10.53.0.1 > rndc.out.test$n +_found2() ( + $DIG version.bind txt ch @10.53.0.1 -p ${PORT} > dig.out.test$n + grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + + try=1 + while test $try -lt 12 + do + [ -f $TMPDIR/example.log.$try ] && return 1 + try=`expr $try + 1` + done + set -- $TMPDIR/example.log.* + [ "$#" -eq 1 ] || return 1 +) +retry_quiet 5 _found2 || ret=1 +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=$((status+ret)) + n=$((n+1)) echo_i "testing unlimited versions ($n)" ret=0 From 1670a738bdb81a6b1e7fb574c8f15c4763944905 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 6 Apr 2023 09:45:55 +0200 Subject: [PATCH 4/5] Add release note and CHANGES for #3991 Bug worth mentioning. (cherry picked from commit ab9230b383b627ce9eab4e08d4c36330d1715299) --- CHANGES | 3 +++ doc/notes/notes-current.rst | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/CHANGES b/CHANGES index 9fff603ef8..7b46c9e2dd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +6161. [bug] Fix log file rotation when using absolute path as + file. [GL #3991] + 6157. [bug] When removing delegations in an OPTOUT range empty-non-terminal NSEC3 records generated by those delegations where not removed. [GL #4027] diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index bb0ff4bc37..c81ed1f9fe 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -45,6 +45,10 @@ Bug Fixes incoming zone transfers now time out properly when not progressing. :gl:`#4004` +- Log file rotation did not clean up older versions of log files when the + logging :any:`channel` configured an absolute path as ``file`` destination. + This has now been fixed. :gl:`#3991`. + Known Issues ~~~~~~~~~~~~ From fa35d059daddebb6afc4e4be698b27223297f788 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 14 Apr 2023 13:53:41 +1000 Subject: [PATCH 5/5] Re-write remove_old_tsversions and greatest_version Stop deliberately breaking const rules by copying file->name into dirbuf and truncating it there. Handle files located in the root directory properly. Use unlinkat() from POSIX 200809. (cherry picked from commit 9fcd42c6726fb75681d2359913af58a4a4280df3) --- lib/isc/log.c | 191 +++++++++++++++++++++++++------------------------- 1 file changed, 95 insertions(+), 96 deletions(-) diff --git a/lib/isc/log.c b/lib/isc/log.c index ca9dc8af71..523fd2d6bb 100644 --- a/lib/isc/log.c +++ b/lib/isc/log.c @@ -20,9 +20,11 @@ #include #include /* dev_t FreeBSD 2.1 */ #include +#include #include #include +#include #include #include #include @@ -1019,25 +1021,37 @@ sync_highest_level(isc_log_t *lctx, isc_logconfig_t *lcfg) { static isc_result_t greatest_version(isc_logfile_t *file, int versions, int *greatestp) { - char *bname, *digit_end; - const char *dirname; + char *digit_end; + char dirbuf[PATH_MAX + 1]; + const char *bname; + const char *dirname = "."; int version, greatest = -1; - size_t bnamelen; isc_dir_t dir; isc_result_t result; - char sep = '/'; + size_t bnamelen; - /* - * It is safe to DE_CONST the file.name because it was copied - * with isc_mem_strdup(). - */ - bname = strrchr(file->name, sep); + bname = strrchr(file->name, '/'); if (bname != NULL) { - *bname++ = '\0'; - dirname = file->name; + /* + * Copy the complete file name to dirbuf. + */ + size_t len = strlcpy(dirbuf, file->name, sizeof(dirbuf)); + if (len >= sizeof(dirbuf)) { + result = ISC_R_NOSPACE; + syslog(LOG_ERR, "unable to remove log files: %s", + isc_result_totext(result)); + return (result); + } + + /* + * Truncate after trailing '/' so the code works for + * files in the root directory. + */ + bname++; + dirbuf[bname - file->name] = '\0'; + dirname = dirbuf; } else { - DE_CONST(file->name, bname); - dirname = "."; + bname = file->name; } bnamelen = strlen(bname); @@ -1048,7 +1062,7 @@ greatest_version(isc_logfile_t *file, int versions, int *greatestp) { * Return if the directory open failed. */ if (result != ISC_R_SUCCESS) { - goto out; + return (result); } while (isc_dir_read(&dir) == ISC_R_SUCCESS) { @@ -1062,26 +1076,23 @@ greatest_version(isc_logfile_t *file, int versions, int *greatestp) { * Remove any backup files that exceed versions. */ if (*digit_end == '\0' && version >= versions) { - char rmfile[PATH_MAX + 1]; - int n = snprintf(rmfile, sizeof(rmfile), - "%s/%s", dirname, - dir.entry.name); - if (n >= (int)sizeof(rmfile) || n < 0) { - result = ISC_R_NOSPACE; - syslog(LOG_ERR, - "unable to remove log files: %s", - isc_result_totext(result)); - break; - } - result = isc_file_remove(rmfile); - if (result != ISC_R_SUCCESS && - result != ISC_R_NOTFOUND) - { - syslog(LOG_ERR, - "unable to remove log file " - "'%s': %s", - rmfile, - isc_result_totext(result)); + int n = unlinkat(dirfd(dir.handle), + dir.entry.name, 0); + if (n < 0) { + result = isc_errno_toresult(errno); + if (result != ISC_R_SUCCESS && + result != ISC_R_FILENOTFOUND) + { + syslog(LOG_ERR, + "unable to remove log " + "file '%s%s': %s", + bname == file->name + ? "" + : dirname, + dir.entry.name, + isc_result_totext( + result)); + } } } else if (*digit_end == '\0' && version > greatest) { greatest = version; @@ -1091,16 +1102,7 @@ greatest_version(isc_logfile_t *file, int versions, int *greatestp) { isc_dir_close(&dir); *greatestp = greatest; - result = ISC_R_SUCCESS; - -out: - /* - * Replace the file separator if it was taken out. - */ - if (bname != file->name) { - *(bname - 1) = sep; - } - return (result); + return (ISC_R_SUCCESS); } static void @@ -1120,7 +1122,8 @@ insert_sort(int64_t to_keep[], int64_t versions, int64_t version) { } static int64_t -last_to_keep(int64_t versions, isc_dir_t *dirp, char *bname, size_t bnamelen) { +last_to_keep(int64_t versions, isc_dir_t *dirp, const char *bname, + size_t bnamelen) { int64_t to_keep[ISC_LOG_MAX_VERSIONS] = { 0 }; int64_t version = 0; @@ -1163,25 +1166,37 @@ last_to_keep(int64_t versions, isc_dir_t *dirp, char *bname, size_t bnamelen) { static isc_result_t remove_old_tsversions(isc_logfile_t *file, int versions) { - isc_result_t result; - char *bname = NULL, *digit_end = NULL; - const char *dirname = NULL; + char *digit_end; + char dirbuf[PATH_MAX + 1]; + const char *bname; + const char *dirname = "."; int64_t version, last = INT64_MAX; - size_t bnamelen; isc_dir_t dir; - char sep = '/'; + isc_result_t result; + size_t bnamelen; - /* - * It is safe to DE_CONST the file.name because it was copied - * with isc_mem_strdup(). - */ - bname = strrchr(file->name, sep); + bname = strrchr(file->name, '/'); if (bname != NULL) { - *bname++ = '\0'; - dirname = file->name; + /* + * Copy the complete file name to dirbuf. + */ + size_t len = strlcpy(dirbuf, file->name, sizeof(dirbuf)); + if (len >= sizeof(dirbuf)) { + result = ISC_R_NOSPACE; + syslog(LOG_ERR, "unable to remove log files: %s", + isc_result_totext(result)); + return (result); + } + + /* + * Truncate after trailing '/' so the code works for + * files in the root directory. + */ + bname++; + dirbuf[bname - file->name] = '\0'; + dirname = dirbuf; } else { - DE_CONST(file->name, bname); - dirname = "."; + bname = file->name; } bnamelen = strlen(bname); @@ -1192,61 +1207,45 @@ remove_old_tsversions(isc_logfile_t *file, int versions) { * Return if the directory open failed. */ if (result != ISC_R_SUCCESS) { - goto out; + return (result); } last = last_to_keep(versions, &dir, bname, bnamelen); - /* - * Then we remove all files that we don't want to_keep - */ while (isc_dir_read(&dir) == ISC_R_SUCCESS) { if (dir.entry.length > bnamelen && strncmp(dir.entry.name, bname, bnamelen) == 0 && dir.entry.name[bnamelen] == '.') { - char *ename = &dir.entry.name[bnamelen + 1]; - version = strtoull(ename, &digit_end, 10); + version = strtoull(&dir.entry.name[bnamelen + 1], + &digit_end, 10); /* * Remove any backup files that exceed versions. */ if (*digit_end == '\0' && version < last) { - char rmfile[PATH_MAX + 1]; - int n = snprintf(rmfile, sizeof(rmfile), - "%s/%s", dirname, - dir.entry.name); - if (n >= (int)sizeof(rmfile) || n < 0) { - result = ISC_R_NOSPACE; - syslog(LOG_ERR, - "unable to remove log files: %s", - isc_result_totext(result)); - break; - } - result = isc_file_remove(rmfile); - if (result != ISC_R_SUCCESS && - result != ISC_R_NOTFOUND) - { - syslog(LOG_ERR, - "unable to remove log file " - "'%s': %s", - rmfile, - isc_result_totext(result)); + int n = unlinkat(dirfd(dir.handle), + dir.entry.name, 0); + if (n < 0) { + result = isc_errno_toresult(errno); + if (result != ISC_R_SUCCESS && + result != ISC_R_FILENOTFOUND) + { + syslog(LOG_ERR, + "unable to remove log " + "file '%s%s': %s", + bname == file->name + ? "" + : dirname, + dir.entry.name, + isc_result_totext( + result)); + } } } } } - isc_dir_close(&dir); - result = ISC_R_SUCCESS; - -out: - /* - * Replace the file separator if it was taken out. - */ - if (bname != file->name) { - *(bname - 1) = sep; - } - return (result); + return (ISC_R_SUCCESS); } static isc_result_t