Example #1
0
int op_write_native_code(op_agent_t hdl, char const * symbol_name,
	uint64_t vma, void const * code, unsigned int const size)
{
	struct jr_code_load rec;
	struct timeval tv;
	size_t sz_symb_name;
	char pad_bytes[7] = { 0, 0, 0, 0, 0, 0, 0 };
	size_t padding_count;
	FILE * dumpfile = (FILE *) hdl;

	if (!dumpfile) {
		errno = EINVAL;
		fprintf(stderr, "Invalid hdl argument\n");
		return -1;
	}
	sz_symb_name = strlen(symbol_name) + 1;

	rec.id = JIT_CODE_LOAD;
	rec.code_size = size;
	rec.vma = vma;
	rec.code_addr = (u64) (uintptr_t) code;
	rec.total_size = code ? sizeof(rec) + sz_symb_name + size :
			sizeof(rec) + sz_symb_name;
	/* calculate amount of padding '\0' */
	padding_count = PADDING_8ALIGNED(rec.total_size);
	rec.total_size += padding_count;
	if (gettimeofday(&tv, NULL)) {
		fprintf(stderr, "gettimeofday failed\n");
		return -1;
	}

	rec.timestamp = tv.tv_sec;

	/* locking makes sure that we continuously write this record, if
	 * we are called within a multi-threaded context */
	flockfile(dumpfile);
	/* Write record, symbol name, code (optionally), and (if necessary)
	 * additonal padding \0 bytes.
	 */
	if (fwrite_unlocked(&rec, sizeof(rec), 1, dumpfile) &&
	    fwrite_unlocked(symbol_name, sz_symb_name, 1, dumpfile)) {
		if (code)
			fwrite_unlocked(code, size, 1, dumpfile);
		if (padding_count)
			fwrite_unlocked(pad_bytes, padding_count, 1, dumpfile);
		/* Always flush to ensure conversion code to elf will see
		 * data as soon as possible */
		fflush_unlocked(dumpfile);
		funlockfile(dumpfile);
		return 0;
	}
	fflush_unlocked(dumpfile);
	funlockfile(dumpfile);
	return -1;
}
Example #2
0
int op_write_native_code(op_agent_t hdl, char const * symbol_name,
	uint64_t vma, void const * code, unsigned int const size)
{
	struct jr_code_load rec;
	struct timeval tv;
	size_t sz_symb_name;
	char pad_bytes[7] = { 0, 0, 0, 0, 0, 0, 0 };
	size_t padding_count;
	FILE * dumpfile = (FILE *) hdl;

	if (!dumpfile) {
		errno = EINVAL;
		fprintf(stderr, "Invalid hdl argument\n");
		return -1;
	}
	sz_symb_name = strlen(symbol_name) + 1;

	rec.id = JIT_CODE_LOAD;
	rec.code_size = size;
	rec.vma = vma;
	rec.code_addr = (u64) (uintptr_t) code;
	rec.total_size = code ? sizeof(rec) + sz_symb_name + size :
			sizeof(rec) + sz_symb_name;
	
	padding_count = PADDING_8ALIGNED(rec.total_size);
	rec.total_size += padding_count;
	if (gettimeofday(&tv, NULL)) {
		fprintf(stderr, "gettimeofday failed\n");
		return -1;
	}

	rec.timestamp = tv.tv_sec;

	flockfile(dumpfile);
	if (fwrite_unlocked(&rec, sizeof(rec), 1, dumpfile) &&
	    fwrite_unlocked(symbol_name, sz_symb_name, 1, dumpfile)) {
		if (code)
			fwrite_unlocked(code, size, 1, dumpfile);
		if (padding_count)
			fwrite_unlocked(pad_bytes, padding_count, 1, dumpfile);
		fflush_unlocked(dumpfile);
		funlockfile(dumpfile);
		return 0;
	}
	fflush_unlocked(dumpfile);
	funlockfile(dumpfile);
	return -1;
}
Example #3
0
void vdebug_log (const char *filename, int line, const char *func, const char *format, va_list ap)
{
	static FILE *fp = fopen ("/tmp/tiary_debug.txt", "w");
	if (fp) {
		fprintf_unlocked (fp, "%s:%d:%s:", filename, line, func);
		vfprintf_unlocked (fp, format, ap);
		fputc_unlocked ('\n', fp);
		fflush_unlocked (fp);
	}
}
int fseeko_unlocked(FILE* fp, off_t offset, int whence)
{
	if ( !fp->seek_func )
		return errno = EBADF, -1;
	if ( fflush_unlocked(fp) != 0 )
		return -1;
	if ( fp->seek_func(fp->user, offset, whence) < 0 )
		return -1;
	fp->flags &= ~_FILE_STATUS_EOF;
	return 0;
}
Example #5
0
int __fflush4(FILE *stream,int next) {
    if (__unlikely(!__stdio_atexit)) {
        __stdio_atexit=1;
        atexit(__stdio_flushall);
    }
    if (__unlikely((stream->flags&BUFINPUT)!=next)) {
        int res=fflush_unlocked(stream);
        stream->flags=(stream->flags&~BUFINPUT)|next;
        return res;
    }
    if (stream->fd==0 && __stdin_is_tty()) __fflush_stdout();
    return 0;
}
size_t fread_unlocked(void *ptr, size_t size, size_t nmemb, FILE *stream) {
  unsigned long i,j;
  j=size*nmemb;
  i=0;

  if (!(stream->flags&CANREAD)) {
    stream->flags|=ERRORINDICATOR;
    return 0;
  }
  if (!j || j/nmemb!=size) return 0;
  if (stream->ungotten) {
    stream->ungotten=0;
    *(char*)ptr=stream->ungetbuf;
    ++i;
    if (j==1) return 1;
  }

#ifdef WANT_FREAD_OPTIMIZATION
  if ( !(stream->flags&FDPIPE) && (j>stream->buflen)) {
    size_t tmp=j-i;
    ssize_t res;
    size_t inbuf=stream->bs-stream->bm;
    memcpy(ptr+i,stream->buf+stream->bm,inbuf);
    stream->bm=stream->bs=0;
    tmp-=inbuf;
    i+=inbuf;
    if (fflush_unlocked(stream)) return 0;
    while ((res=__libc_read(stream->fd,ptr+i,tmp))<(ssize_t)tmp) {
      if (res==-1) {
	stream->flags|=ERRORINDICATOR;
	goto exit;
      } else if (!res) {
	stream->flags|=EOFINDICATOR;
	goto exit;
      }
      i+=res; tmp-=res;
    }
    return nmemb;
  }
#endif
  for (; i<j; ++i) {
    int res;
    res=fgetc_unlocked(stream);
    if (res==EOF)
exit:
      return i/size;
    else
      ((unsigned char*)ptr)[i]=(unsigned char)res;
  }
  return nmemb;
}
Example #7
0
int fputc_unlocked(int c, FILE *stream) {
  if (!__likely(stream->flags&CANWRITE) || __fflush4(stream,0)) {
kaputt:
    stream->flags|=ERRORINDICATOR;
    return EOF;
  }
  if (__unlikely(stream->bm>=stream->buflen-1))
    if (fflush_unlocked(stream)) goto kaputt;
  if (stream->flags&NOBUF) {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    if (__libc_write(stream->fd,&c,1) != 1)
#else
    if (__libc_write(stream->fd,(char*)&c+sizeof(c)-1,1) != 1)
#endif
      goto kaputt;
    return 0;
  }
  stream->buf[stream->bm]=c;
  ++stream->bm;
  if (((stream->flags&BUFLINEWISE) && c=='\n') ||
      ((stream->flags&NOBUF))) /* puke */
    if (fflush_unlocked(stream)) goto kaputt;
  return 0;
}
Example #8
0
static void inline
update_log_file (char *error_buf)
{
  if (! use_log_file)
    return;

  if (! log_file_opened)
    open_log_file ();

  flockfile (log_file);

  while (*error_buf != '\0')
    putc_unlocked (*error_buf++, log_file);
  putc_unlocked ('\n', log_file);

  fflush_unlocked (log_file);
  funlockfile (log_file);
}
Example #9
0
int op_write_debug_line_info(op_agent_t hdl, void const * code,
			     size_t nr_entry,
			     struct debug_line_info const * compile_map)
{
	struct jr_code_debug_info rec;
	long cur_pos, last_pos;
	struct timeval tv;
	size_t i;
	size_t padding_count;
	char padd_bytes[7] = {0, 0, 0, 0, 0, 0, 0};
	int rc = -1;
	FILE * dumpfile = (FILE *) hdl;

