libc: initial import from Harvey

Note that libc is what distinguish "native" software from "non-native"
in Jehanne: further C libraries can be ported to Jehanne, but this libc
will remain the main building block of the system.

Also note that a few files have not been ported from Harvey:

	- 9sys/pushtls.c
	- port/rijndael.c
	- port/rijndael.tbl
	- port/sha2.c

Pushtls.c depends on libmp and libsec so libc is not the appropriate place
for it. The other three will be moved to libsec.
This commit is contained in:
Giacomo Tesio 2015-12-22 11:55:44 +00:00
parent e4ebd7eace
commit 3925b61fa6
212 changed files with 20644 additions and 0 deletions

38
sys/include/ctype.h Normal file
View File

@ -0,0 +1,38 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#pragma src "/sys/src/libc/port"
#pragma lib "libc.a"
#define _U 01
#define _L 02
#define _N 04
#define _S 010
#define _P 020
#define _C 040
#define _B 0100
#define _X 0200
extern unsigned char _ctype[];
#define isalpha(c) (_ctype[(unsigned char)(c)]&(_U|_L))
#define isupper(c) (_ctype[(unsigned char)(c)]&_U)
#define islower(c) (_ctype[(unsigned char)(c)]&_L)
#define isdigit(c) (_ctype[(unsigned char)(c)]&_N)
#define isxdigit(c) (_ctype[(unsigned char)(c)]&_X)
#define isspace(c) (_ctype[(unsigned char)(c)]&_S)
#define ispunct(c) (_ctype[(unsigned char)(c)]&_P)
#define isalnum(c) (_ctype[(unsigned char)(c)]&(_U|_L|_N))
#define isprint(c) (_ctype[(unsigned char)(c)]&(_P|_U|_L|_N|_B))
#define isgraph(c) (_ctype[(unsigned char)(c)]&(_P|_U|_L|_N))
#define iscntrl(c) (_ctype[(unsigned char)(c)]&_C)
#define isascii(c) ((unsigned char)(c)<=0177)
#define _toupper(c) ((c)-'a'+'A')
#define _tolower(c) ((c)-'A'+'a')
#define toascii(c) ((c)&0177)

149
sys/include/fcall.h Normal file
View File

