Merge branch 'wip'

Conflicts:
	README.md
This commit is contained in:
Giacomo Tesio 2016-01-06 18:04:50 +01:00
commit 391252a059
231 changed files with 21004 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
arch/amd64/bin
arch/amd64/kern
arch/amd64/lib
sys/log
sys/src/9/port/error.h
sys/src/9/root/nvram
*.orig
*_orig
*.rej
*~
*.o
o.*
*.a
*.ao
*.out
9pccpuf
cfg/pxe/tftpboot

4
.gitmodules vendored Normal file
View File

@ -0,0 +1,4 @@
[submodule "hacking"]
path = hacking
url = https://github.com/JehanneOS/devtools.git
branch = master

29
.travis.yml Normal file
View File

@ -0,0 +1,29 @@
language: c
install:
- git submodule init
- git submodule update --init --recursive --remote
- ./hacking/buildtools.sh
script:
- ./hacking/continuous-build.sh
compiler:
- gcc-4.8
env:
global:
- ARCH=amd64
- JEHANNE=$TRAVIS_BUILD_DIR
- PATH=$PATH:$JEHANNE/hacking/bin
- secure: eu81pAD2iXg3b/rm9VYf+8bnlg09IpXdw/WMNeiXqxULCoNZI/1N7oEmLSBvqI068x+mzr6eT0P1C8zVm3wxhTSWs2JKzF0klIe4Tj0S2CjSGDx1GenO2zDdH9mSCvnx8a6xvNzms8O3xOGbV4jzolmckJYi2mLqZwtIxmShMijj8Ou046IMXhchEGFd5bx6rwN01OhFcTUVIHS73CMzZJQxXpT5zjuVDXKSnuX3BnTGHCTNNyoVmnomuvwNZmUch0q/SI8tlYzhsQrz77aZXMBkVqpFM5aTE/fOwgmwEf0Gc8kwa3YtQboxPxlXafn4ygVczMUI9mIXS2ql7ek1Mptxsx3IJUiou9iG31IhN7Pi7DyTIwGTcG6FvDw73oOL3zUY+DTfipNVDaN1GTM8ZPWJ0A/s7V9M+7sUqRyJ4sTpjPtPEmCBtDSDfFIXpq54LcjHAGyTjqveCcm/Wn2kTpxrABrQxPGVLbrGgT7dsZx6eD/vIfgbhKLj6NZUyWoDhErv0NFX7ZIG6brsvHAcY7YLu/NlW398VzwTgu38Fy180TRT/zrhxfTvsnhnrN0Jn/kr60CSXi8Fh1yaMl1vY6tcf662mGoX+pwvobGEJzDJYfMWkLjjq02jbV+nd7VkB3B9vgJtV1xfroGH2gN94iFZxg6FLwBpONWHbmh/JjY=
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- rc
- gcc-4.8
coverity_scan:
project:
name: JehanneOS/jehanne
description: Build submitted via Travis CI
notification_email: jehanneos@googlegroups.com
build_command: "build"
branch_pattern: coverity_scan

View File