	if (!dumpfile) {
		errno = EINVAL;
		fprintf(stderr, "Invalid hdl argument\n");
		return -1;
	}
	
	/* write nothing if no entries are provided */
	if (nr_entry == 0)
		return 0;

	rec.id = JIT_CODE_DEBUG_INFO;
	rec.code_addr = (uint64_t)(uintptr_t)code;
	/* will be fixed after writing debug line info */
	rec.total_size = 0;
	rec.nr_entry = nr_entry;
	if (gettimeofday(&tv, NULL)) {
		fprintf(stderr, "gettimeofday failed\n");
		return -1;
	}

	rec.timestamp = tv.tv_sec;

	flockfile(dumpfile);

	if ((cur_pos = ftell(dumpfile)) == -1l)
		goto error;
	if (!fwrite_unlocked(&rec, sizeof(rec), 1, dumpfile))
		goto error;
	for (i = 0; i < nr_entry; ++i) {
		if (!fwrite_unlocked(&compile_map[i].vma,
				     sizeof(compile_map[i].vma), 1,
				     dumpfile) ||
		    !fwrite_unlocked(&compile_map[i].lineno,
				     sizeof(compile_map[i].lineno), 1,
				     dumpfile) ||
		    !fwrite_unlocked(compile_map[i].filename,
				     strlen(compile_map[i].filename) + 1, 1,
				     dumpfile))
			goto error;
	}