@ -0,0 +1,149 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#pragma src "/sys/src/libc/9sys"
#pragma lib "libc.a"
#define VERSION9P "9P2000"
#define MAXWELEM 16
typedef
struct Fcall
{
uint8_t type;
uint32_t fid;
uint16_t tag;
union {
struct {
uint32_t msize; /* Tversion, Rversion */
char *version; /* Tversion, Rversion */
};
struct {
uint16_t oldtag; /* Tflush */
};
struct {
char *ename; /* Rerror */
};
struct {
Qid qid; /* Rattach, Ropen, Rcreate */
uint32_t iounit; /* Ropen, Rcreate */
};
struct {
Qid aqid; /* Rauth */
};
struct {
uint32_t afid; /* Tauth, Tattach */
char *uname; /* Tauth, Tattach */
char *aname; /* Tauth, Tattach */
};
struct {
uint32_t perm; /* Tcreate */
char *name; /* Tcreate */
uint8_t mode; /* Tcreate, Topen */
};
struct {
uint32_t newfid; /* Twalk */
uint16_t nwname; /* Twalk */
char *wname[MAXWELEM]; /* Twalk */
};
struct {
uint16_t nwqid; /* Rwalk */
Qid wqid[MAXWELEM]; /* Rwalk */
};
struct {
int64_t offset; /* Tread, Twrite */
uint32_t count; /* Tread, Twrite, Rread */
char *data; /* Twrite, Rread */
};
struct {
uint16_t nstat; /* Twstat, Rstat */
uint8_t *stat; /* Twstat, Rstat */
};
};
} Fcall;
#define GBIT8(p) ((p)[0])
#define GBIT16(p) ((p)[0]|((p)[1]<<8))
#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))
#define GBIT64(p) ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\
((int64_t)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32))
#define PBIT8(p,v) (p)[0]=(v)
#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24
#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\
(p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56
#define BIT8SZ 1
#define BIT16SZ 2
#define BIT32SZ 4
#define BIT64SZ 8
#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ)
/* STATFIXLEN includes leading 16-bit count */
/* The count, however, excludes itself; total size is BIT16SZ+count */
#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */
#define NOTAG (uint16_t)~0U /* Dummy tag */
#define NOFID (uint32_t)~0U /* Dummy fid */
#define IOHDRSZ 24 /* ample room for Twrite/Rread header (iounit) */
enum
{
Tversion = 100,
Rversion,
Tauth = 102,
Rauth,
Tattach = 104,
Rattach,
Terror = 106, /* illegal */
Rerror,
Tflush = 108,
Rflush,
Twalk = 110,
Rwalk,
Topen = 112,
Ropen,
Tcreate = 114,
Rcreate,
Tread = 116,
Rread,
Twrite = 118,
Rwrite,
Tclunk = 120,
Rclunk,
Tremove = 122,
Rremove,
Tstat = 124,
Rstat,
Twstat = 126,
Rwstat,
Tmax,
};
uint convM2S(uint8_t*, uint, Fcall*);
uint convS2M(Fcall*, uint8_t*, uint);
uint sizeS2M(Fcall*);
int statcheck(uint8_t *abuf, uint nbuf);
uint convM2D(uint8_t*, uint, Dir*, char*);
uint convD2M(Dir*, uint8_t*, uint);
uint sizeD2M(Dir*);
int fcallfmt(Fmt*);
int dirfmt(Fmt*);
int dirmodefmt(Fmt*);
int read9pmsg(int, void*, uint);
#pragma varargck type "F" Fcall*
#pragma varargck type "M" ulong
#pragma varargck type "D" Dir*

763
sys/include/libc.h Normal file
View File

@ -0,0 +1,763 @@
/*
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#pragma lib "libc.a"
#pragma src "/sys/src/libc"
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define offsetof(s, m) (uintptr_t)(&(((s*)0)->m))
#define assert(x) if(x){}else _assert(#x)
extern void (*_abort)(void);
#define abort() if(_abort){_abort();}else{while(*(int*)0);}
/*
* mem routines
*/
extern void* memccpy(void*, const void*, int, uint32_t);
extern void* memset(void*, int, uint32_t);
extern int memcmp(const void*, const void*, uint32_t);
extern void* memcpy(void*, const void*, size_t);
extern void* memmove(void*, const void*, size_t);
extern void* memchr(const void*, int, uint32_t);
/*
* string routines
*/
extern char* strcat(char*, const char*);
extern char* strchr(const char*, int);
extern int strcmp(const char*, const char*);
extern char* strcpy(char*, const char*);
extern char* strecpy(char*, char *, const char*);
extern char* strdup(const char*);
extern char* strncat(char*, const char*, int32_t);
extern char* strncpy(char*, const char*, uint32_t);
extern int strncmp(const char*, const char*, int32_t);
extern char* strpbrk(const char*, const char*);
extern char* strrchr(const char*, int);
extern char* strtok(char*, char*);
extern int32_t strlen(const char*);
extern int32_t strspn(const char*, const char*);
extern int32_t strcspn(const char*, const char*);
extern char* strstr(const char*, const char*);
extern int cistrncmp(const char*, const char*, int);
extern int cistrcmp(const char*, const char*);
extern char* cistrstr(const char*, const char*);
extern int tokenize(char*, char**, int);
enum
{
UTFmax = 4, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
Runeerror = 0xFFFD, /* decoding error in UTF */
Runemax = 0x10FFFF, /* 21-bit rune */
Runemask = 0x1FFFFF, /* bits used by runes (see grep) */
};
/*
* rune routines
*/
extern int runetochar(char*, const Rune*);
extern int chartorune(Rune*, const char*);
extern int runelen(Rune);
extern int runenlen(const Rune*, int);
extern int fullrune(const char*, int);
extern int utflen(const char*);
extern int utfnlen(const char*, int32_t);
extern char* utfrune(const char*, Rune);
extern char* utfrrune(const char*, Rune);
extern char* utfutf(const char*, const char*);
extern char* utfecpy(char*, char *, const char*);
extern Rune* runestrcat(Rune*, const Rune*);
extern Rune* runestrchr(const Rune*, Rune);
extern int runestrcmp(const Rune*, const Rune*);
extern Rune* runestrcpy(Rune*, const Rune*);
extern Rune* runestrncpy(Rune*, const Rune*, int32_t);
extern Rune* runestrecpy(Rune*, Rune*, const Rune*);
extern Rune* runestrdup(const Rune*);
extern Rune* runestrncat(Rune*, const Rune*, int32_t);
extern int runestrncmp(const Rune*, const Rune*, int32_t);
extern Rune* runestrrchr(const Rune*, Rune);
extern int32_t runestrlen(const Rune*);
extern Rune* runestrstr(const Rune*, const Rune*);
extern Rune tolowerrune(Rune);
extern Rune totitlerune(Rune);
extern Rune toupperrune(Rune);
extern Rune tobaserune(Rune);
extern int isalpharune(Rune);
extern int isbaserune(Rune);
extern int isdigitrune(Rune);
extern int islowerrune(Rune);
extern int isspacerune(Rune);
extern int istitlerune(Rune);
extern int isupperrune(Rune);
/*
* malloc
*/
extern void* malloc(size_t);
extern void* mallocz(uint32_t, int);
extern void free(void*);
extern uint32_t msize(void*);
extern void* mallocalign(uint32_t, uint32_t, int32_t, uint32_t);
extern void* calloc(uint32_t, size_t);
extern void* realloc(void*, size_t);
void setmalloctag(void*, uintptr_t);
void setrealloctag(void*, uintptr_t);
uintptr_t getmalloctag(void*);
uintptr_t getrealloctag(void*);
void* malloctopoolblock(void*);
/*
* print routines
*/
typedef struct Fmt Fmt;
struct Fmt{
uint8_t runes; /* output buffer is runes or chars? */
void *start; /* of buffer */
void *to; /* current place in the buffer */
void *stop; /* end of the buffer; overwritten if flush fails */
int (*flush)(Fmt *); /* called when to == stop */
void *farg; /* to make flush a closure */
int nfmt; /* num chars formatted so far */
va_list args; /* args passed to dofmt */
int r; /* % format Rune */
int width;
int prec;
uint32_t flags;
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtZero = FmtSign << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtByte = FmtComma << 1,
FmtFlag = FmtByte << 1
};
extern int print(const char*, ...);
extern char* seprint(char*, char*, const char*, ...);
extern char* vseprint(char*, char*, const char*, va_list);
extern int snprint(char*, int, const char*, ...);
extern int vsnprint(char*, int, const char*, va_list);
extern char* smprint(const char*, ...);
extern char* vsmprint(const char*, va_list);
extern int sprint(char*, const char*, ...);
extern int fprint(int, const char*, ...);
extern int vfprint(int, const char*, va_list);
extern int runesprint(Rune*, const char*, ...);
extern int runesnprint(Rune*, int, const char*, ...);
extern int runevsnprint(Rune*, int, const char*, va_list);
extern Rune* runeseprint(Rune*, Rune*, const char*, ...);
extern Rune* runevseprint(Rune*, Rune*, const char*, va_list);
extern Rune* runesmprint(const char*, ...);
extern Rune* runevsmprint(const char*, va_list);
extern int fmtfdinit(Fmt*, int, char*, int);
extern int fmtfdflush(Fmt*);
extern int fmtstrinit(Fmt*);
extern char* fmtstrflush(Fmt*);
extern int runefmtstrinit(Fmt*);
extern Rune* runefmtstrflush(Fmt*);
#pragma varargck argpos fmtprint 2
#pragma varargck argpos fprint 2
#pragma varargck argpos print 1
#pragma varargck argpos runeseprint 3
#pragma varargck argpos runesmprint 1
#pragma varargck argpos runesnprint 3
#pragma varargck argpos runesprint 2
#pragma varargck argpos seprint 3
#pragma varargck argpos smprint 1
#pragma varargck argpos snprint 3
#pragma varargck argpos sprint 2
#pragma varargck type "lld" vlong
#pragma varargck type "llo" vlong
#pragma varargck type "llx" vlong
#pragma varargck type "llb" vlong
#pragma varargck type "lld" uvlong
#pragma varargck type "llo" uvlong
#pragma varargck type "llx" uvlong
#pragma varargck type "llb" uvlong
#pragma varargck type "ld" long
#pragma varargck type "lo" long
#pragma varargck type "lx" long
#pragma varargck type "lb" long
#pragma varargck type "ld" ulong
#pragma varargck type "lo" ulong
#pragma varargck type "lx" ulong
#pragma varargck type "lb" ulong
#pragma varargck type "d" int
#pragma varargck type "o" int
#pragma varargck type "x" int
#pragma varargck type "c" int
#pragma varargck type "C" int
#pragma varargck type "b" int
#pragma varargck type "d" uint
#pragma varargck type "x" uint
#pragma varargck type "c" uint
#pragma varargck type "C" uint
#pragma varargck type "b" uint
#pragma varargck type "f" double
#pragma varargck type "e" double
#pragma varargck type "g" double
#pragma varargck type "s" char*
#pragma varargck type "q" char*
#pragma varargck type "S" Rune*
#pragma varargck type "Q" Rune*
#pragma varargck type "r" void
#pragma varargck type "%" void
#pragma varargck type "n" int*
#pragma varargck type "p" uintptr
#pragma varargck type "p" void*
#pragma varargck flag ','
#pragma varargck flag ' '
#pragma varargck flag 'h'
#pragma varargck type "<" void*
#pragma varargck type "[" void*
#pragma varargck type "H" void*
#pragma varargck type "lH" void*
extern int fmtinstall(int, int (*)(Fmt*));
extern int dofmt(Fmt*, const char*);
extern int dorfmt(Fmt*, const Rune*);
extern int fmtprint(Fmt*, const char*, ...);
extern int fmtvprint(Fmt*, const char*, va_list);
extern int fmtrune(Fmt*, int);
extern int fmtstrcpy(Fmt*, const char*);
extern int fmtrunestrcpy(Fmt*, const Rune*);
/*
* error string for %r
* supplied on per os basis, not part of fmt library
*/
extern int errfmt(Fmt *f);
/*
* quoted strings
*/
extern char *unquotestrdup(const char*);
extern Rune *unquoterunestrdup(const Rune*);
extern char *quotestrdup(const char*);
extern Rune *quoterunestrdup(const Rune*);
extern int quotestrfmt(Fmt*);
extern int quoterunestrfmt(Fmt*);
extern void quotefmtinstall(void);
extern int (*doquote)(int);
extern int needsrcquote(int);
/*
* random number
*/
extern void srand(int32_t);
extern int rand(void);
extern int nrand(int);
extern int32_t lrand(void);
extern int32_t lnrand(int32_t);
extern double frand(void);
extern uint32_t truerand(void); /* uses /dev/random */
extern uint32_t ntruerand(uint32_t); /* uses /dev/random */
/*
* math
*/
extern uint32_t getfcr(void);
extern void setfsr(uint32_t);
extern uint32_t getfsr(void);
extern void setfcr(uint32_t);
extern double NaN(void);
extern double Inf(int);
extern int isNaN(double);
extern int isInf(double, int);
extern uint32_t umuldiv(uint32_t, uint32_t, uint32_t);
extern int32_t muldiv(int32_t, int32_t, int32_t);
extern double pow(double, double);
extern double atan2(double, double);
extern double fabs(double);
extern double atan(double);
extern double log(double);
extern double log10(double);
extern double exp(double);
extern double floor(double);
extern double ceil(double);
extern double hypot(double, double);
extern double sin(double);
extern double cos(double);
extern double tan(double);
extern double asin(double);
extern double acos(double);
extern double sinh(double);
extern double cosh(double);
extern double tanh(double);
extern double sqrt(double);
extern double fmod(double, double);
#define HUGE 3.4028234e38
#define PIO2 1.570796326794896619231e0
#define PI (PIO2+PIO2)
/*
* Time-of-day
*/
typedef
struct Tm
{
int sec;
int min;
int hour;
int mday;
int mon;
int year;
int wday;
int yday;
char zone[4];
int tzoff;
} Tm;
extern Tm* gmtime(int32_t);
extern Tm* localtime(int32_t);
extern char* asctime(Tm*);
extern char* ctime(int32_t);
extern double cputime(void);
extern int32_t times(int32_t*);
extern int32_t tm2sec(Tm*);
extern int64_t nsec(void);
extern void cycles(uint64_t*); /* 64-bit value of the cycle counter if there is one, 0 if there isn't */
/*
* one-of-a-kind
*/
enum
{
PNPROC = 1,
PNGROUP = 2,
};
extern void _assert(const char*);
extern int abs(int);
extern int atexit(void(*)(void));
extern void atexitdont(void(*)(void));
extern int atnotify(int(*)(void*, char*), int);
extern double atof(const char*);
extern int atoi(const char*);
extern int32_t atol(const char*);
extern int64_t atoll(const char*);
extern double charstod(int(*)(void*), void*);
extern char* cleanname(char*);
extern int decrypt(void*, void*, int);
extern int encrypt(void*, void*, int);
extern int dec64(uint8_t*, int, const char*, int);
extern int enc64(char*, int, const uint8_t*, int);
extern int dec32(uint8_t*, int, const char*, int);
extern int enc32(char*, int, const uint8_t*, int);
extern int dec16(uint8_t*, int, const char*, int);
extern int enc16(char*, int, const uint8_t*, int);
extern int encodefmt(Fmt*);
extern void exits(const char*);
extern double frexp(double, int*);
extern uintptr getcallerpc(void);
extern char* getenv(const char*);
extern int getfields(char*, char**, int, int, const char*);
extern int gettokens(char *, char **, int, const char *);
extern char* getuser(void);
extern char* getwd(char*, int);
extern int iounit(int);
extern int32_t labs(int32_t);
extern double ldexp(double, int);
extern void longjmp(jmp_buf, int);
extern char* mktemp(char*);
extern double modf(double, double*);
extern void notejmp(void*, jmp_buf, int);
extern void perror(const char*);
extern int postnote(int, int, const char *);
extern double pow10(int);
extern int putenv(const char*, const char*);
extern void qsort(void*, int32_t, int32_t,
int (*)(const void*, const void*));
extern int setjmp(jmp_buf);
extern double strtod(const char*, const char**);
extern int32_t strtol(const char*, char**, int);
extern uint32_t strtoul(const char*, char**, int);
extern int64_t strtoll(const char*, char**, int);
extern uint64_t strtoull(const char*, char**, int);
extern void sysfatal(const char*, ...);
#pragma varargck argpos sysfatal 1
extern void syslog(int, const char*, const char*, ...);
#pragma varargck argpos syslog 3
extern int32_t time(int32_t*);
extern int tolower(int);
extern int toupper(int);
/*
* atomic
*/
int32_t ainc(int32_t*);
int32_t adec(int32_t*);
int cas32(uint32_t*, uint32_t, uint32_t);
int casp(void**, void*, void*);
int casl(uint32_t*, uint32_t, uint32_t);
/*
* synchronization
*/
typedef
struct Lock {
int32_t key;
int32_t sem;
} Lock;
extern int _tas(int*);
extern void lock(Lock*);
extern int lockt(Lock*, uint32_t);
extern void unlock(Lock*);
extern int canlock(Lock*);
typedef struct QLp QLp;
struct QLp
{
int inuse;
QLp *next;
char state;
};
typedef
struct QLock
{
Lock lock;
int locked;
QLp *head;
QLp *tail;
} QLock;
extern void qlock(QLock*);
extern int qlockt(QLock*, uint32_t);
extern void qunlock(QLock*);
extern int canqlock(QLock*);
extern void _qlockinit(void* (*)(void*, void*)); /* called only by the thread library */
typedef
struct RWLock
{
Lock lock;
int _readers; /* number of readers */
int writer; /* number of writers */
QLp *head; /* list of waiting processes */
QLp *tail;
} RWLock;
extern void rlock(RWLock*);
extern int rlockt(RWLock*, uint32_t);
extern void runlock(RWLock*);
extern int canrlock(RWLock*);
extern void wlock(RWLock*);
extern int wlockt(RWLock*, uint32_t);
extern void wunlock(RWLock*);
extern int canwlock(RWLock*);
typedef
struct Rendez
{
QLock *l;
QLp *head;
QLp *tail;
} Rendez;
extern void rsleep(Rendez*); /* unlocks r->l, sleeps, locks r->l again */
extern int rsleept(Rendez*, uint32_t); /* unlocks r->l, sleeps (up to ms), locks r->l again (if not timedout) */
extern int rwakeup(Rendez*);
extern int rwakeupall(Rendez*);
extern void** privalloc(void);
extern void privfree(void**);
/*
* network dialing
*/
#define NETPATHLEN 40
extern int accept(int, const char*);
extern int announce(const char*, char*);
extern int dial(const char*, const char*, char*, int*);
extern void setnetmtpt(char*, int, const char*);
extern int hangup(int);
extern int listen(const char*, char*);
extern char* netmkaddr(const char*, const char*, const char*);
extern int reject(int, const char*, const char*);
/*
* encryption
*/
extern int pushssl(int, const char*, const char*, const char*, int*);
extern int pushtls(int, const char*, const char*, int, const char*,
char*);
/*
* network services
*/
typedef struct NetConnInfo NetConnInfo;
struct NetConnInfo
{
char *dir; /* connection directory */
char *root; /* network root */
char *spec; /* binding spec */
char *lsys; /* local system */
char *lserv; /* local service */
char *rsys; /* remote system */
char *rserv; /* remote service */
char *laddr; /* local address */
char *raddr; /* remote address */
};
extern NetConnInfo* getnetconninfo(const char*, int);
extern void freenetconninfo(NetConnInfo*);
/*
* system calls
*
*/
#define STATMAX 65535U /* max length of machine-independent stat structure */
#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */
#define ERRMAX 128 /* max length of error string */
#define MORDER 0x0003 /* mask for bits defining order of mounting */
#define MREPL 0x0000 /* mount replaces object */
#define MBEFORE 0x0001 /* mount goes before others in union directory */
#define MAFTER 0x0002 /* mount goes after others in union directory */
#define MCREATE 0x0004 /* permit creation in mounted directory */
#define MCACHE 0x0010 /* cache some data */
#define MMASK 0x0017 /* all bits on */
#define OREAD 0 /* open for read */
#define OWRITE 1 /* write */
#define ORDWR 2 /* read and write */
#define OEXEC 3 /* execute, == read but check execute permission */
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
#define OCEXEC 32 /* or'ed in, close on exec */
#define ORCLOSE 64 /* or'ed in, remove on close */
#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
// #define OBEHIND 0x2000 /* use write behind for writes [for 9n] */
#define AEXIST 0 /* accessible: exists */
#define AEXEC 1 /* execute access */
#define AWRITE 2 /* write access */
#define AREAD 4 /* read access */
/* Segattch */
#define SG_RONLY 0040 /* read only */
#define SG_CEXEC 0100 /* detach on exec */
#define NCONT 0 /* continue after note */
#define NDFLT 1 /* terminate after note */
#define NSAVE 2 /* clear note but hold state */
#define NRSTR 3 /* restore saved state */
/* bits in Qid.type */
#define QTDIR 0x80 /* type bit for directories */
#define QTAPPEND 0x40 /* type bit for append only files */
#define QTEXCL 0x20 /* type bit for exclusive use files */
#define QTMOUNT 0x10 /* type bit for mounted channel */
#define QTAUTH 0x08 /* type bit for authentication file */
#define QTTMP 0x04 /* type bit for not-backed-up file */
#define QTFILE 0x00 /* plain file */
/* bits in Dir.mode */
#define DMDIR 0x80000000 /* mode bit for directories */
#define DMAPPEND 0x40000000 /* mode bit for append only files */
#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
#define DMAUTH 0x08000000 /* mode bit for authentication file */
#define DMTMP 0x04000000 /* mode bit for non-backed-up files */
#define DMREAD 0x4 /* mode bit for read permission */
#define DMWRITE 0x2 /* mode bit for write permission */
#define DMEXEC 0x1 /* mode bit for execute permission */
/* rfork */
enum
{
RFNAMEG = (1<<0),
RFENVG = (1<<1),
RFFDG = (1<<2),
RFNOTEG = (1<<3),
RFPROC = (1<<4),
RFMEM = (1<<5),
RFNOWAIT = (1<<6),
RFCNAMEG = (1<<10),
RFCENVG = (1<<11),
RFCFDG = (1<<12),
RFREND = (1<<13),
RFNOMNT = (1<<14)
};
typedef
struct Qid
{
uint64_t path;
uint32_t vers;
uint8_t type;
} Qid;
typedef
struct Dir {
/* system-modified data */
uint16_t type; /* server type */
uint dev; /* server subtype */
/* file data */
Qid qid; /* unique id from server */
uint32_t mode; /* permissions */
uint32_t atime; /* last read time */
uint32_t mtime; /* last write time */
int64_t length; /* file length */
char *name; /* last element of path */
char *uid; /* owner name */
char *gid; /* group name */
char *muid; /* last modifier name */
} Dir;
/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
typedef
struct Waitmsg
{
int pid; /* of loved one */
uint32_t time[3]; /* of loved one & descendants */
char *msg;
} Waitmsg;
typedef
struct IOchunk
{
void *addr;
uint32_t len;
} IOchunk;
extern void _exits(const char*);
extern int access(const char*, int);
extern int64_t alarm(uint64_t);
extern int await(char*, int);
extern int64_t awake(int64_t);
extern int awakened(int64_t);
extern int bind(const char*, const char*, int);
extern int brk(void*);
extern int chdir(const char*);
extern int close(int);
extern int create(const char*, int, uint32_t);
extern int dup(int, int);
extern int errstr(char*, uint);
extern int exec(const char*, char* const[]);
extern int execl(const char*, ...);
extern int forgivewkp(int64_t);
extern int fork(void);
extern int rfork(int);
extern int fauth(int, const char*);
extern int fstat(int, uint8_t*, int);
extern int fwstat(int, uint8_t*, int);
extern int fversion(int, int, char*, int);
extern int mount(int, int, const char*, int, const char*, int);
extern int unmount(const char*, const char*);
extern int noted(int);
extern int notify(void(*)(void*, char*));
extern int open(const char*, int);
extern int fd2path(int, char*, int);
// extern int fdflush(int);
extern int pipe(int*);
extern int32_t pread(int, void*, int32_t, int64_t);
extern int32_t preadv(int, IOchunk*, int, int64_t);
extern int32_t pwrite(int, const void*, int32_t, int64_t);
extern int32_t pwritev(int, IOchunk*, int, int64_t);
extern int32_t read(int, void*, int32_t);
extern int32_t readn(int, void*, int32_t);
extern int32_t readv(int, IOchunk*, int);
extern int remove(const char*);
extern void* sbrk(uint32_t);
extern int32_t oseek(int, int32_t, int);
extern int64_t seek(int, int64_t, int);
extern void* segattach(int, const char*, void*, uint32_t);
extern void* segbrk(void*, void*);
extern int segdetach(void*);
extern int segflush(void*, uint32_t);
extern int segfree(void*, uint32_t);
extern int semacquire(int32_t*, int);
extern int32_t semrelease(int32_t*, int32_t);
extern void sleep(int32_t);
extern int stat(const char*, uint8_t*, int);
extern int tsemacquire(int32_t*, uint64_t);
extern Waitmsg* wait(void);
extern int waitpid(void);
extern int32_t write(int, const void*, int32_t);
extern int32_t writev(int, IOchunk*, int);
extern int wstat(const char*, uint8_t*, int);
extern void* rendezvous(void*, void*);
extern Dir* dirstat(const char*);
extern Dir* dirfstat(int);
extern int dirwstat(const char*, Dir*);
extern int dirfwstat(int, Dir*);
extern int32_t dirread(int, Dir**);
extern void nulldir(Dir*);
extern int32_t dirreadall(int, Dir**);
extern int getpid(void);
extern int getppid(void);
extern void rerrstr(char*, uint);
extern char* sysname(void);
extern void werrstr(const char*, ...);
#pragma varargck argpos werrstr 1
/* compiler directives on plan 9 */
#define SET(x) ((x)=0)
#define USED(x) if(x){}else{}
#ifdef __GNUC__
# if __GNUC__ >= 3
# undef USED
# define USED(x) ((void)(x))
# endif
#endif
extern char *argv0;
/* #define ARGBEGIN for((argv0||(argv0=*argv)),argv++,argc--;\ */
#define ARGBEGIN for((argv0?0:(argv0=*argv)),argv++,argc--;\
argv[0] && argv[0][0]=='-' && argv[0][1];\
argc--, argv++) {\
char *_args, *_argt;\
Rune _argc;\
_args = &argv[0][1];\
if(_args[0]=='-' && _args[1]==0){\
argc--; argv++; break;\
}\
_argc = 0;\
while(*_args && (_args += chartorune(&_argc, _args)))\
switch(_argc)
/* #define ARGEND SET(_argt);USED(_argt,_argc,_args);}USED(argv, argc); */
#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
#define ARGF() (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
#define EARGF(x) (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), argc = *(int*)0, (char*)0)))
#define ARGC() _argc
/* this is used by sbrk and brk, it's a really bad idea to redefine it */
extern char end[];

64
sys/include/pool.h Normal file
View File

@ -0,0 +1,64 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
typedef struct Pool Pool;
struct Pool {
char* name;
uint32_t maxsize;
uint32_t cursize;
uint32_t curfree;
uint32_t curalloc;
uint32_t minarena; /* smallest size of new arena */
uint32_t quantum; /* allocated blocks should be multiple of */
uint32_t minblock; /* smallest newly allocated block */
void* freeroot; /* actually Free* */
void* arenalist; /* actually Arena* */
void* (*alloc)(uint32_t);
int (*merge)(void*, void*);
void (*move)(void* from, void* to);
int flags;
int nfree;
int lastcompact;
void (*lock)(Pool*);
void (*unlock)(Pool*);
void (*print)(Pool*, char*, ...);
void (*panic)(Pool*, char*, ...);
void (*logstack)(Pool*);
void* private;
};
extern void* poolalloc(Pool*, uint32_t);
extern void* poolallocalign(Pool*, uint32_t, uint32_t, int32_t,
uint32_t);
extern void poolfree(Pool*, void*);
extern uint32_t poolmsize(Pool*, void*);
extern void* poolrealloc(Pool*, void*, uint32_t);
extern void poolcheck(Pool*);
extern int poolcompact(Pool*);
extern void poolblockcheck(Pool*, void*);
extern Pool* mainmem;
extern Pool* imagmem;
enum { /* flags */
POOL_ANTAGONISM = 1<<0,
POOL_PARANOIA = 1<<1,
POOL_VERBOSITY = 1<<2,
POOL_DEBUGGING = 1<<3,
POOL_LOGGING = 1<<4,
POOL_TOLERANCE = 1<<5,
POOL_NOREUSE = 1<<6,
};

29
sys/include/tos.h Normal file
View File

@ -0,0 +1,29 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
typedef struct Tos Tos;
struct Tos {
uint64_t cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */
int64_t kcycles; /* cycles spent in kernel */
int64_t pcycles; /* cycles spent in process (kernel + user) */
uint32_t pid; /* might as well put the pid here */
uint32_t clock;
/* scratch space for kernel use (e.g., mips fp delay-slot execution) */
uint32_t kscr[4];
/*
* Fields below are not available on Plan 9 kernels.
*/
int nixtype; /* role of the core we are running at */
int core; /* core we are running at */
/* top of stack is here */
};
extern Tos *_tos;

32
sys/src/klib.json Normal file
View File

@ -0,0 +1,32 @@
{
"KernelLibs": {
"Cflags": [
"-std=c11",
"-c",
"-I/$JEHANNE/arch/$ARCH/include",
"-I/$JEHANNE/sys/include",
"-I.",
"-mcmodel=kernel",
"-O0",
"-fplan9-extensions",
"-mno-red-zone",
"-ffreestanding",
"-fno-builtin",
"-Wall",
"-Wno-missing-braces",
"-Wno-parentheses",
"-Wno-unknown-pragmas",
"-Wuninitialized",
"-g"
],
"Oflags": [
"-static"
],
"Post": [
"rm *.o"
],
"Pre": [
"rm -f *.o *.tag.*"
]
}
}

7
sys/src/klibs.json Normal file
View File

@ -0,0 +1,7 @@
{
"klibs": {
"Projects": [
"/sys/src/libc/klibc.json"
]
}
}

16
sys/src/lib.json Normal file
View File

@ -0,0 +1,16 @@
{
"Libs": {
"Include": [
"/arch/$ARCH/include/cflags.json"
],
"Oflags": [
"-static"
],
"Post": [
"rm *.o"
],
"Pre": [
"rm -f *.o *.tag.*"
]
}
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
access(const char *name, int mode)
{
int fd;
Dir *db;
static char omode[] = {
0,
OEXEC,
OWRITE,
ORDWR,
OREAD,
OEXEC, /* only approximate */
ORDWR,
ORDWR /* only approximate */
};
if(mode == AEXIST){
db = dirstat(name);
free(db);
if(db != nil)
return 0;
return -1;
}
fd = open(name, omode[mode&7]);
if(fd >= 0){
close(fd);
return 0;
}
return -1;
}

View File

@ -0,0 +1,284 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <ctype.h>
static int nettrans(const char*, char*, int na, char*, int);
enum
{
Maxpath= 256,
};
/*
* announce a network service.
*/
int
announce(const char *addr, char *dir)
{
int ctl, n, m;
char buf[Maxpath];
char buf2[Maxpath];
char netdir[Maxpath];
char naddr[Maxpath];
char *cp;
/*
* translate the address
*/
if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
return -1;
/*
* get a control channel
*/
ctl = open(netdir, ORDWR);
if(ctl<0){
werrstr("announce opening %s: %r", netdir);
return -1;
}
cp = strrchr(netdir, '/');
if(cp == nil){
werrstr("announce arg format %s", netdir);
close(ctl);
return -1;
}
*cp = 0;
/*
* find out which line we have
*/
n = snprint(buf, sizeof(buf), "%s/", netdir);
m = read(ctl, &buf[n], sizeof(buf)-n-1);
if(m <= 0){
werrstr("announce reading %s: %r", netdir);
close(ctl);
return -1;
}
buf[n+m] = 0;
/*
* make the call
*/
n = snprint(buf2, sizeof(buf2), "announce %s", naddr);
if(write(ctl, buf2, n)!=n){
werrstr("announce writing %s: %r", netdir);
close(ctl);
return -1;
}
/*
* return directory etc.
*/
if(dir){
strncpy(dir, buf, NETPATHLEN);
dir[NETPATHLEN-1] = 0;
}
return ctl;
}
/*
* listen for an incoming call
*/
int
listen(const char *dir, char *newdir)
{
int ctl, n, m;
char buf[Maxpath];
char *cp;
/*
* open listen, wait for a call
*/
snprint(buf, sizeof(buf), "%s/listen", dir);
ctl = open(buf, ORDWR);
if(ctl < 0){
werrstr("listen opening %s: %r", buf);
return -1;
}
/*
* find out which line we have
*/
strncpy(buf, dir, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;
cp = strrchr(buf, '/');
if(cp == nil){
close(ctl);
werrstr("listen arg format %s", dir);
return -1;
}
*++cp = 0;
n = cp-buf;
m = read(ctl, cp, sizeof(buf) - n - 1);
if(m <= 0){
close(ctl);
werrstr("listen reading %s/listen: %r", dir);
return -1;
}
buf[n+m] = 0;
/*
* return directory etc.
*/
if(newdir){
strncpy(newdir, buf, NETPATHLEN);
newdir[NETPATHLEN-1] = 0;
}
return ctl;
}
/*
* accept a call, return an fd to the open data file
*/
int
accept(int ctl, const char *dir)
{
char buf[Maxpath];
const char *num;
int32_t n;
num = strrchr(dir, '/');
if(num == nil)
num = dir;
else
num++;
n = snprint(buf, sizeof(buf), "accept %s", num);
write(ctl, buf, n); /* ignore return value, network might not need accepts */
snprint(buf, sizeof(buf), "%s/data", dir);
return open(buf, ORDWR);
}
/*
* reject a call, tell device the reason for the rejection
*/
int
reject(int ctl, const char *dir, const char *cause)
{
char buf[Maxpath];
const char *num;
int32_t n;
num = strrchr(dir, '/');
if(num == 0)
num = dir;
else
num++;
snprint(buf, sizeof(buf), "reject %s %s", num, cause);
n = strlen(buf);
if(write(ctl, buf, n) != n)
return -1;
return 0;
}
/*
* perform the identity translation (in case we can't reach cs)
*/
static int
identtrans(char *netdir, const char *addr, char *naddr, int na,
char *file, int nf)
{
char proto[Maxpath];
char *p;
USED(nf);
/* parse the protocol */
strncpy(proto, addr, sizeof(proto));
proto[sizeof(proto)-1] = 0;
p = strchr(proto, '!');
if(p)
*p++ = 0;
snprint(file, nf, "%s/%s/clone", netdir, proto);
strncpy(naddr, p, na);
naddr[na-1] = 0;
return 1;
}
/*
* call up the connection server and get a translation
*/
static int
nettrans(const char *addr, char *naddr, int na, char *file, int nf)
{
int i, fd;
char buf[Maxpath];
char netdir[Maxpath];
char *p, *p2;
int32_t n;
/*
* parse, get network directory
*/
p = strchr(addr, '!');
if(p == 0){
werrstr("bad dial string: %s", addr);
return -1;
}
if(*addr != '/'){
strncpy(netdir, "/net", sizeof(netdir));
netdir[sizeof(netdir) - 1] = 0;
} else {
for(p2 = p; *p2 != '/'; p2--)
;
i = p2 - addr;
if(i == 0 || i >= sizeof(netdir)){
werrstr("bad dial string: %s", addr);
return -1;
}
strncpy(netdir, addr, i);
netdir[i] = 0;
addr = p2 + 1;
}
/*
* ask the connection server
*/
snprint(buf, sizeof(buf), "%s/cs", netdir);
fd = open(buf, ORDWR);
if(fd < 0)
return identtrans(netdir, addr, naddr, na, file, nf);
if(write(fd, addr, strlen(addr)) < 0){
close(fd);
return -1;
}
seek(fd, 0, 0);
n = read(fd, buf, sizeof(buf)-1);
close(fd);
if(n <= 0)
return -1;
buf[n] = 0;
/*
* parse the reply
*/
p = strchr(buf, ' ');
if(p == 0)
return -1;
*p++ = 0;
strncpy(naddr, p, na);
naddr[na-1] = 0;
if(buf[0] == '/'){
p = strchr(buf+1, '/');
if(p == nil)
p = buf;
else
p++;
}
snprint(file, nf, "%s/%s", netdir, p);
return 0;
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
*
* Jehanne is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* Jehanne is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <libc.h>
int
awakened(int64_t wakeup)
{
/* awake returns the ticks of the scheduled wakeup in negative,
* thus a wakeup is in the past iff (-awake(0)) >= (-wakeup)
*
* NOTE: this is not a macro so that we can change the awake()
* implementation in the future, without affecting the client code.
*/
assert(wakeup < 0);
return wakeup >= awake(0);
}
int
forgivewkp(int64_t wakeup)
{
/* awake returns the ticks of the scheduled wakeup in negative,
* and is able to remove a wakeup provided such value.
*
* forgivewkp() is just a wrapper to hide awake()'s details that
* could change in the future and make client code easier to
* read.
*
* NOTE: this is not a macro so that we can change the awake()
* implementation in the future, without affecting the client code.
*/
assert(wakeup < 0);
return awake(wakeup);
}

104
sys/src/libc/9sys/convD2M.c Normal file
View File

@ -0,0 +1,104 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
uint
sizeD2M(Dir *d)
{
char *sv[4];
int i, ns;
sv[0] = d->name;
sv[1] = d->uid;
sv[2] = d->gid;
sv[3] = d->muid;
ns = 0;
for(i = 0; i < 4; i++)
if(sv[i])
ns += strlen(sv[i]);
return STATFIXLEN + ns;
}
uint
convD2M(Dir *d, uint8_t *buf, uint nbuf)
{
uint8_t *p, *ebuf;
char *sv[4];
int i, ns, nsv[4], ss;
if(nbuf < BIT16SZ)
return 0;
p = buf;
ebuf = buf + nbuf;
sv[0] = d->name;
sv[1] = d->uid;
sv[2] = d->gid;
sv[3] = d->muid;
ns = 0;
for(i = 0; i < 4; i++){
if(sv[i])
nsv[i] = strlen(sv[i]);
else
nsv[i] = 0;
ns += nsv[i];
}
ss = STATFIXLEN + ns;
/* set size before erroring, so user can know how much is needed */
/* note that length excludes count field itself */
PBIT16(p, ss-BIT16SZ);
p += BIT16SZ;
if(ss > nbuf)
return BIT16SZ;
PBIT16(p, d->type);
p += BIT16SZ;
PBIT32(p, d->dev);
p += BIT32SZ;
PBIT8(p, d->qid.type);
p += BIT8SZ;
PBIT32(p, d->qid.vers);
p += BIT32SZ;
PBIT64(p, d->qid.path);
p += BIT64SZ;
PBIT32(p, d->mode);
p += BIT32SZ;
PBIT32(p, d->atime);
p += BIT32SZ;
PBIT32(p, d->mtime);
p += BIT32SZ;
PBIT64(p, d->length);
p += BIT64SZ;
for(i = 0; i < 4; i++){
ns = nsv[i];
if(p + ns + BIT16SZ > ebuf)
return 0;
PBIT16(p, ns);
p += BIT16SZ;
if(ns)
memmove(p, sv[i], ns);
p += ns;
}
if(ss != p - buf)
return 0;
return p - buf;
}

103
sys/src/libc/9sys/convM2D.c Normal file
View File

@ -0,0 +1,103 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
int
statcheck(uint8_t *buf, uint nbuf)
{
uint8_t *ebuf;
int i;
ebuf = buf + nbuf;
if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
return -1;
buf += STATFIXLEN - 4 * BIT16SZ;
for(i = 0; i < 4; i++){
if(buf + BIT16SZ > ebuf)
return -1;
buf += BIT16SZ + GBIT16(buf);
}
if(buf != ebuf)
return -1;
return 0;
}
static char nullstring[] = "";
uint
convM2D(uint8_t *buf, uint nbuf, Dir *d, char *strs)
{
uint8_t *p, *ebuf;
char *sv[4];
int i, ns;
if(nbuf < STATFIXLEN)
return 0;
p = buf;
ebuf = buf + nbuf;
p += BIT16SZ; /* ignore size */
d->type = GBIT16(p);
p += BIT16SZ;
d->dev = GBIT32(p);
p += BIT32SZ;
d->qid.type = GBIT8(p);
p += BIT8SZ;
d->qid.vers = GBIT32(p);
p += BIT32SZ;
d->qid.path = GBIT64(p);
p += BIT64SZ;
d->mode = GBIT32(p);
p += BIT32SZ;
d->atime = GBIT32(p);
p += BIT32SZ;
d->mtime = GBIT32(p);
p += BIT32SZ;
d->length = GBIT64(p);
p += BIT64SZ;
for(i = 0; i < 4; i++){
if(p + BIT16SZ > ebuf)
return 0;
ns = GBIT16(p);
p += BIT16SZ;
if(p + ns > ebuf)
return 0;
if(strs){
sv[i] = strs;
memmove(strs, p, ns);
strs += ns;
*strs++ = '\0';
}
p += ns;
}
if(strs){
d->name = sv[0];
d->uid = sv[1];
d->gid = sv[2];
d->muid = sv[3];
}else{
d->name = nullstring;
d->uid = nullstring;
d->gid = nullstring;
d->muid = nullstring;
}
return p - buf;
}

324
sys/src/libc/9sys/convM2S.c Normal file
View File

@ -0,0 +1,324 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
static
uint8_t*
gstring(uint8_t *p, uint8_t *ep, char **s)
{
uint n;
if(p+BIT16SZ > ep)
return nil;
n = GBIT16(p);
p += BIT16SZ - 1;
if(p+n+1 > ep)
return nil;
/* move it down, on top of count, to make room for '\0' */
memmove(p, p + 1, n);
p[n] = '\0';
*s = (char*)p;
p += n+1;
return p;
}
static
uint8_t*
gqid(uint8_t *p, uint8_t *ep, Qid *q)
{
if(p+QIDSZ > ep)
return nil;
q->type = GBIT8(p);
p += BIT8SZ;
q->vers = GBIT32(p);
p += BIT32SZ;
q->path = GBIT64(p);
p += BIT64SZ;
return p;
}
/*
* no syntactic checks.
* three causes for error:
* 1. message size field is incorrect
* 2. input buffer too short for its own data (counts too long, etc.)
* 3. too many names or qids
* gqid() and gstring() return nil if they would reach beyond buffer.
* main switch statement checks range and also can fall through
* to test at end of routine.
*/
uint
convM2S(uint8_t *ap, uint nap, Fcall *f)
{
uint8_t *p, *ep;
uint i, size;
p = ap;
ep = p + nap;
if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
return 0;
size = GBIT32(p);
p += BIT32SZ;
if(size < BIT32SZ+BIT8SZ+BIT16SZ)
return 0;
f->type = GBIT8(p);
p += BIT8SZ;
f->tag = GBIT16(p);
p += BIT16SZ;
switch(f->type)
{
default:
return 0;
case Tversion:
if(p+BIT32SZ > ep)
return 0;
f->msize = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->version);
break;
case Tflush:
if(p+BIT16SZ > ep)
return 0;
f->oldtag = GBIT16(p);
p += BIT16SZ;
break;
case Tauth:
if(p+BIT32SZ > ep)
return 0;
f->afid = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->uname);
if(p == nil)
break;
p = gstring(p, ep, &f->aname);
if(p == nil)
break;
break;
case Tattach:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
if(p+BIT32SZ > ep)
return 0;
f->afid = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->uname);
if(p == nil)
break;
p = gstring(p, ep, &f->aname);
if(p == nil)
break;
break;
case Twalk:
if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->newfid = GBIT32(p);
p += BIT32SZ;
f->nwname = GBIT16(p);
p += BIT16SZ;
if(f->nwname > MAXWELEM)
return 0;
for(i=0; i<f->nwname; i++){
p = gstring(p, ep, &f->wname[i]);
if(p == nil)
break;
}
break;
case Topen:
if(p+BIT32SZ+BIT8SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->mode = GBIT8(p);
p += BIT8SZ;
break;
case Tcreate:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->name);
if(p == nil)
break;
if(p+BIT32SZ+BIT8SZ > ep)
return 0;
f->perm = GBIT32(p);
p += BIT32SZ;
f->mode = GBIT8(p);
p += BIT8SZ;
break;
case Tread:
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->offset = GBIT64(p);
p += BIT64SZ;
f->count = GBIT32(p);
p += BIT32SZ;
break;
case Twrite:
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->offset = GBIT64(p);
p += BIT64SZ;
f->count = GBIT32(p);
p += BIT32SZ;
if(p+f->count > ep)
return 0;
f->data = (char*)p;
p += f->count;
break;
case Tclunk:
case Tremove:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
break;
case Tstat:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
break;
case Twstat:
if(p+BIT32SZ+BIT16SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->nstat = GBIT16(p);
p += BIT16SZ;
if(p+f->nstat > ep)
return 0;
f->stat = p;
p += f->nstat;
break;
/*
*/
case Rversion:
if(p+BIT32SZ > ep)
return 0;
f->msize = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->version);
break;
case Rerror:
p = gstring(p, ep, &f->ename);
break;
case Rflush:
break;
case Rauth:
p = gqid(p, ep, &f->aqid);
if(p == nil)
break;
break;
case Rattach:
p = gqid(p, ep, &f->qid);
if(p == nil)
break;
break;
case Rwalk:
if(p+BIT16SZ > ep)
return 0;
f->nwqid = GBIT16(p);
p += BIT16SZ;
if(f->nwqid > MAXWELEM)
return 0;
for(i=0; i<f->nwqid; i++){
p = gqid(p, ep, &f->wqid[i]);
if(p == nil)
break;
}
break;
case Ropen:
case Rcreate:
p = gqid(p, ep, &f->qid);
if(p == nil)
break;
if(p+BIT32SZ > ep)
return 0;
f->iounit = GBIT32(p);
p += BIT32SZ;
break;
case Rread:
if(p+BIT32SZ > ep)
return 0;
f->count = GBIT32(p);
p += BIT32SZ;
if(p+f->count > ep)
return 0;
f->data = (char*)p;
p += f->count;
break;
case Rwrite:
if(p+BIT32SZ > ep)
return 0;
f->count = GBIT32(p);
p += BIT32SZ;
break;
case Rclunk:
case Rremove:
break;
case Rstat:
if(p+BIT16SZ > ep)
return 0;
f->nstat = GBIT16(p);
p += BIT16SZ;
if(p+f->nstat > ep)
return 0;
f->stat = p;
p += f->nstat;
break;
case Rwstat:
break;
}
if(p==nil || p>ep)
return 0;
if(ap+size == p)
return size;
return 0;
}

398
sys/src/libc/9sys/convS2M.c Normal file
View File

@ -0,0 +1,398 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
static
uint8_t*
pstring(uint8_t *p, char *s)
{
uint n;
if(s == nil){
PBIT16(p, 0);
p += BIT16SZ;
return p;
}
n = strlen(s);
/*
* We are moving the string before the length,
* so you can S2M a struct into an existing message
*/
memmove(p + BIT16SZ, s, n);
PBIT16(p, n);
p += n + BIT16SZ;
return p;
}
static
uint8_t*
pqid(uint8_t *p, Qid *q)
{
PBIT8(p, q->type);
p += BIT8SZ;
PBIT32(p, q->vers);
p += BIT32SZ;
PBIT64(p, q->path);
p += BIT64SZ;
return p;
}
static
uint
stringsz(char *s)
{
if(s == nil)
return BIT16SZ;
return BIT16SZ+strlen(s);
}
uint
sizeS2M(Fcall *f)
{
uint n;
int i;
n = 0;
n += BIT32SZ; /* size */
n += BIT8SZ; /* type */
n += BIT16SZ; /* tag */
switch(f->type)
{
default:
return 0;
case Tversion:
n += BIT32SZ;
n += stringsz(f->version);
break;
case Tflush:
n += BIT16SZ;
break;
case Tauth:
n += BIT32SZ;
n += stringsz(f->uname);
n += stringsz(f->aname);
break;
case Tattach:
n += BIT32SZ;
n += BIT32SZ;
n += stringsz(f->uname);
n += stringsz(f->aname);
break;
case Twalk:
n += BIT32SZ;
n += BIT32SZ;
n += BIT16SZ;
for(i=0; i<f->nwname; i++)
n += stringsz(f->wname[i]);
break;
case Topen:
n += BIT32SZ;
n += BIT8SZ;
break;
case Tcreate:
n += BIT32SZ;
n += stringsz(f->name);
n += BIT32SZ;
n += BIT8SZ;
break;
case Tread:
n += BIT32SZ;
n += BIT64SZ;
n += BIT32SZ;
break;
case Twrite:
n += BIT32SZ;
n += BIT64SZ;
n += BIT32SZ;
n += f->count;
break;
case Tclunk:
case Tremove:
n += BIT32SZ;
break;
case Tstat:
n += BIT32SZ;
break;
case Twstat:
n += BIT32SZ;
n += BIT16SZ;
n += f->nstat;
break;
/*
*/
case Rversion:
n += BIT32SZ;
n += stringsz(f->version);
break;
case Rerror:
n += stringsz(f->ename);
break;
case Rflush:
break;
case Rauth:
n += QIDSZ;
break;
case Rattach:
n += QIDSZ;
break;
case Rwalk:
n += BIT16SZ;
n += f->nwqid*QIDSZ;
break;
case Ropen:
case Rcreate:
n += QIDSZ;
n += BIT32SZ;
break;
case Rread:
n += BIT32SZ;
n += f->count;
break;
case Rwrite:
n += BIT32SZ;
break;
case Rclunk:
break;
case Rremove:
break;
case Rstat:
n += BIT16SZ;
n += f->nstat;
break;
case Rwstat:
break;
}
return n;
}
uint
convS2M(Fcall *f, uint8_t *ap, uint nap)
{
uint8_t *p;
uint i, size;
size = sizeS2M(f);
if(size == 0)
return 0;
if(size > nap)
return 0;
p = (uint8_t*)ap;
PBIT32(p, size);
p += BIT32SZ;
PBIT8(p, f->type);
p += BIT8SZ;
PBIT16(p, f->tag);
p += BIT16SZ;
switch(f->type)
{
default:
return 0;
case Tversion:
PBIT32(p, f->msize);
p += BIT32SZ;
p = pstring(p, f->version);
break;
case Tflush:
PBIT16(p, f->oldtag);
p += BIT16SZ;
break;
case Tauth:
PBIT32(p, f->afid);
p += BIT32SZ;
p = pstring(p, f->uname);
p = pstring(p, f->aname);
break;
case Tattach:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT32(p, f->afid);
p += BIT32SZ;
p = pstring(p, f->uname);
p = pstring(p, f->aname);
break;
case Twalk:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT32(p, f->newfid);
p += BIT32SZ;
PBIT16(p, f->nwname);
p += BIT16SZ;
if(f->nwname > MAXWELEM)
return 0;
for(i=0; i<f->nwname; i++)
p = pstring(p, f->wname[i]);
break;
case Topen:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT8(p, f->mode);
p += BIT8SZ;
break;
case Tcreate:
PBIT32(p, f->fid);
p += BIT32SZ;
p = pstring(p, f->name);
PBIT32(p, f->perm);
p += BIT32SZ;
PBIT8(p, f->mode);
p += BIT8SZ;
break;
case Tread:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT64(p, f->offset);
p += BIT64SZ;
PBIT32(p, f->count);
p += BIT32SZ;
break;
case Twrite:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT64(p, f->offset);
p += BIT64SZ;
PBIT32(p, f->count);
p += BIT32SZ;
memmove(p, f->data, f->count);
p += f->count;
break;
case Tclunk:
case Tremove:
PBIT32(p, f->fid);
p += BIT32SZ;
break;
case Tstat:
PBIT32(p, f->fid);
p += BIT32SZ;
break;
case Twstat:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT16(p, f->nstat);
p += BIT16SZ;
memmove(p, f->stat, f->nstat);
p += f->nstat;
break;
/*
*/
case Rversion:
PBIT32(p, f->msize);
p += BIT32SZ;
p = pstring(p, f->version);
break;
case Rerror:
p = pstring(p, f->ename);
break;
case Rflush:
break;
case Rauth:
p = pqid(p, &f->aqid);
break;
case Rattach:
p = pqid(p, &f->qid);
break;
case Rwalk:
PBIT16(p, f->nwqid);
p += BIT16SZ;
if(f->nwqid > MAXWELEM)
return 0;
for(i=0; i<f->nwqid; i++)
p = pqid(p, &f->wqid[i]);
break;
case Ropen:
case Rcreate:
p = pqid(p, &f->qid);
PBIT32(p, f->iounit);
p += BIT32SZ;
break;
case Rread:
PBIT32(p, f->count);
p += BIT32SZ;
memmove(p, f->data, f->count);
p += f->count;
break;
case Rwrite:
PBIT32(p, f->count);
p += BIT32SZ;
break;
case Rclunk:
break;
case Rremove:
break;
case Rstat:
PBIT16(p, f->nstat);
p += BIT16SZ;
memmove(p, f->stat, f->nstat);
p += f->nstat;
break;
case Rwstat:
break;
}
if(size != p-ap)
return 0;
return size;
}

View File

@ -0,0 +1,25 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#define HZ 1000
double
cputime(void)
{
int32_t t[4];
int i;
times(t);
for(i=1; i<4; i++)
t[0] += t[i];
return t[0] / (double)HZ;
}

316
sys/src/libc/9sys/ctime.c Normal file
View File

@ -0,0 +1,316 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* This routine converts time as follows.
* The epoch is 0000 Jan 1 1970 GMT.
* The argument time is in seconds since then.
* The localtime(t) entry returns a pointer to an array
* containing
*
* seconds (0-59)
* minutes (0-59)
* hours (0-23)
* day of month (1-31)
* month (0-11)
* year-1970
* weekday (0-6, Sun is 0)
* day of the year
* daylight savings flag
*
* The routine gets the daylight savings time from the environment.
*
* asctime(tvec))
* where tvec is produced by localtime
* returns a ptr to a character string
* that has the ascii time in the form
*
* \\
* Thu Jan 01 00:00:00 GMT 1970n0
* 012345678901234567890123456789
* 0 1 2
*
* ctime(t) just calls localtime, then asctime.
*/
#include <u.h>
#include <libc.h>
static char dmsize[12] =
{
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
/*
* The following table is used for 1974 and 1975 and
* gives the day number of the first day after the Sunday of the
* change.
*/
static int dysize(int);
static void ct_numb(char*, int);
#define TZSIZE 150
static void readtimezone(void);
static int rd_name(char**, char*);
static int rd_long(char**, int32_t*);
static
struct
{
char stname[4];
char dlname[4];
int32_t stdiff;
int32_t dldiff;
int32_t dlpairs[TZSIZE];
} timezone;
char*
ctime(int32_t t)
{
return asctime(localtime(t));
}
Tm*
localtime(int32_t tim)
{
Tm *ct;
int32_t t, *p;
int dlflag;
if(timezone.stname[0] == 0)
readtimezone();
t = tim + timezone.stdiff;
dlflag = 0;
for(p = timezone.dlpairs; *p; p += 2)
if(t >= p[0])
if(t < p[1]) {
t = tim + timezone.dldiff;
dlflag++;
break;
}
ct = gmtime(t);
if(dlflag){
strcpy(ct->zone, timezone.dlname);
ct->tzoff = timezone.dldiff;
} else {
strcpy(ct->zone, timezone.stname);
ct->tzoff = timezone.stdiff;
}
return ct;
}
Tm*
gmtime(int32_t tim)
{
int d0, d1;
int32_t hms, day;
static Tm xtime;
/*
* break initial number into days
*/
hms = (uint32_t)tim % 86400L;
day = (uint32_t)tim / 86400L;
if(hms < 0) {
hms += 86400L;
day -= 1;
}
/*
* generate hours:minutes:seconds
*/
xtime.sec = hms % 60;
d1 = hms / 60;
xtime.min = d1 % 60;
d1 /= 60;
xtime.hour = d1;
/*
* day is the day number.
* generate day of the week.
* The addend is 4 mod 7 (1/1/1970 was Thursday)
*/
xtime.wday = (day + 7340036L) % 7;
/*
* year number
*/
if(day >= 0)
for(d1 = 1970; day >= dysize(d1); d1++)
day -= dysize(d1);
else
for (d1 = 1970; day < 0; d1--)
day += dysize(d1-1);
xtime.year = d1-1900;
xtime.yday = d0 = day;
/*
* generate month
*/
if(dysize(d1) == 366)
dmsize[1] = 29;
for(d1 = 0; d0 >= dmsize[d1]; d1++)
d0 -= dmsize[d1];
dmsize[1] = 28;
xtime.mday = d0 + 1;
xtime.mon = d1;
strcpy(xtime.zone, "GMT");
return &xtime;
}
char*
asctime(Tm *t)
{
char *ncp;
static char cbuf[30];
strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
cbuf[0] = *ncp++;
cbuf[1] = *ncp++;
cbuf[2] = *ncp;
ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
cbuf[4] = *ncp++;
cbuf[5] = *ncp++;
cbuf[6] = *ncp;
ct_numb(cbuf+8, t->mday);
ct_numb(cbuf+11, t->hour+100);
ct_numb(cbuf+14, t->min+100);
ct_numb(cbuf+17, t->sec+100);
ncp = t->zone;
cbuf[20] = *ncp++;
cbuf[21] = *ncp++;
cbuf[22] = *ncp;
if(t->year >= 100) {
cbuf[24] = '2';
cbuf[25] = '0';
}
ct_numb(cbuf+26, t->year+100);
return cbuf;
}
static
int
dysize(int y)
{
if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
return 366;
return 365;
}
static
void
ct_numb(char *cp, int n)
{
cp[0] = ' ';
if(n >= 10)
cp[0] = (n/10)%10 + '0';
cp[1] = n%10 + '0';
}
static
void
readtimezone(void)
{
char buf[TZSIZE*11+30], *p;
int i;
memset(buf, 0, sizeof(buf));
i = open("/env/timezone", 0);
if(i < 0)
goto error;
if(read(i, buf, sizeof(buf)) >= sizeof(buf)){
close(i);
goto error;
}
close(i);
p = buf;
if(rd_name(&p, timezone.stname))
goto error;
if(rd_long(&p, &timezone.stdiff))
goto error;
if(rd_name(&p, timezone.dlname))
goto error;
if(rd_long(&p, &timezone.dldiff))
goto error;
for(i=0; i<TZSIZE; i++) {
if(rd_long(&p, &timezone.dlpairs[i]))
goto error;
if(timezone.dlpairs[i] == 0)
return;
}
error:
timezone.stdiff = 0;
strcpy(timezone.stname, "GMT");
timezone.dlpairs[0] = 0;
}
static
int
rd_name(char **f, char *p)
{
int c, i;
for(;;) {
c = *(*f)++;
if(c != ' ' && c != '\n')
break;
}
for(i=0; i<3; i++) {
if(c == ' ' || c == '\n')
return 1;
*p++ = c;
c = *(*f)++;
}
if(c != ' ' && c != '\n')
return 1;
*p = 0;
return 0;
}
static
int
rd_long(char **f, int32_t *p)
{
int c, s;
int32_t l;
s = 0;
for(;;) {
c = *(*f)++;
if(c == '-') {
s++;
continue;
}
if(c != ' ' && c != '\n')
break;
}
if(c == 0) {
*p = 0;
return 0;
}
l = 0;
for(;;) {
if(c == ' ' || c == '\n')
break;
if(c < '0' || c > '9')
return 1;
l = l*10 + c-'0';
c = *(*f)++;
}
if(s)
l = -l;
*p = l;
return 0;
}

560
sys/src/libc/9sys/dial.c Normal file
View File

@ -0,0 +1,560 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* dial - connect to a service (parallel version)
*/
#include <u.h>
#include <libc.h>
typedef struct Conn Conn;
typedef struct Dest Dest;
typedef struct DS DS;
enum
{
Maxstring = 128,
Maxpath = 256,
Maxcsreply = 64*80, /* this is probably overly generous */
/*
* this should be a plausible slight overestimate for non-interactive
* use even if it's ridiculously long for interactive use.
*/
Maxconnms = 2*60*1000, /* 2 minutes */
};
struct DS {
/* dist string */
char buf[Maxstring];
char *netdir;
char *proto;
char *rem;
/* other args */
const char *local;
char *dir;
int *cfdp;
};
/*
* malloc these; they need to be writable by this proc & all children.
* the stack is private to each proc, and static allocation in the data
* segment would not permit concurrent dials within a multi-process program.
*/
struct Conn {
int pid;
int dead;
int dfd;
int cfd;
char dir[NETPATHLEN+1];
char err[ERRMAX];
};
struct Dest {
Conn *conn; /* allocated array */
Conn *connend;
int nkid;
int32_t oalarm;
int naddrs;
QLock winlck;
int winner; /* index into conn[] */
char *nextaddr;
char addrlist[Maxcsreply];
};
static int call(char*, char*, DS*, Dest*, Conn*);
static int csdial(DS*);
static void _dial_string_parse(const char*, DS*);
/*
* the dialstring is of the form '[/net/]proto!dest'
*/
static int
dialimpl(const char *dest, const char *local, char *dir, int *cfdp)
{
DS ds;
int rv;
char err[ERRMAX], alterr[ERRMAX];
ds.local = local;
ds.dir = dir;
ds.cfdp = cfdp;
_dial_string_parse(dest, &ds);
if(ds.netdir)
return csdial(&ds);
ds.netdir = "/net";
rv = csdial(&ds);
if(rv >= 0)
return rv;
err[0] = '\0';
errstr(err, sizeof err);
if(strstr(err, "refused") != 0){
werrstr("%s", err);
return rv;
}
ds.netdir = "/net.alt";
rv = csdial(&ds);
if(rv >= 0)
return rv;
alterr[0] = 0;
errstr(alterr, sizeof alterr);
if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
werrstr("%s", err);
else
werrstr("%s", alterr);
return rv;
}
/*
* the thread library can't cope with rfork(RFMEM|RFPROC),
* so it must override this with a private version of dial.
*/
int (*_dial)(const char *, const char *, char *, int *) = dialimpl;
int
dial(const char *dest, const char *local, char *dir, int *cfdp)
{
return (*_dial)(dest, local, dir, cfdp);
}
static int
connsalloc(Dest *dp, int addrs)
{
Conn *conn;
free(dp->conn);
dp->connend = nil;
assert(addrs > 0);
dp->conn = mallocz(addrs * sizeof *dp->conn, 1);
if(dp->conn == nil)
return -1;
dp->connend = dp->conn + addrs;
for(conn = dp->conn; conn < dp->connend; conn++)
conn->cfd = conn->dfd = -1;
return 0;
}
static void
freedest(Dest *dp)
{
int32_t oalarm;
if (dp == nil)
return;
oalarm = dp->oalarm;
free(dp->conn);
free(dp);
if (oalarm >= 0)
alarm(oalarm);
}
static void
closeopenfd(int *fdp)
{
if (*fdp >= 0) {
close(*fdp);
*fdp = -1;
}
}
static void
notedeath(Dest *dp, char *exitsts)
{
int i, n, pid;
char *fields[5]; /* pid + 3 times + error */
Conn *conn;
for (i = 0; i < nelem(fields); i++)
fields[i] = "";
n = tokenize(exitsts, fields, nelem(fields));
if (n < 4)
return;
pid = atoi(fields[0]);
if (pid <= 0)
return;
for (conn = dp->conn; conn < dp->connend; conn++)
if (conn->pid == pid && !conn->dead) { /* it's one we know? */
if (conn - dp->conn != dp->winner) {
closeopenfd(&conn->dfd);
closeopenfd(&conn->cfd);
}
strncpy(conn->err, fields[4], sizeof conn->err - 1);
conn->err[sizeof conn->err - 1] = '\0';
conn->dead = 1;
return;
}
/* not a proc that we forked */
}
static int
outstandingprocs(Dest *dp)
{
Conn *conn;
for (conn = dp->conn; conn < dp->connend; conn++)
if (!conn->dead)
return 1;
return 0;
}
static int
reap(Dest *dp)
{
char exitsts[2*ERRMAX];
if (outstandingprocs(dp) && await(exitsts, sizeof exitsts) >= 0) {
notedeath(dp, exitsts);
return 0;
}
return -1;
}
static int
fillinds(DS *ds, Dest *dp)
{
Conn *conn;
if (dp->winner < 0)
return -1;
conn = &dp->conn[dp->winner];
if (ds->cfdp)
*ds->cfdp = conn->cfd;
if (ds->dir) {
strncpy(ds->dir, conn->dir, NETPATHLEN);
ds->dir[NETPATHLEN-1] = '\0';
}
return conn->dfd;
}
static int
connectwait(Dest *dp, char *besterr)
{
Conn *conn;
/* wait for a winner or all attempts to time out */
while (dp->winner < 0 && reap(dp) >= 0)
;
/* kill all of our still-live kids & reap them */
for (conn = dp->conn; conn < dp->connend; conn++)
if (!conn->dead)
postnote(PNPROC, conn->pid, "alarm");
while (reap(dp) >= 0)
;
/* rummage about and report some error string */
for (conn = dp->conn; conn < dp->connend; conn++)
if (conn - dp->conn != dp->winner && conn->dead &&
conn->err[0]) {
strncpy(besterr, conn->err, ERRMAX-1);
besterr[ERRMAX-1] = '\0';
break;
}
return dp->winner;
}
static int
parsecs(Dest *dp, char **clonep, char **destp)
{
char *dest, *p;
dest = strchr(dp->nextaddr, ' ');
if(dest == nil) {
p = strchr(dp->nextaddr, '\n');
if(p)
*p = '\0';
werrstr("malformed clone cmd from cs `%s'", dp->nextaddr);
if(p)
*p = '\n';
return -1;
}
*dest++ = '\0';
p = strchr(dest, '\n');
if(p == nil)
return -1;
*p++ = '\0';
*clonep = dp->nextaddr;
*destp = dest;
dp->nextaddr = p; /* advance to next line */
return 0;
}
static void
pickuperr(char *besterr, char *err)
{
err[0] = '\0';
errstr(err, ERRMAX);
if(strstr(err, "does not exist") == 0)
strcpy(besterr, err);
}
static int
catcher(void *v, char *s)
{
return strstr(s, "alarm") != nil;
}
/*
* try all addresses in parallel and take the first one that answers;
* this helps when systems have ip v4 and v6 addresses but are
* only reachable from here on one (or some) of them.
*/
static int
dialmulti(DS *ds, Dest *dp)
{
int rv, kid, kidme;
char *clone, *dest;
char besterr[ERRMAX];
dp->winner = -1;
dp->nkid = 0;
while(dp->winner < 0 && *dp->nextaddr != '\0' &&
parsecs(dp, &clone, &dest) >= 0) {
kidme = dp->nkid++; /* make private copy on stack */
kid = rfork(RFPROC|RFMEM); /* spin off a call attempt */
if (kid < 0)
--dp->nkid;
else if (kid == 0) {
char err[ERRMAX];
/* only in kid, to avoid atnotify callbacks in parent */
atnotify(catcher, 1);
*besterr = '\0';
rv = call(clone, dest, ds, dp, &dp->conn[kidme]);
if(rv < 0)
pickuperr(besterr, err);
_exits(besterr); /* avoid atexit callbacks */
}
}
*besterr = '\0';
rv = connectwait(dp, besterr);
if(rv < 0)
werrstr("%s", (*besterr? besterr: "unknown error"));
return rv;
}
static int
csdial(DS *ds)
{
int n, fd, rv, addrs, bleft;
char c;
char *addrp, *clone2, *dest;
char buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
Dest *dp;
werrstr("");
dp = mallocz(sizeof *dp, 1);
if(dp == nil)
return -1;
dp->winner = -1;
dp->oalarm = alarm(0);
if (connsalloc(dp, 1) < 0) { /* room for a single conn. */
freedest(dp);
return -1;
}
/*
* open connection server
*/
snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
fd = open(buf, ORDWR);
if(fd < 0){
/* no connection server, don't translate */
snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
rv = call(clone, ds->rem, ds, dp, &dp->conn[0]);
fillinds(ds, dp);
freedest(dp);
return rv;
}
/*
* ask connection server to translate
* e.g., net!cs.bell-labs.com!smtp
*/
snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
if(write(fd, buf, strlen(buf)) < 0){
close(fd);
freedest(dp);
return -1;
}
/*
* read all addresses from the connection server:
* /net/tcp/clone 135.104.9.78!25
* /net/tcp/clone 2620:0:dc0:1805::29!25
*
* assumes that we'll get one record per read.
*/
seek(fd, 0, 0);
addrs = 0;
addrp = dp->nextaddr = dp->addrlist;
bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */
while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) {
if (addrp[n-1] != '\n')
addrp[n++] = '\n';
addrs++;
addrp += n;
bleft -= n;
}
*addrp = '\0';
/*
* if we haven't read all of cs's output, assume the last line might
* have been truncated and ignore it. we really don't expect this
* to happen.
*/
if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1)
addrs--;
close(fd);
*besterr = 0;
rv = -1; /* pessimistic default */
dp->naddrs = addrs;
if (addrs == 0)
werrstr("no address to dial");
else if (addrs == 1) {
/* common case: dial one address without forking */
if (parsecs(dp, &clone2, &dest) >= 0 &&
(rv = call(clone2, dest, ds, dp, &dp->conn[0])) < 0) {
pickuperr(besterr, err);
werrstr("%s", besterr);
}
} else if (connsalloc(dp, addrs) >= 0)
rv = dialmulti(ds, dp);
/* fill in results */
if (rv >= 0 && dp->winner >= 0)
rv = fillinds(ds, dp);
freedest(dp);
return rv;
}
static int
call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
{
int fd, cfd, n, calleralarm, oalarm;
char cname[Maxpath], name[Maxpath], data[Maxpath], *p;
/* because cs is in a different name space, replace the mount point */
if(*clone == '/'){
p = strchr(clone+1, '/');
if(p == nil)
p = clone;
else
p++;
} else
p = clone;
snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
conn->pid = getpid();
conn->cfd = cfd = open(cname, ORDWR);
if(cfd < 0)
return -1;
/* get directory name */
n = read(cfd, name, sizeof(name)-1);
if(n < 0){
closeopenfd(&conn->cfd);
return -1;
}
name[n] = 0;
for(p = name; *p == ' '; p++)
;
snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
p = strrchr(cname, '/');
*p = 0;
if(ds->dir)
snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name);
snprint(data, sizeof(data), "%s/%s/data", cname, name);
/* should be no alarm pending now; re-instate caller's alarm, if any */
calleralarm = dp->oalarm > 0;
if (calleralarm)
alarm(dp->oalarm);
else if (dp->naddrs > 1) /* in a sub-process? */
alarm(Maxconnms);
/* connect */
if(ds->local)
snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
else
snprint(name, sizeof(name), "connect %s", dest);
if(write(cfd, name, strlen(name)) < 0){
closeopenfd(&conn->cfd);
return -1;
}
oalarm = alarm(0); /* don't let alarm interrupt critical section */
if (calleralarm)
dp->oalarm = oalarm; /* time has passed, so update user's */
/* open data connection */
conn->dfd = fd = open(data, ORDWR);
if(fd < 0){
closeopenfd(&conn->cfd);
alarm(dp->oalarm);
return -1;
}
if(ds->cfdp == nil)
closeopenfd(&conn->cfd);
n = conn - dp->conn;
if (dp->winner < 0) {
qlock(&dp->winlck);
if (dp->winner < 0 && conn < dp->connend)
dp->winner = n;
qunlock(&dp->winlck);
}
alarm(calleralarm? dp->oalarm: 0);
return fd;
}
/*
* parse a dial string
*/
static void
_dial_string_parse(const char *str, DS *ds)
{
char *p, *p2;
strncpy(ds->buf, str, Maxstring);
ds->buf[Maxstring-1] = 0;
p = strchr(ds->buf, '!');
if(p == 0) {
ds->netdir = 0;
ds->proto = "net";
ds->rem = ds->buf;
} else {
if(*ds->buf != '/' && *ds->buf != '#'){
ds->netdir = 0;
ds->proto = ds->buf;
} else {
/* expecting /net.alt/tcp!foo or #I1/tcp!foo */
for(p2 = p; p2 > ds->buf && *p2 != '/'; p2--)
;
*p2++ = 0;
ds->netdir = ds->buf;
ds->proto = p2;
}
*p = 0;
ds->rem = p + 1;
}
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
enum
{
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
};
Dir*
dirfstat(int fd)
{
Dir *d;
uint8_t *buf;
int n, nd, i;
nd = DIRSIZE;
for(i=0; i<2; i++){ /* should work by the second try */
d = malloc(sizeof(Dir) + BIT16SZ + nd);
if(d == nil)
return nil;
buf = (uint8_t*)&d[1];
n = fstat(fd, buf, BIT16SZ+nd);
if(n < BIT16SZ){
free(d);
return nil;
}
nd = GBIT16(buf); /* upper bound on size of Dir + strings */
if(nd <= n){
convM2D(buf, n, d, (char*)&d[1]);
return d;
}
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
free(d);
}
return nil;
}

View File

@ -0,0 +1,28 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
int
dirfwstat(int fd, Dir *d)
{
uint8_t *buf;
int r;
r = sizeD2M(d);
buf = malloc(r);
if(buf == nil)
return -1;
convD2M(d, buf, r);
r = fwstat(fd, buf, r);
free(buf);
return r;
}

View File

@ -0,0 +1,57 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
static char *modes[] =
{
"---",
"--x",
"-w-",
"-wx",
"r--",
"r-x",
"rw-",
"rwx",
};
static void
rwx(int32_t m, char *s)
{
strncpy(s, modes[m], 3);
}
int
dirmodefmt(Fmt *f)
{
static char buf[16];
uint32_t m;
m = va_arg(f->args, uint32_t);
if(m & DMDIR)
buf[0]='d';
else if(m & DMAPPEND)
buf[0]='a';
else if(m & DMAUTH)
buf[0]='A';
else
buf[0]='-';
if(m & DMEXCL)
buf[1]='l';
else
buf[1]='-';
rwx((m>>6)&7, buf+2);
rwx((m>>3)&7, buf+5);
rwx((m>>0)&7, buf+8);
buf[11] = 0;
return fmtstrcpy(f, buf);
}

106
sys/src/libc/9sys/dirread.c Normal file
View File

@ -0,0 +1,106 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
static
int32_t
dirpackage(uint8_t *buf, int32_t ts, Dir **d)
{
char *s;
int32_t ss, i, n, nn, m;
*d = nil;
if(ts <= 0)
return 0;
/*
* first find number of all stats, check they look like stats, & size all associated strings
*/
ss = 0;
n = 0;
for(i = 0; i < ts; i += m){
m = BIT16SZ + GBIT16(&buf[i]);
if(statcheck(&buf[i], m) < 0)
break;
ss += m;
n++;
}
if(i != ts)
return -1;
*d = malloc(n * sizeof(Dir) + ss);
if(*d == nil)
return -1;
/*
* then convert all buffers
*/
s = (char*)*d + n * sizeof(Dir);
nn = 0;
for(i = 0; i < ts; i += m){
m = BIT16SZ + GBIT16((uint8_t*)&buf[i]);
if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
free(*d);
*d = nil;
return -1;
}
nn++;
s += m;
}
return nn;
}
int32_t
dirread(int fd, Dir **d)
{
uint8_t *buf;
int32_t ts;
buf = malloc(DIRMAX);
if(buf == nil)
return -1;
ts = read(fd, buf, DIRMAX);
if(ts >= 0)
ts = dirpackage(buf, ts, d);
free(buf);
return ts;
}
int32_t
dirreadall(int fd, Dir **d)
{
uint8_t *buf, *nbuf;
int32_t n, ts;
buf = nil;
ts = 0;
for(;;){
nbuf = realloc(buf, ts+DIRMAX);
if(nbuf == nil){
free(buf);
return -1;
}
buf = nbuf;
n = read(fd, buf+ts, DIRMAX);
if(n <= 0)
break;
ts += n;
}
if(ts >= 0)
ts = dirpackage(buf, ts, d);
free(buf);
if(ts == 0 && n < 0)
return -1;
return ts;
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
enum
{
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
};
Dir*
dirstat(const char *name)
{
Dir *d;
uint8_t *buf;
int n, nd, i;
nd = DIRSIZE;
for(i=0; i<2; i++){ /* should work by the second try */
d = malloc(sizeof(Dir) + BIT16SZ + nd);
if(d == nil)
return nil;
buf = (uint8_t*)&d[1];
n = stat(name, buf, BIT16SZ+nd);
if(n < BIT16SZ){
free(d);
return nil;
}
nd = GBIT16((uint8_t*)buf); /* upper bound on size of Dir + strings */
if(nd <= n){
convM2D(buf, n, d, (char*)&d[1]);
return d;
}
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
free(d);
}
return nil;
}

View File

@ -0,0 +1,28 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
int
dirwstat(const char *name, Dir *d)
{
uint8_t *buf;
int r;
r = sizeD2M(d);
buf = malloc(r);
if(buf == nil)
return -1;
convD2M(d, buf, r);
r = wstat(name, buf, r);
free(buf);
return r;
}

View File

@ -0,0 +1,244 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
static uint dumpsome(char*, char*, char*, int32_t);
static void fdirconv(char*, char*, Dir*);
static char *qidtype(char*, uint8_t);
#define QIDFMT "(%.16llux %lud %s)"
int
fcallfmt(Fmt *fmt)
{
Fcall *f;
int fid, type, tag, i;
char buf[512], tmp[200];
char *p, *e;
Dir *d;
Qid *q;
e = buf+sizeof(buf);
f = va_arg(fmt->args, Fcall*);
type = f->type;
fid = f->fid;
tag = f->tag;
switch(type){
case Tversion: /* 100 */
seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
break;
case Rversion:
seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
break;
case Tauth: /* 102 */
seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
f->afid, f->uname, f->aname);
break;
case Rauth:
seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
break;
case Tattach: /* 104 */
seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
fid, f->afid, f->uname, f->aname);
break;
case Rattach:
seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
break;
case Rerror: /* 107; 106 (Terror) illegal */
seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
break;
case Tflush: /* 108 */
seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
break;
case Rflush:
seprint(buf, e, "Rflush tag %ud", tag);
break;
case Twalk: /* 110 */
p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
if(f->nwname <= MAXWELEM)
for(i=0; i<f->nwname; i++)
p = seprint(p, e, "%d:%s ", i, f->wname[i]);
break;
case Rwalk:
p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
if(f->nwqid <= MAXWELEM)
for(i=0; i<f->nwqid; i++){
q = &f->wqid[i];
p = seprint(p, e, "%d:" QIDFMT " ", i,
q->path, q->vers, qidtype(tmp, q->type));
}
break;
case Topen: /* 112 */
seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
break;
case Ropen:
seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag,
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
break;
case Tcreate: /* 114 */
seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name,
(uint32_t)f->perm, f->mode);
break;
case Rcreate:
seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
break;
case Tread: /* 116 */
seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
tag, fid, f->offset, f->count);
break;
case Rread:
p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
dumpsome(p, e, f->data, f->count);
break;
case Twrite: /* 118 */
p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
tag, fid, f->offset, f->count);
dumpsome(p, e, f->data, f->count);
break;
case Rwrite:
seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
break;
case Tclunk: /* 120 */
seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
break;
case Rclunk:
seprint(buf, e, "Rclunk tag %ud", tag);
break;
case Tremove: /* 122 */
seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
break;
case Rremove:
seprint(buf, e, "Rremove tag %ud", tag);
break;
case Tstat: /* 124 */
seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
break;
case Rstat:
p = seprint(buf, e, "Rstat tag %ud ", tag);
if(f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
convM2D(f->stat, f->nstat, d, (char*)(d+1));
seprint(p, e, " stat ");
fdirconv(p+6, e, d);
}
break;
case Twstat: /* 126 */
p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
if(f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
convM2D(f->stat, f->nstat, d, (char*)(d+1));
seprint(p, e, " stat ");
fdirconv(p+6, e, d);
}
break;
case Rwstat:
seprint(buf, e, "Rwstat tag %ud", tag);
break;
default:
seprint(buf, e, "unknown type %d", type);
}
return fmtstrcpy(fmt, buf);
}
static char*
qidtype(char *s, uint8_t t)
{
char *p;
p = s;
if(t & QTDIR)
*p++ = 'd';
if(t & QTAPPEND)
*p++ = 'a';
if(t & QTEXCL)
*p++ = 'l';
if(t & QTAUTH)
*p++ = 'A';
*p = '\0';
return s;
}
int
dirfmt(Fmt *fmt)
{
char buf[160];
fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
return fmtstrcpy(fmt, buf);
}
static void
fdirconv(char *buf, char *e, Dir *d)
{
char tmp[16];
seprint(buf, e, "'%s' '%s' '%s' '%s' "
"q " QIDFMT " m %#luo "
"at %ld mt %ld l %lld "
"t %d d %d",
d->name, d->uid, d->gid, d->muid,
d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
d->atime, d->mtime, d->length,
d->type, d->dev);
}
/*
* dump out count (or DUMPL, if count is bigger) bytes from
* buf to ans, as a string if they are all printable,
* else as a series of hex bytes
*/
#define DUMPL 64
static uint
dumpsome(char *ans, char *e, char *buf, int32_t count)
{
int i, printable;
char *p;
if(buf == nil){
seprint(ans, e, "<no data>");
return strlen(ans);
}
printable = 1;
if(count > DUMPL)
count = DUMPL;
for(i=0; i<count && printable; i++)
if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uint8_t)buf[i]>127)
printable = 0;
p = ans;
*p++ = '\'';
if(printable){
if(count > e-p-2)
count = e-p-2;
memmove(p, buf, count);
p += count;
}else{
if(2*count > e-p-2)
count = (e-p-2)/2;
for(i=0; i<count; i++){
if(i>0 && i%4==0)
*p++ = ' ';
sprint(p, "%2.2ux", (uint8_t)buf[i]);
p += 2;
}
}
*p++ = '\'';
*p = 0;
return p - ans;
}