@ -1,3 +1,6 @@
[![Build Status](https://api.travis-ci.org/JehanneOS/jehanne.svg?branch=master)](https://travis-ci.org/JehanneOS/jehanne)
[![Coverity Badge](https://scan.coverity.com/projects/7364/badge.svg)](https://scan.coverity.com/projects/jehanne)
# Jehanne
Jehanne is a [simple][simplicity] operating system.
@ -9,8 +12,70 @@ they are at odds with its goals.
For this reason project is named after the famous French heretic [Joan of Arc][arc].
## Overview
This is the main repository, used to build the system as a whole:
- [arch](./arch/) contains one folder for each
supported architecture, with specific C headers and binaries
- [sys](./sys) is the system folder
* [include](./sys/include) contains portable C headers
* [lib](./sys/lib) contains data and scripts used by the
running system
* [man](./sys/man) contains manual pages
* [src](./sys/src) contains the sources of the system
- [doc](./doc/) contains useful documentation for Jehanne
development
* [license](./doc/license/) contains detailed info
about Jehanne [licenses][lic]
* [hacking](./doc/hacking/) contains details about how
to build and modify Jehanne
- [hacking](./hacking) contains the utilities used to
develop Jehanne
- [qa](./qa) contains the regression tests
- [mnt](./mnt) contains default mount targets
- [usr](./usr) contains the users' folders
- [pkgs](./pkgs) will contains the installed packages
The running system also includes supplemental folders like `/lib`,
`/bin` and `/dev` that are bound during the boot as required.
## Build
To build Jehanne and play with it, you need to have git, golang, qemu,
gcc, binutils and bison installed.
For example on Debian GNU/Linux you should be able to get going with
sudo aptitude install git golang build-essential bison qemu-system
After the repository clone, you can give a look with
git submodule init # we have a lot of submodules
git submodule update --init --recursive --remote
./hacking/devshell.sh # start a shell with appropriate environment
./hacking/continuous-build.sh # to build everything
./hacking/runOver9P.sh # to start the system in QEMU
./hacking/drawterm.sh # to connect Jehanne with drawterm
## Hacking
Jehanne is a work in progress.
Forks and pull requests are welcome.
In [doc/hacking](./doc/hacking/) you will find all you
need to know about its principles, design and weirdness.
There's a lot of work to do, in every area of the system.
To coordinate our efforts, we use the github issues.
To discuss (and even debate) about the design and development of Jehanne
we use the [JehanneOS mailing list][mailinglist]: please join and present
yourself and your attitudes.
[simplicity]: http://plato.stanford.edu/entries/simplicity/ "What is simplicity?"
[harvey]: http://harvey-os.org "Harvey OS"
[plan9]: https://github.com/brho/plan9 "UC Berkeley release of Plan 9 under the GPLv2"
[nix]: https://github.com/rminnich/nix-os
[arc]: https://en.wikipedia.org/wiki/Joan_of_Arc "Jeanne d'Arc"
[lic]: ./LICENSE.md "A summary of Jehanne licensing"
[mailinglist]: https://groups.google.com/forum/#!forum/jehanneos

5
arch/amd64/bin/auth/disable Executable file
View File

@ -0,0 +1,5 @@
#!/bin/rc
if(test -e /mnt/keys/$1)
echo -n disabled > /mnt/keys/$1/status
if(test -e /mnt/netkeys/$1)
echo -n disabled > /mnt/netkeys/$1/status

5
arch/amd64/bin/auth/enable Executable file
View File

@ -0,0 +1,5 @@
#!/bin/rc
if(test -e /mnt/keys/$1)
echo -n ok > /mnt/keys/$1/status
if(test -e /mnt/netkeys/$1)
echo -n ok > /mnt/netkeys/$1/status

36
arch/amd64/bin/auth/status Executable file
View File

@ -0,0 +1,36 @@
#!/bin/rc
cd /mnt/keys/$1 > /dev/null >[2=1] && {
stat=`{cat status}
exp=`{cat expire}
switch($exp){
case never 0
exp='never expires'
case *
exp=(expires on `{date $exp})
}
switch($stat){
case expired
echo user $1: plan 9 key has expired
case *
echo user $1: plan 9 key status is $stat and $exp
}
grep '^'$1'[ ]' /adm/keys.who | tail -1
}
cd /mnt/netkeys/$1 > /dev/null >[2=1] && {
stat=`{cat status}
exp=`{cat expire}
switch($exp){
case never 0
exp='never expires'
case *
exp=(expires on `{date $exp})
}
switch($stat){
case expired
echo user $1: network key has expired
case *
echo user $1: network key status is $stat and $exp
auth/printnetkey $1
}
grep '^'$1'[ ]' /adm/netkeys.who | tail -1
}

View File

@ -0,0 +1,28 @@
{
"buildflags": {
"Cflags": [
"-std=c11",
"-c",
"-I/$JEHANNE/arch/$ARCH/include",
"-I/$JEHANNE/sys/include",
"-I.",
"-ffreestanding",
"-fno-builtin",
"-fno-omit-frame-pointer",
"-fplan9-extensions",
"-fvar-tracking",
"-fvar-tracking-assignments",
"-g",
"-gdwarf-2",
"-ggdb",
"-mcmodel=small",
"-mno-red-zone",
"-O0",
"-static",
"-Wall",
"-Wno-missing-braces",
"-Wno-parentheses",
"-Wno-unknown-pragmas"
]
}
}

97
arch/amd64/include/u.h Normal file
View File

@ -0,0 +1,97 @@
/*
* 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.
*/
#define nil ((void*)0)
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned int uint32_t;
typedef unsigned int uint;
typedef signed int int32_t;
typedef unsigned long long uint64_t;
typedef long long int64_t;
typedef uint64_t uintptr;
typedef uint64_t uintptr_t;
typedef uint32_t usize;
typedef int64_t size_t;
typedef uint32_t Rune;
typedef union FPdbleword FPdbleword;
typedef uintptr jmp_buf[10]; // for registers.
#define JMPBUFSP 6
#define JMPBUFPC 7
#define JMPBUFARG1 8
#define JMPBUFARG2 9
#define JMPBUFDPC 0
typedef unsigned int mpdigit; /* for /sys/include/mp.h */
/* MXCSR */
/* fcr */
#define FPFTZ (1<<15) /* amd64 */
#define FPINEX (1<<12)
#define FPUNFL (1<<11)
#define FPOVFL (1<<10)
#define FPZDIV (1<<9)
#define FPDNRM (1<<8) /* amd64 */
#define FPINVAL (1<<7)
#define FPDAZ (1<<6) /* amd64 */
#define FPRNR (0<<13)
#define FPRZ (3<<13)
#define FPRPINF (2<<13)
#define FPRNINF (1<<13)
#define FPRMASK (3<<13)
#define FPPEXT 0
#define FPPSGL 0
#define FPPDBL 0
#define FPPMASK 0
/* fsr */
#define FPAINEX (1<<5)
#define FPAUNFL (1<<4)
#define FPAOVFL (1<<3)
#define FPAZDIV (1<<2)
#define FPADNRM (1<<1) /* not in plan 9 */
#define FPAINVAL (1<<0)
union FPdbleword
{
double x;
struct { /* little endian */
uint lo;
uint hi;
};
};
/*
#if 0
typedef char* va_list;
#define va_start(list, start) list =\
(sizeof(start) < 8?\
(char*)((int64_t*)&(start)+1):\
(char*)(&(start)+1))
#define va_end(list)\
USED(list)
#define va_arg(list, mode)\
((sizeof(mode) == 1)?\
((list += 8), (mode*)list)[-8]:\
(sizeof(mode) == 2)?\
((list += 8), (mode*)list)[-4]:\
(sizeof(mode) == 4)?\
((list += 8), (mode*)list)[-2]:\
((list += sizeof(mode)), (mode*)list)[-1])
#endif
*/
typedef __builtin_va_list va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
#define va_copy(v,l) __builtin_va_copy(v,l)

42
arch/amd64/include/ureg.h Normal file
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.
*/
struct Ureg {
uint64_t ax;
uint64_t bx;
uint64_t cx;
uint64_t dx;
uint64_t si;
uint64_t di;
uint64_t bp;
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
// these are pointless and I don't want to waste a second on them.
// I'm sure it will break something but let's see.
// Not pushing them simplifies the interrupt handler a lot.
// uint16_t ds;
// uint16_t es;
// uint16_t fs;
// uint16_t gs;
uint64_t type;
uint64_t error; /* error code (or zero) */
uint64_t ip; /* pc */
uint64_t cs; /* old context */
uint64_t flags; /* old flags */
uint64_t sp; /* sp */
uint64_t ss; /* old stack segment */
};

8
build.json Normal file
View File

@ -0,0 +1,8 @@
{
"all": {
"Projects": [
"/sys/src/klibs.json",
"/sys/src/libs.json"
]
}
}

1
hacking Submodule

@ -0,0 +1 @@
Subproject commit 6cc262b43b1d5630c73f079872a260c8d0cd5e0e

2
mnt/acme/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
mnt/temp/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
mnt/term/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
mnt/wsys/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

3
pkgs/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!.gitignore
!README.md

6
pkgs/README.md Normal file
View File

@ -0,0 +1,6 @@
# Jehanne packages
In this folder you find the packages installed in your system.
For each installed package you find a folder named after the package.
Inside such folder you find one folder for each version installed.

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;
}

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