	if ((last_pos = ftell(dumpfile)) == -1l)
		goto error;
	rec.total_size = last_pos - cur_pos;
	padding_count = PADDING_8ALIGNED(rec.total_size);
	rec.total_size += padding_count;
	if (padding_count && !fwrite(padd_bytes, padding_count, 1, dumpfile))
		goto error;
	if (fseek(dumpfile, cur_pos, SEEK_SET) == -1l)
		goto error;
	if (!fwrite_unlocked(&rec, sizeof(rec), 1, dumpfile))
		goto error;
	if (fseek(dumpfile, last_pos + padding_count, SEEK_SET) == -1)
		goto error;

	rc = 0;
error:
	fflush_unlocked(dumpfile);
	funlockfile(dumpfile);
	return rc;
}
Example #10
0
char *
getpass (const char *prompt)
{
  FILE *tty;
  FILE *in, *out;
  struct termios s, t;
  bool tty_changed = false;
  static char *buf;
  static size_t bufsize;
  ssize_t nread;

  /* Try to write to and read from the terminal if we can.
     If we can't open the terminal, use stderr and stdin.  */

  tty = fopen ("/dev/tty", "w+");
  if (tty == NULL)
    {
      in = stdin;
      out = stderr;
    }
  else
    {
      /* We do the locking ourselves.  */
      __fsetlocking (tty, FSETLOCKING_BYCALLER);

      out = in = tty;
    }

  flockfile (out);

  /* Turn echoing off if it is on now.  */
#if HAVE_TCGETATTR
  if (tcgetattr (fileno (in), &t) == 0)
    {
      /* Save the old one. */
      s = t;
      /* Tricky, tricky. */
      t.c_lflag &= ~(ECHO | ISIG);
      tty_changed = (tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &t) == 0);
    }
#endif

  /* Write the prompt.  */
  fputs_unlocked (prompt, out);
  fflush_unlocked (out);

  /* Read the password.  */
  nread = getline (&buf, &bufsize, in);

  /* According to the C standard, input may not be followed by output
     on the same stream without an intervening call to a file
     positioning function.  Suppose in == out; then without this fseek
     call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
     echoed, whereas on IRIX, the following newline is not output as
     it should be.  POSIX imposes similar restrictions if fileno (in)
     == fileno (out).  The POSIX restrictions are tricky and change
     from POSIX version to POSIX version, so play it safe and invoke
     fseek even if in != out.  */
  fseeko (out, 0, SEEK_CUR);

  if (buf != NULL)
    {
      if (nread < 0)
        buf[0] = '\0';
      else if (buf[nread - 1] == '\n')
        {
          /* Remove the newline.  */
          buf[nread - 1] = '\0';
          if (tty_changed)
            {
              /* Write the newline that was not echoed.  */
              putc_unlocked ('\n', out);
            }
        }
    }

  /* Restore the original setting.  */
#if HAVE_TCSETATTR
  if (tty_changed)
    tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &s);
#endif

  funlockfile (out);

  call_fclose (tty);

  return buf;
}
Example #11
0
/**
 * Internal write API, stream lock already held.
 *
 * @returns IPRT status code.
 * @param   pStream             The stream.
 * @param   pvBuf               What to write.
 * @param   cbWrite             How much to write.
 * @param   pcbWritten          Where to optionally return the number of bytes
 *                              written.
 * @param   fSureIsText         Set if we're sure this is UTF-8 text already.
 */