17
sys/src/libc/9sys/fork.c Normal file
View File

@ -0,0 +1,17 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
fork(void)
{
return rfork(RFPROC|RFFDG|RFREND);
}

View File

@ -0,0 +1,45 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
char*
getenv(const char *name)
{
int r, f;
int32_t s;
char *ans;
char *p, *ep, ename[100];
if(strchr(name, '/') != nil)
return nil;
snprint(ename, sizeof ename, "/env/%s", name);
if(strcmp(ename+5, name) != 0)
return nil;
f = open(ename, OREAD);
if(f < 0)
return 0;
s = seek(f, 0, 2);
ans = malloc(s+1);
if(ans) {
setmalloctag(ans, getcallerpc());
seek(f, 0, 0);
r = read(f, ans, s);
if(r >= 0) {
ep = ans + s - 1;
for(p = ans; p < ep; p++)
if(*p == '\0')
*p = ' ';
ans[s] = '\0';
}
}
close(f);
return ans;
}

View File

@ -0,0 +1,142 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static char *unknown = "???";
static void
getendpoint(char *dir, char *file, char **sysp, char **servp)
{
int fd, n;
char buf[128];
char *sys, *serv;
sys = serv = 0;
snprint(buf, sizeof buf, "%s/%s", dir, file);
fd = open(buf, OREAD);
if(fd >= 0){
n = read(fd, buf, sizeof(buf)-1);
if(n>0){
buf[n-1] = 0;
serv = strchr(buf, '!');
if(serv){
*serv++ = 0;
serv = strdup(serv);
}
sys = strdup(buf);
}
close(fd);
}
if(serv == 0)
serv = unknown;
if(sys == 0)
sys = unknown;
*servp = serv;
*sysp = sys;
}
NetConnInfo*
getnetconninfo(const char *dir, int fd)
{
NetConnInfo *nci;
char *cp;
Dir *d;
char spec[10];
char path[128];
char netname[128], *p;
/* get a directory address via fd */
if(dir == nil || *dir == 0){
if(fd2path(fd, path, sizeof(path)) < 0)
return nil;
cp = strrchr(path, '/');
if(cp == nil)
return nil;
*cp = 0;
dir = path;
}
nci = mallocz(sizeof *nci, 1);
if(nci == nil)
return nil;
/* copy connection directory */
nci->dir = strdup(dir);
if(nci->dir == nil)
goto err;
/* get netroot */
nci->root = strdup(dir);
if(nci->root == nil)
goto err;
cp = strchr(nci->root+1, '/');
if(cp == nil)
goto err;
*cp = 0;
/* figure out bind spec */
d = dirstat(nci->dir);
if(d != nil){
sprint(spec, "#%C%d", d->type, d->dev);
nci->spec = strdup(spec);
}
if(nci->spec == nil)
nci->spec = unknown;
free(d);
/* get the two end points */
getendpoint(nci->dir, "local", &nci->lsys, &nci->lserv);
if(nci->lsys == nil || nci->lserv == nil)
goto err;
getendpoint(nci->dir, "remote", &nci->rsys, &nci->rserv);
if(nci->rsys == nil || nci->rserv == nil)
goto err;
strecpy(netname, netname+sizeof netname, nci->dir);
if((p = strrchr(netname, '/')) != nil)
*p = 0;
if(strncmp(netname, "/net/", 5) == 0)
memmove(netname, netname+5, strlen(netname+5)+1);
nci->laddr = smprint("%s!%s!%s", netname, nci->lsys, nci->lserv);
nci->raddr = smprint("%s!%s!%s", netname, nci->rsys, nci->rserv);
if(nci->laddr == nil || nci->raddr == nil)
goto err;
return nci;
err:
freenetconninfo(nci);
return nil;
}
static void
xfree(char *x)
{
if(x == nil || x == unknown)
return;
free(x);
}
void
freenetconninfo(NetConnInfo *nci)
{
if(nci == nil)
return;
xfree(nci->root);
xfree(nci->dir);
xfree(nci->spec);
xfree(nci->lsys);
xfree(nci->lserv);
xfree(nci->rsys);
xfree(nci->rserv);
xfree(nci->laddr);
xfree(nci->raddr);
free(nci);
}

