wrap fgets to retry on EINTR
The read() underlying fgets() can be interrupted by a signal handler causing fgets() to return NULL. Before we started handling SIGWINCH, the odds of interrupting a read were low and typically resulted in termination anyway. Replace all fgets calls with a wrapper that retries in EINTR. Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
This commit is contained in:
parent
9c066dff43
commit
c792262b13
7 changed files with 43 additions and 14 deletions
|
@ -616,7 +616,7 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define READ_NEXT() do { \
|
#define READ_NEXT() do { \
|
||||||
if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) goto error; \
|
if(safe_fgets(line, sizeof(line), fp) == NULL && !feof(fp)) goto error; \
|
||||||
_alpm_strip_newline(line, 0); \
|
_alpm_strip_newline(line, 0); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -627,7 +627,7 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info,
|
||||||
|
|
||||||
#define READ_AND_STORE_ALL(f) do { \
|
#define READ_AND_STORE_ALL(f) do { \
|
||||||
char *linedup; \
|
char *linedup; \
|
||||||
if(fgets(line, sizeof(line), fp) == NULL) {\
|
if(safe_fgets(line, sizeof(line), fp) == NULL) {\
|
||||||
if(!feof(fp)) goto error; else break; \
|
if(!feof(fp)) goto error; else break; \
|
||||||
} \
|
} \
|
||||||
if(_alpm_strip_newline(line, 0) == 0) break; \
|
if(_alpm_strip_newline(line, 0) == 0) break; \
|
||||||
|
@ -636,7 +636,7 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info,
|
||||||
} while(1) /* note the while(1) and not (0) */
|
} while(1) /* note the while(1) and not (0) */
|
||||||
|
|
||||||
#define READ_AND_SPLITDEP(f) do { \
|
#define READ_AND_SPLITDEP(f) do { \
|
||||||
if(fgets(line, sizeof(line), fp) == NULL) {\
|
if(safe_fgets(line, sizeof(line), fp) == NULL) {\
|
||||||
if(!feof(fp)) goto error; else break; \
|
if(!feof(fp)) goto error; else break; \
|
||||||
} \
|
} \
|
||||||
if(_alpm_strip_newline(line, 0) == 0) break; \
|
if(_alpm_strip_newline(line, 0) == 0) break; \
|
||||||
|
@ -682,7 +682,7 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq)
|
||||||
}
|
}
|
||||||
free(path);
|
free(path);
|
||||||
while(!feof(fp)) {
|
while(!feof(fp)) {
|
||||||
if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) {
|
if(safe_fgets(line, sizeof(line), fp) == NULL && !feof(fp)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if(_alpm_strip_newline(line, 0) == 0) {
|
if(_alpm_strip_newline(line, 0) == 0) {
|
||||||
|
@ -771,13 +771,13 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
free(path);
|
free(path);
|
||||||
while(fgets(line, sizeof(line), fp)) {
|
while(safe_fgets(line, sizeof(line), fp)) {
|
||||||
_alpm_strip_newline(line, 0);
|
_alpm_strip_newline(line, 0);
|
||||||
if(strcmp(line, "%FILES%") == 0) {
|
if(strcmp(line, "%FILES%") == 0) {
|
||||||
size_t files_count = 0, files_size = 0, len;
|
size_t files_count = 0, files_size = 0, len;
|
||||||
alpm_file_t *files = NULL;
|
alpm_file_t *files = NULL;
|
||||||
|
|
||||||
while(fgets(line, sizeof(line), fp) &&
|
while(safe_fgets(line, sizeof(line), fp) &&
|
||||||
(len = _alpm_strip_newline(line, 0))) {
|
(len = _alpm_strip_newline(line, 0))) {
|
||||||
if(!_alpm_greedy_grow((void **)&files, &files_size,
|
if(!_alpm_greedy_grow((void **)&files, &files_size,
|
||||||
(files_size ? files_size + sizeof(alpm_file_t) : 8 * sizeof(alpm_file_t)))) {
|
(files_size ? files_size + sizeof(alpm_file_t) : 8 * sizeof(alpm_file_t)))) {
|
||||||
|
@ -797,7 +797,7 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq)
|
||||||
info->files.count = files_count;
|
info->files.count = files_count;
|
||||||
info->files.files = files;
|
info->files.files = files;
|
||||||
} else if(strcmp(line, "%BACKUP%") == 0) {
|
} else if(strcmp(line, "%BACKUP%") == 0) {
|
||||||
while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line, 0)) {
|
while(safe_fgets(line, sizeof(line), fp) && _alpm_strip_newline(line, 0)) {
|
||||||
alpm_backup_t *backup;
|
alpm_backup_t *backup;
|
||||||
CALLOC(backup, 1, sizeof(alpm_backup_t), goto error);
|
CALLOC(backup, 1, sizeof(alpm_backup_t), goto error);
|
||||||
if(_alpm_split_backup(line, &backup)) {
|
if(_alpm_split_backup(line, &backup)) {
|
||||||
|
|
|
@ -280,7 +280,7 @@ static int grep(const char *fn, const char *needle)
|
||||||
}
|
}
|
||||||
while(!feof(fp)) {
|
while(!feof(fp)) {
|
||||||
char line[1024];
|
char line[1024];
|
||||||
if(fgets(line, sizeof(line), fp) == NULL) {
|
if(safe_fgets(line, sizeof(line), fp) == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* TODO: this will not work if the search string
|
/* TODO: this will not work if the search string
|
||||||
|
|
|
@ -576,8 +576,9 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
|
||||||
.type = ALPM_EVENT_SCRIPTLET_INFO,
|
.type = ALPM_EVENT_SCRIPTLET_INFO,
|
||||||
.line = line
|
.line = line
|
||||||
};
|
};
|
||||||
if(fgets(line, PATH_MAX, pipe_file) == NULL)
|
if(safe_fgets(line, PATH_MAX, pipe_file) == NULL) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
alpm_logaction(handle, "ALPM-SCRIPTLET", "%s", line);
|
alpm_logaction(handle, "ALPM-SCRIPTLET", "%s", line);
|
||||||
EVENT(handle, &event);
|
EVENT(handle, &event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -102,6 +103,30 @@ int llstat(char *path, struct stat *buf)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Wrapper around fgets() which properly handles EINTR
|
||||||
|
* @param s string to read into
|
||||||
|
* @param size maximum length to read
|
||||||
|
* @param stream stream to read from
|
||||||
|
* @return value returned by fgets()
|
||||||
|
*/
|
||||||
|
char *safe_fgets(char *s, int size, FILE *stream)
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
int errno_save = errno, ferror_save = ferror(stream);
|
||||||
|
while((ret = fgets(s, size, stream)) == NULL && !feof(stream)) {
|
||||||
|
if(errno == EINTR) {
|
||||||
|
/* clear any errors we set and try again */
|
||||||
|
errno = errno_save;
|
||||||
|
if(!ferror_save) {
|
||||||
|
clearerr(stream);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
/* A quick and dirty implementation derived from glibc */
|
/* A quick and dirty implementation derived from glibc */
|
||||||
/** Determines the length of a fixed-size string.
|
/** Determines the length of a fixed-size string.
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#ifndef _PM_UTIL_COMMON_H
|
#ifndef _PM_UTIL_COMMON_H
|
||||||
#define _PM_UTIL_COMMON_H
|
#define _PM_UTIL_COMMON_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <sys/stat.h> /* struct stat */
|
#include <sys/stat.h> /* struct stat */
|
||||||
|
|
||||||
const char *mbasename(const char *path);
|
const char *mbasename(const char *path);
|
||||||
|
@ -27,6 +28,8 @@ char *mdirname(const char *path);
|
||||||
|
|
||||||
int llstat(char *path, struct stat *buf);
|
int llstat(char *path, struct stat *buf);
|
||||||
|
|
||||||
|
char *safe_fgets(char *s, int size, FILE *stream);
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *strndup(const char *s, size_t n);
|
char *strndup(const char *s, size_t n);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -66,7 +66,7 @@ static int _parse_ini(const char *file, ini_parser_fn cb, void *data,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(fgets(line, PATH_MAX, fp)) {
|
while(safe_fgets(line, PATH_MAX, fp)) {
|
||||||
char *key, *value, *ptr;
|
char *key, *value, *ptr;
|
||||||
size_t line_len;
|
size_t line_len;
|
||||||
|
|
||||||
|
|
|
@ -1403,7 +1403,7 @@ int multiselect_question(char *array, int count)
|
||||||
|
|
||||||
flush_term_input(fileno(stdin));
|
flush_term_input(fileno(stdin));
|
||||||
|
|
||||||
if(fgets(response, response_len, stdin)) {
|
if(safe_fgets(response, response_len, stdin)) {
|
||||||
const size_t response_incr = 64;
|
const size_t response_incr = 64;
|
||||||
size_t len;
|
size_t len;
|
||||||
/* handle buffer not being large enough to read full line case */
|
/* handle buffer not being large enough to read full line case */
|
||||||
|
@ -1416,7 +1416,7 @@ int multiselect_question(char *array, int count)
|
||||||
lastchar = response + response_len - 1;
|
lastchar = response + response_len - 1;
|
||||||
/* sentinel byte */
|
/* sentinel byte */
|
||||||
*lastchar = 1;
|
*lastchar = 1;
|
||||||
if(fgets(response + response_len - response_incr - 1,
|
if(safe_fgets(response + response_len - response_incr - 1,
|
||||||
response_incr + 1, stdin) == 0) {
|
response_incr + 1, stdin) == 0) {
|
||||||
free(response);
|
free(response);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1467,7 +1467,7 @@ int select_question(int count)
|
||||||
|
|
||||||
flush_term_input(fileno(stdin));
|
flush_term_input(fileno(stdin));
|
||||||
|
|
||||||
if(fgets(response, sizeof(response), stdin)) {
|
if(safe_fgets(response, sizeof(response), stdin)) {
|
||||||
size_t len = strtrim(response);
|
size_t len = strtrim(response);
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
int n;
|
int n;
|
||||||
|
@ -1521,7 +1521,7 @@ static int question(short preset, const char *format, va_list args)
|
||||||
|
|
||||||
flush_term_input(fd_in);
|
flush_term_input(fd_in);
|
||||||
|
|
||||||
if(fgets(response, sizeof(response), stdin)) {
|
if(safe_fgets(response, sizeof(response), stdin)) {
|
||||||
size_t len = strtrim(response);
|
size_t len = strtrim(response);
|
||||||
if(len == 0) {
|
if(len == 0) {
|
||||||
return preset;
|
return preset;
|
||||||
|
|
Loading…
Add table
Reference in a new issue