static int rtStrmWriteLocked(PRTSTREAM pStream, const void *pvBuf, size_t cbWrite, size_t *pcbWritten,
                              bool fSureIsText)
{
    int rc = pStream->i32Error;
    if (RT_FAILURE(rc))
        return rc;
    if (pStream->fRecheckMode)
        rtStreamRecheckMode(pStream);

#ifdef RT_OS_WINDOWS
    /*
     * Use the unicode console API when possible in order to avoid stuff
     * getting lost in unnecessary code page translations.
     */
    HANDLE hCon;
    if (rtStrmIsConsoleUnlocked(pStream, &hCon))
    {
# ifdef HAVE_FWRITE_UNLOCKED
        if (!fflush_unlocked(pStream->pFile))
# else
        if (!fflush(pStream->pFile))
# endif
        {
            /** @todo Consider buffering later. For now, we'd rather correct output than
             *        fast output. */
            DWORD    cwcWritten = 0;
            PRTUTF16 pwszSrc = NULL;
            size_t   cwcSrc = 0;
            rc = RTStrToUtf16Ex((const char *)pvBuf, cbWrite, &pwszSrc, 0, &cwcSrc);
            if (RT_SUCCESS(rc))
            {
                if (!WriteConsoleW(hCon, pwszSrc, (DWORD)cwcSrc, &cwcWritten, NULL))
                {
                    /* try write char-by-char to avoid heap problem. */
                    cwcWritten = 0;
                    while (cwcWritten != cwcSrc)
                    {
                        DWORD cwcThis;
                        if (!WriteConsoleW(hCon, &pwszSrc[cwcWritten], 1, &cwcThis, NULL))
                        {
                            if (!pcbWritten || cwcWritten == 0)
                                rc = RTErrConvertFromErrno(GetLastError());
                            break;
                        }
                        if (cwcThis != 1) /* Unable to write current char (amount)? */
                            break;
                        cwcWritten++;
                    }
                }
                if (RT_SUCCESS(rc))
                {
                    if (cwcWritten == cwcSrc)
                    {
                        if (pcbWritten)
                            *pcbWritten = cbWrite;
                    }
                    else if (pcbWritten)
                    {
                        PCRTUTF16   pwszCur = pwszSrc;
                        const char *pszCur  = (const char *)pvBuf;
                        while ((uintptr_t)(pwszCur - pwszSrc) < cwcWritten)
                        {
                            RTUNICP CpIgnored;
                            RTUtf16GetCpEx(&pwszCur, &CpIgnored);
                            RTStrGetCpEx(&pszCur, &CpIgnored);
                        }
                        *pcbWritten = pszCur - (const char *)pvBuf;
                    }
                    else
                        rc = VERR_WRITE_ERROR;
                }
                RTUtf16Free(pwszSrc);
            }
        }
        else
            rc = RTErrConvertFromErrno(errno);
        if (RT_FAILURE(rc))
            ASMAtomicWriteS32(&pStream->i32Error, rc);
        return rc;
    }
#endif /* RT_OS_WINDOWS */

    /*
     * If we're sure it's text output, convert it from UTF-8 to the current
     * code page before printing it.
     *
     * Note! Partial writes are not supported in this scenario because we
     *       cannot easily report back a written length matching the input.
     */
    /** @todo Skip this if the current code set is UTF-8. */
    if (   pStream->fCurrentCodeSet
        && !pStream->fBinary
        && (   fSureIsText
            || rtStrmIsUtf8Text(pvBuf, cbWrite))
       )
    {
        char       *pszSrcFree = NULL;
        const char *pszSrc     = (const char *)pvBuf;
        if (pszSrc[cbWrite])
        {
            pszSrc = pszSrcFree = RTStrDupN(pszSrc, cbWrite);
            if (pszSrc == NULL)
                rc = VERR_NO_STR_MEMORY;
        }
        if (RT_SUCCESS(rc))
        {
            char *pszSrcCurCP;
            rc = RTStrUtf8ToCurrentCP(&pszSrcCurCP, pszSrc);
            if (RT_SUCCESS(rc))
            {
                size_t  cchSrcCurCP = strlen(pszSrcCurCP);
                IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
#ifdef HAVE_FWRITE_UNLOCKED
                ssize_t cbWritten = fwrite_unlocked(pszSrcCurCP, cchSrcCurCP, 1, pStream->pFile);
#else
                ssize_t cbWritten = fwrite(pszSrcCurCP, cchSrcCurCP, 1, pStream->pFile);
#endif
                IPRT_ALIGNMENT_CHECKS_ENABLE();
                if (cbWritten == 1)
                {
                    if (pcbWritten)
                        *pcbWritten = cbWrite;
                }
#ifdef HAVE_FWRITE_UNLOCKED
                else if (!ferror_unlocked(pStream->pFile))
#else
                else if (!ferror(pStream->pFile))
#endif
                {
                    if (pcbWritten)
                        *pcbWritten = 0;
                }
                else
                    rc = VERR_WRITE_ERROR;
                RTStrFree(pszSrcCurCP);
            }
            RTStrFree(pszSrcFree);
        }

        if (RT_FAILURE(rc))
            ASMAtomicWriteS32(&pStream->i32Error, rc);
        return rc;
    }
Example #12
0
void dmn_loggerv(int level, const char* fmt, va_list ap) {
    if(alt_stderr) {
#ifndef NDEBUG

        time_t t = time(NULL);
        struct tm tmp;
        localtime_r(&t, &tmp);
        char tstamp[10];
        if(!strftime(tstamp, 10, "%T ", &tmp))
            strcpy(tstamp, "--:--:-- ");

#  if defined SYS_gettid && !defined __APPLE__
        pid_t tid = syscall(SYS_gettid);
        char tidbuf[16];
        snprintf(tidbuf, 16, " [%i]", tid);
#  endif

        const char* pfx;
        switch(level) {
            case LOG_DEBUG: pfx = pfx_debug; break;
            case LOG_INFO: pfx = pfx_info; break;
            case LOG_WARNING: pfx = pfx_warning; break;
            case LOG_ERR: pfx = pfx_err; break;
            case LOG_CRIT: pfx = pfx_crit; break;
            default: pfx = pfx_unknown; break;
        }
        flockfile(alt_stderr);
        fputs_unlocked(tstamp, alt_stderr);
        if(our_logname)
            fputs_unlocked(our_logname, alt_stderr);
#  if defined SYS_gettid && !defined __APPLE__
        fputs_unlocked(tidbuf, alt_stderr);
#  endif
        fputs_unlocked(pfx, alt_stderr);
        va_list apcpy;
        va_copy(apcpy, ap);
        vfprintf(alt_stderr, fmt, apcpy);
        va_end(apcpy);
        putc_unlocked('\n', alt_stderr);
        fflush_unlocked(alt_stderr);
        funlockfile(alt_stderr);

#else // NDEBUG
        if(level != LOG_INFO || send_stderr_info) {
            va_list apcpy;
            va_copy(apcpy, ap);
            flockfile(alt_stderr);
            vfprintf(alt_stderr, fmt, apcpy);
            va_end(apcpy);
            putc_unlocked('\n', alt_stderr);
            fflush_unlocked(alt_stderr);
            funlockfile(alt_stderr);
        }
#endif // NDEBUG
    }

    if(dmn_syslog_alive)
        vsyslog(level, fmt, ap);

    dmn_fmtbuf_reset();
}
Example #13
0
int fclose(register FILE *stream)
{
    int rv = 0;
    __STDIO_AUTO_THREADLOCK_VAR;

#ifdef __STDIO_HAS_OPENLIST
#if !defined(__UCLIBC_HAS_THREADS__) || !defined(__STDIO_BUFFERS)
    /* First, remove the file from the open file list. */
    {
        FILE *ptr;

        __STDIO_THREADLOCK_OPENLIST_DEL;
        __STDIO_THREADLOCK_OPENLIST_ADD;
        ptr = _stdio_openlist;
        if ((ptr = _stdio_openlist) == stream) {
            _stdio_openlist = stream->__nextopen;
        } else {
            while (ptr) {
                if (ptr->__nextopen == stream) {
                    ptr->__nextopen = stream->__nextopen;
                    break;
                }
                ptr = ptr->__nextopen;
            }
        }
        __STDIO_THREADUNLOCK_OPENLIST_ADD;
        __STDIO_THREADUNLOCK_OPENLIST_DEL;
    }
#endif
#endif

    __STDIO_AUTO_THREADLOCK(stream);

    __STDIO_STREAM_VALIDATE(stream);

#ifdef __STDIO_BUFFERS
    /* Write any pending buffered chars. */
    if (__STDIO_STREAM_IS_WRITING(stream)) {
        rv = fflush_unlocked(stream);
    }
#endif

    if (__CLOSE(stream) < 0) {	/* Must close even if fflush failed. */
        rv = EOF;
    }

    stream->__filedes = -1;

    /* We need a way for freopen to know that a file has been closed.
     * Since a file can't be both readonly and writeonly, that makes
     * an effective signal.  It also has the benefit of disabling
     * transitions to either reading or writing. */
#if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
    /* Before we mark the file as closed, make sure we increment the openlist use count
     * so it isn't freed under us while still cleaning up. */
    __STDIO_OPENLIST_INC_USE;
#endif
    stream->__modeflags &= (__FLAG_FREEBUF|__FLAG_FREEFILE);
    stream->__modeflags |= (__FLAG_READONLY|__FLAG_WRITEONLY);

#ifndef NDEBUG
    __STDIO_STREAM_RESET_GCS(stream);

    /* Reinitialize everything (including putc since fflush could fail). */
    __STDIO_STREAM_DISABLE_GETC(stream);
    __STDIO_STREAM_DISABLE_PUTC(stream);
    __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream);

# ifdef __UCLIBC_HAS_WCHAR__
    stream->__ungot_width[0] = 0;
# endif
# ifdef __STDIO_MBSTATE
    __INIT_MBSTATE(&(stream->__state));
# endif
#endif

    __STDIO_AUTO_THREADUNLOCK(stream);

    __STDIO_STREAM_FREE_BUFFER(stream);
#ifdef __UCLIBC_MJN3_ONLY__
#warning REMINDER: inefficient - locks and unlocks twice and walks whole list
#endif
#if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
    /* inefficient - locks/unlocks twice and walks whole list */
    __STDIO_OPENLIST_INC_DEL_CNT;
    __STDIO_OPENLIST_DEC_USE;	/* This with free the file if necessary. */
#else
    __STDIO_STREAM_FREE_FILE(stream);
#endif

    return rv;
}
Example #14
0
size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
  ssize_t res;
  size_t len=size*nmemb;
  size_t i,done;
  if (!__likely(stream->flags&CANWRITE) || __fflush4(stream,0)) {
kaputt:
    stream->flags|=ERRORINDICATOR;
    return 0;
  }
  if (!nmemb || len/nmemb!=size) return 0; /* check for integer overflow */
  if (__unlikely(len>stream->buflen || (stream->flags&NOBUF))) {
    if (fflush_unlocked(stream)) return 0;
    do {
      res=__libc_write(stream->fd,ptr,len);
    } while (res==-1 && errno==EINTR);
  } else
