aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2013-11-28 03:14:16 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2013-11-28 03:14:16 +0100
commit259b3c047aea430c4aaecbdb9580a07e67691e8d (patch)
tree937c646d6384e0f79c11ef3d6527601ce164911b
parent8bd810bd276d20451faafdae88df4af9c2dd96d1 (diff)
downloadbusybox-w32-259b3c047aea430c4aaecbdb9580a07e67691e8d.tar.gz
busybox-w32-259b3c047aea430c4aaecbdb9580a07e67691e8d.tar.bz2
busybox-w32-259b3c047aea430c4aaecbdb9580a07e67691e8d.zip
sed: open input files sequentially to avoid EMFILE
Currently, sed pre-opens all files, which may cause EMFILE errors on systems with low ulimit -n. Change sed to open one file at a time. function old new delta get_next_line 177 235 +58 sed_main 682 652 -30 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 58/-30) Total: 28 bytes Based on the patch by Daniel Borca <dborca@yahoo.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/sed.c60
-rw-r--r--libbb/fclose_nonstdin.c3
2 files changed, 36 insertions, 27 deletions
diff --git a/editors/sed.c b/editors/sed.c
index 777f38308..87fa00291 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -23,7 +23,7 @@
23 * resulting sed_cmd_t structures are appended to a linked list 23 * resulting sed_cmd_t structures are appended to a linked list
24 * (G.sed_cmd_head/G.sed_cmd_tail). 24 * (G.sed_cmd_head/G.sed_cmd_tail).
25 * 25 *
26 * add_input_file() adds a FILE* to the list of input files. We need to 26 * add_input_file() adds a char* to the list of input files. We need to
27 * know all input sources ahead of time to find the last line for the $ match. 27 * know all input sources ahead of time to find the last line for the $ match.
28 * 28 *
29 * process_files() does actual sedding, reading data lines from each input FILE* 29 * process_files() does actual sedding, reading data lines from each input FILE*
@@ -135,12 +135,15 @@ static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
135struct globals { 135struct globals {
136 /* options */ 136 /* options */
137 int be_quiet, regex_type; 137 int be_quiet, regex_type;
138
138 FILE *nonstdout; 139 FILE *nonstdout;
139 char *outname, *hold_space; 140 char *outname, *hold_space;
141 smallint exitcode;
140 142
141 /* List of input files */ 143 /* list of input files */
142 int input_file_count, current_input_file; 144 int input_file_count, current_input_file;
143 FILE **input_file_list; 145 const char **input_file_list;
146 FILE *current_fp;
144 147
145 regmatch_t regmatch[10]; 148 regmatch_t regmatch[10];
146 regex_t *previous_regex_ptr; 149 regex_t *previous_regex_ptr;
@@ -148,7 +151,7 @@ struct globals {
148 /* linked list of sed commands */ 151 /* linked list of sed commands */
149 sed_cmd_t *sed_cmd_head, **sed_cmd_tail; 152 sed_cmd_t *sed_cmd_head, **sed_cmd_tail;
150 153
151 /* Linked list of append lines */ 154 /* linked list of append lines */
152 llist_t *append_head; 155 llist_t *append_head;
153 156
154 char *add_cmd_line; 157 char *add_cmd_line;
@@ -200,8 +203,8 @@ static void sed_free_and_close_stuff(void)
200 203
201 free(G.hold_space); 204 free(G.hold_space);
202 205
203 while (G.current_input_file < G.input_file_count) 206 if (G.current_fp)
204 fclose(G.input_file_list[G.current_input_file++]); 207 fclose(G.current_fp);
205} 208}
206#else 209#else
207void sed_free_and_close_stuff(void); 210void sed_free_and_close_stuff(void);
@@ -939,8 +942,20 @@ static char *get_next_line(char *gets_char, char *last_puts_char, char last_gets
939 /* will be returned if last line in the file 942 /* will be returned if last line in the file
940 * doesn't end with either '\n' or '\0' */ 943 * doesn't end with either '\n' or '\0' */
941 gc = NO_EOL_CHAR; 944 gc = NO_EOL_CHAR;
942 while (G.current_input_file < G.input_file_count) { 945 for (; G.input_file_list[G.current_input_file]; G.current_input_file++) {
943 FILE *fp = G.input_file_list[G.current_input_file]; 946 FILE *fp = G.current_fp;
947 if (!fp) {
948 const char *path = G.input_file_list[G.current_input_file];
949 fp = stdin;
950 if (path != bb_msg_standard_input) {
951 fp = fopen_or_warn(path, "r");
952 if (!fp) {
953 G.exitcode = EXIT_FAILURE;
954 continue;
955 }
956 }
957 G.current_fp = fp;
958 }
944 /* Read line up to a newline or NUL byte, inclusive, 959 /* Read line up to a newline or NUL byte, inclusive,
945 * return malloc'ed char[]. length of the chunk read 960 * return malloc'ed char[]. length of the chunk read
946 * is stored in len. NULL if EOF/error */ 961 * is stored in len. NULL if EOF/error */
@@ -971,8 +986,8 @@ static char *get_next_line(char *gets_char, char *last_puts_char, char last_gets
971 * (note: *no* newline after "b bang"!) */ 986 * (note: *no* newline after "b bang"!) */
972 } 987 }
973 /* Close this file and advance to next one */ 988 /* Close this file and advance to next one */
974 fclose(fp); 989 fclose_if_not_stdin(fp);
975 G.current_input_file++; 990 G.current_fp = NULL;
976 } 991 }
977 *gets_char = gc; 992 *gets_char = gc;
978 return temp; 993 return temp;
@@ -1399,7 +1414,7 @@ static void add_cmd_block(char *cmdstr)
1399 free(sv); 1414 free(sv);
1400} 1415}
1401 1416
1402static void add_input_file(FILE *file) 1417static void add_input_file(const char *file)
1403{ 1418{
1404 G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count); 1419 G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count);
1405 G.input_file_list[G.input_file_count++] = file; 1420 G.input_file_list[G.input_file_count++] = file;
@@ -1423,8 +1438,6 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1423 "file\0" Required_argument "f"; 1438 "file\0" Required_argument "f";
1424#endif 1439#endif
1425 1440
1426 int status = EXIT_SUCCESS;
1427
1428 INIT_G(); 1441 INIT_G();
1429 1442
1430 /* destroy command strings on exit */ 1443 /* destroy command strings on exit */
@@ -1491,27 +1504,21 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1491 if (argv[0] == NULL) { 1504 if (argv[0] == NULL) {
1492 if (opt & OPT_in_place) 1505 if (opt & OPT_in_place)
1493 bb_error_msg_and_die(bb_msg_requires_arg, "-i"); 1506 bb_error_msg_and_die(bb_msg_requires_arg, "-i");
1494 add_input_file(stdin); 1507 add_input_file(bb_msg_standard_input);
1495 } else { 1508 } else {
1496 int i; 1509 int i;
1497 1510
1498 for (i = 0; argv[i]; i++) { 1511 for (i = 0; argv[i]; i++) {
1499 struct stat statbuf; 1512 struct stat statbuf;
1500 int nonstdoutfd; 1513 int nonstdoutfd;
1501 FILE *file;
1502 sed_cmd_t *sed_cmd; 1514 sed_cmd_t *sed_cmd;
1503 1515
1504 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { 1516 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
1505 add_input_file(stdin); 1517 add_input_file(bb_msg_standard_input);
1506 process_files(); 1518 process_files();
1507 continue; 1519 continue;
1508 } 1520 }
1509 file = fopen_or_warn(argv[i], "r"); 1521 add_input_file(argv[i]);
1510 if (!file) {
1511 status = EXIT_FAILURE;
1512 continue;
1513 }
1514 add_input_file(file);
1515 if (!(opt & OPT_in_place)) { 1522 if (!(opt & OPT_in_place)) {
1516 continue; 1523 continue;
1517 } 1524 }
@@ -1523,7 +1530,7 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1523 G.nonstdout = xfdopen_for_write(nonstdoutfd); 1530 G.nonstdout = xfdopen_for_write(nonstdoutfd);
1524 1531
1525 /* Set permissions/owner of output file */ 1532 /* Set permissions/owner of output file */
1526 fstat(fileno(file), &statbuf); 1533 stat(argv[i], &statbuf);
1527 /* chmod'ing AFTER chown would preserve suid/sgid bits, 1534 /* chmod'ing AFTER chown would preserve suid/sgid bits,
1528 * but GNU sed 4.2.1 does not preserve them either */ 1535 * but GNU sed 4.2.1 does not preserve them either */
1529 fchmod(nonstdoutfd, statbuf.st_mode); 1536 fchmod(nonstdoutfd, statbuf.st_mode);
@@ -1549,12 +1556,13 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1549 } 1556 }
1550 } 1557 }
1551 /* Here, to handle "sed 'cmds' nonexistent_file" case we did: 1558 /* Here, to handle "sed 'cmds' nonexistent_file" case we did:
1552 * if (G.current_input_file >= G.input_file_count) 1559 * if (G.current_input_file[G.current_input_file] == NULL)
1553 * return status; 1560 * return G.exitcode;
1554 * but it's not needed since process_files() works correctly 1561 * but it's not needed since process_files() works correctly
1555 * in this case too. */ 1562 * in this case too. */
1556 } 1563 }
1564
1557 process_files(); 1565 process_files();
1558 1566
1559 return status; 1567 return G.exitcode;
1560} 1568}
diff --git a/libbb/fclose_nonstdin.c b/libbb/fclose_nonstdin.c
index 5ce9d5b48..1b1441347 100644
--- a/libbb/fclose_nonstdin.c
+++ b/libbb/fclose_nonstdin.c
@@ -18,7 +18,8 @@ int FAST_FUNC fclose_if_not_stdin(FILE *f)
18{ 18{
19 /* Some more paranoid applets want ferror() check too */ 19 /* Some more paranoid applets want ferror() check too */
20 int r = ferror(f); /* NB: does NOT set errno! */ 20 int r = ferror(f); /* NB: does NOT set errno! */
21 if (r) errno = EIO; /* so we'll help it */ 21 if (r)
22 errno = EIO; /* so we'll help it */
22 if (f != stdin) 23 if (f != stdin)
23 return (r | fclose(f)); /* fclose does set errno on error */ 24 return (r | fclose(f)); /* fclose does set errno on error */
24 return r; 25 return r;