mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-09 08:34:28 +00:00
Complete stdio
This commit is contained in:
parent
b7505c3c9c
commit
39dbffadfe
@ -1,6 +1,5 @@
|
|||||||
#include "nolibc/crt.h"
|
#include "nolibc/crt.h"
|
||||||
#include "nolibc/arch.h"
|
#include "nolibc/arch.h"
|
||||||
#include "nolibc/stdio.h"
|
|
||||||
|
|
||||||
// errno
|
// errno
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
char **environ;
|
char **environ;
|
||||||
const unsigned long *_auxv;
|
const unsigned long *_auxv;
|
||||||
void _exit(int);
|
void _exit(int);
|
||||||
|
void __init_stdio(void);
|
||||||
|
|
||||||
typedef void init_func_t(int, char*[], char*[]);
|
typedef void init_func_t(int, char*[], char*[]);
|
||||||
typedef void fini_func_t(void);
|
typedef void fini_func_t(void);
|
||||||
@ -68,6 +69,7 @@ void __attribute__((used)) _start_c(long *sp)
|
|||||||
_auxv = auxv;
|
_auxv = auxv;
|
||||||
|
|
||||||
/* call preinit and init */
|
/* call preinit and init */
|
||||||
|
__init_stdio();
|
||||||
call_array(__preinit_array_start, __preinit_array_end, argc, argv, envp);
|
call_array(__preinit_array_start, __preinit_array_end, argc, argv, envp);
|
||||||
call_array(__init_array_start, __init_array_end, argc, argv, envp);
|
call_array(__init_array_start, __init_array_end, argc, argv, envp);
|
||||||
|
|
||||||
|
@ -1,250 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
|
||||||
/*
|
|
||||||
* minimal stdio function definitions for NOLIBC
|
|
||||||
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _NOLIBC_STDIO_H
|
|
||||||
#define _NOLIBC_STDIO_H
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifndef EOF
|
|
||||||
#define EOF (-1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Buffering mode used by setvbuf. */
|
|
||||||
#define _IOFBF 0 /* Fully buffered. */
|
|
||||||
#define _IOLBF 1 /* Line buffered. */
|
|
||||||
#define _IONBF 2 /* No buffering. */
|
|
||||||
|
|
||||||
/* just define FILE as a non-empty type. The value of the pointer gives
|
|
||||||
* the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
|
|
||||||
* are immediately identified as abnormal entries (i.e. possible copies
|
|
||||||
* of valid pointers to something else).
|
|
||||||
*/
|
|
||||||
typedef struct __sFILE {
|
|
||||||
char dummy[1];
|
|
||||||
} FILE;
|
|
||||||
|
|
||||||
extern int vfprintf(FILE *stream, const char *fmt, va_list args);
|
|
||||||
|
|
||||||
FILE* stdin = (FILE*)(intptr_t)~STDIN_FILENO;
|
|
||||||
FILE* stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
|
|
||||||
FILE* stderr = (FILE*)(intptr_t)~STDERR_FILENO;
|
|
||||||
|
|
||||||
/* provides a FILE* equivalent of fd. The mode is ignored. */
|
|
||||||
FILE *fdopen(int fd, const char *mode __attribute__((unused)))
|
|
||||||
{
|
|
||||||
if (fd < 0) {
|
|
||||||
errno = EBADF;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return (FILE*)(intptr_t)~fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* provides the fd of stream. */
|
|
||||||
int fileno(FILE *stream)
|
|
||||||
{
|
|
||||||
intptr_t i = (intptr_t)stream;
|
|
||||||
|
|
||||||
if (i >= 0) {
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return ~i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush a stream. */
|
|
||||||
int fflush(FILE *stream)
|
|
||||||
{
|
|
||||||
intptr_t i = (intptr_t)stream;
|
|
||||||
|
|
||||||
/* NULL is valid here. */
|
|
||||||
if (i > 0) {
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't do anything, nolibc does not support buffering. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush a stream. */
|
|
||||||
int fclose(FILE *stream)
|
|
||||||
{
|
|
||||||
intptr_t i = (intptr_t)stream;
|
|
||||||
|
|
||||||
if (i >= 0) {
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close(~i))
|
|
||||||
return EOF;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* getc(), fgetc(), getchar() */
|
|
||||||
|
|
||||||
#define getc(stream) fgetc(stream)
|
|
||||||
|
|
||||||
int fgetc(FILE* stream)
|
|
||||||
{
|
|
||||||
unsigned char ch;
|
|
||||||
|
|
||||||
if (read(fileno(stream), &ch, 1) <= 0)
|
|
||||||
return EOF;
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getchar(void)
|
|
||||||
{
|
|
||||||
return fgetc(stdin);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* putc(), fputc(), putchar() */
|
|
||||||
|
|
||||||
#define putc(c, stream) fputc(c, stream)
|
|
||||||
|
|
||||||
int fputc(int c, FILE* stream)
|
|
||||||
{
|
|
||||||
unsigned char ch = c;
|
|
||||||
|
|
||||||
if (write(fileno(stream), &ch, 1) <= 0)
|
|
||||||
return EOF;
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
int putchar(int c)
|
|
||||||
{
|
|
||||||
return fputc(c, stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
|
|
||||||
|
|
||||||
/* internal fwrite()-like function which only takes a size and returns 0 on
|
|
||||||
* success or EOF on error. It automatically retries on short writes.
|
|
||||||
*/
|
|
||||||
static int _fwrite(const void *buf, size_t size, FILE *stream)
|
|
||||||
{
|
|
||||||
ssize_t ret;
|
|
||||||
int fd = fileno(stream);
|
|
||||||
|
|
||||||
while (size) {
|
|
||||||
ret = write(fd, buf, size);
|
|
||||||
if (ret <= 0)
|
|
||||||
return EOF;
|
|
||||||
size -= ret;
|
|
||||||
buf += ret;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
|
|
||||||
{
|
|
||||||
size_t written;
|
|
||||||
|
|
||||||
for (written = 0; written < nmemb; written++) {
|
|
||||||
if (_fwrite(s, size, stream) != 0)
|
|
||||||
break;
|
|
||||||
s += size;
|
|
||||||
}
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fputs(const char *s, FILE *stream)
|
|
||||||
{
|
|
||||||
return _fwrite(s, strlen(s), stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
int puts(const char *s)
|
|
||||||
{
|
|
||||||
if (fputs(s, stdout) == EOF)
|
|
||||||
return EOF;
|
|
||||||
return putchar('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* fgets() */
|
|
||||||
char *fgets(char *s, int size, FILE *stream)
|
|
||||||
{
|
|
||||||
int ofs;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
for (ofs = 0; ofs + 1 < size;) {
|
|
||||||
c = fgetc(stream);
|
|
||||||
if (c == EOF)
|
|
||||||
break;
|
|
||||||
s[ofs++] = c;
|
|
||||||
if (c == '\n')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ofs < size)
|
|
||||||
s[ofs] = 0;
|
|
||||||
return ofs ? s : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vprintf(const char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
return vfprintf(stdout, fmt, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((format(printf, 2, 3)))
|
|
||||||
int fprintf(FILE *stream, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
ret = vfprintf(stream, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((format(printf, 1, 2)))
|
|
||||||
int printf(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
ret = vfprintf(stdout, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void perror(const char *msg)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
int setvbuf(FILE *stream __attribute__((unused)),
|
|
||||||
char *buf __attribute__((unused)),
|
|
||||||
int mode,
|
|
||||||
size_t size __attribute__((unused)))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* nolibc does not support buffering so this is a nop. Just check mode
|
|
||||||
* is valid as required by the spec.
|
|
||||||
*/
|
|
||||||
switch (mode) {
|
|
||||||
case _IOFBF:
|
|
||||||
case _IOLBF:
|
|
||||||
case _IONBF:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _NOLIBC_STDIO_H */
|
|
@ -1,6 +1,127 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct file_ptr_t {
|
||||||
|
int fd;
|
||||||
|
void *cookie;
|
||||||
|
int (*read_fn)(void*, char*, int);
|
||||||
|
int (*write_fn)(void*, const char*, int);
|
||||||
|
fpos_t (*seek_fn)(void*, fpos_t, int);
|
||||||
|
int (*close_fn)(void*);
|
||||||
|
} file_ptr_t;
|
||||||
|
|
||||||
|
static int fp_read_fn(void *p, char *buf, int sz) {
|
||||||
|
intptr_t fd = (intptr_t) p;
|
||||||
|
return read(fd, buf, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fp_write_fn(void *p, const char *buf, int sz) {
|
||||||
|
intptr_t fd = (intptr_t) p;
|
||||||
|
return write(fd, buf, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fpos_t fp_seek_fn(void *p, fpos_t pos, int whence) {
|
||||||
|
intptr_t fd = (intptr_t) p;
|
||||||
|
return lseek(fd, pos, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fp_close_fn(void *p) {
|
||||||
|
intptr_t fd = (intptr_t) p;
|
||||||
|
return close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_fp_fd(file_ptr_t *fp, int fd) {
|
||||||
|
fp->fd = fd;
|
||||||
|
fp->cookie = NULL;
|
||||||
|
fp->read_fn = fp_read_fn;
|
||||||
|
fp->write_fn = fp_write_fn;
|
||||||
|
fp->seek_fn = fp_seek_fn;
|
||||||
|
fp->close_fn = fp_close_fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static file_ptr_t __stdio_fp[3];
|
||||||
|
|
||||||
|
FILE* stdin = (FILE *) &__stdio_fp[0];
|
||||||
|
FILE* stdout = (FILE *) &__stdio_fp[1];
|
||||||
|
FILE* stderr = (FILE *) &__stdio_fp[2];
|
||||||
|
|
||||||
|
void __init_stdio(void) {
|
||||||
|
set_fp_fd((file_ptr_t *) stdin, 0);
|
||||||
|
set_fp_fd((file_ptr_t *) stdout, 1);
|
||||||
|
set_fp_fd((file_ptr_t *) stderr, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *fdopen(int fd, const char *mode __attribute__((unused))) {
|
||||||
|
file_ptr_t *fp = malloc(sizeof(file_ptr_t));
|
||||||
|
set_fp_fd(fp, fd);
|
||||||
|
return (FILE *) fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *funopen(const void* cookie,
|
||||||
|
int (*read_fn)(void*, char*, int),
|
||||||
|
int (*write_fn)(void*, const char*, int),
|
||||||
|
fpos_t (*seek_fn)(void*, fpos_t, int),
|
||||||
|
int (*close_fn)(void*)) {
|
||||||
|
file_ptr_t *fp = malloc(sizeof(file_ptr_t));
|
||||||
|
fp->fd = -1;
|
||||||
|
fp->cookie = (void *) cookie;
|
||||||
|
fp->read_fn = read_fn;
|
||||||
|
fp->write_fn = write_fn;
|
||||||
|
fp->seek_fn = seek_fn;
|
||||||
|
fp->close_fn = close_fn;
|
||||||
|
return (FILE *) fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define fn_arg (fp->fd > 0 ? (void*)(intptr_t) fp->fd : fp->cookie)
|
||||||
|
|
||||||
|
int fclose(FILE *stream) {
|
||||||
|
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||||
|
int ret = fp->close_fn(fn_arg);
|
||||||
|
free(stream);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fileno(FILE *stream) {
|
||||||
|
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||||
|
return fp->fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fputc(int ch, FILE *stream) {
|
||||||
|
char c = ch;
|
||||||
|
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||||
|
return fp->write_fn(fn_arg, &c, 1) >= 0 ? 0 : EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fwrite(const void* buf, size_t size, size_t count, FILE* stream) {
|
||||||
|
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||||
|
int ret = fp->write_fn(fn_arg, buf, size * count);
|
||||||
|
return ret >= 0 ? ret : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fputs(const char* s, FILE* stream) {
|
||||||
|
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||||
|
size_t length = strlen(s);
|
||||||
|
return fp->write_fn(fn_arg, s, length) == length ? 0 : EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fgetc(FILE *stream) {
|
||||||
|
char ch;
|
||||||
|
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||||
|
if (fp->read_fn(fn_arg, &ch, 1) == 1) {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fread(void *buf, size_t size, size_t count, FILE* stream) {
|
||||||
|
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||||
|
int ret = fp->read_fn(fn_arg, buf, size * count);
|
||||||
|
return ret >= 0 ? ret : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setbuf(FILE* fp, char* buf) {}
|
||||||
|
|
||||||
#include "tinystdio/tinystdio.c"
|
#include "tinystdio/tinystdio.c"
|
||||||
|
|
||||||
@ -33,6 +154,30 @@ int vasprintf(char **strp, const char *fmt, va_list ap) {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vprintf(const char *fmt, va_list args) {
|
||||||
|
return vfprintf(stdout, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fprintf(FILE *stream, const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
ret = vfprintf(stream, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int printf(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
ret = vfprintf(stdout, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int sscanf(const char *str, const char *format, ...) {
|
int sscanf(const char *str, const char *format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int retval;
|
int retval;
|
||||||
@ -42,3 +187,42 @@ int sscanf(const char *str, const char *format, ...) {
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Original source: https://github.com/freebsd/freebsd/blob/master/contrib/file/src/getline.c
|
||||||
|
// License: BSD, full copyright notice please check original source
|
||||||
|
ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) {
|
||||||
|
char *ptr, *eptr;
|
||||||
|
|
||||||
|
if (*buf == NULL || *bufsiz == 0) {
|
||||||
|
*bufsiz = BUFSIZ;
|
||||||
|
if ((*buf = (char *) malloc(*bufsiz)) == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
|
||||||
|
int c = fgetc(fp);
|
||||||
|
if (c == -1) {
|
||||||
|
return ptr == *buf ? -1 : ptr - *buf;
|
||||||
|
}
|
||||||
|
*ptr++ = c;
|
||||||
|
if (c == delimiter) {
|
||||||
|
*ptr = '\0';
|
||||||
|
return ptr - *buf;
|
||||||
|
}
|
||||||
|
if (ptr + 2 >= eptr) {
|
||||||
|
char *nbuf;
|
||||||
|
size_t nbufsiz = *bufsiz * 2;
|
||||||
|
ssize_t d = ptr - *buf;
|
||||||
|
if ((nbuf = (char *) realloc(*buf, nbufsiz)) == NULL)
|
||||||
|
return -1;
|
||||||
|
*buf = nbuf;
|
||||||
|
*bufsiz = nbufsiz;
|
||||||
|
eptr = nbuf + nbufsiz;
|
||||||
|
ptr = nbuf + d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t getline(char **buf, size_t *bufsiz, FILE *fp) {
|
||||||
|
return getdelim(buf, bufsiz, '\n', fp);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user