again:
         {
    /* try to make the common case fast */
    size_t todo=stream->buflen-stream->bm;
    if (todo>len) todo=len;

    if (todo) {
      if (stream->flags&BUFLINEWISE) {
	if (__unlikely((stream->flags&CHECKLINEWISE)!=0)) {
	  stream->flags&=~CHECKLINEWISE;
	  /* stdout is set to BUFLINEWISE|CHECKLINEWISE by default. */
	  /* that means we should check whether it is connected to a
	   * tty on first flush, and if not so, reset BUFLINEWISE */
	  if (!isatty(stream->fd)) {
	    stream->flags&=~BUFLINEWISE;
	    goto notlinewise;
	  }
	}
	for (i=0; i<todo; ++i) {
	  if ((stream->buf[stream->bm++]=((char*)ptr)[i])=='\n') {
	    if (fflush_unlocked(stream)) goto kaputt;
	  }
	}
      } else {
notlinewise:
	memcpy(stream->buf+stream->bm,ptr,todo);
	stream->bm+=todo;
	if (stream->bm==stream->buflen) {
	  if (fflush_unlocked(stream)) return 0;
	  /* if we are here, we should not have an empty buffer */
	  len-=todo;
	  if (!len) return nmemb;
	  ptr+=todo;
	  goto again;
	} else
	  return nmemb;
      }
      done=todo;
    } else
      done=0;
    for (i=done; i<len; ++i)
      if (fputc_unlocked(((char*)ptr)[i],stream) == EOF) {
	res=len-i;
	goto abort;
      }
    res=len;
  }
  if (res<0) {
    stream->flags|=ERRORINDICATOR;
    return 0;
  }
abort:
  return size?res/size:0;
}