View File

@ -0,0 +1,26 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
getpid(void)
{
char b[20];
int f;
memset(b, 0, sizeof(b));
f = open("#c/pid", 0);
if(f >= 0) {
read(f, b, sizeof(b));
close(f);
}
return atol(b);
}

View File

@ -0,0 +1,26 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
getppid(void)
{
char b[20];
int f;
memset(b, 0, sizeof(b));
f = open("/dev/ppid", 0);
if(f >= 0) {
read(f, b, sizeof(b));
close(f);
}
return atol(b);
}

26
sys/src/libc/9sys/getwd.c Normal file
View File

@ -0,0 +1,26 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
char*
getwd(char *buf, int nbuf)
{
int n, fd;
fd = open(".", OREAD);
if(fd < 0)
return nil;
n = fd2path(fd, buf, nbuf);
close(fd);
if(n < 0)
return nil;
return buf;
}

View File

@ -0,0 +1,36 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
/*
* Format:
3 r M 4 (0000000000457def 11 00) 8192 512 /rc/lib/rcmain
*/
int
iounit(int fd)
{
int i, cfd;
char buf[128], *args[10];
snprint(buf, sizeof buf, "#d/%dctl", fd);
cfd = open(buf, OREAD);
if(cfd < 0)
return 0;
i = read(cfd, buf, sizeof buf-1);
close(cfd);
if(i <= 0)
return 0;
buf[i] = '\0';
if(tokenize(buf, args, nelem(args)) != nelem(args))
return 0;
return atoi(args[7]);
}

