/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "utility.h"
#include "initialize.h"
#include "statistics.h"
#include "streams_common.h"
#include "streams.h"
/*
* utility
*
* Overview
* utility.c contains the general purpose routines used in various locations
* throughout sort. It provides a number of interfaces that maintain local
* state relevant to this instance of sort. We discuss the more significant
* of these interfaces below.
*
* Output guard
* sort is one of the few Unix utilities that is capable of working "in
* place"; that is, sort can manipulate an input file and place its output in
* a file of the same name safely. This is handled in this implementation by
* the output guard facility. In the case of an interrupt or other fatal
* signal, sort essays to restore the original input file.
*
* Temporary file cleanup
* Similar to the output guard facility, sort cleans up its temporary files in
* the case of interruption (or normal exit, for that matter); this is handled
* by registering a list of file pointers for later use by the atexit handler.
*
* Temporary filename security
* sort protects against "open-through-link" security attacks by verifying
* that the selected temporary file name is unused. If the file name is in
* use, the pattern is readjusted until an available name pattern is
* discovered.
*
* Buffered I/O
* sort has a simple buffered I/O facility of its own, to facilitate writing
* data in large quantities (particularly for multibyte locales). cxwrite()
* is the base routine, while wxwrite(), which handles multibyte buffers, is
* built on top of cxwrite().
*/
#define EXIT_OK 0
static int output_guard_copy_complete = 0;
static char *current_tmpdir;
static char *current_template;
void
swap(void **a, void **b)
{
void *t;
t = *a;
*a = *b;
*b = t;
__S(stats_incr_swaps());
}
/*
* Temporary file name template handling.
*/
static void
{
struct stat s;
do {
(void) mktemp(current_template);
}
int
{
struct stat s;
int n = strlen(current_template);
int i;
current_template[i]++;
if (current_template[i] > '9')
current_template[i] = '0';
else
break;
}
/*
* Template has been exhausted, so reset.
*/
}
if (lstat(current_template, &s) == 0) {
/*
* Our newly bumped template has been anticipated; reset to
* avoid possible "link-through" attack.
*/
}
return (0);
}
void
set_file_template(char **T)
{
struct stat s;
int check_tmpdir = 0;
if (*T != NULL) {
current_tmpdir = strdup(*T);
check_tmpdir = 1;
check_tmpdir = 1;
} else {
current_tmpdir = (char *)default_tmpdir;
}
/*
* Check that the temporary directory given exists, and is a directory.
*/
if (check_tmpdir) {
if (stat(current_tmpdir, &s) != 0) {
current_tmpdir = (char *)default_tmpdir;
"using default temporary directory"),
current_tmpdir = (char *)default_tmpdir;
}
}
}
char *
{
return (current_template);
}
/*
* Output guard routines.
*/
void
{
if (S->m_output_to_stdout)
return;
/*
* We needn't protect an empty file.
*/
strp->s_filesize > 0) {
if (bump_file_template() < 0)
return;
}
}
}
}
void
{
}
void
{
}
/*
* atexit_handler() cleans up any temporary files outstanding after a fatal
* signal, a call to die() or at exit(). To preserve the input file under low
* storage conditions (and both the output file and the temporary files are
* directed at the same filesystem), we remove all temporary files but the
* output guard first, and then restore the original file. Of course, this is
* not foolproof, as another writer may have exhausted storage.
*/
void
{
if (cleanup_chain && *cleanup_chain)
if (output_guard_tempname) {
}
__S(stats_display());
}
strtomem(char *S)
{
return (0);
if (units == '%') {
return (0);
} else
switch (units) {
case 't' : /* terabytes */
case 'T' :
val *= 1024;
/*FALLTHROUGH*/
case 'g' : /* gigabytes */
case 'G' :
val *= 1024;
/*FALLTHROUGH*/
case 'm' : /* megabytes */
case 'M' :
val *= 1024;
/*FALLTHROUGH*/
case 'k' : /* kilobytes */
case 'K' :
val *= 1024;
/*FALLTHROUGH*/
case 'b' : /* bytes */
case 'B' :
break;
default :
/*
* default is kilobytes
*/
val *= 1024;
break;
}
return (0);
return (retval);
}
{
if (mem_limit != 0) {
#ifdef DEBUG
/*
* In the debug case, we want to test the temporary files
* handling, so no lower bound on the memory limit is imposed.
*/
#else
#endif /* DEBUG */
} else {
}
return (avail);
}
void
{
if (S->m_c_locale) {
return;
}
if (S->m_single_byte_locale) {
return;
}
}
void *
{
/*
* safe_realloc() is not meant as an alternative free() mechanism--we
* disallow reallocations to size zero.
*/
return (ptr);
/*NOTREACHED*/
return (NULL); /* keep gcc happy */
}
void
{
if (ptr)
}
void *
{
void *pa;
if (pa == MAP_FAILED)
return (pa);
}
void
usage()
{
gettext("usage: %s [-cmu] [-o output] [-T directory] [-S mem]"
" [-z recsz]\n\t[-dfiMnr] [-b] [-t char] [-k keydef]"
" [+pos1 [-pos2]] files...\n"), CMDNAME);
}
/*
* hold_file_descriptor() and release_file_descriptor() reserve a single file
* descriptor entry for later use. We issue the hold prior to any loop that has
* an exit condition based on the receipt of EMFILE from an open() call; once we
* have exited, we can release, typically prior to opening a file for output.
*/
void
{
}
void
{
held_fd = -1;
}
void
{
(void) memcpy(b, a, sizeof (line_rec_t));
}
void
{
if (feof(f))
return;
}
/*
* int cxwrite(int, char *, size_t)
*
* Overview
* cxwrite() implements a buffered version of fwrite(ptr, nbytes, 1, .) on
* file descriptors. It returns -1 in the case that the write() fails to
* write the current buffer contents. cxwrite() must be flushed before being
* applied to a new file descriptor.
*
* Return values
* 0 on success, -1 on error.
*/
int
{
errno = 0;
if (errno)
break;
}
if (offset)
return (-1);
return (0);
}
while (nbytes != 0) {
else
if (nbytes) {
errno = 0;
if (errno)
break;
}
if (offset)
return (-1);
}
}
return (0);
}
/*
* int wxwrite(int, wchar_t *)
*
* Overview
* wxwrite() implements a buffered write() function for null-terminated wide
* character buffers with similar calling semantics to cxwrite(). It returns
* -1 in the case that it fails to write the current buffer contents.
* wxwrite() must be flushed before being applied to a new file descriptor.
*
* Return values
* 0 on success, -1 on error.
*/
int
{
static char *convert_buffer;
if (convert_buffer == NULL)
/*
* We use wcstombs(NULL, ., .) to verify that we have an adequate
* buffer size for the conversion. Since this buffer was converted into
* wide character format earlier, we can safely assume that the buffer
* can be converted back to the external multibyte form.
*/
if (req_bufsize > convert_bufsize) {
}
}
int
xstreql(const char *a, const char *b)
{
return (strcmp(a, b) == 0);
}
int
{
return (strncmp(a, b, l) == 0);
}
char *
{
const char *eS = S + n;
do {
if (*S == (char)c)
return ((char *)S);
} while (++S < eS);
return (NULL);
}
void
{
ssize_t i;
s[i] = UCHAR_MAX - s[i];
}
int
{
}
wchar_t *
{
do {
return (NULL);
}
void
{
ssize_t i;
s[i] = WCHAR_MAX - s[i];
}
#ifdef _LITTLE_ENDIAN
void
{
ssize_t i;
for (i = 0; i < length; i++, s++) {
char *t = (char *)s;
char u;
u = *t;
*t = *(t + 3);
*(t + 3) = u;
u = *(t + 1);
*(t + 1) = *(t + 2);
*(t + 2) = u;
}
}
#endif /* _LITTLE_ENDIAN */
wchar_t *
{
while (--i > 0) {
if (*s == w)
return (s);
s++;
}
return (NULL);
}
void
{
void *mm_in;
int i;
return;
for (i = 0; i < nchunks; i++) {
i * chunksize)) == MAP_FAILED)
}
if (lastchunk) {
}
}
/*PRINTFLIKE1*/
void
{
}
/*PRINTFLIKE1*/
void
{
}
#ifdef DEBUG
/*
* pprintc() is called only by xdump().
*/
static void
{
else
}
static void
{
if (iswspace(c))
else if (iswprint(c))
else
}
/*
* xdump() is used only for debugging purposes.
*/
void
{
int i;
if (nc % BYTES_PER_LINE == 0) {
}
nc++;
if (nc % BYTES_PER_LINE == 0) {
if (wide) {
for (i = 0; i < BYTES_PER_LINE;
i += sizeof (wchar_t))
} else {
for (i = 0; i < BYTES_PER_LINE; i++)
}
}
}
if (wide) {
} else {
for (i = 0; i < nc % BYTES_PER_LINE; i++)
}
}
#endif /* DEBUG */