diff --git a/lib/commonio.c b/lib/commonio.c index 73fdb3a1..9349597a 100644 --- a/lib/commonio.c +++ b/lib/commonio.c @@ -140,7 +140,7 @@ static int do_lock_file (const char *file, const char *lock, bool log) pid = getpid (); snprintf (buf, sizeof buf, "%lu", (unsigned long) pid); len = (ssize_t) strlen (buf) + 1; - if (write_full (fd, buf, (size_t) len) != len) { + if (write_full(fd, buf, len) == -1) { if (log) { (void) fprintf (shadow_logfd, "%s: %s file write error: %s\n", diff --git a/lib/prototypes.h b/lib/prototypes.h index d20abf3e..47ed2ca1 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -527,7 +527,7 @@ extern unsigned long active_sessions_count(const char *name, extern bool valid (const char *, const struct passwd *); /* write_full.c */ -extern ssize_t write_full(int fd, const void *buf, size_t count); +extern int write_full(int fd, const void *buf, size_t count); /* xgetpwnam.c */ extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *); diff --git a/lib/write_full.c b/lib/write_full.c index cde52fbf..4ef902cd 100644 --- a/lib/write_full.c +++ b/lib/write_full.c @@ -1,7 +1,8 @@ /* - * SPDX-FileCopyrightText: 2023, Christian Göttsche + * SPDX-FileCopyrightText: 2023, Christian Göttsche + * SPDX-FileCopyrightText: 2023, Alejandro Colomar * - * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: BSD-3-Clause */ @@ -9,44 +10,68 @@ #ident "$Id$" -#include "prototypes.h" - #include #include +#include "prototypes.h" + /* - * write_full - write entire buffer + * SYNOPSIS + * int write_full(int fd, const void *buf, size_t count); * - * Write up to count bytes from the buffer starting at buf to the - * file referred to by the file descriptor fd. - * Retry in case of a short write. + * ARGUMENTS + * fd File descriptor. + * buf Source buffer to write(2) into 'fd'. + * count Size of 'buf'. * - * Returns the number of bytes written on success, -1 on error. + * DESCRIPTION + * Write 'count' bytes from the buffer starting at 'buf' to the + * file referred to by 'fd'. + * + * This function is similar to write(2), except that it retries + * in case of a short write. + * + * Since this function either performs a full write, or fails, the + * return value is simpler than for write(2). + * + * RETURN VALUE + * 0 On success. + * -1 On error. + * + * ERRORS + * See write(2). + * + * CAVEATS + * This function can still perform partial writes: if the function + * fails in the loop after one or more write(2) calls have + * succeeded, it will report a failure, but some data may have been + * written. In such a case, it's the caller's responsibility to + * make sure that the partial write is not problematic, and + * remediate it if it is --maybe by trying to remove the file--. */ -ssize_t write_full(int fd, const void *buf, size_t count) { - ssize_t written = 0; + + +int +write_full(int fd, const void *buf, size_t count) +{ + ssize_t w; + const unsigned char *p; + + p = buf; while (count > 0) { - ssize_t res; - - res = write(fd, buf, count); - if (res < 0) { - if (errno == EINTR) { + w = write(fd, p, count); + if (w == -1) { + if (errno == EINTR) continue; - } - return res; + return -1; } - if (res == 0) { - break; - } - - written += res; - buf = (const unsigned char*)buf + res; - count -= res; + p += w; + count -= w; } - return written; + return 0; } diff --git a/libmisc/copydir.c b/libmisc/copydir.c index cc1a30d2..bbee719f 100644 --- a/libmisc/copydir.c +++ b/libmisc/copydir.c @@ -816,7 +816,7 @@ static int copy_file (const struct path_info *src, const struct path_info *dst, break; } - if (write_full (ofd, buf, cnt) < 0) { + if (write_full(ofd, buf, cnt) == -1) { (void) close (ofd); (void) close (ifd); return -1; diff --git a/libmisc/failure.c b/libmisc/failure.c index 6fc575c1..205eec9c 100644 --- a/libmisc/failure.c +++ b/libmisc/failure.c @@ -86,7 +86,7 @@ void failure (uid_t uid, const char *tty, struct faillog *fl) */ if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write_full (fd, fl, sizeof *fl) != (ssize_t) sizeof *fl) + || (write_full(fd, fl, sizeof *fl) == -1) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't write faillog entry for UID %lu in %s.", @@ -185,7 +185,7 @@ int failcheck (uid_t uid, struct faillog *fl, bool failed) fail.fail_cnt = 0; if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write_full (fd, &fail, sizeof fail) != (ssize_t) sizeof fail) + || (write_full(fd, &fail, sizeof fail) == -1) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't reset faillog entry for UID %lu in %s.", diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c index ae8c4b93..b4e459e6 100644 --- a/libmisc/idmapping.c +++ b/libmisc/idmapping.c @@ -215,7 +215,7 @@ void write_mapping(int proc_dir_fd, int ranges, const struct map_range *mappings log_get_progname(), map_file, strerror(errno)); exit(EXIT_FAILURE); } - if (write_full(fd, buf, pos - buf) != (pos - buf)) { + if (write_full(fd, buf, pos - buf) == -1) { fprintf(log_get_logfd(), _("%s: write to %s failed: %s\n"), log_get_progname(), map_file, strerror(errno)); exit(EXIT_FAILURE); diff --git a/libmisc/log.c b/libmisc/log.c index cc38d6dc..fb867b27 100644 --- a/libmisc/log.c +++ b/libmisc/log.c @@ -82,7 +82,7 @@ void dolastlog ( strncpy (newlog.ll_host, host, sizeof (newlog.ll_host) - 1); #endif if ( (lseek (fd, offset, SEEK_SET) != offset) - || (write_full (fd, &newlog, sizeof newlog) != (ssize_t) sizeof newlog) + || (write_full(fd, &newlog, sizeof newlog) == -1) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't write lastlog entry for UID %lu in %s.", diff --git a/libmisc/utmp.c b/libmisc/utmp.c index 7c7da697..2cccdcd2 100644 --- a/libmisc/utmp.c +++ b/libmisc/utmp.c @@ -97,7 +97,7 @@ static void failtmp (const char *username, const struct utmp *failent) * Append the new failure record and close the log file. */ - if ( (write_full (fd, failent, sizeof *failent) != (ssize_t) sizeof *failent) + if ( (write_full(fd, failent, sizeof *failent) == -1) || (close (fd) != 0)) { SYSLOG ((LOG_WARN, "Can't append failure of user %s to %s.", @@ -194,7 +194,7 @@ static void updwtmp (const char *filename, const struct utmp *ut) fd = open (filename, O_APPEND | O_WRONLY, 0); if (fd >= 0) { - write_full (fd, ut, sizeof (*ut)); + write_full(fd, ut, sizeof(*ut)); close (fd); } } diff --git a/src/login.c b/src/login.c index b5562923..0f308dc1 100644 --- a/src/login.c +++ b/src/login.c @@ -400,7 +400,7 @@ static void exit_handler (unused int sig) static void alarm_handler (unused int sig) { - write_full (STDERR_FILENO, tmsg, strlen (tmsg)); + write_full(STDERR_FILENO, tmsg, strlen(tmsg)); signal(SIGALRM, exit_handler); alarm(2); } diff --git a/src/su.c b/src/su.c index 84b92468..b0334413 100644 --- a/src/su.c +++ b/src/su.c @@ -164,9 +164,9 @@ static void kill_child (int unused(s)) { if (0 != pid_child) { (void) kill (-pid_child, SIGKILL); - (void) write_full (STDERR_FILENO, kill_msg, strlen (kill_msg)); + (void) write_full(STDERR_FILENO, kill_msg, strlen(kill_msg)); } else { - (void) write_full (STDERR_FILENO, wait_msg, strlen (wait_msg)); + (void) write_full(STDERR_FILENO, wait_msg, strlen(wait_msg)); } _exit (255); } diff --git a/src/useradd.c b/src/useradd.c index 5b601e01..a6909927 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -2067,7 +2067,7 @@ static void faillog_reset (uid_t uid) return; } if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write_full (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl)) + || (write_full(fd, &fl, sizeof (fl)) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to reset the faillog entry of UID %lu: %s\n"), diff --git a/src/usermod.c b/src/usermod.c index 9e896802..61cd11a8 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -1941,7 +1941,7 @@ static void update_lastlog (void) && (read (fd, &ll, sizeof ll) == (ssize_t) sizeof ll)) { /* Copy the old entry to its new location */ if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write_full (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) + || (write_full(fd, &ll, sizeof ll) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), @@ -1957,7 +1957,7 @@ static void update_lastlog (void) /* Reset the new uid's lastlog entry */ memzero (&ll, sizeof (ll)); if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write_full (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) + || (write_full(fd, &ll, sizeof ll) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), @@ -2001,7 +2001,7 @@ static void update_faillog (void) && (read (fd, &fl, sizeof fl) == (ssize_t) sizeof fl)) { /* Copy the old entry to its new location */ if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write_full (fd, &fl, sizeof fl) != (ssize_t) sizeof fl) + || (write_full(fd, &fl, sizeof fl) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"), @@ -2017,7 +2017,8 @@ static void update_faillog (void) /* Reset the new uid's faillog entry */ memzero (&fl, sizeof (fl)); if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write_full (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)) { + || (write_full(fd, &fl, sizeof fl) == -1)) + { fprintf (stderr, _("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"), Prog, (unsigned long) user_id, (unsigned long) user_newid, strerror (errno));