View File

@ -0,0 +1,18 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
void
nulldir(Dir *d)
{
memset(d, ~0, sizeof(Dir));
d->name = d->uid = d->gid = d->muid = "";
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
postnote(int group, int pid, const char *note)
{
char file[128];
int f, r;
switch(group) {
case PNPROC:
sprint(file, "/proc/%d/note", pid);
break;
case PNGROUP:
sprint(file, "/proc/%d/notepg", pid);
break;
default:
return -1;
}
f = open(file, OWRITE);
if(f < 0)
return -1;
r = strlen(note);
if(write(f, note, r) != r) {
close(f);
return -1;
}
close(f);
return 0;
}

View File

@ -0,0 +1,54 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static Lock privlock;
static int privinit = 0;
static void **privs;
extern void **_privates;
extern int _nprivates;
void **
privalloc(void)
{
void **p;
int i;
lock(&privlock);
if(!privinit){
privinit = 1;
if(_nprivates){
_privates[0] = 0;
for(i = 1; i < _nprivates; i++)
_privates[i] = &_privates[i - 1];
privs = &_privates[i - 1];
}
}
p = privs;
if(p != nil){
privs = *p;
*p = nil;
}
unlock(&privlock);
return p;
}
void
privfree(void **p)
{
lock(&privlock);
if(p != nil && privinit){
*p = privs;
privs = p;
}
unlock(&privlock);
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
/*
* Since the SSL device uses decimal file descriptors to name channels,
* it is impossible for a user-level file server to stand in for the kernel device.
* Thus we hard-code #D rather than use /net/ssl.
*/
int
pushssl(int fd, const char *alg, const char *secin, const char *secout, int *cfd)
{
char buf[8];
char dname[64];
int n, data, ctl;
ctl = open("#D/ssl/clone", ORDWR);
if(ctl < 0)
return -1;
n = read(ctl, buf, sizeof(buf)-1);
if(n < 0)
goto error;
buf[n] = 0;
sprint(dname, "#D/ssl/%s/data", buf);
data = open(dname, ORDWR);
if(data < 0)
goto error;
if(fprint(ctl, "fd %d", fd) < 0 ||
fprint(ctl, "secretin %s", secin) < 0 ||
fprint(ctl, "secretout %s", secout) < 0 ||
fprint(ctl, "alg %s", alg) < 0){
close(data);
goto error;
}
close(fd);
if(cfd != 0)
*cfd = ctl;
else
close(ctl);
return data;
error:
close(ctl);
return -1;
}

View File

@ -0,0 +1,35 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
putenv(const char *name, const char *val)
{
int f;
char ename[100];
int32_t s;
if(strchr(name, '/') != nil)
return -1;
snprint(ename, sizeof ename, "/env/%s", name);
if(strcmp(ename+5, name) != 0)
return -1;
f = create(ename, OWRITE, 0664);
if(f < 0)
return -1;
s = strlen(val);
if(write(f, val, s) != s){
close(f);
return -1;
}
close(f);
return 0;
}

633
sys/src/libc/9sys/qlock.c Normal file
View File

@ -0,0 +1,633 @@
/*
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static struct {
QLp *p;
QLp x[1024];
} ql = {
ql.x
};
enum
{
Queuing,
QueuingR,
QueuingW,
Sleeping,
};
static void* (*_rendezvousp)(void*, void*) = rendezvous;
/* this gets called by the thread library ONLY to get us to use its rendezvous */
void
_qlockinit(void* (*r)(void*, void*))
{
_rendezvousp = r;
}
/* find a free shared memory location to queue ourselves in */
static QLp*
getqlp(void)
{
QLp *p, *op;
op = ql.p;
for(p = op+1; ; p++){
if(p == &ql.x[nelem(ql.x)])
p = ql.x;
if(p == op)
abort();
if(_tas(&(p->inuse)) == 0){
ql.p = p;
p->next = nil;
break;
}
}
return p;
}
static void
releaseqlp(QLp **head, QLp **tail, QLp *mp)
{
/* NOTE: we assume a lock is held during the execution to prevent
* modifications to the chain
*/
QLp *p;
p = *head;
while(p != nil && p != mp && p->next != mp && p != *tail)
p = p->next;
if(p == nil)
abort(); /* mp must be somewhere */
if(p == mp){
/* mp was head */
*head = mp->next;
} else {
p->next = mp->next;
}
if(*head == nil)
*tail = nil;
mp->inuse = 0;
}
void
qlock(QLock *q)
{
QLp *p, *mp;
lock(&q->lock);
if(!q->locked){
q->locked = 1;
unlock(&q->lock);
return;
}
/* chain into waiting list */
mp = getqlp();
p = q->tail;
if(p == nil)
q->head = mp;
else
p->next = mp;
q->tail = mp;
mp->state = Queuing;
unlock(&q->lock);
/* wait */
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
;
mp->inuse = 0;
}
void
qunlock(QLock *q)
{
QLp *p;
lock(&q->lock);
if (q->locked == 0)
fprint(2, "qunlock called with qlock not held, from %#p\n",
getcallerpc());
p = q->head;
if(p != nil){
/* wakeup head waiting process */
q->head = p->next;
if(q->head == nil)
q->tail = nil;
unlock(&q->lock);
while((*_rendezvousp)(p, (void*)0x12345) == (void*)~0)
;
return;
}
q->locked = 0;
unlock(&q->lock);
}
int
qlockt(QLock *q, uint32_t ms)
{
QLp *p, *mp;
int64_t wkup;
/* set up awake to interrupt rendezvous */
wkup = awake(ms);
if(!lockt(&q->lock, ms)){
forgivewkp(wkup);
return 0;
}
if(!q->locked){
forgivewkp(wkup);
q->locked = 1;
unlock(&q->lock);
return 1;
}
/* chain into waiting list */
mp = getqlp();
p = q->tail;
if(p == nil)
q->head = mp;
else
p->next = mp;
q->tail = mp;
mp->state = Queuing;
if (awakened(wkup)) { /* do not miss already occurred wakeups */
releaseqlp(&q->head, &q->tail, mp);
unlock(&q->lock);
return 0;
}
unlock(&q->lock);
/* wait */
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
if (awakened(wkup)){
/* interrupted by awake */
lock(&q->lock);
releaseqlp(&q->head, &q->tail, mp);
unlock(&q->lock);
return 0;
}
forgivewkp(wkup);
mp->inuse = 0;
return 1;
}
int
canqlock(QLock *q)
{
if(!canlock(&q->lock))
return 0;
if(!q->locked){
q->locked = 1;
unlock(&q->lock);
return 1;
}
unlock(&q->lock);
return 0;
}
void
rlock(RWLock *q)
{
QLp *p, *mp;
lock(&q->lock);
if(q->writer == 0 && q->head == nil){
/* no writer, go for it */
q->_readers++;
unlock(&q->lock);
return;
}
mp = getqlp();
p = q->tail;
if(p == 0)
q->head = mp;
else
p->next = mp;
q->tail = mp;
mp->next = nil;
mp->state = QueuingR;
unlock(&q->lock);
/* wait in kernel */
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
;
mp->inuse = 0;
}
int
rlockt(RWLock *q, uint32_t ms)
{
QLp *p, *mp;
int64_t wkup;
/* set up awake to interrupt rendezvous */
wkup = awake(ms);
if(!lockt(&q->lock, ms)) {
forgivewkp(wkup);
return 0;
}
if(q->writer == 0 && q->head == nil){
/* no writer, go for it */
forgivewkp(wkup);
q->_readers++;
unlock(&q->lock);
return 1;
}
/* chain into waiting list */
mp = getqlp();
p = q->tail;
if(p == 0)
q->head = mp;
else
p->next = mp;
q->tail = mp;
mp->next = nil;
mp->state = QueuingR;
if (awakened(wkup)) { /* do not miss already occurred wakeups */
releaseqlp(&q->head, &q->tail, mp);
unlock(&q->lock);
return 0;
}
unlock(&q->lock);
/* wait in kernel */
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
if (awakened(wkup)){
/* interrupted by awake */
lock(&q->lock);
releaseqlp(&q->head, &q->tail, mp);
unlock(&q->lock);
return 0;
}
forgivewkp(wkup);
mp->inuse = 0;
return 1;
}
int
canrlock(RWLock *q)
{
lock(&q->lock);
if (q->writer == 0 && q->head == nil) {
/* no writer; go for it */
q->_readers++;
unlock(&q->lock);
return 1;
}
unlock(&q->lock);
return 0;
}
void
runlock(RWLock *q)
{
QLp *p;
lock(&q->lock);
if(q->_readers <= 0)
abort();
p = q->head;
if(--(q->_readers) > 0 || p == nil){
unlock(&q->lock);
return;
}
/* start waiting writer */
if(p->state != QueuingW)
abort();
q->head = p->next;
if(q->head == 0)
q->tail = 0;
q->writer = 1;
unlock(&q->lock);
/* wakeup waiter */
while((*_rendezvousp)(p, 0) == (void*)~0)
;
}
void
wlock(RWLock *q)
{
QLp *p, *mp;
lock(&q->lock);
if(q->_readers == 0 && q->writer == 0){
/* noone waiting, go for it */
q->writer = 1;
unlock(&q->lock);
return;
}
/* chain into waiting list */
p = q->tail;
mp = getqlp();
if(p == nil)
q->head = mp;
else
p->next = mp;
q->tail = mp;
mp->next = nil;
mp->state = QueuingW;
unlock(&q->lock);
/* wait in kernel */
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
;
mp->inuse = 0;
}
int
wlockt(RWLock *q, uint32_t ms)
{
QLp *p, *mp;
int64_t wkup;
/* set up awake to interrupt rendezvous */
wkup = awake(ms);
if(!lockt(&q->lock, ms)) {
forgivewkp(wkup);
return 0;
}
if(q->_readers == 0 && q->writer == 0){
/* noone waiting, go for it */
forgivewkp(wkup);
q->writer = 1;
unlock(&q->lock);
return 1;
}
/* chain into waiting list */
p = q->tail;
mp = getqlp();
if(p == nil)
q->head = mp;
else
p->next = mp;
q->tail = mp;
mp->next = nil;
mp->state = QueuingW;
if (awakened(wkup)) { /* do not miss already occurred wakeups */
releaseqlp(&q->head, &q->tail, mp);
unlock(&q->lock);
return 0;
}
unlock(&q->lock);
/* wait in kernel */
while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
if (awakened(wkup)){
/* interrupted by awake */
lock(&q->lock);
releaseqlp(&q->head, &q->tail, mp);
unlock(&q->lock);
return 0;
}
forgivewkp(wkup);
mp->inuse = 0;
return 1;
}
int
canwlock(RWLock *q)
{
lock(&q->lock);
if (q->_readers == 0 && q->writer == 0) {
/* no one waiting; go for it */
q->writer = 1;
unlock(&q->lock);
return 1;
}
unlock(&q->lock);
return 0;
}
void
wunlock(RWLock *q)
{
QLp *p;
lock(&q->lock);
if(q->writer == 0)
abort();
p = q->head;
if(p == nil){
q->writer = 0;
unlock(&q->lock);
return;
}
if(p->state == QueuingW){
/* start waiting writer */
q->head = p->next;
if(q->head == nil)
q->tail = nil;
unlock(&q->lock);
while((*_rendezvousp)(p, 0) == (void*)~0)
;
return;
}
if(p->state != QueuingR)
abort();
/* wake waiting readers */
while(q->head != nil && q->head->state == QueuingR){
p = q->head;
q->head = p->next;
q->_readers++;
while((*_rendezvousp)(p, 0) == (void*)~0)
;
}
if(q->head == nil)
q->tail = nil;
q->writer = 0;
unlock(&q->lock);
}
void
rsleep(Rendez *r)
{
QLp *t, *me;
if(!r->l)
abort();
lock(&r->l->lock);
/* we should hold the qlock */
if(!r->l->locked)
abort();
/* add ourselves to the wait list */
me = getqlp();
me->state = Sleeping;
if(r->head == nil)
r->head = me;
else
r->tail->next = me;
me->next = nil;
r->tail = me;
/* pass the qlock to the next guy */
t = r->l->head;
if(t){
r->l->head = t->next;
if(r->l->head == nil)
r->l->tail = nil;
unlock(&r->l->lock);
while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0)
;
}else{
r->l->locked = 0;
unlock(&r->l->lock);
}
/* wait for a wakeup */
while((*_rendezvousp)(me, (void*)1) == (void*)~0)
;
me->inuse = 0;
}
int
rsleept(Rendez *r, uint32_t ms)
{
QLp *t, *me;
int64_t wkup;
if(!r->l)
abort();
/* set up awake to interrupt rendezvous */
wkup = awake(ms);
if(!lockt(&r->l->lock, ms)){
forgivewkp(wkup);
return 0;
}
/* we should hold the qlock */
if(!r->l->locked)
abort();
/* add ourselves to the wait list */
me = getqlp();
me->state = Sleeping;
if(r->head == nil)
r->head = me;
else
r->tail->next = me;
me->next = nil;
r->tail = me;
/* pass the qlock to the next guy */
t = r->l->head;
if(t){
r->l->head = t->next;
if(r->l->head == nil)
r->l->tail = nil;
unlock(&r->l->lock);
while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0)
;
}else{
r->l->locked = 0;
unlock(&r->l->lock);
}
/* wait for a rwakeup (or a timeout) */
do
{
if (awakened(wkup)){
/* interrupted by awake */
lock(&r->l->lock);
releaseqlp(&r->head, &r->tail, me);
unlock(&r->l->lock);
return 0;
}
}
while((*_rendezvousp)(me, (void*)1) == (void*)~0);
forgivewkp(wkup);
me->inuse = 0;
return 1;
}
int
rwakeup(Rendez *r)
{
QLp *t;
/*
* take off wait and put on front of queue
* put on front so guys that have been waiting will not get starved
*/
if(!r->l)
abort();
lock(&r->l->lock);
if(!r->l->locked)
abort();
t = r->head;
if(t == nil){
unlock(&r->l->lock);
return 0;
}
r->head = t->next;
if(r->head == nil)
r->tail = nil;
t->next = r->l->head;
r->l->head = t;
if(r->l->tail == nil)
r->l->tail = t;
t->state = Queuing;
unlock(&r->l->lock);
return 1;
}
int
rwakeupall(Rendez *r)
{
int i;
for(i=0; rwakeup(r); i++)
;
return i;
}

26
sys/src/libc/9sys/read.c Normal file
View File

