summaryrefslogtreecommitdiff
path: root/src/sort.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sort.c')
-rw-r--r--src/sort.c79
1 files changed, 60 insertions, 19 deletions
diff --git a/src/sort.c b/src/sort.c
index 7410abca..c2493192 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -1,5 +1,5 @@
/* sort - sort lines of text (with all kinds of options).
- Copyright (C) 1988-2013 Free Software Foundation, Inc.
+ Copyright (C) 1988-2014 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -221,7 +221,7 @@ struct keyfield
bool general_numeric; /* Flag for general, numeric comparison.
Handle numbers in exponential notation. */
bool human_numeric; /* Flag for sorting by human readable
- units with either SI xor IEC prefixes. */
+ units with either SI or IEC prefixes. */
bool month; /* Flag for comparison by month name. */
bool reverse; /* Reverse the sense of comparison. */
bool version; /* sort by version number */
@@ -373,6 +373,34 @@ static bool debug;
number are present, temp files will be used. */
static unsigned int nmerge = NMERGE_DEFAULT;
+/* Output an error to stderr using async-signal-safe routines, and _exit().
+ This can be used safely from signal handlers,
+ and between fork() and exec() of multithreaded processes. */
+
+static void async_safe_die (int, const char *) ATTRIBUTE_NORETURN;
+static void
+async_safe_die (int errnum, const char *errstr)
+{
+ ignore_value (write (STDERR_FILENO, errstr, strlen (errstr)));
+
+ /* Even if defined HAVE_STRERROR_R, we can't use it,
+ as it may return a translated string etc. and even if not
+ may malloc() which is unsafe. We might improve this
+ by testing for sys_errlist and using that if available.
+ For now just report the error number. */
+ if (errnum)
+ {
+ char errbuf[INT_BUFSIZE_BOUND (errnum)];
+ char *p = inttostr (errnum, errbuf);
+ ignore_value (write (STDERR_FILENO, ": errno ", 8));
+ ignore_value (write (STDERR_FILENO, p, strlen (p)));
+ }
+
+ ignore_value (write (STDERR_FILENO, "\n", 1));
+
+ _exit (SORT_FAILURE);
+}
+
/* Report MESSAGE for FILE, then clean up and exit.
If FILE is null, it represents standard output. */
@@ -476,7 +504,7 @@ Other options:\n\
\n\
"), DEFAULT_TMPDIR);
fputs (_("\
- -z, --zero-terminated end lines with 0 byte, not newline\n\
+ -z, --zero-terminated line delimiter is NUL, not newline\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -982,8 +1010,8 @@ move_fd_or_die (int oldfd, int newfd)
{
if (oldfd != newfd)
{
- if (dup2 (oldfd, newfd) < 0)
- error (SORT_FAILURE, errno, _("dup2 failed"));
+ /* This should never fail for our usage. */
+ dup2 (oldfd, newfd);
close (oldfd);
}
}
@@ -1095,13 +1123,15 @@ maybe_create_temp (FILE **pfp, bool survive_fd_exhaustion)
}
else if (node->pid == 0)
{
+ /* Being the child of a multithreaded program before exec(),
+ we're restricted to calling async-signal-safe routines here. */
close (pipefds[1]);
move_fd_or_die (tempfd, STDOUT_FILENO);
move_fd_or_die (pipefds[0], STDIN_FILENO);
- if (execlp (compress_program, compress_program, (char *) NULL) < 0)
- error (SORT_FAILURE, errno, _("couldn't execute %s"),
- compress_program);
+ execlp (compress_program, compress_program, (char *) NULL);
+
+ async_safe_die (errno, "couldn't execute compress program");
}
}
@@ -1153,13 +1183,15 @@ open_temp (struct tempnode *temp)
break;
case 0:
+ /* Being the child of a multithreaded program before exec(),
+ we're restricted to calling async-signal-safe routines here. */
close (pipefds[0]);
move_fd_or_die (tempfd, STDIN_FILENO);
move_fd_or_die (pipefds[1], STDOUT_FILENO);
execlp (compress_program, compress_program, "-d", (char *) NULL);
- error (SORT_FAILURE, errno, _("couldn't execute %s -d"),
- compress_program);
+
+ async_safe_die (errno, "couldn't execute compress program (with -d)");
default:
temp->pid = child;
@@ -1557,7 +1589,8 @@ initbuf (struct buffer *buf, size_t line_bytes, size_t alloc)
static inline struct line *
buffer_linelim (struct buffer const *buf)
{
- return (struct line *) (buf->buf + buf->alloc);
+ void *linelim = buf->buf + buf->alloc;
+ return linelim;
}
/* Return a pointer to the first character of the field specified
@@ -3204,8 +3237,17 @@ merge_tree_init (size_t nthreads, size_t nlines, struct line *dest)
/* Destroy the merge tree. */
static void
-merge_tree_destroy (struct merge_node *merge_tree)
+merge_tree_destroy (size_t nthreads, struct merge_node *merge_tree)
{
+ size_t n_nodes = nthreads * 2;
+ struct merge_node *node = merge_tree;
+
+ while (n_nodes--)
+ {
+ pthread_mutex_destroy (&node->lock);
+ node++;
+ }
+
free (merge_tree);
}
@@ -3321,8 +3363,8 @@ queue_insert (struct merge_node_queue *queue, struct merge_node *node)
pthread_mutex_lock (&queue->mutex);
heap_insert (queue->priority_queue, node);
node->queued = true;
- pthread_mutex_unlock (&queue->mutex);
pthread_cond_signal (&queue->cond);
+ pthread_mutex_unlock (&queue->mutex);
}
/* Pop the top node off the priority QUEUE, lock the node, return it. */
@@ -3607,8 +3649,6 @@ sortlines (struct line *restrict lines, size_t nthreads,
queue_insert (queue, node);
merge_loop (queue, total_lines, tfp, temp_output);
}
-
- pthread_mutex_destroy (&node->lock);
}
/* Scan through FILES[NTEMPS .. NFILES-1] looking for files that are
@@ -3912,13 +3952,14 @@ sort (char *const *files, size_t nfiles, char const *output_file,
queue_init (&queue, nthreads);
struct merge_node *merge_tree =
merge_tree_init (nthreads, buf.nlines, line);
- struct merge_node *root = merge_tree + 1;
- sortlines (line, nthreads, buf.nlines, root,
+ sortlines (line, nthreads, buf.nlines, merge_tree + 1,
&queue, tfp, temp_output);
+
+#ifdef lint
+ merge_tree_destroy (nthreads, merge_tree);
queue_destroy (&queue);
- pthread_mutex_destroy (&root->lock);
- merge_tree_destroy (merge_tree);
+#endif
}
else
write_unique (line - 1, tfp, temp_output);