rename libc to libjehanne; improve libposix
This is to avoid conflicts between standards' assumptions and Jehanne's choices
This commit is contained in:
1
sys/src/lib/jehanne/.gitignore
vendored
Normal file
1
sys/src/lib/jehanne/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
amd64/syscalls.c
|
60
sys/src/lib/jehanne/9sys/access.c
Normal file
60
sys/src/lib/jehanne/9sys/access.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016-2017 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
|
||||
jehanne_access(const char *name, int mode)
|
||||
{
|
||||
int fd, reqmode;
|
||||
|
||||
static char omode[] = {
|
||||
OSTAT,
|
||||
OEXEC,
|
||||
OWRITE,
|
||||
ORDWR,
|
||||
OREAD,
|
||||
OEXEC, /* 5=4+1 READ|EXEC, EXEC is enough */
|
||||
ORDWR,
|
||||
ORDWR /* 7=4+2+1 READ|WRITE|EXEC, ignore EXEC */
|
||||
};
|
||||
|
||||
reqmode = omode[mode&AMASK];
|
||||
fd = sys_open(name, reqmode);
|
||||
if(fd >= 0){
|
||||
sys_close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* WARNING:
|
||||
*
|
||||
* In Plan 9 access(AWRITE) and access(AEXEC) in directories
|
||||
* fail despite the actual permission of the directory.
|
||||
*
|
||||
* This is well understood in Plan 9, but it's counter intuitive.
|
||||
*
|
||||
* In Plan 9, to create a file in a directory you need write
|
||||
* permission in the directory. Still you don't need to (and you
|
||||
* cannot) open the directory for writing before calling create.
|
||||
*
|
||||
* To my eyes this is a UNIX inheritance that could be "fixed"
|
||||
* but there are some trade off.
|
||||
*/
|
||||
return -1;
|
||||
}
|
284
sys/src/lib/jehanne/9sys/announce.c
Normal file
284
sys/src/lib/jehanne/9sys/announce.c
Normal 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
|
||||
jehanne_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 = sys_open(netdir, ORDWR);
|
||||
if(ctl<0){
|
||||
jehanne_werrstr("announce opening %s: %r", netdir);
|
||||
return -1;
|
||||
}
|
||||
cp = jehanne_strrchr(netdir, '/');
|
||||
if(cp == nil){
|
||||
jehanne_werrstr("announce arg format %s", netdir);
|
||||
sys_close(ctl);
|
||||
return -1;
|
||||
}
|
||||
*cp = 0;
|
||||
|
||||
/*
|
||||
* find out which line we have
|
||||
*/
|
||||
n = jehanne_snprint(buf, sizeof(buf), "%s/", netdir);
|
||||
m = jehanne_read(ctl, &buf[n], sizeof(buf)-n-1);
|
||||
if(m <= 0){
|
||||
jehanne_werrstr("announce reading %s: %r", netdir);
|
||||
sys_close(ctl);
|
||||
return -1;
|
||||
}
|
||||
buf[n+m] = 0;
|
||||
|
||||
/*
|
||||
* make the call
|
||||
*/
|
||||
n = jehanne_snprint(buf2, sizeof(buf2), "announce %s", naddr);
|
||||
if(jehanne_write(ctl, buf2, n)!=n){
|
||||
jehanne_werrstr("announce writing %s: %r", netdir);
|
||||
sys_close(ctl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* return directory etc.
|
||||
*/
|
||||
if(dir){
|
||||
jehanne_strncpy(dir, buf, NETPATHLEN);
|
||||
dir[NETPATHLEN-1] = 0;
|
||||
}
|
||||
return ctl;
|
||||
}
|
||||
|
||||
/*
|
||||
* listen for an incoming call
|
||||
*/
|
||||
int
|
||||
jehanne_listen(const char *dir, char *newdir)
|
||||
{
|
||||
int ctl, n, m;
|
||||
char buf[Maxpath];
|
||||
char *cp;
|
||||
|
||||
/*
|
||||
* open listen, wait for a call
|
||||
*/
|
||||
jehanne_snprint(buf, sizeof(buf), "%s/listen", dir);
|
||||
ctl = sys_open(buf, ORDWR);
|
||||
if(ctl < 0){
|
||||
jehanne_werrstr("listen opening %s: %r", buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* find out which line we have
|
||||
*/
|
||||
jehanne_strncpy(buf, dir, sizeof(buf) - 1);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
cp = jehanne_strrchr(buf, '/');
|
||||
if(cp == nil){
|
||||
sys_close(ctl);
|
||||
jehanne_werrstr("listen arg format %s", dir);
|
||||
return -1;
|
||||
}
|
||||
*++cp = 0;
|
||||
n = cp-buf;
|
||||
m = jehanne_read(ctl, cp, sizeof(buf) - n - 1);
|
||||
if(m <= 0){
|
||||
sys_close(ctl);
|
||||
jehanne_werrstr("listen reading %s/listen: %r", dir);
|
||||
return -1;
|
||||
}
|
||||
buf[n+m] = 0;
|
||||
|
||||
/*
|
||||
* return directory etc.
|
||||
*/
|
||||
if(newdir){
|
||||
jehanne_strncpy(newdir, buf, NETPATHLEN);
|
||||
newdir[NETPATHLEN-1] = 0;
|
||||
}
|
||||
return ctl;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* accept a call, return an fd to the open data file
|
||||
*/
|
||||
int
|
||||
jehanne_accept(int ctl, const char *dir)
|
||||
{
|
||||
char buf[Maxpath];
|
||||
const char *num;
|
||||
int32_t n;
|
||||
|
||||
num = jehanne_strrchr(dir, '/');
|
||||
if(num == nil)
|
||||
num = dir;
|
||||
else
|
||||
num++;
|
||||
|
||||
n = jehanne_snprint(buf, sizeof(buf), "accept %s", num);
|
||||
jehanne_write(ctl, buf, n); /* ignore return value, network might not need accepts */
|
||||
|
||||
jehanne_snprint(buf, sizeof(buf), "%s/data", dir);
|
||||
return sys_open(buf, ORDWR);
|
||||
}
|
||||
|
||||
/*
|
||||
* reject a call, tell device the reason for the rejection
|
||||
*/
|
||||
int
|
||||
jehanne_reject(int ctl, const char *dir, const char *cause)
|
||||
{
|
||||
char buf[Maxpath];
|
||||
const char *num;
|
||||
int32_t n;
|
||||
|
||||
num = jehanne_strrchr(dir, '/');
|
||||
if(num == 0)
|
||||
num = dir;
|
||||
else
|
||||
num++;
|
||||
jehanne_snprint(buf, sizeof(buf), "reject %s %s", num, cause);
|
||||
n = jehanne_strlen(buf);
|
||||
if(jehanne_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 */
|
||||
jehanne_strncpy(proto, addr, sizeof(proto));
|
||||
proto[sizeof(proto)-1] = 0;
|
||||
p = jehanne_strchr(proto, '!');
|
||||
if(p)
|
||||
*p++ = 0;
|
||||
|
||||
jehanne_snprint(file, nf, "%s/%s/clone", netdir, proto);
|
||||
jehanne_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 = jehanne_strchr(addr, '!');
|
||||
if(p == 0){
|
||||
jehanne_werrstr("bad dial string: %s", addr);
|
||||
return -1;
|
||||
}
|
||||
if(*addr != '/'){
|
||||
jehanne_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)){
|
||||
jehanne_werrstr("bad dial string: %s", addr);
|
||||
return -1;
|
||||
}
|
||||
jehanne_strncpy(netdir, addr, i);
|
||||
netdir[i] = 0;
|
||||
addr = p2 + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ask the connection server
|
||||
*/
|
||||
jehanne_snprint(buf, sizeof(buf), "%s/cs", netdir);
|
||||
fd = sys_open(buf, ORDWR);
|
||||
if(fd < 0)
|
||||
return identtrans(netdir, addr, naddr, na, file, nf);
|
||||
if(jehanne_write(fd, addr, jehanne_strlen(addr)) < 0){
|
||||
sys_close(fd);
|
||||
return -1;
|
||||
}
|
||||
sys_seek(fd, 0, 0);
|
||||
n = jehanne_read(fd, buf, sizeof(buf)-1);
|
||||
sys_close(fd);
|
||||
if(n <= 0)
|
||||
return -1;
|
||||
buf[n] = 0;
|
||||
|
||||
/*
|
||||
* parse the reply
|
||||
*/
|
||||
p = jehanne_strchr(buf, ' ');
|
||||
if(p == 0)
|
||||
return -1;
|
||||
*p++ = 0;
|
||||
jehanne_strncpy(naddr, p, na);
|
||||
naddr[na-1] = 0;
|
||||
|
||||
if(buf[0] == '/'){
|
||||
p = jehanne_strchr(buf+1, '/');
|
||||
if(p == nil)
|
||||
p = buf;
|
||||
else
|
||||
p++;
|
||||
}
|
||||
jehanne_snprint(file, nf, "%s/%s", netdir, p);
|
||||
return 0;
|
||||
}
|
50
sys/src/lib/jehanne/9sys/awakened.c
Normal file
50
sys/src/lib/jehanne/9sys/awakened.c
Normal 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
|
||||
jehanne_awakened(int64_t wakeup)
|
||||
{
|
||||
/* awake returns the ticks of the scheduled wakeup in negative,
|
||||
* thus a wakeup is in the past iff (-sys_awake(0)) >= (-wakeup)
|
||||
*
|
||||
* NOTE: this is not a macro so that we can change the sys_awake()
|
||||
* implementation in the future, without affecting the client code.
|
||||
*/
|
||||
assert(wakeup < 0);
|
||||
return wakeup >= sys_awake(0);
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_forgivewkp(int64_t wakeup)
|
||||
{
|
||||
/* awake returns the ticks of the scheduled wakeup in negative,
|
||||
* and is able to remove a wakeup provided such value.
|
||||
*
|
||||
* jehanne_forgivewkp() is just a wrapper to hide sys_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 sys_awake()
|
||||
* implementation in the future, without affecting the client code.
|
||||
*/
|
||||
assert(wakeup < 0);
|
||||
return sys_awake(wakeup);
|
||||
}
|
38
sys/src/lib/jehanne/9sys/chdir.c
Normal file
38
sys/src/lib/jehanne/9sys/chdir.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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
|
||||
jehanne_chdir(const char *dirname)
|
||||
{
|
||||
char buf[32];
|
||||
int tmp, fd;
|
||||
|
||||
tmp = jehanne_getpid();
|
||||
jehanne_snprint(buf, sizeof(buf), "/proc/%d/wdir", tmp);
|
||||
fd = sys_open(buf, OWRITE);
|
||||
if(fd < 0)
|
||||
fd = sys_open("#0/wdir", OWRITE);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
tmp = jehanne_write(fd, dirname, 1+jehanne_strlen(dirname));
|
||||
sys_close(fd);
|
||||
return tmp;
|
||||
}
|
104
sys/src/lib/jehanne/9sys/convD2M.c
Normal file
104
sys/src/lib/jehanne/9sys/convD2M.c
Normal 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 <9P2000.h>
|
||||
|
||||
uint32_t
|
||||
jehanne_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 += jehanne_strlen(sv[i]);
|
||||
|
||||
return STATFIXLEN + ns;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
jehanne_convD2M(Dir *d, uint8_t *buf, uint32_t 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] = jehanne_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)
|
||||
jehanne_memmove(p, sv[i], ns);
|
||||
p += ns;
|
||||
}
|
||||
|
||||
if(ss != p - buf)
|
||||
return 0;
|
||||
|
||||
return p - buf;
|
||||
}
|
105
sys/src/lib/jehanne/9sys/convM2D.c
Normal file
105
sys/src/lib/jehanne/9sys/convM2D.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 <9P2000.h>
|
||||
|
||||
int
|
||||
statcheck(uint8_t *buf, uint32_t 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[] = "";
|
||||
|
||||
uint32_t
|
||||
jehanne_convM2D(uint8_t *buf, uint32_t 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);
|
||||
if(ns < 0)
|
||||
return 0;
|
||||
p += BIT16SZ;
|
||||
if(p + ns > ebuf)
|
||||
return 0;
|
||||
if(strs){
|
||||
sv[i] = strs;
|
||||
jehanne_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;
|
||||
}
|
25
sys/src/lib/jehanne/9sys/cputime.c
Normal file
25
sys/src/lib/jehanne/9sys/cputime.c
Normal 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
|
||||
jehanne_cputime(void)
|
||||
{
|
||||
int32_t t[4];
|
||||
int i;
|
||||
|
||||
jehanne_times(t);
|
||||
for(i=1; i<4; i++)
|
||||
t[0] += t[i];
|
||||
return t[0] / (double)HZ;
|
||||
}
|
316
sys/src/lib/jehanne/9sys/ctime.c
Normal file
316
sys/src/lib/jehanne/9sys/ctime.c
Normal 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 jehanne_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.
|
||||
*
|
||||
* jehanne_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
|
||||
*
|
||||
* jehanne_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*
|
||||
jehanne_ctime(int32_t t)
|
||||
{
|
||||
return jehanne_asctime(jehanne_localtime(t));
|
||||
}
|
||||
|
||||
Tm*
|
||||
jehanne_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 = jehanne_gmtime(t);
|
||||
if(dlflag){
|
||||
jehanne_strcpy(ct->zone, timezone.dlname);
|
||||
ct->tzoff = timezone.dldiff;
|
||||
} else {
|
||||
jehanne_strcpy(ct->zone, timezone.stname);
|
||||
ct->tzoff = timezone.stdiff;
|
||||
}
|
||||
return ct;
|
||||
}
|
||||
|
||||
Tm*
|
||||
jehanne_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;
|
||||
jehanne_strcpy(xtime.zone, "GMT");
|
||||
return &xtime;
|
||||
}
|
||||
|
||||
char*
|
||||
jehanne_asctime(Tm *t)
|
||||
{
|
||||
char *ncp;
|
||||
static char cbuf[30];
|
||||
|
||||
jehanne_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;
|
||||
|
||||
jehanne_memset(buf, 0, sizeof(buf));
|
||||
i = sys_open("/env/timezone", OREAD);
|
||||
if(i < 0)
|
||||
goto error;
|
||||
if(jehanne_read(i, buf, sizeof(buf)) >= sizeof(buf)){
|
||||
sys_close(i);
|
||||
goto error;
|
||||
}
|
||||
sys_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;
|
||||
jehanne_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;
|
||||
}
|
563
sys/src/lib/jehanne/9sys/dial.c
Normal file
563
sys/src/lib/jehanne/9sys/dial.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
|
||||
* See /doc/license/gpl-2.0.txt for details about the licensing.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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';
|
||||
sys_errstr(err, sizeof err);
|
||||
if(jehanne_strstr(err, "refused") != 0){
|
||||
jehanne_werrstr("%s", err);
|
||||
return rv;
|
||||
}
|
||||
ds.netdir = "/net.alt";
|
||||
rv = csdial(&ds);
|
||||
if(rv >= 0)
|
||||
return rv;
|
||||
|
||||
alterr[0] = 0;
|
||||
sys_errstr(alterr, sizeof alterr);
|
||||
if(jehanne_strstr(alterr, "translate") || jehanne_strstr(alterr, "does not exist"))
|
||||
jehanne_werrstr("%s", err);
|
||||
else
|
||||
jehanne_werrstr("%s", alterr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* the thread library can't cope with sys_rfork(RFMEM|RFPROC),
|
||||
* so it must override this with a private version of dial.
|
||||
*/
|
||||
int (*_dial)(const char *, const char *, char *, int *) = dialimpl;
|
||||
|
||||
int
|
||||
jehanne_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;
|
||||
|
||||
jehanne_free(dp->conn);
|
||||
dp->connend = nil;
|
||||
assert(addrs > 0);
|
||||
|
||||
dp->conn = jehanne_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;
|
||||
jehanne_free(dp->conn);
|
||||
jehanne_free(dp);
|
||||
if (oalarm >= 0)
|
||||
sys_alarm(oalarm);
|
||||
}
|
||||
|
||||
static void
|
||||
closeopenfd(int *fdp)
|
||||
{
|
||||
if (*fdp >= 0) {
|
||||
sys_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 = jehanne_tokenize(exitsts, fields, nelem(fields));
|
||||
if (n < 4)
|
||||
return;
|
||||
pid = jehanne_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);
|
||||
}
|
||||
jehanne_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) && sys_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) {
|
||||
jehanne_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)
|
||||
jehanne_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]) {
|
||||
jehanne_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 = jehanne_strchr(dp->nextaddr, ' ');
|
||||
if(dest == nil) {
|
||||
p = jehanne_strchr(dp->nextaddr, '\n');
|
||||
if(p)
|
||||
*p = '\0';
|
||||
jehanne_werrstr("malformed clone cmd from cs `%s'", dp->nextaddr);
|
||||
if(p)
|
||||
*p = '\n';
|
||||
return -1;
|
||||
}
|
||||
*dest++ = '\0';
|
||||
p = jehanne_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';
|
||||
sys_errstr(err, ERRMAX);
|
||||
if(jehanne_strstr(err, "does not exist") == 0)
|
||||
jehanne_strcpy(besterr, err);
|
||||
}
|
||||
|
||||
static int
|
||||
catcher(void *v, char *s)
|
||||
{
|
||||
return jehanne_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 = sys_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 */
|
||||
jehanne_atnotify(catcher, 1);
|
||||
|
||||
*besterr = '\0';
|
||||
rv = call(clone, dest, ds, dp, &dp->conn[kidme]);
|
||||
if(rv < 0)
|
||||
pickuperr(besterr, err);
|
||||
sys__exits(besterr); /* avoid atexit callbacks */
|
||||
}
|
||||
}
|
||||
*besterr = '\0';
|
||||
rv = connectwait(dp, besterr);
|
||||
if(rv < 0)
|
||||
jehanne_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;
|
||||
|
||||
jehanne_werrstr("");
|
||||
dp = jehanne_mallocz(sizeof *dp, 1);
|
||||
if(dp == nil)
|
||||
return -1;
|
||||
dp->winner = -1;
|
||||
dp->oalarm = sys_alarm(0);
|
||||
if (connsalloc(dp, 1) < 0) { /* room for a single conn. */
|
||||
freedest(dp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* open connection server
|
||||
*/
|
||||
jehanne_snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
|
||||
fd = sys_open(buf, ORDWR);
|
||||
if(fd < 0){
|
||||
/* no connection server, don't translate */
|
||||
jehanne_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
|
||||
*/
|
||||
jehanne_snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
|
||||
if(jehanne_write(fd, buf, jehanne_strlen(buf)) < 0){
|
||||
sys_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.
|
||||
*/
|
||||
sys_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 = jehanne_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 && jehanne_read(fd, &c, 1) == 1)
|
||||
addrs--;
|
||||
sys_close(fd);
|
||||
|
||||
*besterr = 0;
|
||||
rv = -1; /* pessimistic default */
|
||||
dp->naddrs = addrs;
|
||||
if (addrs == 0)
|
||||
jehanne_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);
|
||||
jehanne_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 = jehanne_strchr(clone+1, '/');
|
||||
if(p == nil)
|
||||
p = clone;
|
||||
else
|
||||
p++;
|
||||
} else
|
||||
p = clone;
|
||||
jehanne_snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
|
||||
|
||||
conn->pid = jehanne_getpid();
|
||||
conn->cfd = cfd = sys_open(cname, ORDWR);
|
||||
if(cfd < 0)
|
||||
return -1;
|
||||
|
||||
/* get directory name */
|
||||
n = jehanne_read(cfd, name, sizeof(name)-1);
|
||||
if(n < 0){
|
||||
closeopenfd(&conn->cfd);
|
||||
return -1;
|
||||
}
|
||||
name[n] = 0;
|
||||
for(p = name; *p == ' '; p++)
|
||||
;
|
||||
jehanne_snprint(name, sizeof(name), "%ld", jehanne_strtoul(p, 0, 0));
|
||||
p = jehanne_strrchr(cname, '/');
|
||||
*p = 0;
|
||||
if(ds->dir)
|
||||
jehanne_snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name);
|
||||
jehanne_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)
|
||||
sys_alarm(dp->oalarm);
|
||||
else if (dp->naddrs > 1) /* in a sub-process? */
|
||||
sys_alarm(Maxconnms);
|
||||
|
||||
/* connect */
|
||||
if(ds->local)
|
||||
jehanne_snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
|
||||
else
|
||||
jehanne_snprint(name, sizeof(name), "connect %s", dest);
|
||||
if(jehanne_write(cfd, name, jehanne_strlen(name)) < 0){
|
||||
closeopenfd(&conn->cfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oalarm = sys_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 = sys_open(data, ORDWR);
|
||||
if(fd < 0){
|
||||
closeopenfd(&conn->cfd);
|
||||
sys_alarm(dp->oalarm);
|
||||
return -1;
|
||||
}
|
||||
if(ds->cfdp == nil)
|
||||
closeopenfd(&conn->cfd);
|
||||
|
||||
n = conn - dp->conn;
|
||||
if (dp->winner < 0) {
|
||||
jehanne_qlock(&dp->winlck);
|
||||
if (dp->winner < 0 && conn < dp->connend)
|
||||
dp->winner = n;
|
||||
jehanne_qunlock(&dp->winlck);
|
||||
}
|
||||
sys_alarm(calleralarm? dp->oalarm: 0);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse a dial string
|
||||
*/
|
||||
static void
|
||||
_dial_string_parse(const char *str, DS *ds)
|
||||
{
|
||||
char *p, *p2;
|
||||
|
||||
jehanne_strncpy(ds->buf, str, Maxstring);
|
||||
ds->buf[Maxstring-1] = 0;
|
||||
|
||||
p = jehanne_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;
|
||||
}
|
||||
}
|
46
sys/src/lib/jehanne/9sys/dirfstat.c
Normal file
46
sys/src/lib/jehanne/9sys/dirfstat.c
Normal 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 <9P2000.h>
|
||||
|
||||
enum
|
||||
{
|
||||
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
|
||||
};
|
||||
|
||||
Dir*
|
||||
jehanne_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 = jehanne_malloc(sizeof(Dir) + BIT16SZ + nd);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
buf = (uint8_t*)&d[1];
|
||||
n = sys_fstat(fd, buf, BIT16SZ+nd);
|
||||
if(n < BIT16SZ){
|
||||
jehanne_free(d);
|
||||
return nil;
|
||||
}
|
||||
nd = GBIT16(buf); /* upper bound on size of Dir + strings */
|
||||
if(nd <= n){
|
||||
jehanne_convM2D(buf, n, d, (char*)&d[1]);
|
||||
return d;
|
||||
}
|
||||
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
|
||||
jehanne_free(d);
|
||||
}
|
||||
return nil;
|
||||
}
|
28
sys/src/lib/jehanne/9sys/dirfwstat.c
Normal file
28
sys/src/lib/jehanne/9sys/dirfwstat.c
Normal 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 <9P2000.h>
|
||||
|
||||
int
|
||||
jehanne_dirfwstat(int fd, Dir *d)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int r;
|
||||
|
||||
r = jehanne_sizeD2M(d);
|
||||
buf = jehanne_malloc(r);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
jehanne_convD2M(d, buf, r);
|
||||
r = sys_fwstat(fd, buf, r);
|
||||
jehanne_free(buf);
|
||||
return r;
|
||||
}
|
57
sys/src/lib/jehanne/9sys/dirmodefmt.c
Normal file
57
sys/src/lib/jehanne/9sys/dirmodefmt.c
Normal 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 <9P2000.h>
|
||||
|
||||
static char *modes[] =
|
||||
{
|
||||
"---",
|
||||
"--x",
|
||||
"-w-",
|
||||
"-wx",
|
||||
"r--",
|
||||
"r-x",
|
||||
"rw-",
|
||||
"rwx",
|
||||
};
|
||||
|
||||
static void
|
||||
rwx(int32_t m, char *s)
|
||||
{
|
||||
jehanne_strncpy(s, modes[m], 3);
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_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 jehanne_fmtstrcpy(f, buf);
|
||||
}
|
106
sys/src/lib/jehanne/9sys/dirread.c
Normal file
106
sys/src/lib/jehanne/9sys/dirread.c
Normal 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.
|
||||
*/
|
||||
#define PORTABLE_SYSCALLS
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <9P2000.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 = jehanne_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 || jehanne_convM2D(&buf[i], m, *d + nn, s) != m){
|
||||
jehanne_free(*d);
|
||||
*d = nil;
|
||||
return -1;
|
||||
}
|
||||
nn++;
|
||||
s += m;
|
||||
}
|
||||
|
||||
return nn;
|
||||
}
|
||||
|
||||
int32_t
|
||||
jehanne_dirread(int fd, Dir **d)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int32_t ts;
|
||||
|
||||
buf = jehanne_malloc(DIRMAX);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
ts = jehanne_read(fd, buf, DIRMAX);
|
||||
if(ts >= 0)
|
||||
ts = dirpackage(buf, ts, d);
|
||||
jehanne_free(buf);
|
||||
return ts;
|
||||
}
|
||||
|
||||
int32_t
|
||||
jehanne_dirreadall(int fd, Dir **d)
|
||||
{
|
||||
uint8_t *buf, *nbuf;
|
||||
int32_t n, ts;
|
||||
|
||||
buf = nil;
|
||||
ts = 0;
|
||||
for(;;){
|
||||
nbuf = jehanne_realloc(buf, ts+DIRMAX);
|
||||
if(nbuf == nil){
|
||||
jehanne_free(buf);
|
||||
return -1;
|
||||
}
|
||||
buf = nbuf;
|
||||
n = jehanne_read(fd, buf+ts, DIRMAX);
|
||||
if(n <= 0)
|
||||
break;
|
||||
ts += n;
|
||||
}
|
||||
if(ts >= 0)
|
||||
ts = dirpackage(buf, ts, d);
|
||||
jehanne_free(buf);
|
||||
if(ts == 0 && n < 0)
|
||||
return -1;
|
||||
return ts;
|
||||
}
|
46
sys/src/lib/jehanne/9sys/dirstat.c
Normal file
46
sys/src/lib/jehanne/9sys/dirstat.c
Normal 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 <9P2000.h>
|
||||
|
||||
enum
|
||||
{
|
||||
DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
|
||||
};
|
||||
|
||||
Dir*
|
||||
jehanne_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 = jehanne_malloc(sizeof(Dir) + BIT16SZ + nd);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
buf = (uint8_t*)&d[1];
|
||||
n = jehanne_stat(name, buf, BIT16SZ+nd);
|
||||
if(n < BIT16SZ){
|
||||
jehanne_free(d);
|
||||
return nil;
|
||||
}
|
||||
nd = GBIT16((uint8_t*)buf); /* upper bound on size of Dir + strings */
|
||||
if(nd <= n){
|
||||
jehanne_convM2D(buf, n, d, (char*)&d[1]);
|
||||
return d;
|
||||
}
|
||||
/* else sizeof(Dir)+BIT16SZ+nd is plenty */
|
||||
jehanne_free(d);
|
||||
}
|
||||
return nil;
|
||||
}
|
28
sys/src/lib/jehanne/9sys/dirwstat.c
Normal file
28
sys/src/lib/jehanne/9sys/dirwstat.c
Normal 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 <9P2000.h>
|
||||
|
||||
int
|
||||
jehanne_dirwstat(const char *name, Dir *d)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int r;
|
||||
|
||||
r = jehanne_sizeD2M(d);
|
||||
buf = jehanne_malloc(r);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
jehanne_convD2M(d, buf, r);
|
||||
r = jehanne_wstat(name, buf, r);
|
||||
jehanne_free(buf);
|
||||
return r;
|
||||
}
|
40
sys/src/lib/jehanne/9sys/dup.c
Normal file
40
sys/src/lib/jehanne/9sys/dup.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
jehanne_dup(int oldfd, int newfd)
|
||||
{
|
||||
FdPair in, out;
|
||||
long f;
|
||||
|
||||
in.fd[0] = oldfd;
|
||||
in.fd[1] = newfd;
|
||||
|
||||
f = sys_create("#d/new", -1, in.aslong);
|
||||
if(f == -1)
|
||||
return -1;
|
||||
if(f >= 0){
|
||||
/* this should never happen */
|
||||
sys_close(f);
|
||||
return -1;
|
||||
}
|
||||
out.aslong = ~f;
|
||||
return out.fd[1];
|
||||
}
|
17
sys/src/lib/jehanne/9sys/fork.c
Normal file
17
sys/src/lib/jehanne/9sys/fork.c
Normal 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
|
||||
jehanne_fork(void)
|
||||
{
|
||||
return sys_rfork(RFPROC|RFFDG|RFREND);
|
||||
}
|
70
sys/src/lib/jehanne/9sys/getenv.c
Normal file
70
sys/src/lib/jehanne/9sys/getenv.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 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>
|
||||
|
||||
char*
|
||||
jehanne_getenv(const char *name)
|
||||
{
|
||||
int f;
|
||||
int32_t l;
|
||||
char path[127+5+1], *value;
|
||||
|
||||
assert(name != nil);
|
||||
if(name[0]=='\0')
|
||||
goto BadName;
|
||||
if(jehanne_strcmp(name, ".")==0 || jehanne_strcmp(name, "..")==0)
|
||||
goto BadName;
|
||||
if(jehanne_strchr(name, '/')!=nil)
|
||||
goto BadName;
|
||||
|
||||
jehanne_snprint(path, sizeof path, "/env/%s", name);
|
||||
if(jehanne_strcmp(path+5, name) != 0)
|
||||
goto BadName;
|
||||
|
||||
f = sys_open(path, OREAD);
|
||||
if(f < 0){
|
||||
/* try with #e, in case of a previous sys_rfork(RFCNAMEG)
|
||||
*
|
||||
* NOTE: /env is bound to #ec by default, so we
|
||||
* cannot simply use always #e instead of /env. Also
|
||||
* using #ec when the open in #e fails is both
|
||||
* slow and not flexible enough.
|
||||
*/
|
||||
jehanne_snprint(path, sizeof path, "#e/%s", name);
|
||||
f = sys_open(path, OREAD);
|
||||
if(f < 0)
|
||||
return nil;
|
||||
}
|
||||
l = sys_seek(f, 0, 2);
|
||||
value = jehanne_malloc(l+1);
|
||||
if(value == nil)
|
||||
goto Done;
|
||||
jehanne_setmalloctag(value, jehanne_getcallerpc());
|
||||
sys_seek(f, 0, 0);
|
||||
if(jehanne_read(f, value, l) >= 0)
|
||||
value[l] = '\0';
|
||||
Done:
|
||||
sys_close(f);
|
||||
return value;
|
||||
|
||||
BadName:
|
||||
jehanne_werrstr("bad env name: '%s'", name);
|
||||
return nil;
|
||||
}
|
35
sys/src/lib/jehanne/9sys/getmainpid.c
Normal file
35
sys/src/lib/jehanne/9sys/getmainpid.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
extern int32_t _mainpid; /* declared in $ARCH/argv0.c
|
||||
* set by $ARCH/main9.S and $ARCH/syscall.c
|
||||
*/
|
||||
|
||||
int32_t
|
||||
jehanne_getmainpid(void)
|
||||
{
|
||||
/* getmainpid returns the pid of the process at the top of the
|
||||
* stack, that is the process that started the main() function.
|
||||
*
|
||||
* it replace the old Plan9 _tos->pid
|
||||
*/
|
||||
return _mainpid;
|
||||
}
|
142
sys/src/lib/jehanne/9sys/getnetconninfo.c
Normal file
142
sys/src/lib/jehanne/9sys/getnetconninfo.c
Normal 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;
|
||||
|
||||
jehanne_snprint(buf, sizeof buf, "%s/%s", dir, file);
|
||||
fd = sys_open(buf, OREAD);
|
||||
if(fd >= 0){
|
||||
n = jehanne_read(fd, buf, sizeof(buf)-1);
|
||||
if(n>0){
|
||||
buf[n-1] = 0;
|
||||
serv = jehanne_strchr(buf, '!');
|
||||
if(serv){
|
||||
*serv++ = 0;
|
||||
serv = jehanne_strdup(serv);
|
||||
}
|
||||
sys = jehanne_strdup(buf);
|
||||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
if(serv == 0)
|
||||
serv = unknown;
|
||||
if(sys == 0)
|
||||
sys = unknown;
|
||||
*servp = serv;
|
||||
*sysp = sys;
|
||||
}
|
||||
|
||||
NetConnInfo*
|
||||
jehanne_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(sys_fd2path(fd, path, sizeof(path)) < 0)
|
||||
return nil;
|
||||
cp = jehanne_strrchr(path, '/');
|
||||
if(cp == nil)
|
||||
return nil;
|
||||
*cp = 0;
|
||||
dir = path;
|
||||
}
|
||||
|
||||
nci = jehanne_mallocz(sizeof *nci, 1);
|
||||
if(nci == nil)
|
||||
return nil;
|
||||
|
||||
/* copy connection directory */
|
||||
nci->dir = jehanne_strdup(dir);
|
||||
if(nci->dir == nil)
|
||||
goto err;
|
||||
|
||||
/* get netroot */
|
||||
nci->root = jehanne_strdup(dir);
|
||||
if(nci->root == nil)
|
||||
goto err;
|
||||
cp = jehanne_strchr(nci->root+1, '/');
|
||||
if(cp == nil)
|
||||
goto err;
|
||||
*cp = 0;
|
||||
|
||||
/* figure out bind spec */
|
||||
d = jehanne_dirstat(nci->dir);
|
||||
if(d != nil){
|
||||
jehanne_sprint(spec, "#%C%d", d->type, d->dev);
|
||||
nci->spec = jehanne_strdup(spec);
|
||||
}
|
||||
if(nci->spec == nil)
|
||||
nci->spec = unknown;
|
||||
jehanne_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;
|
||||
|
||||
jehanne_strecpy(netname, netname+sizeof netname, nci->dir);
|
||||
if((p = jehanne_strrchr(netname, '/')) != nil)
|
||||
*p = 0;
|
||||
if(jehanne_strncmp(netname, "/net/", 5) == 0)
|
||||
jehanne_memmove(netname, netname+5, jehanne_strlen(netname+5)+1);
|
||||
nci->laddr = jehanne_smprint("%s!%s!%s", netname, nci->lsys, nci->lserv);
|
||||
nci->raddr = jehanne_smprint("%s!%s!%s", netname, nci->rsys, nci->rserv);
|
||||
if(nci->laddr == nil || nci->raddr == nil)
|
||||
goto err;
|
||||
return nci;
|
||||
err:
|
||||
jehanne_freenetconninfo(nci);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
xfree(char *x)
|
||||
{
|
||||
if(x == nil || x == unknown)
|
||||
return;
|
||||
jehanne_free(x);
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_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);
|
||||
jehanne_free(nci);
|
||||
}
|
28
sys/src/lib/jehanne/9sys/getpid.c
Normal file
28
sys/src/lib/jehanne/9sys/getpid.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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
|
||||
jehanne_getpid(void)
|
||||
{
|
||||
int pid;
|
||||
pid = (int)sys_remove("#0/pid");
|
||||
return pid;
|
||||
}
|
28
sys/src/lib/jehanne/9sys/getppid.c
Normal file
28
sys/src/lib/jehanne/9sys/getppid.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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
|
||||
jehanne_getppid(void)
|
||||
{
|
||||
int pid;
|
||||
pid = (int)sys_remove("#0/ppid");
|
||||
return pid;
|
||||
}
|
45
sys/src/lib/jehanne/9sys/getwd.c
Normal file
45
sys/src/lib/jehanne/9sys/getwd.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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>
|
||||
|
||||
/* Fills buf with the current workking directory.
|
||||
*
|
||||
* Returns
|
||||
* - 0 on error
|
||||
* - the negated length of the working directory path if nbuf is too small
|
||||
* - the (positive) length of the working directory on success
|
||||
*/
|
||||
long
|
||||
jehanne_getwd(char *buf, int nbuf)
|
||||
{
|
||||
long n;
|
||||
int fd;
|
||||
|
||||
fd = sys_open("#0/wdir", OREAD);
|
||||
if(fd < 0)
|
||||
return 0;
|
||||
n = jehanne_read(fd, nil, -1);
|
||||
if(n == ~0) /* an error occurred */
|
||||
return 0;
|
||||
if(nbuf >= ~n)
|
||||
n = jehanne_read(fd, buf, nbuf);
|
||||
sys_close(fd);
|
||||
return n;
|
||||
}
|
36
sys/src/lib/jehanne/9sys/iounit.c
Normal file
36
sys/src/lib/jehanne/9sys/iounit.c
Normal 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 /arch/rc/lib/rcmain
|
||||
*/
|
||||
|
||||
int
|
||||
jehanne_iounit(int fd)
|
||||
{
|
||||
int i, cfd;
|
||||
char buf[128], *args[10];
|
||||
|
||||
jehanne_snprint(buf, sizeof buf, "#d/%dctl", fd);
|
||||
cfd = sys_open(buf, OREAD);
|
||||
if(cfd < 0)
|
||||
return 0;
|
||||
i = jehanne_read(cfd, buf, sizeof buf-1);
|
||||
sys_close(cfd);
|
||||
if(i <= 0)
|
||||
return 0;
|
||||
buf[i] = '\0';
|
||||
if(jehanne_tokenize(buf, args, nelem(args)) != nelem(args))
|
||||
return 0;
|
||||
return jehanne_atoi(args[7]);
|
||||
}
|
30
sys/src/lib/jehanne/9sys/nsec.c
Normal file
30
sys/src/lib/jehanne/9sys/nsec.c
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 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/>.
|
||||
*/
|
||||
#define PORTABLE_SYSCALLS
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
unsigned long
|
||||
jehanne_nsec(void)
|
||||
{
|
||||
long r;
|
||||
r = sys_remove("/dev/time");
|
||||
if(r == -1)
|
||||
r = sys_remove("#c/time");
|
||||
return r;
|
||||
}
|
18
sys/src/lib/jehanne/9sys/nulldir.c
Normal file
18
sys/src/lib/jehanne/9sys/nulldir.c
Normal 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
|
||||
jehanne_nulldir(Dir *d)
|
||||
{
|
||||
jehanne_memset(d, ~0, sizeof(Dir));
|
||||
d->name = d->uid = d->gid = d->muid = "";
|
||||
}
|
69
sys/src/lib/jehanne/9sys/ocreate.c
Normal file
69
sys/src/lib/jehanne/9sys/ocreate.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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>
|
||||
|
||||
/* ocreate works like the Plan 9 create(2) syscall, but with different races.
|
||||
* In Plan 9 there is a race due to the different behaviour between the
|
||||
* create syscall and the Tcreate message in 9P2000 when the file already exists:
|
||||
* see https://github.com/brho/plan9/blob/master/sys/src/9/port/chan.c#L1564-L1603
|
||||
* for details.
|
||||
*
|
||||
* In Jehanne the create syscall fails on existing files just like the Tcreate message.
|
||||
* However the Plan 9/UNIX semantic is often useful, thus ocreate mimic it in userspace.
|
||||
* As wisely noted by Charles Forsyth, such implementation introduce a different race
|
||||
* due to the multiple evaluations of the path: on concurrent namespace changes, the
|
||||
* different syscalls here could be handled by different devices/fileservers.
|
||||
* However, given the user is responsible of such namespace changes, we prefer this race
|
||||
* to the original Plan 9 one.
|
||||
*
|
||||
* For more info see http://marc.info/?t=146412533100003&r=1&w=2
|
||||
*/
|
||||
int
|
||||
jehanne_ocreate(const char *path, unsigned int omode, unsigned int perm)
|
||||
{
|
||||
int fd;
|
||||
Dir *s;
|
||||
|
||||
fd = sys_open(path, omode|OTRUNC);
|
||||
if(fd < 0){
|
||||
fd = sys_create(path, omode, perm);
|
||||
if(fd < 0){
|
||||
fd = sys_open(path, omode|OTRUNC);
|
||||
if(fd < 0)
|
||||
goto Done;
|
||||
} else {
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
s = jehanne_dirfstat(fd);
|
||||
if(s == nil){
|
||||
sys_close(fd);
|
||||
return -1;
|
||||
}
|
||||
if(s->mode != perm){
|
||||
s->mode = perm;
|
||||
jehanne_dirfwstat(fd, s); /* we ignore the return value, the device/server is allowed to ignore us */
|
||||
}
|
||||
jehanne_free(s);
|
||||
|
||||
Done:
|
||||
return fd;
|
||||
}
|
41
sys/src/lib/jehanne/9sys/pexec.c
Normal file
41
sys/src/lib/jehanne/9sys/pexec.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 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>
|
||||
#include <envvars.h>
|
||||
|
||||
int
|
||||
jehanne_pexec(const char *f, char *args[])
|
||||
{
|
||||
char *epath, *path, *entries[33];
|
||||
int n, i;
|
||||
|
||||
if(f[0] == '/' || (epath = jehanne_getenv(ENV_PATH)) == nil)
|
||||
return sys_exec(f, (const char**)args);
|
||||
|
||||
n = jehanne_getfields(epath, entries, nelem(entries), 1, ":");
|
||||
for(i = 0; i < n; ++i){
|
||||
path = jehanne_smprint("%s/%s", entries[i], f);
|
||||
sys_exec(path, (const char**)args);
|
||||
jehanne_free(path);
|
||||
}
|
||||
|
||||
jehanne_free(epath);
|
||||
return -1;
|
||||
}
|
31
sys/src/lib/jehanne/9sys/pipe.c
Normal file
31
sys/src/lib/jehanne/9sys/pipe.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015-2017 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
|
||||
jehanne_pipe(int pipes[2])
|
||||
{
|
||||
FdPair pset;
|
||||
pset.aslong = sys_remove("#0/pipes");
|
||||
if(pset.aslong == -1)
|
||||
return -1;
|
||||
pipes[0] = pset.fd[0];
|
||||
pipes[1] = pset.fd[1];
|
||||
return 0;
|
||||
}
|
82
sys/src/lib/jehanne/9sys/postnote.c
Normal file
82
sys/src/lib/jehanne/9sys/postnote.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
static int
|
||||
openprocnotes(int pid)
|
||||
{
|
||||
char file[128];
|
||||
int32_t f;
|
||||
|
||||
jehanne_sprint(file, "#p/%d/note", pid);
|
||||
f = sys_open(file, OWRITE);
|
||||
if(f < 0){
|
||||
jehanne_sprint(file, "/proc/%d/note", pid);
|
||||
f = sys_open(file, OWRITE);
|
||||
}
|
||||
if(f < 0)
|
||||
jehanne_werrstr("postnote: cannot open neither #p/%d/note nor /proc/%d/note", pid, pid);
|
||||
return f;
|
||||
}
|
||||
|
||||
static int
|
||||
opengroupnotes(int pid)
|
||||
{
|
||||
char file[128];
|
||||
int32_t f;
|
||||
|
||||
jehanne_sprint(file, "#p/%d/notepg", pid);
|
||||
f = sys_open(file, OWRITE);
|
||||
if(f < 0){
|
||||
jehanne_sprint(file, "/proc/%d/notepg", pid);
|
||||
f = sys_open(file, OWRITE);
|
||||
}
|
||||
if(f < 0)
|
||||
jehanne_werrstr("postnote: cannot open neither #p/%d/notepg nor /proc/%d/notepg", pid, pid);
|
||||
return f;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_postnote(int group, int pid, const char *note)
|
||||
{
|
||||
int f, r;
|
||||
|
||||
switch(group) {
|
||||
case PNPROC:
|
||||
f = openprocnotes(pid);
|
||||
break;
|
||||
case PNGROUP:
|
||||
f = opengroupnotes(pid);
|
||||
break;
|
||||
default:
|
||||
jehanne_werrstr("postnote: invalid group flag %d", group);
|
||||
return -1;
|
||||
}
|
||||
if(f < 0)
|
||||
return f;
|
||||
|
||||
r = jehanne_strlen(note);
|
||||
if(jehanne_write(f, note, r) != r) {
|
||||
sys_close(f);
|
||||
return -1;
|
||||
}
|
||||
sys_close(f);
|
||||
return 0;
|
||||
}
|
22
sys/src/lib/jehanne/9sys/privalloc.c
Normal file
22
sys/src/lib/jehanne/9sys/privalloc.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static Lock privlock;
|
||||
|
||||
extern void **_privates;
|
||||
extern int _nprivates;
|
||||
|
||||
void **
|
||||
jehanne_privalloc(void)
|
||||
{
|
||||
void **p;
|
||||
|
||||
jehanne_lock(&privlock);
|
||||
if(_nprivates > 0)
|
||||
p = &_privates[--_nprivates];
|
||||
else
|
||||
p = nil;
|
||||
jehanne_unlock(&privlock);
|
||||
|
||||
return p;
|
||||
}
|
53
sys/src/lib/jehanne/9sys/pushssl.c
Normal file
53
sys/src/lib/jehanne/9sys/pushssl.c
Normal 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
|
||||
jehanne_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 = sys_open("#D/ssl/clone", ORDWR);
|
||||
if(ctl < 0)
|
||||
return -1;
|
||||
n = jehanne_read(ctl, buf, sizeof(buf)-1);
|
||||
if(n < 0)
|
||||
goto error;
|
||||
buf[n] = 0;
|
||||
jehanne_sprint(dname, "#D/ssl/%s/data", buf);
|
||||
data = sys_open(dname, ORDWR);
|
||||
if(data < 0)
|
||||
goto error;
|
||||
if(jehanne_fprint(ctl, "fd %d", fd) < 0 ||
|
||||
jehanne_fprint(ctl, "secretin %s", secin) < 0 ||
|
||||
jehanne_fprint(ctl, "secretout %s", secout) < 0 ||
|
||||
jehanne_fprint(ctl, "alg %s", alg) < 0){
|
||||
sys_close(data);
|
||||
goto error;
|
||||
}
|
||||
sys_close(fd);
|
||||
if(cfd != 0)
|
||||
*cfd = ctl;
|
||||
else
|
||||
sys_close(ctl);
|
||||
return data;
|
||||
error:
|
||||
sys_close(ctl);
|
||||
return -1;
|
||||
}
|
62
sys/src/lib/jehanne/9sys/putenv.c
Normal file
62
sys/src/lib/jehanne/9sys/putenv.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016-2017 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
|
||||
jehanne_putenv(const char *name, const char *value)
|
||||
{
|
||||
int f;
|
||||
int32_t l;
|
||||
char path[127+5+1];
|
||||
|
||||
assert(name != nil);
|
||||
assert(value != nil);
|
||||
if(name[0]=='\0')
|
||||
goto BadName;
|
||||
if(jehanne_strcmp(name, ".")==0 || jehanne_strcmp(name, "..")==0)
|
||||
goto BadName;
|
||||
if(jehanne_strchr(name, '/')!=nil)
|
||||
goto BadName;
|
||||
|
||||
jehanne_snprint(path, sizeof path, "/env/%s", name);
|
||||
if(jehanne_strcmp(path+5, name) != 0)
|
||||
goto BadName;
|
||||
|
||||
f = jehanne_ocreate(path, OWRITE, 0664);
|
||||
if(f < 0){
|
||||
/* try with #e, in case of a previous sys_rfork(RFCNAMEG)
|
||||
*/
|
||||
jehanne_snprint(path, sizeof path, "#e/%s", name);
|
||||
f = jehanne_ocreate(path, OWRITE, 0664);
|
||||
if(f < 0)
|
||||
return -1;
|
||||
}
|
||||
l = jehanne_strlen(value);
|
||||
if(l > 0 && jehanne_write(f, value, l) != l){
|
||||
sys_close(f);
|
||||
return -1;
|
||||
}
|
||||
sys_close(f);
|
||||
return 0;
|
||||
|
||||
BadName:
|
||||
jehanne_werrstr("bad env name: '%s'", name);
|
||||
return -1;
|
||||
}
|
823
sys/src/lib/jehanne/9sys/qlock.c
Normal file
823
sys/src/lib/jehanne/9sys/qlock.c
Normal file
@@ -0,0 +1,823 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016-2019 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>
|
||||
|
||||
static struct {
|
||||
QLp *p;
|
||||
QLp x[1024];
|
||||
} ql = {
|
||||
ql.x
|
||||
};
|
||||
|
||||
/* The possible state transitions of a QLp are
|
||||
*
|
||||
* Free -> Queuing -> Timedout|Done -> Free
|
||||
* Free -> QueuingR -> Timedout|Done -> Free
|
||||
* Free -> QueuingW -> Timedout|Done -> Free
|
||||
* Free -> Sleeping -> Timedout -> Free
|
||||
* Free -> Sleeping -> Queuing -> Done -> Free
|
||||
*
|
||||
* QLp starts as Free and move to one of the custom states on getqlp.
|
||||
* Timedout is optional and alternative to Done.
|
||||
* Timedout can only occur if the QLp was allocated by a variant that
|
||||
* support timeouts (qlockt, rlockt, wlockt and rsleept).
|
||||
* Done is reached just before wakeup if and only if the current state
|
||||
* is the expected custom one (all transitions use CAS).
|
||||
*
|
||||
* All QLp need to reach the Free state to be released.
|
||||
*
|
||||
* All transitions are protected by a lock, except
|
||||
* - the ones that lead to Timedout, so that if a QLp is not in
|
||||
* the expected state, it's Timedout.
|
||||
* - the ones from Done to Free since Done is
|
||||
* a terminal state: Freeing is just book keeping.
|
||||
*
|
||||
* NOTE: The rsleep/rwakeup transitions mean that a you should never
|
||||
* use a qlockt a Qlock that is going to be used with a rsleept.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
Free,
|
||||
Queuing,
|
||||
QueuingR,
|
||||
QueuingW,
|
||||
Sleeping,
|
||||
Timedout,
|
||||
Done,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
typedef struct RendezvousLog
|
||||
{
|
||||
void *tag;
|
||||
long pid;
|
||||
long start;
|
||||
long end;
|
||||
void *addr;
|
||||
void *caller;
|
||||
void *r;
|
||||
} RendezvousLog;
|
||||
RendezvousLog logs[1024];
|
||||
int logidx;
|
||||
static void*
|
||||
debugrendezvous(void *tag, void *val)
|
||||
{
|
||||
static void** pidp;
|
||||
int i;
|
||||
|
||||
if(pidp == nil)
|
||||
pidp = jehanne_privalloc();
|
||||
if(*pidp == 0)
|
||||
*pidp = (void*)(long)jehanne_getpid();
|
||||
|
||||
i = jehanne_ainc(&logidx) - 1;
|
||||
logs[i].tag = tag;
|
||||
logs[i].pid = (long)*pidp;
|
||||
logs[i].start = jehanne_nsec();
|
||||
logs[i].addr = __builtin_return_address(0);
|
||||
logs[i].caller = __builtin_return_address(1);
|
||||
logs[i].r = (void*)0xffabcdefffabcdef;
|
||||
logs[i].r = sys_rendezvous(tag, (void*)logs[i].addr);
|
||||
logs[i].end = jehanne_nsec();
|
||||
return logs[i].r;
|
||||
}
|
||||
void
|
||||
printdebugrendezvouslogs(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < logidx; ++i)
|
||||
jehanne_print("[%d] %#p @ %#p sys_rendezvous(%#p, %#p) -> %#p @ %#p\n", logs[i].pid, logs[i].caller, logs[i].start, logs[i].tag, logs[i].addr, logs[i].r, logs[i].end);
|
||||
}
|
||||
static void* (*_rendezvousp)(void*, void*) = debugrendezvous;
|
||||
|
||||
#else
|
||||
|
||||
static void*
|
||||
__rendezvous(void* tag, void* val)
|
||||
{
|
||||
return sys_rendezvous(tag, val);
|
||||
}
|
||||
static void* (*_rendezvousp)(void*, void*) = __rendezvous;
|
||||
|
||||
#endif
|
||||
|
||||
# define RENDEZVOUS(...) (*_rendezvousp)(__VA_ARGS__)
|
||||
//# define RENDEZVOUS(...) sys_rendezvous(__VA_ARGS__)
|
||||
//# define RENDEZVOUS(tag, val) __rendezvous(tag, __builtin_return_address(0))
|
||||
|
||||
/* this gets called by the thread library ONLY to get us to use its rendezvous */
|
||||
void
|
||||
jehanne__qlockinit(void* (*r)(void*, void*))
|
||||
{
|
||||
_rendezvousp = r;
|
||||
}
|
||||
|
||||
/* find a free shared memory location to queue ourselves in */
|
||||
static QLp*
|
||||
getqlp(uint8_t use)
|
||||
{
|
||||
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(cas(&p->state, Free, use)){
|
||||
ql.p = p;
|
||||
p->next = nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_qlock(QLock *q)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
jehanne_lock(&q->lock);
|
||||
if(!q->locked){
|
||||
q->locked = 1;
|
||||
jehanne_unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* chain into waiting list */
|
||||
mp = getqlp(Queuing);
|
||||
p = q->tail;
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
jehanne_unlock(&q->lock);
|
||||
|
||||
/* wait */
|
||||
while(RENDEZVOUS(mp, (void*)1) == (void*)~0)
|
||||
;
|
||||
if(!cas(&mp->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", mp, mp->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_qunlock(QLock *q)
|
||||
{
|
||||
QLp *p, *tmp;
|
||||
|
||||
jehanne_lock(&q->lock);
|
||||
if (q->locked == 0)
|
||||
jehanne_fprint(2, "qunlock called with qlock not held, from %#p\n",
|
||||
jehanne_getcallerpc());
|
||||
p = q->head;
|
||||
while(p != nil && !cas(&p->state, Queuing, Done)){
|
||||
/* the lock in p timed out */
|
||||
if(p->state != Timedout){
|
||||
jehanne_print("qunlock mp %#p: state %d (should be Timedout) pc %#p\n", p, p->state, (uintptr_t)__builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
tmp = p->next;
|
||||
p->state = Free;
|
||||
p = tmp;
|
||||
}
|
||||
if(p != nil){
|
||||
/* wakeup head waiting process */
|
||||
if(p->state != Done){
|
||||
jehanne_print("qunlock: p %#p p->state %d\n", p, p->state);
|
||||
abort();
|
||||
}
|
||||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
jehanne_unlock(&q->lock);
|
||||
while(RENDEZVOUS(p, (void*)0x12345) == (void*)~0)
|
||||
;
|
||||
return;
|
||||
} else {
|
||||
/* all pending locks timedout */
|
||||
q->head = nil;
|
||||
q->tail = nil;
|
||||
}
|
||||
q->locked = 0;
|
||||
jehanne_unlock(&q->lock);
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_qlockt(QLock *q, uint32_t ms)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
int64_t wkup;
|
||||
|
||||
if(!jehanne_lockt(&q->lock, ms))
|
||||
return 0;
|
||||
|
||||
if(!q->locked){
|
||||
q->locked = 1;
|
||||
jehanne_unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
mp = getqlp(Queuing);
|
||||
p = q->tail;
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
|
||||
jehanne_unlock(&q->lock);
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = sys_awake(ms);
|
||||
|
||||
/* wait */
|
||||
while(RENDEZVOUS(mp, (void*)1) == (void*)~0)
|
||||
if (jehanne_awakened(wkup)){
|
||||
/* interrupted by awake */
|
||||
if(cas(&mp->state, Queuing, Timedout))
|
||||
/* if we can atomically mark the QLp
|
||||
* the next qunlock will release it...
|
||||
*/
|
||||
return 0;
|
||||
/* ... otherwise we are going to take the lock
|
||||
* on the next rendezvous from qunlock
|
||||
*/
|
||||
assert(mp->state == Done);
|
||||
}
|
||||
|
||||
jehanne_forgivewkp(wkup);
|
||||
if(!cas(&mp->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", mp, mp->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_canqlock(QLock *q)
|
||||
{
|
||||
if(!jehanne_canlock(&q->lock))
|
||||
return 0;
|
||||
if(!q->locked){
|
||||
q->locked = 1;
|
||||
jehanne_unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
jehanne_unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_rlock(RWLock *q)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
jehanne_lock(&q->lock);
|
||||
if(q->writer == 0 && q->head == nil){
|
||||
/* no writer, go for it */
|
||||
q->_readers++;
|
||||
jehanne_unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mp = getqlp(QueuingR);
|
||||
p = q->tail;
|
||||
if(p == 0)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
jehanne_unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while(RENDEZVOUS(mp, (void*)1) == (void*)~0)
|
||||
;
|
||||
if(!cas(&mp->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", mp, mp->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_rlockt(RWLock *q, uint32_t ms)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
int64_t wkup;
|
||||
|
||||
if(!jehanne_lockt(&q->lock, ms))
|
||||
return 0;
|
||||
|
||||
if(q->writer == 0 && q->head == nil){
|
||||
/* no writer, go for it */
|
||||
q->_readers++;
|
||||
jehanne_unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
mp = getqlp(QueuingR);
|
||||
p = q->tail;
|
||||
if(p == 0)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
|
||||
jehanne_unlock(&q->lock);
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = sys_awake(ms);
|
||||
|
||||
/* wait in kernel */
|
||||
while(RENDEZVOUS(mp, (void*)1) == (void*)~0)
|
||||
if (jehanne_awakened(wkup)){
|
||||
/* interrupted by awake */
|
||||
if(cas(&mp->state, QueuingR, Timedout))
|
||||
/* if we can atomically mark the QLp
|
||||
* a future wunlock will release it...
|
||||
*/
|
||||
return 0;
|
||||
/* ... otherwise we are going to take the lock
|
||||
* on the next rendezvous from wunlock
|
||||
*/
|
||||
assert(mp->state == Done);
|
||||
}
|
||||
|
||||
jehanne_forgivewkp(wkup);
|
||||
if(!cas(&mp->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", mp, mp->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_canrlock(RWLock *q)
|
||||
{
|
||||
jehanne_lock(&q->lock);
|
||||
if (q->writer == 0 && q->head == nil) {
|
||||
/* no writer; go for it */
|
||||
q->_readers++;
|
||||
jehanne_unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
jehanne_unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_runlock(RWLock *q)
|
||||
{
|
||||
QLp *p, *tmp;
|
||||
|
||||
jehanne_lock(&q->lock);
|
||||
if(q->_readers <= 0)
|
||||
abort();
|
||||
p = q->head;
|
||||
if(--(q->_readers) > 0 || p == nil){
|
||||
runlockWithoutWriters:
|
||||
jehanne_unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* start waiting writer */
|
||||
while(p != nil && !cas(&p->state, QueuingW, Done)){
|
||||
/* the lock in p timed out
|
||||
*
|
||||
* Note that p cannot have reached Done or Free already
|
||||
* since we hold q->lock, and the only transactions that
|
||||
* do not require this lock are timeout ones.
|
||||
*/
|
||||
if(p->state != Timedout)
|
||||
abort();
|
||||
tmp = p->next;
|
||||
p->state = Free;
|
||||
p = tmp;
|
||||
}
|
||||
if(p == nil)
|
||||
goto runlockWithoutWriters;
|
||||
|
||||
q->head = p->next;
|
||||
if(q->head == 0)
|
||||
q->tail = 0;
|
||||
q->writer = 1;
|
||||
jehanne_unlock(&q->lock);
|
||||
|
||||
/* wakeup waiter */
|
||||
while(RENDEZVOUS(p, 0) == (void*)~0)
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_wlock(RWLock *q)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
jehanne_lock(&q->lock);
|
||||
if(q->_readers == 0 && q->writer == 0){
|
||||
/* noone waiting, go for it */
|
||||
q->writer = 1;
|
||||
jehanne_unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
p = q->tail;
|
||||
mp = getqlp(QueuingW);
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
jehanne_unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while(RENDEZVOUS(mp, (void*)1) == (void*)~0)
|
||||
;
|
||||
|
||||
if(!cas(&mp->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", mp, mp->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
jehanne_wlockt(RWLock *q, uint32_t ms)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
int64_t wkup;
|
||||
|
||||
if(!jehanne_lockt(&q->lock, ms))
|
||||
return 0;
|
||||
|
||||
if(q->_readers == 0 && q->writer == 0){
|
||||
/* noone waiting, go for it */
|
||||
q->writer = 1;
|
||||
jehanne_unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* chain into waiting list */
|
||||
p = q->tail;
|
||||
mp = getqlp(QueuingW);
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
|
||||
jehanne_unlock(&q->lock);
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = sys_awake(ms);
|
||||
|
||||
/* wait in kernel */
|
||||
while(RENDEZVOUS(mp, (void*)1) == (void*)~0)
|
||||
if (jehanne_awakened(wkup)){
|
||||
/* interrupted by awake */
|
||||
if(cas(&mp->state, QueuingW, Timedout))
|
||||
/* if we can atomically mark the QLp
|
||||
* a future runlock/wunlock will release it...
|
||||
*/
|
||||
return 0;
|
||||
/* ... otherwise we are going to take the lock
|
||||
* on the next rendezvous from runlock/wunlock
|
||||
*/
|
||||
assert(mp->state == Done);
|
||||
}
|
||||
jehanne_forgivewkp(wkup);
|
||||
if(!cas(&mp->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", mp, mp->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_canwlock(RWLock *q)
|
||||
{
|
||||
jehanne_lock(&q->lock);
|
||||
if (q->_readers == 0 && q->writer == 0) {
|
||||
/* no one waiting; go for it */
|
||||
q->writer = 1;
|
||||
jehanne_unlock(&q->lock);
|
||||
return 1;
|
||||
}
|
||||
jehanne_unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_wunlock(RWLock *q)
|
||||
{
|
||||
QLp *p, *tmp;
|
||||
|
||||
jehanne_lock(&q->lock);
|
||||
if(q->writer == 0)
|
||||
abort();
|
||||
p = q->head;
|
||||
if(p == nil){
|
||||
q->writer = 0;
|
||||
jehanne_unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
while(p != nil){
|
||||
wakeupPendingWriter: /* when we jump here, we know p is not nil */
|
||||
switch(casv(&p->state, QueuingW, Done)){
|
||||
case QueuingW:
|
||||
/* start waiting writer */
|
||||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
jehanne_unlock(&q->lock);
|
||||
while(RENDEZVOUS(p, 0) == (void*)~0)
|
||||
;
|
||||
return;
|
||||
case Timedout:
|
||||
/* R and W have the same fate, once Timedout */
|
||||
tmp = p->next;
|
||||
p->state = Free;
|
||||
p = tmp;
|
||||
break;
|
||||
case QueuingR:
|
||||
/* wakeup pending readers */
|
||||
goto wakeupPendingReaders;
|
||||
default:
|
||||
jehanne_print("wunlock: %#p has state %d instead of QueuingW\n", p, p->state);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* wake waiting readers */
|
||||
while(p != nil){
|
||||
wakeupPendingReaders: /* when we jump here, we know p is not nil */
|
||||
switch(casv(&p->state, QueuingR, Done)){
|
||||
case QueuingR:
|
||||
q->_readers++;
|
||||
tmp = p->next;
|
||||
jehanne_unlock(&q->lock);
|
||||
while(RENDEZVOUS(p, 0) == (void*)~0)
|
||||
;
|
||||
/* after the rendezvous, p->state will be set to Free
|
||||
* from the reader we are going to wakeup, thus p could
|
||||
* be reused before we are scheduled again: we need tmp
|
||||
* to keep track of the next QLp to test
|
||||
*/
|
||||
jehanne_lock(&q->lock);
|
||||
p = tmp;
|
||||
break;
|
||||
case Timedout:
|
||||
/* R and W have the same fate, once Timedout */
|
||||
tmp = p->next;
|
||||
p->state = Free;
|
||||
p = tmp;
|
||||
break;
|
||||
case QueuingW:
|
||||
if(q->_readers > 0){
|
||||
goto allPendingReadersStarted;
|
||||
} else {
|
||||
/* all readers timedout: wakeup the pending writer */
|
||||
goto wakeupPendingWriter;
|
||||
}
|
||||
default:
|
||||
jehanne_print("wunlock: %#p has state %d instead of QueuingR\n", p, p->state);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
allPendingReadersStarted:
|
||||
q->head = p;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
q->writer = 0;
|
||||
jehanne_unlock(&q->lock);
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_rsleep(Rendez *r)
|
||||
{
|
||||
QLp *t, *me, *tmp;
|
||||
|
||||
if(!r->l)
|
||||
abort();
|
||||
jehanne_lock(&r->l->lock);
|
||||
/* we should hold the qlock */
|
||||
if(!r->l->locked)
|
||||
abort();
|
||||
|
||||
/* add ourselves to the wait list */
|
||||
me = getqlp(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;
|
||||
while(t != nil && !cas(&t->state, Queuing, Done)){
|
||||
/* the lock in t timed out */
|
||||
if(t->state != Timedout){
|
||||
jehanne_print("rsleep mp %#p: state %d (should be Timedout) pc %#p\n", t, t->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
tmp = t->next;
|
||||
t->state = Free;
|
||||
t = tmp;
|
||||
}
|
||||
if(t != nil){
|
||||
r->l->head = t->next;
|
||||
if(r->l->head == nil)
|
||||
r->l->tail = nil;
|
||||
jehanne_unlock(&r->l->lock);
|
||||
while(RENDEZVOUS(t, (void*)0x12345) == (void*)~0)
|
||||
;
|
||||
}else{
|
||||
r->l->head = nil;
|
||||
r->l->tail = nil;
|
||||
r->l->locked = 0;
|
||||
jehanne_unlock(&r->l->lock);
|
||||
}
|
||||
|
||||
/* wait for a wakeup */
|
||||
while(RENDEZVOUS(me, (void*)1) == (void*)~0)
|
||||
;
|
||||
if(!cas(&me->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", me, me->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_rsleept(Rendez *r, uint32_t ms)
|
||||
{
|
||||
QLp *t, *me, *tmp;
|
||||
int64_t wkup;
|
||||
|
||||
if(!r->l)
|
||||
abort();
|
||||
|
||||
if(!jehanne_lockt(&r->l->lock, ms))
|
||||
return 0;
|
||||
|
||||
/* we should hold the qlock */
|
||||
if(!r->l->locked)
|
||||
abort();
|
||||
|
||||
/* add ourselves to the wait list */
|
||||
me = getqlp(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;
|
||||
while(t != nil && !cas(&t->state, Queuing, Done)){
|
||||
/* the lock in t timed out */
|
||||
if(t->state != Timedout){
|
||||
jehanne_print("rsleept mp %#p: state %d (should be Timedout) pc %#p\n", t, t->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
tmp = t->next;
|
||||
t->state = Free;
|
||||
t = tmp;
|
||||
}
|
||||
if(t != nil){
|
||||
r->l->head = t->next;
|
||||
if(r->l->head == nil)
|
||||
r->l->tail = nil;
|
||||
jehanne_unlock(&r->l->lock);
|
||||
|
||||
while(RENDEZVOUS(t, (void*)0x12345) == (void*)~0)
|
||||
;
|
||||
}else{
|
||||
r->l->head = nil;
|
||||
r->l->tail = nil;
|
||||
r->l->locked = 0;
|
||||
jehanne_unlock(&r->l->lock);
|
||||
}
|
||||
|
||||
/* set up awake to interrupt rendezvous */
|
||||
wkup = sys_awake(ms);
|
||||
|
||||
/* wait for a rwakeup (or a timeout) */
|
||||
while(RENDEZVOUS(me, (void*)1) == (void*)~0)
|
||||
if (jehanne_awakened(wkup)){
|
||||
if(cas(&me->state, Sleeping, Timedout)){
|
||||
/* if we can atomically mark the QLp
|
||||
* a future rwakeup will release it...
|
||||
*/
|
||||
jehanne_qlock(r->l);
|
||||
return 0;
|
||||
}
|
||||
/* ... otherwise we are going to take the lock
|
||||
* on the next rendezvous from rwakeup
|
||||
*/
|
||||
assert(me->state == Done);
|
||||
}
|
||||
|
||||
jehanne_forgivewkp(wkup);
|
||||
if(!cas(&me->state, Done, Free)){
|
||||
jehanne_print("mp %#p: state %d pc %#p\n", me, me->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_rwakeup(Rendez *r)
|
||||
{
|
||||
QLp *t, *tmp;
|
||||
|
||||
/*
|
||||
* 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();
|
||||
jehanne_lock(&r->l->lock);
|
||||
if(!r->l->locked)
|
||||
abort();
|
||||
|
||||
t = r->head;
|
||||
if(t != nil && t->state == Free)
|
||||
abort();
|
||||
|
||||
while(t != nil && !cas(&t->state, Sleeping, Queuing)){
|
||||
if(t->state != Timedout){
|
||||
jehanne_print("rwakeup mp %#p: state %d (should be Timedout) pc %#p\n", t, t->state, __builtin_return_address(0));
|
||||
abort();
|
||||
}
|
||||
tmp = t->next;
|
||||
t->state = Free;
|
||||
t = tmp;
|
||||
}
|
||||
if(t == nil){
|
||||
r->head = nil;
|
||||
r->tail = nil;
|
||||
jehanne_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;
|
||||
|
||||
jehanne_unlock(&r->l->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_rwakeupall(Rendez *r)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; jehanne_rwakeup(r); i++)
|
||||
;
|
||||
return i;
|
||||
}
|
25
sys/src/lib/jehanne/9sys/read.c
Normal file
25
sys/src/lib/jehanne/9sys/read.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015-2020 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>
|
||||
|
||||
long
|
||||
jehanne_read(int fd, void* buf, int nbytes)
|
||||
{
|
||||
return sys_pread(fd, buf, nbytes, ~0LL);
|
||||
}
|
22
sys/src/lib/jehanne/9sys/rerrstr.c
Normal file
22
sys/src/lib/jehanne/9sys/rerrstr.c
Normal 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
|
||||
jehanne_rerrstr(char *buf, uint32_t nbuf)
|
||||
{
|
||||
char tmp[ERRMAX];
|
||||
|
||||
tmp[0] = 0;
|
||||
sys_errstr(tmp, sizeof tmp);
|
||||
jehanne_utfecpy(buf, buf+nbuf, tmp);
|
||||
sys_errstr(tmp, sizeof tmp);
|
||||
}
|
68
sys/src/lib/jehanne/9sys/segattach.c
Normal file
68
sys/src/lib/jehanne/9sys/segattach.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015-2017 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*
|
||||
jehanne_segattach(int attr, const char *class, void *va, unsigned long len)
|
||||
{
|
||||
int fd;
|
||||
long tmp;
|
||||
char msg[256];
|
||||
|
||||
fd = sys_open("#0/segments", OWRITE);
|
||||
if(fd < 0)
|
||||
return (void*)-1;
|
||||
|
||||
tmp = jehanne_snprint(msg, sizeof(msg), "attach 0x%ux %#p %ulld %s", attr, va, len, class);
|
||||
tmp = jehanne_write(fd, msg, tmp);
|
||||
sys_close(fd);
|
||||
return (void*)tmp;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_segdetach(void *addr)
|
||||
{
|
||||
int fd, tmp;
|
||||
char msg[256];
|
||||
|
||||
fd = sys_open("#0/segments", OWRITE);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
|
||||
tmp = jehanne_snprint(msg, sizeof(msg), "detach %#p", addr);
|
||||
tmp = jehanne_write(fd, msg, tmp);
|
||||
sys_close(fd);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_segfree(void *addr, unsigned long len)
|
||||
{
|
||||
int fd, tmp;
|
||||
char msg[256];
|
||||
|
||||
fd = sys_open("#0/segments", OWRITE);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
|
||||
tmp = jehanne_snprint(msg, sizeof(msg), "free %#p %ulld", addr, len);
|
||||
tmp = jehanne_write(fd, msg, tmp);
|
||||
sys_close(fd);
|
||||
return tmp;
|
||||
}
|
60
sys/src/lib/jehanne/9sys/segbrk.c
Normal file
60
sys/src/lib/jehanne/9sys/segbrk.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 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/>.
|
||||
*/
|
||||
#define PORTABLE_SYSCALLS
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
extern char end[];
|
||||
static char *last_brk = { end };
|
||||
|
||||
#define ROUND_BRK(b) (((uintptr_t)b + 7) & ~7)
|
||||
|
||||
static uintptr_t
|
||||
setbrk(uintptr_t p)
|
||||
{
|
||||
long b;
|
||||
/* assert: devself is still working */
|
||||
assert((b = sys_create("#0/brk/set", -1, p)) < 0);
|
||||
if(b == -1)
|
||||
return ~0; // an error occurred
|
||||
return (uintptr_t)~b;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_brk(void *p)
|
||||
{
|
||||
uintptr_t new_brk;
|
||||
|
||||
new_brk = ROUND_BRK(p);
|
||||
if(setbrk(new_brk) == ~0)
|
||||
return -1;
|
||||
last_brk = (char*)new_brk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
jehanne_segbrk(uint32_t increment)
|
||||
{
|
||||
uintptr_t new_brk;
|
||||
|
||||
new_brk = ROUND_BRK(last_brk);
|
||||
if(setbrk(new_brk+increment) == ~0)
|
||||
return (void*)-1;
|
||||
last_brk = (char*)new_brk + increment;
|
||||
return (void*)new_brk;
|
||||
}
|
25
sys/src/lib/jehanne/9sys/setnetmtpt.c
Normal file
25
sys/src/lib/jehanne/9sys/setnetmtpt.c
Normal 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
|
||||
jehanne_setnetmtpt(char *net, int n, const char *x)
|
||||
{
|
||||
if(x == nil)
|
||||
x = "/net";
|
||||
|
||||
if(*x == '/'){
|
||||
jehanne_strncpy(net, x, n);
|
||||
net[n-1] = 0;
|
||||
} else {
|
||||
jehanne_snprint(net, n, "/net%s", x);
|
||||
}
|
||||
}
|
32
sys/src/lib/jehanne/9sys/sleep.c
Normal file
32
sys/src/lib/jehanne/9sys/sleep.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015-2017 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
|
||||
jehanne_sleep(unsigned int millisecs)
|
||||
{
|
||||
long wakeup;
|
||||
|
||||
wakeup = sys_awake(millisecs); // give up the processor, in any case
|
||||
if(millisecs > 0)
|
||||
while(sys_rendezvous((void*)~0, (void*)1) == (void*)~0)
|
||||
if(jehanne_awakened(wakeup))
|
||||
return;
|
||||
}
|
50
sys/src/lib/jehanne/9sys/stat.c
Normal file
50
sys/src/lib/jehanne/9sys/stat.c
Normal 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
|
||||
jehanne_stat(const char* name, uint8_t* edir, int nedir)
|
||||
{
|
||||
int fd, statsz;
|
||||
|
||||
fd = sys_open(name, OSTAT);
|
||||
if(fd < 0){
|
||||
jehanne_werrstr("stat: %r");
|
||||
return fd;
|
||||
}
|
||||
statsz = sys_fstat(fd, edir, nedir);
|
||||
sys_close(fd);
|
||||
return statsz;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_wstat(const char* name, uint8_t* edir, int nedir)
|
||||
{
|
||||
int fd, statsz;
|
||||
|
||||
fd = sys_open(name, OSTAT);
|
||||
if(fd < 0){
|
||||
jehanne_werrstr("wstat: %r");
|
||||
return fd;
|
||||
}
|
||||
statsz = sys_fwstat(fd, edir, nedir);
|
||||
sys_close(fd);
|
||||
return statsz;
|
||||
}
|
38
sys/src/lib/jehanne/9sys/sysfatal.c
Normal file
38
sys/src/lib/jehanne/9sys/sysfatal.c
Normal 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.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
|
||||
static void
|
||||
_sysfatalimpl(const char *fmt, va_list arg)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
jehanne_vseprint(buf, buf+sizeof(buf), fmt, arg);
|
||||
if(argv0)
|
||||
jehanne_fprint(2, "%s: %s\n", argv0, buf);
|
||||
else
|
||||
jehanne_fprint(2, "%s\n", buf);
|
||||
jehanne_exits(buf);
|
||||
}
|
||||
|
||||
void (*_sysfatal)(const char *fmt, va_list arg) = _sysfatalimpl;
|
||||
|
||||
void
|
||||
jehanne_sysfatal(const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
(*_sysfatal)(fmt, arg);
|
||||
va_end(arg);
|
||||
jehanne_exits("sysfatal");
|
||||
}
|
125
sys/src/lib/jehanne/9sys/syslog.c
Normal file
125
sys/src/lib/jehanne/9sys/syslog.c
Normal 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)
|
||||
sys_close(sl.fd);
|
||||
jehanne_snprint(buf, sizeof(buf), "/sys/log/%s", sl.name);
|
||||
sl.fd = sys_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
|
||||
jehanne_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';
|
||||
sys_errstr(err, sizeof err);
|
||||
jehanne_lock(&sl);
|
||||
|
||||
/*
|
||||
* paranoia makes us stat to make sure a fork+close
|
||||
* hasn't broken our fd's
|
||||
*/
|
||||
d = jehanne_dirfstat(sl.fd);
|
||||
if(sl.fd < 0 || sl.name == nil || jehanne_strcmp(sl.name, logname) != 0 ||
|
||||
!eqdirdev(d, sl.d)){
|
||||
jehanne_free(sl.name);
|
||||
sl.name = jehanne_strdup(logname);
|
||||
if(sl.name == nil)
|
||||
cons = 1;
|
||||
else{
|
||||
jehanne_free(sl.d);
|
||||
sl.d = nil;
|
||||
_syslogopen();
|
||||
if(sl.fd < 0)
|
||||
cons = 1;
|
||||
else
|
||||
sl.d = jehanne_dirfstat(sl.fd);
|
||||
}
|
||||
}
|
||||
jehanne_free(d);
|
||||
if(cons){
|
||||
d = jehanne_dirfstat(sl.consfd);
|
||||
if(sl.consfd < 0 || !eqdirdev(d, sl.consd)){
|
||||
jehanne_free(sl.consd);
|
||||
sl.consd = nil;
|
||||
sl.consfd = sys_open("#c/cons", OWRITE|OCEXEC);
|
||||
if(sl.consfd >= 0)
|
||||
sl.consd = jehanne_dirfstat(sl.consfd);
|
||||
}
|
||||
jehanne_free(d);
|
||||
}
|
||||
|
||||
if(fmt == nil){
|
||||
jehanne_unlock(&sl);
|
||||
return;
|
||||
}
|
||||
|
||||
ctim = jehanne_ctime(jehanne_time(0));
|
||||
p = buf + jehanne_snprint(buf, sizeof(buf)-1, "%s ", jehanne_sysname());
|
||||
jehanne_strncpy(p, ctim+4, 15);
|
||||
p += 15;
|
||||
*p++ = ' ';
|
||||
sys_errstr(err, sizeof err);
|
||||
va_start(arg, fmt);
|
||||
p = jehanne_vseprint(p, buf+sizeof(buf)-1, fmt, arg);
|
||||
va_end(arg);
|
||||
*p++ = '\n';
|
||||
n = p - buf;
|
||||
|
||||
if(sl.fd >= 0){
|
||||
sys_seek(sl.fd, 0, 2);
|
||||
jehanne_write(sl.fd, buf, n);
|
||||
}
|
||||
|
||||
if(cons && sl.consfd >=0)
|
||||
jehanne_write(sl.consfd, buf, n);
|
||||
|
||||
jehanne_unlock(&sl);
|
||||
}
|
30
sys/src/lib/jehanne/9sys/sysname.c
Normal file
30
sys/src/lib/jehanne/9sys/sysname.c
Normal 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*
|
||||
jehanne_sysname(void)
|
||||
{
|
||||
int f, n;
|
||||
static char b[128];
|
||||
|
||||
if(b[0])
|
||||
return b;
|
||||
|
||||
f = sys_open("#c/sysname", OREAD);
|
||||
if(f >= 0) {
|
||||
n = jehanne_read(f, b, sizeof(b)-1);
|
||||
if(n > 0)
|
||||
b[n] = 0;
|
||||
sys_close(f);
|
||||
}
|
||||
return b;
|
||||
}
|
22
sys/src/lib/jehanne/9sys/time.c
Normal file
22
sys/src/lib/jehanne/9sys/time.c
Normal 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
|
||||
jehanne_time(int32_t *tp)
|
||||
{
|
||||
int64_t t;
|
||||
|
||||
t = jehanne_nsec()/1000000000LL;
|
||||
if(tp != nil)
|
||||
*tp = t;
|
||||
return t;
|
||||
}
|
69
sys/src/lib/jehanne/9sys/times.c
Normal file
69
sys/src/lib/jehanne/9sys/times.c
Normal 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
|
||||
jehanne_times(int32_t *t)
|
||||
{
|
||||
char b[200], *p;
|
||||
static int f = -1;
|
||||
int i, retries;
|
||||
uint32_t r = -1;
|
||||
|
||||
jehanne_memset(b, 0, sizeof(b));
|
||||
for(retries = 0; retries < 100; retries++){
|
||||
if(f < 0)
|
||||
f = sys_open("/dev/cputime", OREAD|OCEXEC);
|
||||
if(f < 0)
|
||||
break;
|
||||
if(sys_seek(f, 0, 0) < 0 || (i = jehanne_read(f, b, sizeof(b))) < 0){
|
||||
sys_close(f);
|
||||
f = -1;
|
||||
} else {
|
||||
if(i != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
p = b;
|
||||
if(t)
|
||||
t[0] = jehanne_atol(p);
|
||||
p = skip(p);
|
||||
if(t)
|
||||
t[1] = jehanne_atol(p);
|
||||
p = skip(p);
|
||||
r = jehanne_atol(p);
|
||||
if(t){
|
||||
p = skip(p);
|
||||
t[2] = jehanne_atol(p);
|
||||
p = skip(p);
|
||||
t[3] = jehanne_atol(p);
|
||||
}
|
||||
return r;
|
||||
}
|
205
sys/src/lib/jehanne/9sys/tm2sec.c
Normal file
205
sys/src/lib/jehanne/9sys/tm2sec.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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
|
||||
jehanne_tm2sec(Tm *tm)
|
||||
{
|
||||
int32_t secs;
|
||||
int i, yday, year, *d2m;
|
||||
|
||||
if(jehanne_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(jehanne_strcmp(tm->zone, timezone.stname) == 0)
|
||||
secs -= timezone.stdiff;
|
||||
else if(jehanne_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;
|
||||
|
||||
jehanne_memset(buf, 0, sizeof(buf));
|
||||
i = sys_open("/env/timezone", OREAD);
|
||||
if(i < 0)
|
||||
goto error;
|
||||
if(jehanne_read(i, buf, sizeof(buf)) >= sizeof(buf)){
|
||||
sys_close(1);
|
||||
goto error;
|
||||
}
|
||||
sys_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;
|
||||
jehanne_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;
|
||||
}
|
26
sys/src/lib/jehanne/9sys/truerand.c
Normal file
26
sys/src/lib/jehanne/9sys/truerand.c
Normal 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
|
||||
jehanne_truerand(void)
|
||||
{
|
||||
uint32_t x;
|
||||
static int randfd = -1;
|
||||
|
||||
if(randfd < 0)
|
||||
randfd = sys_open("/dev/random", OREAD|OCEXEC);
|
||||
if(randfd < 0)
|
||||
jehanne_sysfatal("can't open /dev/random");
|
||||
if(jehanne_read(randfd, &x, sizeof(x)) != sizeof(x))
|
||||
jehanne_sysfatal("can't read /dev/random");
|
||||
return x;
|
||||
}
|
36
sys/src/lib/jehanne/9sys/tsemacquire.c
Normal file
36
sys/src/lib/jehanne/9sys/tsemacquire.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
jehanne_tsemacquire(int* addr, long ms)
|
||||
{
|
||||
long wkup;
|
||||
wkup = sys_awake(ms);
|
||||
while(sys_semacquire(addr, 1) < 0){
|
||||
if(jehanne_awakened(wkup)){
|
||||
/* copy canlock semantic for return values */
|
||||
return 0;
|
||||
}
|
||||
/* interrupted; try again */
|
||||
}
|
||||
jehanne_forgivewkp(wkup);
|
||||
return 1;
|
||||
}
|
40
sys/src/lib/jehanne/9sys/wait.c
Normal file
40
sys/src/lib/jehanne/9sys/wait.c
Normal 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 <9P2000.h>
|
||||
|
||||
Waitmsg*
|
||||
jehanne_wait(void)
|
||||
{
|
||||
int n, l;
|
||||
char buf[512], *fld[5];
|
||||
Waitmsg *w;
|
||||
|
||||
n = sys_await(buf, sizeof buf-1);
|
||||
if(n < 0)
|
||||
return nil;
|
||||
buf[n] = '\0';
|
||||
if(jehanne_tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
||||
jehanne_werrstr("couldn't parse wait message");
|
||||
return nil;
|
||||
}
|
||||
l = jehanne_strlen(fld[4])+1;
|
||||
w = jehanne_malloc(sizeof(Waitmsg)+l);
|
||||
if(w == nil)
|
||||
return nil;
|
||||
w->pid = jehanne_atoi(fld[0]);
|
||||
w->time[0] = jehanne_atoi(fld[1]);
|
||||
w->time[1] = jehanne_atoi(fld[2]);
|
||||
w->time[2] = jehanne_atoi(fld[3]);
|
||||
jehanne_memmove(w->msg, fld[4], l);
|
||||
return w;
|
||||
}
|
||||
|
30
sys/src/lib/jehanne/9sys/waitpid.c
Normal file
30
sys/src/lib/jehanne/9sys/waitpid.c
Normal 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 <9P2000.h>
|
||||
|
||||
int
|
||||
jehanne_waitpid(void)
|
||||
{
|
||||
int n;
|
||||
char buf[512], *fld[5];
|
||||
|
||||
n = sys_await(buf, sizeof buf-1);
|
||||
if(n <= 0)
|
||||
return -1;
|
||||
buf[n] = '\0';
|
||||
if(jehanne_tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
||||
jehanne_werrstr("couldn't parse wait message");
|
||||
return -1;
|
||||
}
|
||||
return jehanne_atoi(fld[0]);
|
||||
}
|
||||
|
23
sys/src/lib/jehanne/9sys/werrstr.c
Normal file
23
sys/src/lib/jehanne/9sys/werrstr.c
Normal 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
|
||||
jehanne_werrstr(const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char buf[ERRMAX];
|
||||
|
||||
va_start(arg, fmt);
|
||||
jehanne_vseprint(buf, buf+ERRMAX, fmt, arg);
|
||||
va_end(arg);
|
||||
sys_errstr(buf, ERRMAX);
|
||||
}
|
25
sys/src/lib/jehanne/9sys/write.c
Normal file
25
sys/src/lib/jehanne/9sys/write.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015-2019 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>
|
||||
|
||||
long
|
||||
jehanne_write(int fd, const void* buf, int nbytes)
|
||||
{
|
||||
return sys_pwrite(fd, buf, nbytes, ~0LL);
|
||||
}
|
8
sys/src/lib/jehanne/amd64/argv0.c
Normal file
8
sys/src/lib/jehanne/amd64/argv0.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void (*_abort)(void);
|
||||
char *argv0;
|
||||
int32_t _mainpid;
|
||||
char *_privates;
|
||||
char *_nprivates;
|
38
sys/src/lib/jehanne/amd64/atom.s
Normal file
38
sys/src/lib/jehanne/amd64/atom.s
Normal file
@@ -0,0 +1,38 @@
|
||||
.text
|
||||
|
||||
.globl jehanne_ainc /* long ainc(long *); */
|
||||
/* N.B.: long in Plan 9 is 32 BITS! */
|
||||
jehanne_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 jehanne_adec /* long adec(long*); */
|
||||
jehanne_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
|
||||
|
||||
/*
|
||||
* void mfence(void);
|
||||
*/
|
||||
.globl jehanne_mfence
|
||||
jehanne_mfence:
|
||||
mfence
|
||||
ret
|
||||
|
41
sys/src/lib/jehanne/amd64/crt0.s
Normal file
41
sys/src/lib/jehanne/amd64/crt0.s
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
.text
|
||||
|
||||
.globl _main
|
||||
_main:
|
||||
/* clear the frame pointer */
|
||||
xorq %rbp, %rbp
|
||||
|
||||
/* set argc (%rdi) and argv (%rsi) */
|
||||
movq 0(%rsp), %rdi
|
||||
leaq 8(%rsp), %rsi
|
||||
|
||||
/* set _mainpid */
|
||||
movl %r12d, _mainpid
|
||||
|
||||
movq %rsp, %rbp
|
||||
pushq %rsi
|
||||
pushq %rdi
|
||||
call _init
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
|
||||
call __jehanne_libc_init
|
||||
|
||||
.size _main,.-_main
|
30
sys/src/lib/jehanne/amd64/crti.s
Normal file
30
sys/src/lib/jehanne/amd64/crti.s
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
.section .init
|
||||
.global _init
|
||||
_init:
|
||||
push %rbp
|
||||
movq %rsp, %rbp
|
||||
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
||||
|
||||
.section .fini
|
||||
.global _fini
|
||||
_fini:
|
||||
push %rbp
|
||||
movq %rsp, %rbp
|
||||
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
7
sys/src/lib/jehanne/amd64/crtn.s
Normal file
7
sys/src/lib/jehanne/amd64/crtn.s
Normal file
@@ -0,0 +1,7 @@
|
||||
.section .init
|
||||
popq %rbp
|
||||
ret
|
||||
|
||||
.section .fini
|
||||
popq %rbp
|
||||
ret
|
11
sys/src/lib/jehanne/amd64/cycles.c
Normal file
11
sys/src/lib/jehanne/amd64/cycles.c
Normal 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));
|
||||
|
||||
}
|
||||
|
61
sys/src/lib/jehanne/amd64/getfcr.s
Normal file
61
sys/src/lib/jehanne/amd64/getfcr.s
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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/>.
|
||||
*/
|
||||
|
||||
.text
|
||||
|
||||
.globl jehanne_setfcr
|
||||
jehanne_setfcr:
|
||||
xor $(0x3F<<7), %edi
|
||||
and $0xFFC0, %edi
|
||||
wait
|
||||
stmxcsr -8(%rsp)
|
||||
mov -8(%rsp), %eax
|
||||
and $~0x3F, %eax
|
||||
or %edi, %eax
|
||||
mov %eax, -8(%rsp)
|
||||
ldmxcsr -8(%rsp)
|
||||
ret
|
||||
|
||||
.globl jehanne_getfcr
|
||||
jehanne_getfcr:
|
||||
wait
|
||||
stmxcsr -8(%rsp)
|
||||
movzx -8(%rsp), %ax
|
||||
andl $0xFFC0, %eax
|
||||
xorl $(0x3F<<7), %eax
|
||||
ret
|
||||
|
||||
.globl jehanne_getfsr
|
||||
jehanne_getfsr:
|
||||
wait
|
||||
stmxcsr -8(%rsp)
|
||||
mov -8(%rsp), %eax
|
||||
and $0x3F, %eax
|
||||
RET
|
||||
|
||||
.globl jehanne_setfsr
|
||||
jehanne_setfsr:
|
||||
and $0x3F, %edi
|
||||
wait
|
||||
stmxcsr -8(%rsp)
|
||||
mov -8(%rsp), %eax
|
||||
and $~0x3F, %eax
|
||||
or %edi, %eax
|
||||
mov %eax, -8(%rsp)
|
||||
ldmxcsr -8(%rsp)
|
||||
ret
|
56
sys/src/lib/jehanne/amd64/initlib.c
Normal file
56
sys/src/lib/jehanne/amd64/initlib.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017-2019 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 3 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>
|
||||
|
||||
extern void **_privates;
|
||||
extern int _nprivates;
|
||||
|
||||
static void call_main(int argc, char *argv[]) __attribute__((noreturn));
|
||||
|
||||
/* can be overwritten to do anything before calling main */
|
||||
extern void __libc_init(int argc, char *argv[]) __attribute__((weak, noreturn));
|
||||
|
||||
void
|
||||
__jehanne_libc_init(int argc, char *argv[])
|
||||
{
|
||||
/* Initialize per process structures on the stack */
|
||||
void *privates[NPRIVATES];
|
||||
|
||||
_nprivates = NPRIVATES;
|
||||
for(_nprivates = 0; _nprivates < NPRIVATES; ++_nprivates)
|
||||
privates[_nprivates] = nil;
|
||||
_privates = privates;
|
||||
|
||||
if(__libc_init != nil)
|
||||
__libc_init(argc, argv);
|
||||
call_main(argc, argv);
|
||||
}
|
||||
|
||||
static void
|
||||
call_main(int argc, char *argv[])
|
||||
{
|
||||
extern void main(int argc, char *argv[]) __attribute__((weak));
|
||||
|
||||
if(main != nil){
|
||||
main(argc, argv);
|
||||
jehanne_exits("main");
|
||||
} else {
|
||||
jehanne_exits("missing main");
|
||||
}
|
||||
}
|
16
sys/src/lib/jehanne/amd64/notejmp.c
Normal file
16
sys/src/lib/jehanne/amd64/notejmp.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ureg.h>
|
||||
|
||||
void
|
||||
jehanne_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;
|
||||
sys_noted(NCONT);
|
||||
}
|
9
sys/src/lib/jehanne/amd64/rdpmc.c
Normal file
9
sys/src/lib/jehanne/amd64/rdpmc.c
Normal 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)) ;
|
||||
}
|
||||
|
39
sys/src/lib/jehanne/amd64/setjmp.s
Normal file
39
sys/src/lib/jehanne/amd64/setjmp.s
Normal file
@@ -0,0 +1,39 @@
|
||||
.text
|
||||
|
||||
.globl jehanne_longjmp
|
||||
jehanne_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 jehanne_setjmp
|
||||
jehanne_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
|
5
sys/src/lib/jehanne/amd64/sqrt.s
Normal file
5
sys/src/lib/jehanne/amd64/sqrt.s
Normal file
@@ -0,0 +1,5 @@
|
||||
.globl jehanne_sqrt
|
||||
jehanne_sqrt:
|
||||
sqrtsd %xmm0, %xmm0
|
||||
ret
|
||||
|
43
sys/src/lib/jehanne/amd64/stackchk.c
Normal file
43
sys/src/lib/jehanne/amd64/stackchk.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2015-2016 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>
|
||||
|
||||
#if defined(__SSP__) || defined(__SSP_ALL__) || defined(__SSP_STRONG__)
|
||||
|
||||
#define STACK_CHK_GUARD 0x2101170925071803
|
||||
uintptr_t __stack_chk_guard = STACK_CHK_GUARD;
|
||||
__attribute__((noreturn))
|
||||
void
|
||||
__stack_chk_fail(void)
|
||||
{
|
||||
#if __STDC_HOSTED__
|
||||
abort();
|
||||
__builtin_unreachable();
|
||||
#else
|
||||
extern void panic(char *fmt, ...) __attribute__ ((noreturn));
|
||||
panic("Stack smashing detected");
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* no stack protector */
|
||||
|
||||
uintptr_t __stack_chk_guard = 0;
|
||||
|
||||
#endif
|
10
sys/src/lib/jehanne/amd64/tas.s
Normal file
10
sys/src/lib/jehanne/amd64/tas.s
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* The kernel and the libc use the same constant for TAS
|
||||
*/
|
||||
.text
|
||||
.globl jehanne__tas
|
||||
jehanne__tas:
|
||||
movl $0xdeaddead, %eax
|
||||
xchgl %eax, 0(%rdi) /* lock->key */
|
||||
ret
|
||||
|
27
sys/src/lib/jehanne/apw/abort.c
Normal file
27
sys/src/lib/jehanne/apw/abort.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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 <apw/stdlib.h>
|
||||
|
||||
void
|
||||
abort(void)
|
||||
{
|
||||
if(_abort)
|
||||
_abort();
|
||||
else
|
||||
while(*(int*)0);
|
||||
}
|
55
sys/src/lib/jehanne/apw/div.c
Normal file
55
sys/src/lib/jehanne/apw/div.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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 <apw/stdlib.h>
|
||||
|
||||
div_t
|
||||
div(int num, int denom)
|
||||
{
|
||||
div_t r;
|
||||
|
||||
r.quot = num / denom;
|
||||
r.rem = num % denom;
|
||||
if (num >= 0 && r.rem < 0) {
|
||||
++r.quot;
|
||||
r.rem -= denom;
|
||||
}
|
||||
else if (num < 0 && r.rem > 0) {
|
||||
--r.quot;
|
||||
r.rem += denom;
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
|
||||
ldiv_t
|
||||
ldiv(long num, long denom)
|
||||
{
|
||||
ldiv_t r;
|
||||
|
||||
r.quot = num / denom;
|
||||
r.rem = num % denom;
|
||||
if (num >= 0 && r.rem < 0) {
|
||||
++r.quot;
|
||||
r.rem -= denom;
|
||||
}
|
||||
else if (num < 0 && r.rem > 0) {
|
||||
--r.quot;
|
||||
r.rem += denom;
|
||||
}
|
||||
return (r);
|
||||
}
|
25
sys/src/lib/jehanne/apw/eprintf.c
Normal file
25
sys/src/lib/jehanne/apw/eprintf.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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 <apw/stdlib.h>
|
||||
|
||||
void
|
||||
__eprintf(const char *format, const char *file, unsigned int line, const char *expression)
|
||||
{
|
||||
jehanne_fprint(2, format, file, line, expression);
|
||||
abort();
|
||||
}
|
26
sys/src/lib/jehanne/apw/exit.c
Normal file
26
sys/src/lib/jehanne/apw/exit.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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 <apw/stdlib.h>
|
||||
|
||||
void
|
||||
exit(int status)
|
||||
{
|
||||
if(status == EXIT_SUCCESS)
|
||||
jehanne_exits(nil);
|
||||
jehanne_exits(jehanne_smprint(__POSIX_EXIT_PREFIX "%d", status));
|
||||
}
|
54
sys/src/lib/jehanne/apw/system.c
Normal file
54
sys/src/lib/jehanne/apw/system.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2016 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 <apw/stdlib.h>
|
||||
|
||||
int
|
||||
system(const char *command)
|
||||
{
|
||||
pid_t pid;
|
||||
Waitmsg *w;
|
||||
int ret = 0;
|
||||
char *s = nil;
|
||||
if(command == nil)
|
||||
return jehanne_access("/cmd/rc", AEXEC) == 0;
|
||||
switch(pid = sys_rfork(RFFDG|RFREND|RFPROC|RFENVG|RFNOTEG)){
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
jehanne_execl("/cmd/rc", "rc", "-c", command, nil);
|
||||
jehanne_sysfatal("execl returned");
|
||||
return -1;
|
||||
default:
|
||||
// TODO: fix this http://man7.org/linux/man-pages/man3/system.3.html
|
||||
while((w = jehanne_wait()) && w->pid != pid)
|
||||
jehanne_free(w);
|
||||
if(w == nil)
|
||||
return -1;
|
||||
if(w->msg[0] != 0){
|
||||
s = jehanne_strstr(w->msg, __POSIX_EXIT_PREFIX);
|
||||
if(s){
|
||||
s += (sizeof(__POSIX_EXIT_PREFIX)/sizeof(char) - 1);
|
||||
ret = jehanne_atoi(s);
|
||||
} else
|
||||
ret = 127;
|
||||
}
|
||||
jehanne_free(w);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
246
sys/src/lib/jehanne/build.json
Normal file
246
sys/src/lib/jehanne/build.json
Normal file
@@ -0,0 +1,246 @@
|
||||
{
|
||||
"CrtFiles": {
|
||||
"Cflags": [
|
||||
"-fasm"
|
||||
],
|
||||
"Include": [
|
||||
"../lib.json"
|
||||
],
|
||||
"Post": [
|
||||
"cp crt0.o crti.o crtn.o $JEHANNE/arch/$ARCH/lib/"
|
||||
],
|
||||
"SourceFiles": [
|
||||
"$ARCH/crt0.s",
|
||||
"$ARCH/crti.s",
|
||||
"$ARCH/crtn.s"
|
||||
]
|
||||
},
|
||||
"LibJehanne": {
|
||||
"Cflags": [
|
||||
"-fasm"
|
||||
],
|
||||
"Include": [
|
||||
"../lib.json"
|
||||
],
|
||||
"Install": "/arch/$ARCH/lib/",
|
||||
"Library": "libjehanne.a",
|
||||
"Pre": [
|
||||
"usyscalls header $JEHANNE/sys/src/sysconf.json > $JEHANNE/arch/amd64/include/syscalls.h",
|
||||
"usyscalls code $JEHANNE/sys/src/sysconf.json > $JEHANNE/sys/src/lib/jehanne/amd64/syscalls.c"
|
||||
],
|
||||
"Post": [
|
||||
"TOOL=ar; $TOOLPREFIX$TOOL rcs $JEHANNE/arch/$ARCH/lib/libssp.a",
|
||||
"TOOL=ar; $TOOLPREFIX$TOOL rcs $JEHANNE/arch/$ARCH/lib/libssp_nonshared.a"
|
||||
],
|
||||
"SourceFiles": [
|
||||
"9sys/access.c",
|
||||
"9sys/announce.c",
|
||||
"9sys/awakened.c",
|
||||
"9sys/chdir.c",
|
||||
"9sys/convD2M.c",
|
||||
"9sys/convM2D.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/dup.c",
|
||||
"9sys/fork.c",
|
||||
"9sys/getnetconninfo.c",
|
||||
"9sys/getenv.c",
|
||||
"9sys/getmainpid.c",
|
||||
"9sys/getpid.c",
|
||||
"9sys/getppid.c",
|
||||
"9sys/getwd.c",
|
||||
"9sys/iounit.c",
|
||||
"9sys/nsec.c",
|
||||
"9sys/nulldir.c",
|
||||
"9sys/ocreate.c",
|
||||
"9sys/pexec.c",
|
||||
"9sys/pipe.c",
|
||||
"9sys/postnote.c",
|
||||
"9sys/privalloc.c",
|
||||
"9sys/pushssl.c",
|
||||
"9sys/putenv.c",
|
||||
"9sys/qlock.c",
|
||||
"9sys/read.c",
|
||||
"9sys/rerrstr.c",
|
||||
"9sys/segbrk.c",
|
||||
"9sys/segattach.c",
|
||||
"9sys/setnetmtpt.c",
|
||||
"9sys/sleep.c",
|
||||
"9sys/stat.c",
|
||||
"9sys/sysfatal.c",
|
||||
"9sys/syslog.c",
|
||||
"9sys/sysname.c",
|
||||
"9sys/time.c",
|
||||
"9sys/times.c",
|
||||
"9sys/tm2sec.c",
|
||||
"9sys/truerand.c",
|
||||
"9sys/tsemacquire.c",
|
||||
"9sys/wait.c",
|
||||
"9sys/waitpid.c",
|
||||
"9sys/werrstr.c",
|
||||
"9sys/write.c",
|
||||
"apw/abort.c",
|
||||
"apw/div.c",
|
||||
"apw/eprintf.c",
|
||||
"apw/exit.c",
|
||||
"apw/system.c",
|
||||
"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/bsearch.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/exits.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/initlib.c",
|
||||
"$ARCH/syscalls.c",
|
||||
"$ARCH/notejmp.c",
|
||||
"$ARCH/cycles.c",
|
||||
"$ARCH/argv0.c",
|
||||
"$ARCH/rdpmc.c",
|
||||
"$ARCH/setjmp.s",
|
||||
"$ARCH/stackchk.c",
|
||||
"$ARCH/getfcr.s",
|
||||
"$ARCH/sqrt.s",
|
||||
"$ARCH/tas.s",
|
||||
"$ARCH/atom.s"
|
||||
]
|
||||
}
|
||||
}
|
539
sys/src/lib/jehanne/fmt/dofmt.c
Normal file
539
sys/src/lib/jehanne/fmt/dofmt.c
Normal 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
|
||||
jehanne_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 += jehanne_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 = jehanne_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 || jehanne_fullrune(m, me-m))
|
||||
m += jehanne_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 || jehanne_fullrune(m, me-m))
|
||||
m += jehanne_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
|
||||
jehanne_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 += jehanne_chartorune(&r, s+i);
|
||||
return _fmtcpy(f, s, j, i);
|
||||
}
|
||||
return _fmtcpy(f, s, jehanne_utflen(s), jehanne_strlen(s));
|
||||
}
|
||||
|
||||
/* fmt out a null terminated utf string */
|
||||
int
|
||||
_strfmt(Fmt *f)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = va_arg(f->args, char *);
|
||||
return jehanne_fmtstrcpy(f, s);
|
||||
}
|
||||
|
||||
/* public helper routine: fmt out a null terminated rune string already in hand */
|
||||
int
|
||||
jehanne_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 jehanne_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_t 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_t);
|
||||
if(sizeof(uintptr_t) == 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, uint32_t);
|
||||
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/lib/jehanne/fmt/dorfmt.c
Normal file
54
sys/src/lib/jehanne/fmt/dorfmt.c
Normal 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
|
||||
jehanne_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;
|
||||
}
|
||||
}
|
26
sys/src/lib/jehanne/fmt/errfmt.c
Normal file
26
sys/src/lib/jehanne/fmt/errfmt.c
Normal 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>
|
||||
#include "fmtdef.h"
|
||||
|
||||
int
|
||||
jehanne_errfmt(Fmt *f)
|
||||
{
|
||||
#if __STDC_HOSTED__
|
||||
char buf[ERRMAX+1];
|
||||
|
||||
jehanne_rerrstr(buf, ERRMAX);
|
||||
return _fmtcpy(f, buf, jehanne_utflen(buf), jehanne_strlen(buf));
|
||||
#else
|
||||
extern void panic(char *fmt, ...) __attribute__ ((noreturn));
|
||||
panic("No errfmt in kernel");
|
||||
#endif
|
||||
}
|
327
sys/src/lib/jehanne/fmt/fltfmt.c
Normal file
327
sys/src/lib/jehanne/fmt/fltfmt.c
Normal 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(jehanne_isNaN(f)) {
|
||||
jehanne_strcpy(s2, "NaN");
|
||||
return;
|
||||
}
|
||||
if(jehanne_isInf(f, 1)) {
|
||||
jehanne_strcpy(s2, "+Inf");
|
||||
return;
|
||||
}
|
||||
if(jehanne_isInf(f, -1)) {
|
||||
jehanne_strcpy(s2, "-Inf");
|
||||
return;
|
||||
}
|
||||
sign = 0;
|
||||
if(f < 0) {
|
||||
f = -f;
|
||||
sign++;
|
||||
}
|
||||
ucase = 0;
|
||||
chr = fmt->r;
|
||||
if(isupper(chr)) {
|
||||
ucase = 1;
|
||||
chr = jehanne_tolower(chr);
|
||||
}
|
||||
|
||||
e = 0;
|
||||
g = f;
|
||||
if(g != 0) {
|
||||
jehanne_frexp(f, &e);
|
||||
e = e * .301029995664;
|
||||
if(e >= -150 && e <= +150) {
|
||||
d = 0;
|
||||
h = f;
|
||||
} else {
|
||||
d = e/2;
|
||||
h = f * jehanne_pow10(-d);
|
||||
}
|
||||
g = h * jehanne_pow10(d-e);
|
||||
while(g < 1) {
|
||||
e--;
|
||||
g = h * jehanne_pow10(d-e);
|
||||
}
|
||||
while(g >= 10) {
|
||||
e++;
|
||||
g = h * jehanne_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) {
|
||||
jehanne_strcpy(s2, s1);
|
||||
d = e;
|
||||
s1[NSIGNIF-2] = '0';
|
||||
s1[NSIGNIF-1] = '0';
|
||||
jehanne_sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
|
||||
g = jehanne_strtod(s1, nil);
|
||||
if(g == f)
|
||||
goto found;
|
||||
if(xadd(s1, NSIGNIF-3, 1)) {
|
||||
e++;
|
||||
jehanne_sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
|
||||
}
|
||||
g = jehanne_strtod(s1, nil);
|
||||
if(g == f)
|
||||
goto found;
|
||||
jehanne_strcpy(s1, s2);
|
||||
e = d;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert back so s1 gets exact answer
|
||||
*/
|
||||
for(;;) {
|
||||
jehanne_sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
|
||||
g = jehanne_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, jehanne_strlen(s), jehanne_strlen(s));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_efgfmt(Fmt *f)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = va_arg(f->args, double);
|
||||
return _floatfmt(f, d);
|
||||
}
|
227
sys/src/lib/jehanne/fmt/fmt.c
Normal file
227
sys/src/lib/jehanne/fmt/fmt.c
Normal 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', jehanne_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
|
||||
jehanne_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 + jehanne_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/lib/jehanne/fmt/fmtdef.h
Normal file
94
sys/src/lib/jehanne/fmt/fmtdef.h
Normal 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 = jehanne_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 += jehanne_runetochar(t, &_rune);\
|
||||
}\
|
||||
}while(0)
|
40
sys/src/lib/jehanne/fmt/fmtfd.c
Normal file
40
sys/src/lib/jehanne/fmt/fmtfd.c
Normal 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
|
||||
jehanne_fmtfdflush(Fmt *f)
|
||||
{
|
||||
if(_fmtFdFlush(f) <= 0)
|
||||
return -1;
|
||||
return f->nfmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize an output buffer for buffered printing
|
||||
*/
|
||||
int
|
||||
jehanne_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;
|
||||
}
|
25
sys/src/lib/jehanne/fmt/fmtlock.c
Normal file
25
sys/src/lib/jehanne/fmt/fmtlock.c
Normal 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)
|
||||
{
|
||||
jehanne_lock(&fmtl);
|
||||
}
|
||||
|
||||
void
|
||||
_fmtunlock(void)
|
||||
{
|
||||
jehanne_unlock(&fmtl);
|
||||
}
|
30
sys/src/lib/jehanne/fmt/fmtprint.c
Normal file
30
sys/src/lib/jehanne/fmt/fmtprint.c
Normal 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
|
||||
jehanne_fmtprint(Fmt *f, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
int n;
|
||||
|
||||
va_start(va, fmt);
|
||||
n = jehanne_fmtvprint(f, fmt, va);
|
||||
va_end(va);
|
||||
return n;
|
||||
}
|
||||
|
259
sys/src/lib/jehanne/fmt/fmtquote.c
Normal file
259
sys/src/lib/jehanne/fmt/fmtquote.c
Normal 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 = jehanne_chartorune(&c, s);
|
||||
else{
|
||||
c = *r;
|
||||
w = jehanne_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 || jehanne_fullrune(m, me-m))
|
||||
m += jehanne_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);
|
||||
//jehanne_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
|
||||
jehanne_quotestrfmt(Fmt *f)
|
||||
{
|
||||
return _quotestrfmt(0, f);
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_quoterunestrfmt(Fmt *f)
|
||||
{
|
||||
return _quotestrfmt(1, f);
|
||||
}
|
||||
|
||||
void
|
||||
jehanne_quotefmtinstall(void)
|
||||
{
|
||||
jehanne_fmtinstall('q', jehanne_quotestrfmt);
|
||||
jehanne_fmtinstall('Q', jehanne_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;
|
||||
}
|
34
sys/src/lib/jehanne/fmt/fmtrune.c
Normal file
34
sys/src/lib/jehanne/fmt/fmtrune.c
Normal 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
|
||||
jehanne_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/lib/jehanne/fmt/fmtstr.c
Normal file
20
sys/src/lib/jehanne/fmt/fmtstr.c
Normal 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*
|
||||
jehanne_fmtstrflush(Fmt *f)
|
||||
{
|
||||
if(f->start == nil)
|
||||
return nil;
|
||||
*(char*)f->to = '\0';
|
||||
return f->start;
|
||||
}
|
39
sys/src/lib/jehanne/fmt/fmtvprint.c
Normal file
39
sys/src/lib/jehanne/fmt/fmtvprint.c
Normal 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
|
||||
jehanne_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 = jehanne_dofmt(f, fmt);
|
||||
va_end(f->args);
|
||||
va_copy(f->args,va);
|
||||
va_end(va);
|
||||
//f->args = va;
|
||||
if(n >= 0)
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
23
sys/src/lib/jehanne/fmt/fprint.c
Normal file
23
sys/src/lib/jehanne/fmt/fprint.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
jehanne_fprint(int fd, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = jehanne_vfprint(fd, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
23
sys/src/lib/jehanne/fmt/print.c
Normal file
23
sys/src/lib/jehanne/fmt/print.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
jehanne_print(const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = jehanne_vfprint(1, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
20
sys/src/lib/jehanne/fmt/runefmtstr.c
Normal file
20
sys/src/lib/jehanne/fmt/runefmtstr.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
jehanne_runefmtstrflush(Fmt *f)
|
||||
{
|
||||
if(f->start == nil)
|
||||
return nil;
|
||||
*(Rune*)f->to = '\0';
|
||||
return f->start;
|
||||
}
|
23
sys/src/lib/jehanne/fmt/runeseprint.c
Normal file
23
sys/src/lib/jehanne/fmt/runeseprint.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
jehanne_runeseprint(Rune *buf, Rune *e, const char *fmt, ...)
|
||||
{
|
||||
Rune *p;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = jehanne_runevseprint(buf, e, fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
23
sys/src/lib/jehanne/fmt/runesmprint.c
Normal file
23
sys/src/lib/jehanne/fmt/runesmprint.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
jehanne_runesmprint(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
Rune *p;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = jehanne_runevsmprint(fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
24
sys/src/lib/jehanne/fmt/runesnprint.c
Normal file
24
sys/src/lib/jehanne/fmt/runesnprint.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
jehanne_runesnprint(Rune *buf, int len, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = jehanne_runevsnprint(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
||||
|
23
sys/src/lib/jehanne/fmt/runesprint.c
Normal file
23
sys/src/lib/jehanne/fmt/runesprint.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
jehanne_runesprint(Rune *buf, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = jehanne_runevsnprint(buf, 256, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
34
sys/src/lib/jehanne/fmt/runevseprint.c
Normal file
34
sys/src/lib/jehanne/fmt/runevseprint.c
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
Rune*
|
||||
jehanne_runevseprint(Rune *buf, Rune *e, const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(e <= buf)
|
||||
return nil;
|
||||
f.runes = 1;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = e - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
jehanne_dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
*(Rune*)f.to = '\0';
|
||||
return f.to;
|
||||
}
|
||||
|
83
sys/src/lib/jehanne/fmt/runevsmprint.c
Normal file
83
sys/src/lib/jehanne/fmt/runevsmprint.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "fmtdef.h"
|
||||
|
||||
static int
|
||||
runeFmtStrFlush(Fmt *f)
|
||||
{
|
||||
Rune *s;
|
||||
int n;
|
||||
|
||||
if(f->start == nil)
|
||||
return 0;
|
||||
n = (int)(uintptr_t)f->farg;
|
||||
n *= 2;
|
||||
s = f->start;
|
||||
f->start = jehanne_realloc(s, sizeof(Rune)*n);
|
||||
if(f->start == nil){
|
||||
f->farg = nil;
|
||||
f->to = nil;
|
||||
f->stop = nil;
|
||||
jehanne_free(s);
|
||||
return 0;
|
||||
}
|
||||
f->farg = (void*)(uintptr_t)n;
|
||||
f->to = (Rune*)f->start + ((Rune*)f->to - s);
|
||||
f->stop = (Rune*)f->start + n - 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
jehanne_runefmtstrinit(Fmt *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
jehanne_memset(f, 0, sizeof *f);
|
||||
f->runes = 1;
|
||||
n = 32;
|
||||
f->start = jehanne_malloc(sizeof(Rune)*n);
|
||||
if(f->start == nil)
|
||||
return -1;
|
||||
jehanne_setmalloctag(f->start, jehanne_getcallerpc());
|
||||
f->to = f->start;
|
||||
f->stop = (Rune*)f->start + n - 1;
|
||||
f->flush = runeFmtStrFlush;
|
||||
f->farg = (void*)(uintptr_t)n;
|
||||
f->nfmt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* print into an allocated string buffer
|
||||
*/
|
||||
Rune*
|
||||
jehanne_runevsmprint(const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
int n;
|
||||
|
||||
if(jehanne_runefmtstrinit(&f) < 0)
|
||||
return nil;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
n = jehanne_dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
if(f.start == nil) /* realloc failed? */
|
||||
return nil;
|
||||
if(n < 0){
|
||||
jehanne_free(f.start);
|
||||
return nil;
|
||||
}
|
||||
jehanne_setmalloctag(f.start, jehanne_getcallerpc());
|
||||
*(Rune*)f.to = '\0';
|
||||
return f.start;
|
||||
}
|
33
sys/src/lib/jehanne/fmt/runevsnprint.c
Normal file
33
sys/src/lib/jehanne/fmt/runevsnprint.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
jehanne_runevsnprint(Rune *buf, int len, const char *fmt, va_list args)
|
||||
{
|
||||
Fmt f;
|
||||
|
||||
if(len <= 0)
|
||||
return -1;
|
||||
f.runes = 1;
|
||||
f.start = buf;
|
||||
f.to = buf;
|
||||
f.stop = buf + len - 1;
|
||||
f.flush = nil;
|
||||
f.farg = nil;
|
||||
f.nfmt = 0;
|
||||
//f.args = args;
|
||||
va_copy(f.args,args);
|
||||
jehanne_dofmt(&f, fmt);
|
||||
va_end(f.args);
|
||||
*(Rune*)f.to = '\0';
|
||||
return (Rune*)f.to - buf;
|
||||
}
|
23
sys/src/lib/jehanne/fmt/seprint.c
Normal file
23
sys/src/lib/jehanne/fmt/seprint.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
jehanne_seprint(char *buf, char *e, const char *fmt, ...)
|
||||
{
|
||||
char *p;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = jehanne_vseprint(buf, e, fmt, args);
|
||||
va_end(args);
|
||||
return p;
|
||||
}
|
24
sys/src/lib/jehanne/fmt/smprint.c
Normal file
24
sys/src/lib/jehanne/fmt/smprint.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
jehanne_smprint(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *p;
|
||||
|
||||
va_start(args, fmt);
|
||||
p = jehanne_vsmprint(fmt, args);
|
||||
va_end(args);
|
||||
jehanne_setmalloctag(p, jehanne_getcallerpc());
|
||||
return p;
|
||||
}
|
24
sys/src/lib/jehanne/fmt/snprint.c
Normal file
24
sys/src/lib/jehanne/fmt/snprint.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||
* terms in the LICENSE file found in the top-level directory of this
|
||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
||||
* modified, propagated, or distributed except according to the terms contained
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
jehanne_snprint(char *buf, int len, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = jehanne_vsnprint(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
return n;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user