@ -0,0 +1,26 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
*
* Jehanne is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* Jehanne is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <libc.h>
int32_t
read(int fd, void* buf, int32_t nbytes)
{
return pread(fd, buf, nbytes, ~0LL);
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
int
read9pmsg(int fd, void *abuf, uint n)
{
int m, len;
uint8_t *buf;
buf = abuf;
/* read count */
m = readn(fd, buf, BIT32SZ);
if(m != BIT32SZ){
if(m < 0)
return -1;
return 0;
}
len = GBIT32(buf);
if(len <= BIT32SZ || len > n){
werrstr("bad length in 9P2000 message header");
return -1;
}
len -= BIT32SZ;
m = readn(fd, buf+BIT32SZ, len);
if(m < len)
return 0;
return BIT32SZ+m;
}

58
sys/src/libc/9sys/readv.c Normal file
View File

@ -0,0 +1,58 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static
int32_t
ioreadv(int fd, IOchunk *io, int nio, int64_t offset)
{
int i;
int32_t m, n, tot;
char *buf, *p;
tot = 0;
for(i=0; i<nio; i++)
tot += io[i].len;
buf = malloc(tot);
if(buf == nil)
return -1;
tot = pread(fd, buf, tot, offset);
p = buf;
n = tot;
for(i=0; i<nio; i++){
if(n <= 0)
break;
m = io->len;
if(m > n)
m = n;
memmove(io->addr, p, m);
n -= m;
p += m;
io++;
}
free(buf);
return tot;
}
int32_t
readv(int fd, IOchunk *io, int nio)
{
return ioreadv(fd, io, nio, -1LL);
}
int32_t
preadv(int fd, IOchunk *io, int nio, int64_t off)
{
return ioreadv(fd, io, nio, off);
}

View File

@ -0,0 +1,22 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
void
rerrstr(char *buf, uint nbuf)
{
char tmp[ERRMAX];
tmp[0] = 0;
errstr(tmp, sizeof tmp);
utfecpy(buf, buf+nbuf, tmp);
errstr(tmp, sizeof tmp);
}

44
sys/src/libc/9sys/sbrk.c Normal file
View File

@ -0,0 +1,44 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
extern char end[];
static char *bloc = { end };
extern int brk_(void*);
enum
{
Round = 7
};
int
brk(void *p)
{
uintptr bl;
bl = ((uintptr)p + Round) & ~Round;
if(brk_((void*)bl) < 0)
return -1;
bloc = (char*)bl;
return 0;
}
void*
sbrk(uint32_t n)
{
uintptr bl;
bl = ((uintptr)bloc + Round) & ~Round;
if(brk_((void*)(bl+n)) < 0)
return (void*)-1;
bloc = (char*)bl + n;
return (void*)bl;
}

View File

@ -0,0 +1,25 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
void
setnetmtpt(char *net, int n, const char *x)
{
if(x == nil)
x = "/net";
if(*x == '/'){
strncpy(net, x, n);
net[n-1] = 0;
} else {
snprint(net, n, "/net%s", x);
}
}

31
sys/src/libc/9sys/sleep.c Normal file
View File

@ -0,0 +1,31 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
*
* Jehanne is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* Jehanne is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <libc.h>
void
sleep(int32_t millisecs)
{
int64_t wakeup;
wakeup = awake(millisecs);
while(!awakened(wakeup) && rendezvous(&wakeup, (void*)1) == (void*)~0)
;
}

View File

@ -0,0 +1,37 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static void
_sysfatalimpl(const char *fmt, va_list arg)
{
char buf[1024];
vseprint(buf, buf+sizeof(buf), fmt, arg);
if(argv0)
fprint(2, "%s: %s\n", argv0, buf);
else
fprint(2, "%s\n", buf);
exits(buf);
}
void (*_sysfatal)(const char *fmt, va_list arg) = _sysfatalimpl;
void
sysfatal(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
(*_sysfatal)(fmt, arg);
va_end(arg);
}

125
sys/src/libc/9sys/syslog.c Normal file
View File

@ -0,0 +1,125 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static struct
{
int fd;
int consfd;
char *name;
Dir *d;
Dir *consd;
Lock;
} sl =
{
-1, -1,
};
static void
_syslogopen(void)
{
char buf[1024];
if(sl.fd >= 0)
close(sl.fd);
snprint(buf, sizeof(buf), "/sys/log/%s", sl.name);
sl.fd = open(buf, OWRITE|OCEXEC);
}
static int
eqdirdev(Dir *a, Dir *b)
{
return a != nil && b != nil &&
a->dev == b->dev && a->type == b->type &&
a->qid.path == b->qid.path;
}
/*
* Print
* sysname: time: mesg
* on /sys/log/logname.
* If cons or log file can't be opened, print on the system console, too.
*/
void
syslog(int cons, const char *logname, const char *fmt, ...)
{
char buf[1024];
char *ctim, *p;
va_list arg;
int n;
Dir *d;
char err[ERRMAX];
err[0] = '\0';
errstr(err, sizeof err);
lock(&sl);
/*
* paranoia makes us stat to make sure a fork+close
* hasn't broken our fd's
*/
d = dirfstat(sl.fd);
if(sl.fd < 0 || sl.name == nil || strcmp(sl.name, logname) != 0 ||
!eqdirdev(d, sl.d)){
free(sl.name);
sl.name = strdup(logname);
if(sl.name == nil)
cons = 1;
else{
free(sl.d);
sl.d = nil;
_syslogopen();
if(sl.fd < 0)
cons = 1;
else
sl.d = dirfstat(sl.fd);
}
}
free(d);
if(cons){
d = dirfstat(sl.consfd);
if(sl.consfd < 0 || !eqdirdev(d, sl.consd)){
free(sl.consd);
sl.consd = nil;
sl.consfd = open("#c/cons", OWRITE|OCEXEC);
if(sl.consfd >= 0)
sl.consd = dirfstat(sl.consfd);
}
free(d);
}
if(fmt == nil){
unlock(&sl);
return;
}
ctim = ctime(time(0));
p = buf + snprint(buf, sizeof(buf)-1, "%s ", sysname());
strncpy(p, ctim+4, 15);
p += 15;
*p++ = ' ';
errstr(err, sizeof err);
va_start(arg, fmt);
p = vseprint(p, buf+sizeof(buf)-1, fmt, arg);
va_end(arg);
*p++ = '\n';
n = p - buf;
if(sl.fd >= 0){
seek(sl.fd, 0, 2);
write(sl.fd, buf, n);
}
if(cons && sl.consfd >=0)
write(sl.consfd, buf, n);
unlock(&sl);
}

View File

@ -0,0 +1,30 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
char*
sysname(void)
{
int f, n;
static char b[128];
if(b[0])
return b;
f = open("#c/sysname", 0);
if(f >= 0) {
n = read(f, b, sizeof(b)-1);
if(n > 0)
b[n] = 0;
close(f);
}
return b;
}

22
sys/src/libc/9sys/time.c Normal file
View File

@ -0,0 +1,22 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int32_t
time(int32_t *tp)
{
int64_t t;
t = nsec()/1000000000LL;
if(tp != nil)
*tp = t;
return t;
}

69
sys/src/libc/9sys/times.c Normal file
View File

@ -0,0 +1,69 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static
char*
skip(char *p)
{
while(*p == ' ')
p++;
while(*p != ' ' && *p != 0)
p++;
return p;
}
/*
* after a fork with fd's copied, both fd's are pointing to
* the same Chan structure. Since the offset is kept in the Chan
* structure, the seek's and read's in the two processes can be
* are competing moving the offset around. Hence the unusual loop
* in the middle of this routine.
*/
int32_t
times(int32_t *t)
{
char b[200], *p;
static int f = -1;
int i, retries;
uint32_t r;
memset(b, 0, sizeof(b));
for(retries = 0; retries < 100; retries++){
if(f < 0)
f = open("/dev/cputime", OREAD|OCEXEC);
if(f < 0)
break;
if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){
close(f);
f = -1;
} else {
if(i != 0)
break;
}
}
p = b;
if(t)
t[0] = atol(p);
p = skip(p);
if(t)
t[1] = atol(p);
p = skip(p);
r = atol(p);
if(t){
p = skip(p);
t[2] = atol(p);
p = skip(p);
t[3] = atol(p);
}
return r;
}

203
sys/src/libc/9sys/tm2sec.c Normal file
View File

@ -0,0 +1,203 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#define TZSIZE 150
static void readtimezone(void);
static int rd_name(char**, char*);
static int rd_long(char**, int32_t*);
static
struct
{
char stname[4];
char dlname[4];
int32_t stdiff;
int32_t dldiff;
int32_t dlpairs[TZSIZE];
} timezone;
#define SEC2MIN 60L
#define SEC2HOUR (60L*SEC2MIN)
#define SEC2DAY (24L*SEC2HOUR)
/*
* days per month plus days/year
*/
static int dmsize[] =
{
365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static int ldmsize[] =
{
366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
/*
* return the days/month for the given year
*/
static int *
yrsize(int y)
{
if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
return ldmsize;
else
return dmsize;
}
/*
* compute seconds since Jan 1 1970 GMT
* and convert to our timezone.
*/
int32_t
tm2sec(Tm *tm)
{
int32_t secs;
int i, yday, year, *d2m;
if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0)
readtimezone();
secs = 0;
/*
* seconds per year
*/
year = tm->year + 1900;
for(i = 1970; i < year; i++){
d2m = yrsize(i);
secs += d2m[0] * SEC2DAY;
}
/*
* if mday is set, use mon and mday to compute yday
*/
if(tm->mday){
yday = 0;
d2m = yrsize(year);
for(i=0; i<tm->mon; i++)
yday += d2m[i+1];
yday += tm->mday-1;
}else{
yday = tm->yday;
}
secs += yday * SEC2DAY;
/*
* hours, minutes, seconds
*/
secs += tm->hour * SEC2HOUR;
secs += tm->min * SEC2MIN;
secs += tm->sec;
/*
* Only handles zones mentioned in /env/timezone,
* but things get too ambiguous otherwise.
*/
if(strcmp(tm->zone, timezone.stname) == 0)
secs -= timezone.stdiff;
else if(strcmp(tm->zone, timezone.dlname) == 0)
secs -= timezone.dldiff;
if(secs < 0)
secs = 0;
return secs;
}
static
void
readtimezone(void)
{
char buf[TZSIZE*11+30], *p;
int i;
memset(buf, 0, sizeof(buf));
i = open("/env/timezone", 0);
if(i < 0)
goto error;
if(read(i, buf, sizeof(buf)) >= sizeof(buf))
goto error;
close(i);
p = buf;
if(rd_name(&p, timezone.stname))
goto error;
if(rd_long(&p, &timezone.stdiff))
goto error;
if(rd_name(&p, timezone.dlname))
goto error;
if(rd_long(&p, &timezone.dldiff))
goto error;
for(i=0; i<TZSIZE; i++) {
if(rd_long(&p, &timezone.dlpairs[i]))
goto error;
if(timezone.dlpairs[i] == 0)
return;
}
error:
timezone.stdiff = 0;
strcpy(timezone.stname, "GMT");
timezone.dlpairs[0] = 0;
}
static int
rd_name(char **f, char *p)
{
int c, i;
for(;;) {
c = *(*f)++;
if(c != ' ' && c != '\n')
break;
}
for(i=0; i<3; i++) {
if(c == ' ' || c == '\n')
return 1;
*p++ = c;
c = *(*f)++;
}
if(c != ' ' && c != '\n')
return 1;
*p = 0;
return 0;
}
static int
rd_long(char **f, int32_t *p)
{
int c, s;
int32_t l;
s = 0;
for(;;) {
c = *(*f)++;
if(c == '-') {
s++;
continue;
}
if(c != ' ' && c != '\n')
break;
}
if(c == 0) {
*p = 0;
return 0;
}
l = 0;
for(;;) {
if(c == ' ' || c == '\n')
break;
if(c < '0' || c > '9')
return 1;
l = l*10 + c-'0';
c = *(*f)++;
}
if(s)
l = -l;
*p = l;
return 0;
}

View File

@ -0,0 +1,26 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
uint32_t
truerand(void)
{
uint32_t x;
static int randfd = -1;
if(randfd < 0)
randfd = open("/dev/random", OREAD|OCEXEC);
if(randfd < 0)
sysfatal("can't open /dev/random");
if(read(randfd, &x, sizeof(x)) != sizeof(x))
sysfatal("can't read /dev/random");
return x;
}

41
sys/src/libc/9sys/wait.c Normal file
View File

@ -0,0 +1,41 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
Waitmsg*
wait(void)
{
int n, l;
char buf[512], *fld[5];
Waitmsg *w;
n = await(buf, sizeof buf-1);
if(n < 0)
return nil;
buf[n] = '\0';
if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
werrstr("couldn't parse wait message");
return nil;
}
l = strlen(fld[4])+1;
w = malloc(sizeof(Waitmsg)+l);
if(w == nil)
return nil;
w->pid = atoi(fld[0]);
w->time[0] = atoi(fld[1]);
w->time[1] = atoi(fld[2]);
w->time[2] = atoi(fld[3]);
w->msg = (char*)&w[1];
memmove(w->msg, fld[4], l);
return w;
}

View File

@ -0,0 +1,30 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
int
waitpid(void)
{
int n;
char buf[512], *fld[5];
n = await(buf, sizeof buf-1);
if(n <= 0)
return -1;
buf[n] = '\0';
if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
werrstr("couldn't parse wait message");
return -1;
}
return atoi(fld[0]);
}

View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
void
werrstr(const char *fmt, ...)
{
va_list arg;
char buf[ERRMAX];
va_start(arg, fmt);
vseprint(buf, buf+ERRMAX, fmt, arg);
va_end(arg);
errstr(buf, ERRMAX);
}

26
sys/src/libc/9sys/write.c Normal file
View File

@ -0,0 +1,26 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
*
* Jehanne is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* Jehanne is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <libc.h>
int32_t
write(int fd, const void* buf, int32_t nbytes)
{
return pwrite(fd, buf, nbytes, ~0LL);
}

View File

@ -0,0 +1,51 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static
int32_t
iowritev(int fd, IOchunk *io, int nio, int64_t offset)
{
int i;
int32_t tot;
char *buf, *p;
tot = 0;
for(i=0; i<nio; i++)
tot += io[i].len;
buf = malloc(tot);
if(buf == nil)
return -1;
p = buf;
for(i=0; i<nio; i++){
memmove(p, io->addr, io->len);
p += io->len;
io++;
}
tot = pwrite(fd, buf, tot, offset);
free(buf);
return tot;
}
int32_t
writev(int fd, IOchunk *io, int nio)
{
return iowritev(fd, io, nio, -1LL);
}
int32_t
pwritev(int fd, IOchunk *io, int nio, int64_t off)
{
return iowritev(fd, io, nio, off);
}

3
sys/src/libc/9syscall/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/*.s
/*.o
/sys.h

View File

@ -0,0 +1,8 @@
{
"KernelLibc": {
"Pre": [
"mksys -o sys.h '-mode=sys.h' $JEHANNE/sys/src/sysconf.json",
"mksys -o . '-mode=syscallfiles' $JEHANNE/sys/src/sysconf.json"
]
}
}

View File

@ -0,0 +1,9 @@
#include <u.h>
#include <libc.h>
void (*_abort)(void);
char *argv0;
char *_tos;
char *_privates;
char *_nprivates;

86
sys/src/libc/amd64/atom.S Normal file
View File

@ -0,0 +1,86 @@
.text
.globl ainc /* long ainc(long *); */
/* N.B.: long in Plan 9 is 32 BITS! */
ainc:
pushq %rcx
ainclp:
movl (%rdi), %eax
movl %eax, %ecx
incl %ecx /* new */
lock; cmpxchgl %ecx, (%rdi)
jnz ainclp
movl %ecx, %eax
popq %rcx
ret
.globl adec /* long adec(long*); */
adec:
pushq %rcx
adeclp:
movl (%rdi), %eax
movl %eax, %ecx
decl %ecx /* new */
lock; cmpxchgl %ecx, (%rdi)
jnz adeclp
movl %ecx, %eax
popq %rcx
ret
/*
* int cas32(u32int *p, u32int ov, u32int nv);
* int cas(uint *p, int ov, int nv);
* int casul(ulong *p, ulong ov, ulong nv);
*/
.globl cas32
cas32:
.globl cas
cas:
.globl casul
casul:
.globl casl
casl:
pushq %rcx
movl 16(%rdi), %eax
movl 24(%rdi), %ebx
lock; cmpxchgl %ecx, (%rdi)
movl $1, %eax
jnz _cas32r0
_cas32r1:
ret
_cas32r0:
decl %eax
popq %rcx
ret
/*
* int cas64(u64int *p, u64int ov, u64int nv);
* int casp(void **p, void *ov, void *nv);
*/
.globl cas64
cas64:
.globl casp
casp:
pushq %rcx
movq 16(%rdi), %rax
movq 24(%rdi), %rbx
lock; cmpxchgq %rbx, (%rdi)
movl $1, %eax
jnz _cas64r0
_cas64r1:
ret
_cas64r0:
decq %rax
popq %rcx
ret
/*
* void mfence(void);
*/
.globl mfence
mfence:
mfence
ret

View File

@ -0,0 +1,11 @@
#include <u.h>
#include <libc.h>
void _cycles(uint64_t *x)
{
uint32_t a, d;
asm __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
}

View File

@ -0,0 +1,32 @@
#define NPRIVATES 16
.text
// %rdi and %rsi are set up as argc, argv for main.
// %rdx points to top of stack
.globl _main
_main:
movq 0(%rsp), %rdi
leaq 8(%rsp), %rsi
movq %rdx, _tos
movq $-128, _privates
addq %rsp, _privates
movl $NPRIVATES, _nprivates
leaq -160(%rsp), %rsp
call main
loop:
movq $_exits, %rdi
call exits
jmp loop
.data
_exits:
.ascii "main"
.globl gettls0
gettls0:
movq %fs:0, %rax
ret

View File

@ -0,0 +1,16 @@
#include <u.h>
#include <libc.h>
#include <ureg.h>
void
notejmp(void *vr, jmp_buf j, int ret)
{
struct Ureg *r = vr;
r->ax = ret;
if(ret == 0)
r->ax = 1;
r->ip = j[JMPBUFPC];
r->sp = j[JMPBUFSP] + 8;
noted(NCONT);
}

View File

@ -0,0 +1,9 @@
#include <u.h>
#include <libc.h>
void
rdpmc (int counter, int low, int high)
{
asm __volatile__("rdpmc" : "=a" (low), "=d" (high) : "c" (counter)) ;
}

View File

@ -0,0 +1,39 @@
.text
.globl longjmp
longjmp:
movq %rdi, %r9
movq 0(%r9), %rbx
movq 8(%r9), %r12
movq 16(%r9), %r13
movq 24(%r9), %r14
movq 32(%r9), %r15
movq 40(%r9), %rbp
movq 48(%r9), %rsp
movl %esi, %eax
test %eax, %eax /* if val != 0 */
jnz 1f /* return val */
incl %eax /* else return 1 */
1:
movq 56(%r9), %r8 /* return to caller of setjmp */
movq 64(%r9), %rdi /* 1st function argument */
movq 72(%r9), %rsi /* 2nd function argument */
jmp *%r8
.globl setjmp
setjmp:
movq %rbx, 0(%rdi)
movq %r12, 8(%rdi)
movq %r13, 16(%rdi)
movq %r14, 24(%rdi)
movq %r15, 32(%rdi)
movq %rbp, 40(%rdi)
popq %rdx /* return address */
movq %rsp, 48(%rdi)
movq %rdx, 56(%rdi)
xorl %eax, %eax /* return 0 */
jmp *%rdx

View File

@ -0,0 +1,5 @@
.globl sqrt
sqrt:
sqrtsd %xmm0, %xmm0
ret

10
sys/src/libc/amd64/tas.s Normal file
View File

@ -0,0 +1,10 @@
/*
* The kernel and the libc use the same constant for TAS
*/
.text
.globl _tas
_tas:
movl $0xdeaddead, %eax
xchgl %eax, 0(%rdi) /* lock->key */
ret

255
sys/src/libc/build.json Normal file
View File

@ -0,0 +1,255 @@
{
"Libc": {
"Cflags": [
"-fasm",
"-Werror"
],
"Include": [
"../lib.json"
],
"Install": "/arch/$ARCH/lib/",
"Library": "libc.a",
"Post": [
"rm 9syscall/*.s"
],
"Projects": [
"9syscall/9syscall.json"
],
"SourceFiles": [
"9sys/access.c",
"9sys/announce.c",
"9sys/awakened.c",
"9sys/convD2M.c",
"9sys/convM2D.c",
"9sys/convM2S.c",
"9sys/convS2M.c",
"9sys/cputime.c",
"9sys/ctime.c",
"9sys/dial.c",
"9sys/dirfstat.c",
"9sys/dirfwstat.c",
"9sys/dirmodefmt.c",
"9sys/dirread.c",
"9sys/dirstat.c",
"9sys/dirwstat.c",
"9sys/fcallfmt.c",
"9sys/fork.c",
"9sys/getnetconninfo.c",
"9sys/getenv.c",
"9sys/getpid.c",
"9sys/getppid.c",
"9sys/getwd.c",
"9sys/iounit.c",
"9sys/nulldir.c",
"9sys/postnote.c",
"9sys/privalloc.c",
"9sys/pushssl.c",
"9sys/putenv.c",
"9sys/qlock.c",
"9sys/read9pmsg.c",
"9sys/read.c",
"9sys/readv.c",
"9sys/rerrstr.c",
"9sys/sbrk.c",
"9sys/setnetmtpt.c",
"9sys/sleep.c",
"9sys/sysfatal.c",
"9sys/syslog.c",
"9sys/sysname.c",
"9sys/time.c",
"9sys/times.c",
"9sys/tm2sec.c",
"9sys/truerand.c",
"9sys/wait.c",
"9sys/waitpid.c",
"9sys/werrstr.c",
"9sys/write.c",
"9sys/writev.c",
"9syscall/alarm.s",
"9syscall/await.s",
"9syscall/awake.s",
"9syscall/bind.s",
"9syscall/brk_.s",
"9syscall/chdir.s",
"9syscall/close.s",
"9syscall/create.s",
"9syscall/dup.s",
"9syscall/errstr.s",
"9syscall/exec.s",
"9syscall/_exits.s",
"9syscall/fauth.s",
"9syscall/fd2path.s",
"9syscall/fstat.s",
"9syscall/fversion.s",
"9syscall/fwstat.s",
"9syscall/mount.s",
"9syscall/noted.s",
"9syscall/notify.s",
"9syscall/nsec.s",
"9syscall/open.s",
"9syscall/pipe.s",
"9syscall/pread.s",
"9syscall/pwrite.s",
"9syscall/remove.s",
"9syscall/rendezvous.s",
"9syscall/rfork.s",
"9syscall/seek.s",
"9syscall/segattach.s",
"9syscall/segbrk.s",
"9syscall/segdetach.s",
"9syscall/segflush.s",
"9syscall/segfree.s",
"9syscall/semacquire.s",
"9syscall/semrelease.s",
"9syscall/stat.s",
"9syscall/tsemacquire.s",
"9syscall/unmount.s",
"9syscall/wstat.s",
"fmt/dofmt.c",
"fmt/dorfmt.c",
"fmt/errfmt.c",
"fmt/fltfmt.c",
"fmt/fmt.c",
"fmt/fmtfd.c",
"fmt/fmtlock.c",
"fmt/fmtprint.c",
"fmt/fmtquote.c",
"fmt/fmtrune.c",
"fmt/fmtstr.c",
"fmt/fmtvprint.c",
"fmt/fprint.c",
"fmt/print.c",
"fmt/runefmtstr.c",
"fmt/runeseprint.c",
"fmt/runesmprint.c",
"fmt/runesnprint.c",
"fmt/runesprint.c",
"fmt/runevseprint.c",
"fmt/runevsmprint.c",
"fmt/runevsnprint.c",
"fmt/seprint.c",
"fmt/smprint.c",
"fmt/snprint.c",
"fmt/sprint.c",
"fmt/vfprint.c",
"fmt/vseprint.c",
"fmt/vsmprint.c",
"fmt/vsnprint.c",
"port/_assert.c",
"port/abs.c",
"port/asin.c",
"port/atan.c",
"port/atan2.c",
"port/atexit.c",
"port/atnotify.c",
"port/atof.c",
"port/atol.c",
"port/atoll.c",
"port/cistrcmp.c",
"port/cistrncmp.c",
"port/cistrstr.c",
"port/charstod.c",
"port/cleanname.c",
"port/ctype.c",
"port/encodefmt.c",
"port/execl.c",
"port/exp.c",
"port/fabs.c",
"port/floor.c",
"port/fmod.c",
"port/frand.c",
"port/frexp.c",
"port/getcallerpc.c",
"port/getfields.c",
"port/getuser.c",
"port/hangup.c",
"port/hypot.c",
"port/lnrand.c",
"port/lock.c",
"port/log.c",
"port/lrand.c",
"port/malloc.c",
"port/memccpy.c",
"port/memchr.c",
"port/memcmp.c",
"port/memmove.c",
"port/memset.c",
"port/mktemp.c",
"port/muldiv.c",
"port/nan.c",
"port/needsrcquote.c",
"port/netmkaddr.c",
"port/nrand.c",
"port/ntruerand.c",
"port/perror.c",
"port/pool.c",
"port/pow.c",
"port/pow10.c",
"port/qsort.c",
"port/quote.c",
"port/rand.c",
"port/readn.c",
"port/rune.c",
"port/runebase.c",
"port/runebsearch.c",
"port/runestrcat.c",
"port/runestrchr.c",
"port/runestrcmp.c",
"port/runestrcpy.c",
"port/runestrecpy.c",
"port/runestrdup.c",
"port/runestrncat.c",
"port/runestrncmp.c",
"port/runestrncpy.c",
"port/runestrrchr.c",
"port/runestrlen.c",
"port/runestrstr.c",
"port/runetype.c",
"port/sin.c",
"port/sinh.c",
"port/strcat.c",
"port/strchr.c",
"port/strcmp.c",
"port/strcpy.c",
"port/strecpy.c",
"port/strcspn.c",
"port/strdup.c",
"port/strlen.c",
"port/strncat.c",
"port/strncmp.c",
"port/strncpy.c",
"port/strpbrk.c",
"port/strrchr.c",
"port/strspn.c",
"port/strstr.c",
"port/strtod.c",
"port/strtok.c",
"port/strtol.c",
"port/strtoll.c",
"port/strtoul.c",
"port/strtoull.c",
"port/tan.c",
"port/tanh.c",
"port/tokenize.c",
"port/toupper.c",
"port/utfecpy.c",
"port/utflen.c",
"port/utfnlen.c",
"port/utfrune.c",
"port/utfrrune.c",
"port/utfutf.c",
"port/u16.c",
"port/u32.c",
"port/u64.c",
"$ARCH/notejmp.c",
"$ARCH/cycles.c",
"$ARCH/argv0.c",
"$ARCH/rdpmc.c",
"$ARCH/setjmp.s",
"$ARCH/sqrt.s",
"$ARCH/tas.s",
"$ARCH/atom.S",
"$ARCH/main9.S"
]
}
}

539
sys/src/libc/fmt/dofmt.c Normal file
View File

@ -0,0 +1,539 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
/* format the output into f->to and return the number of characters fmted */
int
dofmt(Fmt *f, const char *fmt)
{
Rune rune, *rt, *rs;
int r;
char *t, *s;
int n, nfmt;
nfmt = f->nfmt;
for(;;){
if(f->runes){
rt = f->to;
rs = f->stop;
while((r = *(uint8_t*)fmt) && r != '%'){
if(r < Runeself)
fmt++;
else{
fmt += chartorune(&rune, fmt);
r = rune;
}
FMTRCHAR(f, rt, rs, r);
}
fmt++;
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(!r)
return f->nfmt - nfmt;
f->stop = rs;
}else{
t = f->to;
s = f->stop;
while((r = *(uint8_t*)fmt) && r != '%'){
if(r < Runeself){
FMTCHAR(f, t, s, r);
fmt++;
}else{
n = chartorune(&rune, fmt);
if(t + n > s){
t = _fmtflush(f, t, n);
if(t != nil)
s = f->stop;
else
return -1;
}
while(n--)
*t++ = *fmt++;
}
}
fmt++;
f->nfmt += t - (char *)f->to;
f->to = t;
if(!r)
return f->nfmt - nfmt;
f->stop = s;
}
fmt = _fmtdispatch(f, fmt, 0);
if(fmt == nil)
return -1;
}
}
void *
_fmtflush(Fmt *f, void *t, int len)
{
if(f->runes)
f->nfmt += (Rune*)t - (Rune*)f->to;
else
f->nfmt += (char*)t - (char *)f->to;
f->to = t;
if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
f->stop = f->to;
return nil;
}
return f->to;
}
/*
* put a formatted block of memory sz bytes long of n runes into the output buffer,
* left/right justified in a field of at least f->width charactes
*/
int
_fmtpad(Fmt *f, int n)
{
char *t, *s;
int i;
t = f->to;
s = f->stop;
for(i = 0; i < n; i++)
FMTCHAR(f, t, s, ' ');
f->nfmt += t - (char *)f->to;
f->to = t;
return 0;
}
int
_rfmtpad(Fmt *f, int n)
{
Rune *t, *s;
int i;
t = f->to;
s = f->stop;
for(i = 0; i < n; i++)
FMTRCHAR(f, t, s, ' ');
f->nfmt += t - (Rune *)f->to;
f->to = t;
return 0;
}
int
_fmtcpy(Fmt *f, const void *vm, int n, int sz)
{
Rune *rt, *rs, r;
char *t, *s;
const char *m, *me;
uint32_t fl;
int nc, w;
m = vm;
me = m + sz;
w = f->width;
fl = f->flags;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
return -1;
rt = f->to;
rs = f->stop;
for(nc = n; nc > 0; nc--){
r = *(uint8_t*)m;
if(r < Runeself)
m++;
else if((me - m) >= UTFmax || fullrune(m, me-m))
m += chartorune(&r, m);
else
break;
FMTRCHAR(f, rt, rs, r);
}
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
return -1;
}else{
if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
return -1;
t = f->to;
s = f->stop;
for(nc = n; nc > 0; nc--){
r = *(uint8_t*)m;
if(r < Runeself)
m++;
else if((me - m) >= UTFmax || fullrune(m, me-m))
m += chartorune(&r, m);
else
break;
FMTRUNE(f, t, s, r);
}
f->nfmt += t - (char *)f->to;
f->to = t;
if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
return -1;
}
return 0;
}
int
_fmtrcpy(Fmt *f, const void *vm, int n)
{
Rune r, *rt, *rs;
const Rune *m, *me;
char *t, *s;
uint32_t fl;
int w;
m = vm;
w = f->width;
fl = f->flags;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
return -1;
rt = f->to;
rs = f->stop;
for(me = m + n; m < me; m++)
FMTRCHAR(f, rt, rs, *m);
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
return -1;
}else{
if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
return -1;
t = f->to;
s = f->stop;
for(me = m + n; m < me; m++){
r = *m;
FMTRUNE(f, t, s, r);
}
f->nfmt += t - (char *)f->to;
f->to = t;
if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
return -1;
}
return 0;
}
/* fmt out one character */
int
_charfmt(Fmt *f)
{
char x[1];
x[0] = va_arg(f->args, int);
f->prec = 1;
return _fmtcpy(f, x, 1, 1);
}
/* fmt out one rune */
int
_runefmt(Fmt *f)
{
Rune x[1];
x[0] = va_arg(f->args, int);
return _fmtrcpy(f, x, 1);
}
/* public helper routine: fmt out a null terminated string already in hand */
int
fmtstrcpy(Fmt *f, const char *s)
{
int i, j;
Rune r;
if(!s)
return _fmtcpy(f, "<nil>", 5, 5);
/* if precision is specified, make sure we don't wander off the end */
if(f->flags & FmtPrec){
i = 0;
for(j=0; j<f->prec && s[i]; j++)
i += chartorune(&r, s+i);
return _fmtcpy(f, s, j, i);
}
return _fmtcpy(f, s, utflen(s), strlen(s));
}
/* fmt out a null terminated utf string */
int
_strfmt(Fmt *f)
{
char *s;
s = va_arg(f->args, char *);
return fmtstrcpy(f, s);
}
/* public helper routine: fmt out a null terminated rune string already in hand */
int
fmtrunestrcpy(Fmt *f, const Rune *s)
{
const Rune *e;
int n, p;
if(!s)
return _fmtcpy(f, "<nil>", 5, 5);
/* if precision is specified, make sure we don't wander off the end */
if(f->flags & FmtPrec){
p = f->prec;
for(n = 0; n < p; n++)
if(s[n] == 0)
break;
}else{
for(e = s; *e; e++)
;
n = e - s;
}
return _fmtrcpy(f, s, n);
}
/* fmt out a null terminated rune string */
int
_runesfmt(Fmt *f)
{
Rune *s;
s = va_arg(f->args, Rune *);
return fmtrunestrcpy(f, s);
}
/* fmt a % */
int
_percentfmt(Fmt *f)
{
Rune x[1];
x[0] = f->r;
f->prec = 1;
return _fmtrcpy(f, x, 1);
}
enum {
/* %,#llb could emit a sign, "0b" and 64 digits with 21 commas */
Maxintwidth = 1 + 2 + 64 + 64/3,
};
/* fmt an integer */
int
_ifmt(Fmt *f)
{
char buf[Maxintwidth + 1], *p, *conv;
uint64_t vu;
uint32_t u;
uintptr pu;
int neg, base, i, n, fl, w, isv;
neg = 0;
fl = f->flags;
isv = 0;
vu = 0;
u = 0;
if(f->r == 'p'){
pu = va_arg(f->args, uintptr);
if(sizeof(uintptr) == sizeof(uint64_t)){
vu = pu;
isv = 1;
}else
u = pu;
f->r = 'x';
fl |= FmtUnsigned;
}else if(fl & FmtVLong){
isv = 1;
if(fl & FmtUnsigned)
vu = va_arg(f->args, uint64_t);
else
vu = va_arg(f->args, int64_t);
}else if(fl & FmtLong){
if(fl & FmtUnsigned)
u = va_arg(f->args, uint32_t);
else
u = va_arg(f->args, int32_t);
}else if(fl & FmtByte){
if(fl & FmtUnsigned)
u = (uint8_t)va_arg(f->args, int);
else
u = (char)va_arg(f->args, int);
}else if(fl & FmtShort){
if(fl & FmtUnsigned)
u = (uint16_t)va_arg(f->args, int);
else
u = (int16_t)va_arg(f->args, int);
}else{
if(fl & FmtUnsigned)
u = va_arg(f->args, uint);
else
u = va_arg(f->args, int);
}
conv = "0123456789abcdef";
switch(f->r){
case 'd':
base = 10;
break;
case 'x':
base = 16;
break;
case 'X':
base = 16;
conv = "0123456789ABCDEF";
break;
case 'b':
base = 2;
break;
case 'o':
base = 8;
break;
default:
return -1;
}
if(!(fl & FmtUnsigned)){
if(isv && (int64_t)vu < 0){
vu = -(int64_t)vu;
neg = 1;
}else if(!isv && (int32_t)u < 0){
u = -(int32_t)u;
neg = 1;
}
}
p = buf + sizeof buf - 1;
n = 0;
if(isv){
while(vu){
i = vu % base;
vu /= base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
}
*p-- = conv[i];
n++;
}
}else{
while(u){
i = u % base;
u /= base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
}
*p-- = conv[i];
n++;
}
}
if(n == 0){
*p-- = '0';
n = 1;
}
for(w = f->prec; n < w && p > buf+3; n++)
*p-- = '0';
if(neg || (fl & (FmtSign|FmtSpace)))
n++;
if(fl & FmtSharp){
if(base == 16)
n += 2;
else if(base == 8){
if(p[1] == '0')
fl &= ~FmtSharp;
else
n++;
}
}
if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
for(w = f->width; n < w && p > buf+3; n++)
*p-- = '0';
f->width = 0;
}
if(fl & FmtSharp){
if(base == 16)
*p-- = f->r;
if(base == 16 || base == 8)
*p-- = '0';
}
if(neg)
*p-- = '-';
else if(fl & FmtSign)
*p-- = '+';
else if(fl & FmtSpace)
*p-- = ' ';
f->flags &= ~FmtPrec;
return _fmtcpy(f, p + 1, n, n);
}
int
_countfmt(Fmt *f)
{
void *p;
uint32_t fl;
fl = f->flags;
p = va_arg(f->args, void*);
if(fl & FmtVLong){
*(int64_t*)p = f->nfmt;
}else if(fl & FmtLong){
*(int32_t*)p = f->nfmt;
}else if(fl & FmtByte){
*(char*)p = f->nfmt;
}else if(fl & FmtShort){
*(int16_t*)p = f->nfmt;
}else{
*(int*)p = f->nfmt;
}
return 0;
}
int
_flagfmt(Fmt *f)
{
switch(f->r){
case ',':
f->flags |= FmtComma;
break;
case '-':
f->flags |= FmtLeft;
break;
case '+':
f->flags |= FmtSign;
break;
case '#':
f->flags |= FmtSharp;
break;
case ' ':
f->flags |= FmtSpace;
break;
case 'u':
f->flags |= FmtUnsigned;
break;
case 'h':
if(f->flags & FmtShort)
f->flags |= FmtByte;
f->flags |= FmtShort;
break;
case 'l':
if(f->flags & FmtLong)
f->flags |= FmtVLong;
f->flags |= FmtLong;
break;
}
return 1;
}
/* default error format */
int
_badfmt(Fmt *f)
{
Rune x[3];
x[0] = '%';
x[1] = f->r;
x[2] = '%';
f->prec = 3;
_fmtrcpy(f, x, 3);
return 0;
}

54
sys/src/libc/fmt/dorfmt.c Normal file
View File

@ -0,0 +1,54 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
/* format the output into f->to and return the number of characters fmted */
int
dorfmt(Fmt *f, const Rune *fmt)
{
Rune *rt, *rs;
int r;
char *t, *s;
int nfmt;
nfmt = f->nfmt;
for(;;){
if(f->runes){
rt = f->to;
rs = f->stop;
while((r = *fmt++) && r != '%'){
FMTRCHAR(f, rt, rs, r);
}
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(!r)
return f->nfmt - nfmt;
f->stop = rs;
}else{
t = f->to;
s = f->stop;
while((r = *fmt++) && r != '%'){
FMTRUNE(f, t, f->stop, r);
}
f->nfmt += t - (char *)f->to;
f->to = t;
if(!r)
return f->nfmt - nfmt;
f->stop = s;
}
fmt = _fmtdispatch(f, fmt, 1);
if(fmt == nil)
return -1;
}
}

21
sys/src/libc/fmt/errfmt.c Normal file
View File

@ -0,0 +1,21 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
int
errfmt(Fmt *f)
{
char buf[ERRMAX];
rerrstr(buf, sizeof buf);
return _fmtcpy(f, buf, utflen(buf), strlen(buf));
}

327
sys/src/libc/fmt/fltfmt.c Normal file
View File

@ -0,0 +1,327 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include "fmtdef.h"
enum
{
FDIGIT = 30,
FDEFLT = 6,
NSIGNIF = 17,
NEXP10 = 308,
};
static int
xadd(char *a, int n, int v)
{
char *b;
int c;
if(n < 0 || n >= NSIGNIF)
return 0;
for(b = a+n; b >= a; b--) {
c = *b + v;
if(c <= '9') {
*b = c;
return 0;
}
*b = '0';
v = 1;
}
*a = '1'; // overflow adding
return 1;
}
static int
xsub(char *a, int n, int v)
{
char *b;
int c;
for(b = a+n; b >= a; b--) {
c = *b - v;
if(c >= '0') {
*b = c;
return 0;
}
*b = '9';
v = 1;
}
*a = '9'; // underflow subtracting
return 1;
}
static void
xdtoa(Fmt *fmt, char *s2, double f)
{
char s1[NSIGNIF+10];
double g, h;
int e, d, i, n;
int c1, c2, c3, c4, ucase, sign, chr, prec;
prec = FDEFLT;
if(fmt->flags & FmtPrec)
prec = fmt->prec;
if(prec > FDIGIT)
prec = FDIGIT;
if(isNaN(f)) {
strcpy(s2, "NaN");
return;
}
if(isInf(f, 1)) {
strcpy(s2, "+Inf");
return;
}
if(isInf(f, -1)) {
strcpy(s2, "-Inf");
return;
}
sign = 0;
if(f < 0) {
f = -f;
sign++;
}
ucase = 0;
chr = fmt->r;
if(isupper(chr)) {
ucase = 1;
chr = tolower(chr);
}
e = 0;
g = f;
if(g != 0) {
frexp(f, &e);
e = e * .301029995664;
if(e >= -150 && e <= +150) {
d = 0;
h = f;
} else {
d = e/2;
h = f * pow10(-d);
}
g = h * pow10(d-e);
while(g < 1) {
e--;
g = h * pow10(d-e);
}
while(g >= 10) {
e++;
g = h * pow10(d-e);
}
}
/*
* convert NSIGNIF digits and convert
* back to get accuracy.
*/
for(i=0; i<NSIGNIF; i++) {
d = g;
s1[i] = d + '0';
g = (g - d) * 10;
}
s1[i] = 0;
/*
* try decimal rounding to eliminate 9s
*/
c2 = prec + 1;
if(chr == 'f')
c2 += e;
if(c2 >= NSIGNIF-2) {
strcpy(s2, s1);
d = e;
s1[NSIGNIF-2] = '0';
s1[NSIGNIF-1] = '0';
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
g = strtod(s1, nil);
if(g == f)
goto found;
if(xadd(s1, NSIGNIF-3, 1)) {
e++;
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
}
g = strtod(s1, nil);
if(g == f)
goto found;
strcpy(s1, s2);
e = d;
}
/*
* convert back so s1 gets exact answer
*/
for(;;) {
sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
g = strtod(s1, nil);
if(f > g) {
if(xadd(s1, NSIGNIF-1, 1))
e--;
continue;
}
if(f < g) {
if(xsub(s1, NSIGNIF-1, 1))
e++;
continue;
}
break;
}
found:
/*
* sign
*/
d = 0;
i = 0;
if(sign)
s2[d++] = '-';
else if(fmt->flags & FmtSign)
s2[d++] = '+';
else if(fmt->flags & FmtSpace)
s2[d++] = ' ';
/*
* copy into final place
* c1 digits of leading '0'
* c2 digits from conversion
* c3 digits of trailing '0'
* c4 digits after '.'
*/
c1 = 0;
c2 = prec + 1;
c3 = 0;
c4 = prec;
switch(chr) {
default:
if(xadd(s1, c2, 5))
e++;
break;
case 'g':
/*
* decide on 'e' of 'f' style convers
*/
if(xadd(s1, c2, 5))
e++;
if(e >= -5 && e <= prec) {
c1 = -e - 1;
c4 = prec - e;
chr = 'h'; // flag for 'f' style
}
break;
case 'f':
if(xadd(s1, c2+e, 5))
e++;
c1 = -e;
if(c1 > prec)
c1 = c2;
c2 += e;
break;
}
/*
* clean up c1 c2 and c3
*/
if(c1 < 0)
c1 = 0;
if(c2 < 0)
c2 = 0;
if(c2 > NSIGNIF) {
c3 = c2-NSIGNIF;
c2 = NSIGNIF;
}
/*
* copy digits
*/
while(c1 > 0) {
if(c1+c2+c3 == c4)
s2[d++] = '.';
s2[d++] = '0';
c1--;
}
while(c2 > 0) {
if(c2+c3 == c4)
s2[d++] = '.';
s2[d++] = s1[i++];
c2--;
}
while(c3 > 0) {
if(c3 == c4)
s2[d++] = '.';
s2[d++] = '0';
c3--;
}
/*
* strip trailing '0' on g conv
*/
if(fmt->flags & FmtSharp) {
if(0 == c4)
s2[d++] = '.';
} else
if(chr == 'g' || chr == 'h') {
for(n=d-1; n>=0; n--)
if(s2[n] != '0')
break;
for(i=n; i>=0; i--)
if(s2[i] == '.') {
d = n;
if(i != n)
d++;
break;
}
}
if(chr == 'e' || chr == 'g') {
if(ucase)
s2[d++] = 'E';
else
s2[d++] = 'e';
c1 = e;
if(c1 < 0) {
s2[d++] = '-';
c1 = -c1;
} else
s2[d++] = '+';
if(c1 >= 100) {
s2[d++] = c1/100 + '0';
c1 = c1%100;
}
s2[d++] = c1/10 + '0';
s2[d++] = c1%10 + '0';
}
s2[d] = 0;
}
int
_floatfmt(Fmt *fmt, double f)
{
char s[1+NEXP10+1+FDIGIT+1];
/*
* The max length of a %f string is
* '[+-]'+"max exponent"+'.'+"max precision"+'\0'
* which is 341 currently.
*/
xdtoa(fmt, s, f);
fmt->flags &= FmtWidth|FmtLeft;
_fmtcpy(fmt, s, strlen(s), strlen(s));
return 0;
}
int
_efgfmt(Fmt *f)
{
double d;
d = va_arg(f->args, double);
return _floatfmt(f, d);
}

227
sys/src/libc/fmt/fmt.c Normal file
View File

@ -0,0 +1,227 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
enum
{
Maxfmt = 64
};
typedef struct Convfmt Convfmt;
struct Convfmt
{
int c;
volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
};
struct
{
/* lock by calling _fmtlock, _fmtunlock */
int nfmt;
Convfmt fmt[Maxfmt];
} fmtalloc;
static Convfmt knownfmt[] = {
' ', _flagfmt,
'#', _flagfmt,
'%', _percentfmt,
'+', _flagfmt,
',', _flagfmt,
'-', _flagfmt,
'C', _runefmt,
'E', _efgfmt,
'G', _efgfmt,
'S', _runesfmt,
'X', _ifmt,
'b', _ifmt,
'c', _charfmt,
'd', _ifmt,
'e', _efgfmt,
'f', _efgfmt,
'g', _efgfmt,
'h', _flagfmt,
'l', _flagfmt,
'n', _countfmt,
'o', _ifmt,
'p', _ifmt,
'r', errfmt,
's', _strfmt,
'u', _flagfmt,
'x', _ifmt,
0, nil,
};
int (*doquote)(int);
/*
* _fmtlock() must be set
*/
static int
_fmtinstall(int c, Fmts f)
{
Convfmt *p, *ep;
if(c<=0 || c>=65536)
return -1;
if(!f)
f = _badfmt;
ep = &fmtalloc.fmt[fmtalloc.nfmt];
for(p=fmtalloc.fmt; p<ep; p++)
if(p->c == c)
break;
if(p == &fmtalloc.fmt[Maxfmt])
return -1;
p->fmt = f;
if(p == ep){ /* installing a new format character */
fmtalloc.nfmt++;
p->c = c;
}
return 0;
}
int
fmtinstall(int c, Fmts f)
{
int ret;
_fmtlock();
ret = _fmtinstall(c, f);
_fmtunlock();
return ret;
}
static Fmts
fmtfmt(int c)
{
Convfmt *p, *ep;
ep = &fmtalloc.fmt[fmtalloc.nfmt];
for(p=fmtalloc.fmt; p<ep; p++)
if(p->c == c){
while(p->fmt == nil) /* loop until value is updated */
;
return p->fmt;
}
/* is this a predefined format char? */
_fmtlock();
for(p=knownfmt; p->c; p++)
if(p->c == c){
_fmtinstall(p->c, p->fmt);
_fmtunlock();
return p->fmt;
}
_fmtunlock();
return _badfmt;
}
void*
_fmtdispatch(Fmt *f, const void *fmt, int isrunes)
{
Rune rune, r;
int i, n, w, p;
uint32_t fl;
const void *ret;
w = f->width;
p = f->prec;
fl = f->flags;
f->flags = 0;
f->width = f->prec = 0;
for(;;){
if(isrunes){
r = *(Rune*)fmt;
fmt = (Rune*)fmt + 1;
}else{
fmt = (char*)fmt + chartorune(&rune, fmt);
r = rune;
}
f->r = r;
switch(r){
case '\0':
ret = nil;
goto end;
case '.':
f->flags |= FmtWidth|FmtPrec;
continue;
case '0':
if(!(f->flags & FmtWidth)){
f->flags |= FmtZero;
continue;
}
/* fall through */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
i = 0;
while(r >= '0' && r <= '9'){
i = i * 10 + r - '0';
if(isrunes){
r = *(Rune*)fmt;
fmt = (Rune*)fmt + 1;
}else{
r = *(char*)fmt;
fmt = (char*)fmt + 1;
}
}
if(isrunes)
fmt = (Rune*)fmt - 1;
else
fmt = (char*)fmt - 1;
numflag:
if(f->flags & FmtWidth){
f->flags |= FmtPrec;
f->prec = i;
}else{
f->flags |= FmtWidth;
f->width = i;
}
continue;
case '*':
i = va_arg(f->args, int);
if(i < 0){
/*
* negative precision =>
* ignore the precision.
*/
if(f->flags & FmtPrec){
f->flags &= ~FmtPrec;
f->prec = 0;
continue;
}
i = -i;
f->flags |= FmtLeft;
}
goto numflag;
}
n = (*fmtfmt(r))(f);
if(n < 0){
ret = nil;
break;
}
if(n == 0){
ret = fmt;
break;
}
}
end:
f->width = w;
f->prec = p;
f->flags = fl;
return (void*)ret;
}

94
sys/src/libc/fmt/fmtdef.h Normal file
View File

@ -0,0 +1,94 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* dofmt -- format to a buffer
* the number of characters formatted is returned,
* or -1 if there was an error.
* if the buffer is ever filled, flush is called.
* it should reset the buffer and return whether formatting should continue.
*/
typedef int (*Fmts)(Fmt*);
typedef struct Quoteinfo Quoteinfo;
struct Quoteinfo
{
int quoted; /* if set, string must be quoted */
int nrunesin; /* number of input runes that can be accepted */
int nbytesin; /* number of input bytes that can be accepted */
int nrunesout; /* number of runes that will be generated */
int nbytesout; /* number of bytes that will be generated */
};
void *_fmtflush(Fmt*, void*, int);
void *_fmtdispatch(Fmt*, const void*, int);
int _floatfmt(Fmt*, double);
int _fmtpad(Fmt*, int);
int _rfmtpad(Fmt*, int);
int _fmtFdFlush(Fmt*);
int _efgfmt(Fmt*);
int _charfmt(Fmt*);
int _countfmt(Fmt*);
int _flagfmt(Fmt*);
int _percentfmt(Fmt*);
int _ifmt(Fmt*);
int _runefmt(Fmt*);
int _runesfmt(Fmt*);
int _strfmt(Fmt*);
int _badfmt(Fmt*);
int _fmtcpy(Fmt*, const void*, int, int);
int _fmtrcpy(Fmt*, const void*, int n);
void _fmtlock(void);
void _fmtunlock(void);
#define FMTCHAR(f, t, s, c)\
do{\
if(t + 1 > (char*)s){\
t = _fmtflush(f, t, 1);\
if(t != nil)\
s = f->stop;\
else\
return -1;\
}\
*t++ = c;\
}while(0)
#define FMTRCHAR(f, t, s, c)\
do{\
if(t + 1 > (Rune*)s){\
t = _fmtflush(f, t, sizeof(Rune));\
if(t != nil)\
s = f->stop;\
else\
return -1;\
}\
*t++ = c;\
}while(0)
#define FMTRUNE(f, t, s, r)\
do{\
Rune _rune;\
int _runelen;\
if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
t = _fmtflush(f, t, _runelen);\
if(t != nil)\
s = f->stop;\
else\
return -1;\
}\
if(r < Runeself)\
*t++ = r;\
else{\
_rune = r;\
t += runetochar(t, &_rune);\
}\
}while(0)

40
sys/src/libc/fmt/fmtfd.c Normal file
View File

@ -0,0 +1,40 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
/*
* public routine for final flush of a formatting buffer
* to a file descriptor; returns total char count.
*/
int
fmtfdflush(Fmt *f)
{
if(_fmtFdFlush(f) <= 0)
return -1;
return f->nfmt;
}
/*
* initialize an output buffer for buffered printing
*/
int
fmtfdinit(Fmt *f, int fd, char *buf, int size)
{
f->runes = 0;
f->start = buf;
f->to = buf;
f->stop = buf + size;
f->flush = _fmtFdFlush;
f->farg = (void*)(uintptr_t)fd;
f->nfmt = 0;
return 0;
}

View File

@ -0,0 +1,25 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
static Lock fmtl;
void
_fmtlock(void)
{
lock(&fmtl);
}
void
_fmtunlock(void)
{
unlock(&fmtl);
}

View File

@ -0,0 +1,30 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
/*
* format a string into the output buffer
* designed for formats which themselves call fmt
*/
int
fmtprint(Fmt *f, const char *fmt, ...)
{
va_list va;
int n;
va_start(va, fmt);
n = fmtvprint(f, fmt, va);
va_end(va);
return n;
}

259
sys/src/libc/fmt/fmtquote.c Normal file
View File

@ -0,0 +1,259 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
/*
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
* How many runes? How much of the input will be consumed?
* The parameter q is filled in by _quotesetup.
* The string may be UTF or Runes (s or r).
* Return count does not include NUL.
* Terminate the scan at the first of:
* NUL in input
* count exceeded in input
* count exceeded on output
* *ninp is set to number of input bytes accepted.
* nin may be <0 initially, to avoid checking input by count.
*/
void
_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q,
int sharp, int runesout)
{
int w;
Rune c;
q->quoted = 0;
q->nbytesout = 0;
q->nrunesout = 0;
q->nbytesin = 0;
q->nrunesin = 0;
if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
if(nout < 2)
return;
q->quoted = 1;
q->nbytesout = 2;
q->nrunesout = 2;
}
for(; nin!=0; nin--){
if(s)
w = chartorune(&c, s);
else{
c = *r;
w = runelen(c);
}
if(c == '\0')
break;
if(runesout){
if(q->nrunesout+1 > nout)
break;
}else{
if(q->nbytesout+w > nout)
break;
}
if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
if(!q->quoted){
if(runesout){
if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
break;
}else{
if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
break;
}
q->nrunesout += 2; /* include quotes */
q->nbytesout += 2; /* include quotes */
q->quoted = 1;
}
if(c == '\'') {
if(runesout){
if(1+q->nrunesout+1 > nout) /* no room for quotes */
break;
}else{
if(1+q->nbytesout+w > nout) /* no room for quotes */
break;
}
q->nbytesout++;
q->nrunesout++; /* quotes reproduce as two characters */
}
}
/* advance input */
if(s)
s += w;
else
r++;
q->nbytesin += w;
q->nrunesin++;
/* advance output */
q->nbytesout += w;
q->nrunesout++;
}
}
static int
qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
{
Rune r, *rm, *rme;
char *t, *s, *m, *me;
Rune *rt, *rs;
uint32_t fl;
int nc, w;
m = sin;
me = m + q->nbytesin;
rm = rin;
rme = rm + q->nrunesin;
w = f->width;
fl = f->flags;
if(f->runes){
if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0)
return -1;
}else{
if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0)
return -1;
}
t = f->to;
s = f->stop;
rt = f->to;
rs = f->stop;
if(f->runes)
FMTRCHAR(f, rt, rs, '\'');
else
FMTRUNE(f, t, s, '\'');
for(nc = q->nrunesin; nc > 0; nc--){
if(sin){
r = *(uint8_t*)m;
if(r < Runeself)
m++;
else if((me - m) >= UTFmax || fullrune(m, me-m))
m += chartorune(&r, m);
else
break;
}else{
if(rm >= rme)
break;
r = *(uint8_t*)rm++;
}
if(f->runes){
FMTRCHAR(f, rt, rs, r);
if(r == '\'')
FMTRCHAR(f, rt, rs, r);
}else{
FMTRUNE(f, t, s, r);
if(r == '\'')
FMTRUNE(f, t, s, r);
}
}
if(f->runes){
FMTRCHAR(f, rt, rs, '\'');
USED(rs);
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
return -1;
}else{
FMTRUNE(f, t, s, '\'');
USED(s);
f->nfmt += t - (char *)f->to;
f->to = t;
if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
return -1;
}
return 0;
}
int
_quotestrfmt(int runesin, Fmt *f)
{
int nin, outlen;
Rune *r;
char *s;
Quoteinfo q;
nin = -1;
if(f->flags&FmtPrec)
nin = f->prec;
if(runesin){
r = va_arg(f->args, Rune *);
s = nil;
}else{
s = va_arg(f->args, char *);
r = nil;
}
if(!s && !r)
return _fmtcpy(f, "<nil>", 5, 5);
if(f->flush)
outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
else if(f->runes)
outlen = (Rune*)f->stop - (Rune*)f->to;
else
outlen = (char*)f->stop - (char*)f->to;
_quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
if(runesin){
if(!q.quoted)
return _fmtrcpy(f, r, q.nrunesin);
return qstrfmt(nil, r, &q, f);
}
if(!q.quoted)
return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
return qstrfmt(s, nil, &q, f);
}
int
quotestrfmt(Fmt *f)
{
return _quotestrfmt(0, f);
}
int
quoterunestrfmt(Fmt *f)
{
return _quotestrfmt(1, f);
}
void
quotefmtinstall(void)
{
fmtinstall('q', quotestrfmt);
fmtinstall('Q', quoterunestrfmt);
}
int
_needsquotes(char *s, int *quotelenp)
{
Quoteinfo q;
_quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
*quotelenp = q.nbytesout;
return q.quoted;
}
int
_runeneedsquotes(Rune *r, int *quotelenp)
{
Quoteinfo q;
_quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
*quotelenp = q.nrunesout;
return q.quoted;
}

View File

@ -0,0 +1,34 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
int
fmtrune(Fmt *f, int r)
{
Rune *rt;
char *t;
int n;
if(f->runes){
rt = f->to;
FMTRCHAR(f, rt, f->stop, r);
f->to = rt;
n = 1;
}else{
t = f->to;
FMTRUNE(f, t, f->stop, r);
n = t - (char*)f->to;
f->to = t;
}
f->nfmt += n;
return 0;
}

20
sys/src/libc/fmt/fmtstr.c Normal file
View File

@ -0,0 +1,20 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
char*
fmtstrflush(Fmt *f)
{
if(f->start == nil)
return nil;
*(char*)f->to = '\0';
return f->start;
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
/*
* format a string into the output buffer
* designed for formats which themselves call fmt
*/
int
fmtvprint(Fmt *f, const char *fmt, va_list args)
{
va_list va;
int n;
//va = f->args;
//f->args = args;
va_copy(va,f->args);
va_end(f->args);
va_copy(f->args,args);
n = dofmt(f, fmt);
va_end(f->args);
va_copy(f->args,va);
va_end(va);
//f->args = va;
if(n >= 0)
return 0;
return n;
}

23
sys/src/libc/fmt/fprint.c Normal file
View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
fprint(int fd, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vfprint(fd, fmt, args);
va_end(args);
return n;
}

23
sys/src/libc/fmt/print.c Normal file
View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
print(const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vfprint(1, fmt, args);
va_end(args);
return n;
}

View File

@ -0,0 +1,20 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
Rune*
runefmtstrflush(Fmt *f)
{
if(f->start == nil)
return nil;
*(Rune*)f->to = '\0';
return f->start;
}

View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
Rune*
runeseprint(Rune *buf, Rune *e, const char *fmt, ...)
{
Rune *p;
va_list args;
va_start(args, fmt);
p = runevseprint(buf, e, fmt, args);
va_end(args);
return p;
}

View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
Rune*
runesmprint(const char *fmt, ...)
{
va_list args;
Rune *p;
va_start(args, fmt);
p = runevsmprint(fmt, args);
va_end(args);
return p;
}

View File

@ -0,0 +1,24 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
runesnprint(Rune *buf, int len, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = runevsnprint(buf, len, fmt, args);
va_end(args);
return n;
}

View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
runesprint(Rune *buf, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = runevsnprint(buf, 256, fmt, args);
va_end(args);
return n;
}

View File

@ -0,0 +1,34 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
Rune*
runevseprint(Rune *buf, Rune *e, const char *fmt, va_list args)
{
Fmt f;
if(e <= buf)
return nil;
f.runes = 1;
f.start = buf;
f.to = buf;
f.stop = e - 1;
f.flush = nil;
f.farg = nil;
f.nfmt = 0;
//f.args = args;
va_copy(f.args,args);
dofmt(&f, fmt);
va_end(f.args);
*(Rune*)f.to = '\0';
return f.to;
}

View File

@ -0,0 +1,83 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
static int
runeFmtStrFlush(Fmt *f)
{
Rune *s;
int n;
if(f->start == nil)
return 0;
n = (int)(uintptr)f->farg;
n *= 2;
s = f->start;
f->start = realloc(s, sizeof(Rune)*n);
if(f->start == nil){
f->farg = nil;
f->to = nil;
f->stop = nil;
free(s);
return 0;
}
f->farg = (void*)(uintptr_t)n;
f->to = (Rune*)f->start + ((Rune*)f->to - s);
f->stop = (Rune*)f->start + n - 1;
return 1;
}
int
runefmtstrinit(Fmt *f)
{
int n;
memset(f, 0, sizeof *f);
f->runes = 1;
n = 32;
f->start = malloc(sizeof(Rune)*n);
if(f->start == nil)
return -1;
setmalloctag(f->start, getcallerpc());
f->to = f->start;
f->stop = (Rune*)f->start + n - 1;
f->flush = runeFmtStrFlush;
f->farg = (void*)(uintptr_t)n;
f->nfmt = 0;
return 0;
}
/*
* print into an allocated string buffer
*/
Rune*
runevsmprint(const char *fmt, va_list args)
{
Fmt f;
int n;
if(runefmtstrinit(&f) < 0)
return nil;
//f.args = args;
va_copy(f.args,args);
n = dofmt(&f, fmt);
va_end(f.args);
if(f.start == nil) /* realloc failed? */
return nil;
if(n < 0){
free(f.start);
return nil;
}
setmalloctag(f.start, getcallerpc());
*(Rune*)f.to = '\0';
return f.start;
}

View File

@ -0,0 +1,33 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
runevsnprint(Rune *buf, int len, const char *fmt, va_list args)
{
Fmt f;
if(len <= 0)
return -1;
f.runes = 1;
f.start = buf;
f.to = buf;
f.stop = buf + len - 1;
f.flush = nil;
f.farg = nil;
f.nfmt = 0;
//f.args = args;
va_copy(f.args,args);
dofmt(&f, fmt);
va_end(f.args);
*(Rune*)f.to = '\0';
return (Rune*)f.to - buf;
}

View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
char*
seprint(char *buf, char *e, const char *fmt, ...)
{
char *p;
va_list args;
va_start(args, fmt);
p = vseprint(buf, e, fmt, args);
va_end(args);
return p;
}

View File

@ -0,0 +1,24 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
char*
smprint(const char *fmt, ...)
{
va_list args;
char *p;
va_start(args, fmt);
p = vsmprint(fmt, args);
va_end(args);
setmalloctag(p, getcallerpc());
return p;
}

View File

@ -0,0 +1,24 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
snprint(char *buf, int len, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vsnprint(buf, len, fmt, args);
va_end(args);
return n;
}

23
sys/src/libc/fmt/sprint.c Normal file
View File

@ -0,0 +1,23 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
sprint(char *buf, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vsnprint(buf, 65536, fmt, args); /* big number, but sprint is deprecated anyway */
va_end(args);
return n;
}

View File

@ -0,0 +1,45 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
/*
* generic routine for flushing a formatting buffer
* to a file descriptor
*/
int
_fmtFdFlush(Fmt *f)
{
int n;
n = (char*)f->to - (char*)f->start;
if(n && write((int)(uintptr)f->farg, f->start, n) != n)
return 0;
f->to = f->start;
return 1;
}
int
vfprint(int fd, const char *fmt, va_list args)
{
Fmt f;
char buf[256];
int n;
fmtfdinit(&f, fd, buf, sizeof(buf));
//f.args = args;
va_copy(f.args,args);
n = dofmt(&f, fmt);
va_end(f.args);
if(n > 0 && _fmtFdFlush(&f) == 0)
return -1;
return n;
}

View File

@ -0,0 +1,34 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
char*
vseprint(char *buf, char *e, const char *fmt, va_list args)
{
Fmt f;
if(e <= buf)
return nil;
f.runes = 0;
f.start = buf;
f.to = buf;
f.stop = e - 1;
f.flush = nil;
f.farg = nil;
f.nfmt = 0;
//f.args = args;
va_copy(f.args,args);
dofmt(&f, fmt);
va_end(f.args);
*(char*)f.to = '\0';
return f.to;
}

View File

@ -0,0 +1,85 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "fmtdef.h"
static int
fmtStrFlush(Fmt *f)
{
char *s;
int n;
if(f->start == nil)
return 0;
n = (int)(uintptr)f->farg;
n *= 2;
s = f->start;
f->start = realloc(s, n);
if(f->start == nil){
f->farg = nil;
f->to = nil;
f->stop = nil;
free(s);
return 0;
}
f->farg = (void*)(uintptr_t)n;
f->to = (char*)f->start + ((char*)f->to - s);
f->stop = (char*)f->start + n - 1;
return 1;
}
int
fmtstrinit(Fmt *f)
{
int n;
memset(f, 0, sizeof *f);
f->runes = 0;
n = 32;
/* this should not be necessary */
n = 4096;
f->start = malloc(n);
if(f->start == nil)
return -1;
setmalloctag(f->start, getcallerpc());
f->to = f->start;
f->stop = (char*)f->start + n - 1;
f->flush = fmtStrFlush;
f->farg = (void*)(uintptr_t)n;
f->nfmt = 0;
return 0;
}
/*
* print into an allocated string buffer
*/
char*
vsmprint(const char *fmt, va_list args)
{
Fmt f;
int n;
if(fmtstrinit(&f) < 0)
return nil;
//f.args = args;
va_copy(f.args,args);
n = dofmt(&f, fmt);
va_end(f.args);
if(f.start == nil) /* realloc failed? */
return nil;
if(n < 0){
free(f.start);
return nil;
}
setmalloctag(f.start, getcallerpc());
*(char*)f.to = '\0';
return f.start;
}

View File

@ -0,0 +1,33 @@
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
int
vsnprint(char *buf, int len, const char *fmt, va_list args)
{
Fmt f;
if(len <= 0)
return -1;
f.runes = 0;
f.start = buf;
f.to = buf;
f.stop = buf + len - 1;
f.flush = nil;
f.farg = nil;
f.nfmt = 0;
//f.args = args;
va_copy(f.args,args);
dofmt(&f, fmt);
va_end(f.args);
*(char*)f.to = '\0';
return (char*)f.to - buf;
}

Some files were not shown because too many files have changed in this diff Show More