Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3351 → Rev 3386

/branches/network/uspace/lib/libc/generic/vfs.c
File deleted
/branches/network/uspace/lib/libc/generic/io/asprintf.c
0,0 → 1,79
/*
* Copyright (c) 2006 Josef Cejka
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <io/printf_core.h>
 
static int asprintf_prewrite(const char *str, size_t count, void *unused)
{
return count;
}
 
/** Allocate and print to string.
*
* @param strp Address of the pointer where to store the address of
* the newly allocated string.
* @fmt Format strin.
*
* @return Number of characters printed or a negative error code.
*/
int asprintf(char **strp, const char *fmt, ...)
{
struct printf_spec ps = {
asprintf_prewrite,
NULL
};
int ret;
va_list args;
 
va_start(args, fmt);
ret = printf_core(fmt, &ps, args);
va_end(args);
if (ret > 0) {
*strp = malloc(ret + 20);
if (!*strp)
return -1;
va_start(args, fmt);
vsprintf(*strp, fmt, args);
va_end(args);
}
 
return ret;
}
 
/** @}
*/
/branches/network/uspace/lib/libc/generic/io/vsnprintf.c
38,22 → 38,27
#include <io/printf_core.h>
 
struct vsnprintf_data {
size_t size; /* total space for string */
size_t len; /* count of currently used characters */
char *string; /* destination string */
size_t size; /* total space for string */
size_t len; /* count of currently used characters */
char *string; /* destination string */
};
 
/** Write string to given buffer.
* Write at most data->size characters including trailing zero. According to C99 has snprintf to return number
* of characters that would have been written if enough space had been available. Hence the return value is not
* number of really printed characters but size of input string. Number of really used characters
* is stored in data->len.
* @param str source string to print
* @param count size of source string
* @param data structure with destination string, counter of used space and total string size.
* @return number of characters to print (not characters really printed!)
* Write at most data->size characters including trailing zero. According to C99
* has snprintf to return number of characters that would have been written if
* enough space had been available. Hence the return value is not number of
* really printed characters but size of input string. Number of really used
* characters is stored in data->len.
*
* @param str Source string to print.
* @param count Size of the source string.
* @param data Structure with destination string, counter of used space
* and total string size.
* @return Number of characters to print (not characters really
* printed!)
*/
static int vsnprintf_write(const char *str, size_t count, struct vsnprintf_data *data)
static int
vsnprintf_write(const char *str, size_t count, struct vsnprintf_data *data)
{
size_t i;
i = data->size - data->len;
63,7 → 68,10
}
if (i == 1) {
/* We have only one free byte left in buffer => write there trailing zero */
/*
* We have only one free byte left in buffer => write there
* trailing zero.
*/
data->string[data->size - 1] = 0;
data->len = data->size;
return count;
70,17 → 78,23
}
if (i <= count) {
/* We have not enought space for whole string with the trailing zero => print only a part of string */
memcpy((void *)(data->string + data->len), (void *)str, i - 1);
data->string[data->size - 1] = 0;
data->len = data->size;
return count;
/*
* We have not enought space for whole string with the trailing
* zero => print only a part of string.
*/
memcpy((void *)(data->string + data->len), (void *)str, i - 1);
data->string[data->size - 1] = 0;
data->len = data->size;
return count;
}
/* Buffer is big enought to print whole string */
memcpy((void *)(data->string + data->len), (void *)str, count);
data->len += count;
/* Put trailing zero at end, but not count it into data->len so it could be rewritten next time */
/*
* Put trailing zero at end, but not count it into data->len so it could
* be rewritten next time.
*/
data->string[data->len] = 0;
 
return count;
87,17 → 101,22
}
 
/** Print formatted to the given buffer with limited size.
* @param str buffer
* @param size buffer size
* @param fmt format string
* @param str Buffer.
* @param size Bffer size.
* @param fmt Format string.
* \see For more details about format string see printf_core.
*/
int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
{
struct vsnprintf_data data = {size, 0, str};
struct printf_spec ps = {(int(*)(void *, size_t, void *)) vsnprintf_write, &data};
struct printf_spec ps = {
(int(*)(void *, size_t, void *)) vsnprintf_write,
&data
};
 
/* Print 0 at end of string - fix the case that nothing will be printed */
/*
* Print 0 at end of string - fix the case that nothing will be printed.
*/
if (size > 0)
str[0] = 0;
/branches/network/uspace/lib/libc/generic/io/sprintf.c
48,7 → 48,6
va_start(args, fmt);
ret = vsprintf(str, fmt, args);
 
va_end(args);
 
return ret;
/branches/network/uspace/lib/libc/generic/io/printf_core.c
94,12 → 94,9
if (str == NULL)
return printf_putnchars("(NULL)", 6, ps);
 
for (count = 0; str[count] != 0; count++);
count = strlen(str);
 
if (ps->write((void *) str, count, ps->data) == count)
return 0;
return EOF;
return ps->write((void *) str, count, ps->data);
}
 
/** Print one character to output
/branches/network/uspace/lib/libc/generic/io/stream.c
56,52 → 56,63
 
ssize_t read_stdin(void *buf, size_t count)
{
ipcarg_t r0, r1;
size_t i = 0;
 
while (i < count) {
if (async_req_0_2(console_phone, CONSOLE_GETCHAR, &r0,
&r1) < 0) {
return -1;
open_console();
if (console_phone >= 0) {
ipcarg_t r0, r1;
size_t i = 0;
while (i < count) {
if (async_req_0_2(console_phone, CONSOLE_GETCHAR, &r0, &r1) < 0)
return -1;
((char *) buf)[i++] = r0;
}
((char *) buf)[i++] = r0;
return i;
} else {
return -1;
}
return i;
}
 
ssize_t write_stdout(const void *buf, size_t count)
{
int i;
 
for (i = 0; i < count; i++)
async_msg_1(console_phone, CONSOLE_PUTCHAR,
((const char *) buf)[i]);
open_console();
if (console_phone >= 0) {
int i;
return count;
for (i = 0; i < count; i++)
async_msg_1(console_phone, CONSOLE_PUTCHAR,
((const char *) buf)[i]);
return count;
} else
return __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, count);
}
 
void open_stdin(void)
void open_console(void)
{
if (console_phone < 0) {
while ((console_phone = ipc_connect_me_to(PHONE_NS,
SERVICE_CONSOLE, 0, 0)) < 0) {
usleep(10000);
}
int phone = ipc_connect_me_to(PHONE_NS, SERVICE_CONSOLE, 0, 0);
if (phone >= 0)
console_phone = phone;
}
}
 
void open_stdout(void)
void close_console(void)
{
if (console_phone < 0) {
while ((console_phone = ipc_connect_me_to(PHONE_NS,
SERVICE_CONSOLE, 0, 0)) < 0) {
usleep(10000);
if (console_phone >= 0) {
if (ipc_hangup(console_phone) == 0) {
console_phone = -1;
}
}
}
 
void klog_update(void)
{
(void) __SYSCALL3(SYS_KLOG, 1, NULL, 0);
}
 
int get_cons_phone(void)
{
open_console();
return console_phone;
}
 
/branches/network/uspace/lib/libc/generic/getopt.c
0,0 → 1,478
/* $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $ */
 
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
 
/* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */
 
#include <assert.h>
#include <stdarg.h>
#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
 
/* HelenOS Port : We're incorporating only the modern getopt_long with wrappers
* to keep legacy getopt() usage from breaking. All references to REPLACE_GETOPT
* are dropped, we just include the code */
 
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
 
 
#define IGNORE_FIRST (*options == '-' || *options == '+')
#define PRINT_ERROR ((opterr) && ((*options != ':') \
|| (IGNORE_FIRST && options[1] != ':')))
/*HelenOS Port - POSIXLY_CORRECT is always false */
#define IS_POSIXLY_CORRECT 0
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
/* XXX: GNU ignores PC if *options == '-' */
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
 
/* return values */
#define BADCH (int)'?'
#define BADARG ((IGNORE_FIRST && options[1] == ':') \
|| (*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
 
#define EMSG ""
 
static int getopt_internal(int, char **, const char *);
static int gcd(int, int);
static void permute_args(int, int, int, char **);
 
static const char *place = EMSG; /* option letter processing */
 
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
 
/* Error messages */
 
/* HelenOS Port: Calls to warnx() were eliminated (as we have no stderr that
* may be redirected) and replaced with printf. As such, error messages now
* end in a newline */
 
static const char recargchar[] = "option requires an argument -- %c\n";
static const char recargstring[] = "option requires an argument -- %s\n";
static const char ambig[] = "ambiguous option -- %.*s\n";
static const char noarg[] = "option doesn't take an argument -- %.*s\n";
static const char illoptchar[] = "unknown option -- %c\n";
static const char illoptstring[] = "unknown option -- %s\n";
 
 
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(a, b)
int a;
int b;
{
int c;
 
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return b;
}
 
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(panonopt_start, panonopt_end, opt_end, nargv)
int panonopt_start;
int panonopt_end;
int opt_end;
char **nargv;
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
 
assert(nargv != NULL);
 
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
 
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
nargv[pos] = nargv[cstart];
nargv[cstart] = swap;
}
}
}
 
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
* Returns -2 if -- is found (can be long option or end of options marker).
*/
static int
getopt_internal(nargc, nargv, options)
int nargc;
char **nargv;
const char *options;
{
char *oli; /* option letter list index */
int optchar;
 
assert(nargv != NULL);
assert(options != NULL);
 
optarg = NULL;
 
/*
* XXX Some programs (like rsyncd) expect to be able to
* XXX re-initialize optind to 0 and have getopt_long(3)
* XXX properly function again. Work around this braindamage.
*/
if (optind == 0)
optind = 1;
 
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((*(place = nargv[optind]) != '-')
|| (place[1] == '\0')) { /* found non-option */
place = EMSG;
if (IN_ORDER) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return INORDER;
}
if (!PERMUTE) {
/*
* if no permutation wanted, stop parsing
* at first non-option
*/
return -1;
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
if (place[1] && *++place == '-') { /* found "--" */
place++;
return -2;
}
}
if ((optchar = (int)*place++) == (int)':' ||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
/* option letter unknown or ':' */
if (!*place)
++optind;
if (PRINT_ERROR)
printf(illoptchar, optchar);
optopt = optchar;
return BADCH;
}
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
/* XXX: what if no long options provided (called by getopt)? */
if (*place)
return -2;
 
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
printf(recargchar, optchar);
optopt = optchar;
return BADARG;
} else /* white space */
place = nargv[optind];
/*
* Handle -W arg the same as --arg (which causes getopt to
* stop parsing).
*/
return -2;
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = *place;
/* XXX: disable test for :: if PC? (GNU doesn't) */
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
printf(recargchar, optchar);
optopt = optchar;
return BADARG;
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return optchar;
}
 
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
int retval;
 
assert(nargv != NULL);
assert(options != NULL);
 
retval = getopt_internal(nargc, (char **)nargv, options);
if (retval == -2) {
++optind;
/*
* We found an option (--), so if we skipped non-options,
* we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind,
(char **)nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
retval = -1;
}
return retval;
}
 
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(nargc, nargv, options, long_options, idx)
int nargc;
char * const *nargv;
const char *options;
const struct option *long_options;
int *idx;
{
int retval;
 
#define IDENTICAL_INTERPRETATION(_x, _y) \
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
long_options[(_x)].flag == long_options[(_y)].flag && \
long_options[(_x)].val == long_options[(_y)].val)
 
assert(nargv != NULL);
assert(options != NULL);
assert(long_options != NULL);
/* idx may be NULL */
 
retval = getopt_internal(nargc, (char **)nargv, options);
if (retval == -2) {
char *current_argv, *has_equal;
size_t current_argv_len;
int i, ambiguous, match;
 
current_argv = (char *)place;
match = -1;
ambiguous = 0;
 
optind++;
place = EMSG;
 
if (*current_argv == '\0') { /* found "--" */
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, (char **)nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
 
if (strlen(long_options[i].name) ==
(unsigned)current_argv_len) {
/* exact match */
match = i;
ambiguous = 0;
break;
}
if (match == -1) /* partial match */
match = i;
else if (!IDENTICAL_INTERPRETATION(i, match))
ambiguous = 1;
}
if (ambiguous) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
printf(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return BADCH;
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
printf(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of
* flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return BADARG;
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use
* next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':'
* indicates no error should be generated
*/
if (PRINT_ERROR)
printf(recargstring, current_argv);
/*
* XXX: GNU sets optopt to val regardless
* of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return BADARG;
}
} else { /* unknown option */
if (PRINT_ERROR)
printf(illoptstring, current_argv);
optopt = 0;
return BADCH;
}
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
retval = 0;
} else
retval = long_options[match].val;
if (idx)
*idx = match;
}
return retval;
#undef IDENTICAL_INTERPRETATION
}
 
/branches/network/uspace/lib/libc/generic/ipc.c
682,7 → 682,7
{
int res;
sysarg_t tmp_flags;
res = ipc_call_sync_3_2(phoneid, IPC_M_SHARE_IN, (ipcarg_t) dst,
res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (ipcarg_t) dst,
(ipcarg_t) size, arg, NULL, &tmp_flags);
if (flags)
*flags = tmp_flags;
742,7 → 742,7
*/
int ipc_share_out_start(int phoneid, void *src, int flags)
{
return ipc_call_sync_3_0(phoneid, IPC_M_SHARE_OUT, (ipcarg_t) src, 0,
return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (ipcarg_t) src, 0,
(ipcarg_t) flags);
}
 
770,7 → 770,7
assert(flags);
 
*callid = async_get_call(&data);
if (IPC_GET_METHOD(data) != IPC_M_DATA_WRITE)
if (IPC_GET_METHOD(data) != IPC_M_SHARE_OUT)
return 0;
*size = (size_t) IPC_GET_ARG2(data);
*flags = (int) IPC_GET_ARG3(data);
803,7 → 803,7
*/
int ipc_data_read_start(int phoneid, void *dst, size_t size)
{
return ipc_call_sync_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst,
return async_req_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst,
(ipcarg_t) size);
}
 
862,7 → 862,7
*/
int ipc_data_write_start(int phoneid, void *src, size_t size)
{
return ipc_call_sync_2_0(phoneid, IPC_M_DATA_WRITE, (ipcarg_t) src,
return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (ipcarg_t) src,
(ipcarg_t) size);
}
 
/branches/network/uspace/lib/libc/generic/vfs/canonify.c
0,0 → 1,340
/*
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup libc
* @{
*/
 
/**
* @file
* @brief
*/
 
#include <stdlib.h>
 
/** Token types used for tokenization of path. */
typedef enum {
TK_INVALID,
TK_SLASH,
TK_DOT,
TK_DOTDOT,
TK_COMP,
TK_NUL
} tokval_t;
 
typedef struct {
tokval_t kind;
char *start;
char *stop;
} token_t;
 
/** Fake up the TK_SLASH token. */
static token_t slash_token(char *start)
{
token_t ret;
ret.kind = TK_SLASH;
ret.start = start;
ret.stop = start;
return ret;
}
 
/** Given a token, return the next token. */
static token_t next_token(token_t *cur)
{
token_t ret;
 
if (cur->stop[1] == '\0') {
ret.kind = TK_NUL;
ret.start = cur->stop + 1;
ret.stop = ret.start;
return ret;
}
if (cur->stop[1] == '/') {
ret.kind = TK_SLASH;
ret.start = cur->stop + 1;
ret.stop = ret.start;
return ret;
}
if (cur->stop[1] == '.' && (!cur->stop[2] || cur->stop[2] == '/')) {
ret.kind = TK_DOT;
ret.start = cur->stop + 1;
ret.stop = ret.start;
return ret;
}
if (cur->stop[1] == '.' && cur->stop[2] == '.' &&
(!cur->stop[3] || cur->stop[3] == '/')) {
ret.kind = TK_DOTDOT;
ret.start = cur->stop + 1;
ret.stop = cur->stop + 2;
return ret;
}
unsigned i;
for (i = 1; cur->stop[i] && cur->stop[i] != '/'; i++)
;
ret.kind = TK_COMP;
ret.start = &cur->stop[1];
ret.stop = &cur->stop[i - 1];
return ret;
}
 
/** States used by canonify(). */
typedef enum {
S_INI,
S_A,
S_B,
S_C,
S_ACCEPT,
S_RESTART,
S_REJECT
} state_t;
 
typedef struct {
state_t s;
void (* f)(token_t *, token_t *, token_t *);
} change_state_t;
 
/*
* Actions that can be performed when transitioning from one
* state of canonify() to another.
*/
static void set_first_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
{
*tfsl = *t;
*tlcomp = *t;
}
static void save_component(token_t *t, token_t *tfsl, token_t *tlcomp)
{
*tlcomp = *t;
}
static void terminate_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
{
if (tfsl->stop[1]) /* avoid writing to a well-formatted path */
tfsl->stop[1] = '\0';
}
static void remove_trailing_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
{
t->start[-1] = '\0';
}
/** Eat the extra '/'..
*
* @param t The current TK_SLASH token.
*/
static void shift_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
{
char *p = t->start;
char *q = t->stop + 1;
while ((*p++ = *q++))
;
}
/** Eat the extra '.'.
*
* @param t The current TK_DOT token.
*/
static void shift_dot(token_t *t, token_t *tfsl, token_t *tlcomp)
{
char *p = t->start;
char *q = t->stop + 1;
while ((*p++ = *q++))
;
}
/** Collapse the TK_COMP TK_SLASH TK_DOTDOT pattern.
*
* @param t The current TK_DOTDOT token.
* @param tlcomp The last TK_COMP token.
*/
static void shift_dotdot(token_t *t, token_t *tfsl, token_t *tlcomp)
{
char *p = tlcomp->start;
char *q = t->stop + 1;
while ((*p++ = *q++))
;
}
 
/** Transition function for canonify(). */
static change_state_t trans[4][6] = {
[S_INI] = {
[TK_SLASH] = {
.s = S_A,
.f = set_first_slash,
},
[TK_DOT] = {
.s = S_REJECT,
.f = NULL,
},
[TK_DOTDOT] = {
.s = S_REJECT,
.f = NULL,
},
[TK_COMP] = {
.s = S_REJECT,
.f = NULL,
},
[TK_NUL] = {
.s = S_REJECT,
.f = NULL,
},
[TK_INVALID] = {
.s = S_REJECT,
.f = NULL,
},
},
[S_A] = {
[TK_SLASH] = {
.s = S_A,
.f = set_first_slash,
},
[TK_DOT] = {
.s = S_A,
.f = NULL,
},
[TK_DOTDOT] = {
.s = S_A,
.f = NULL,
},
[TK_COMP] = {
.s = S_B,
.f = save_component,
},
[TK_NUL] = {
.s = S_ACCEPT,
.f = terminate_slash,
},
[TK_INVALID] = {
.s = S_REJECT,
.f = NULL,
},
},
[S_B] = {
[TK_SLASH] = {
.s = S_C,
.f = NULL,
},
[TK_DOT] = {
.s = S_REJECT,
.f = NULL,
},
[TK_DOTDOT] = {
.s = S_REJECT,
.f = NULL,
},
[TK_COMP] = {
.s = S_REJECT,
.f = NULL,
},
[TK_NUL] = {
.s = S_ACCEPT,
.f = NULL,
},
[TK_INVALID] = {
.s = S_REJECT,
.f = NULL,
},
},
[S_C] = {
[TK_SLASH] = {
.s = S_RESTART,
.f = shift_slash,
},
[TK_DOT] = {
.s = S_RESTART,
.f = shift_dot,
},
[TK_DOTDOT] = {
.s = S_RESTART,
.f = shift_dotdot,
},
[TK_COMP] = {
.s = S_B,
.f = save_component,
},
[TK_NUL] = {
.s = S_ACCEPT,
.f = remove_trailing_slash,
},
[TK_INVALID] = {
.s = S_REJECT,
.f = NULL,
},
}
};
 
/** Canonify a file system path.
*
* A file system path is canonical, if the following holds:
* 1) the path is absolute (i.e. a/b/c is not canonical)
* 2) there is no trailing slash in the path (i.e. /a/b/c is not canonical)
* 3) there is no extra slash in the path (i.e. /a//b/c is not canonical)
* 4) there is no '.' component in the path (i.e. /a/./b/c is not canonical)
* 5) there is no '..' component in the path (i.e. /a/b/../c is not canonical)
*
* This function makes a potentially non-canonical file system path canonical.
* It works in-place and requires a NULL-terminated input string.
*
* @param path Path to be canonified.
* @param lenp Pointer where the length of the final path will be
* stored. Can be NULL.
*
* @return Canonified path or NULL on failure.
*/
char *canonify(char *path, size_t *lenp)
{
state_t state;
token_t t;
token_t tfsl; /* first slash */
token_t tlcomp; /* last component */
if (*path != '/')
return NULL;
tfsl = slash_token(path);
restart:
state = S_INI;
t = tfsl;
tlcomp = tfsl;
while (state != S_ACCEPT && state != S_RESTART && state != S_REJECT) {
if (trans[state][t.kind].f)
trans[state][t.kind].f(&t, &tfsl, &tlcomp);
state = trans[state][t.kind].s;
t = next_token(&t);
}
switch (state) {
case S_RESTART:
goto restart;
case S_REJECT:
return NULL;
case S_ACCEPT:
if (lenp)
*lenp = (size_t)((tlcomp.stop - tfsl.start) + 1);
return tfsl.start;
default:
abort();
}
}
 
/**
* @}
*/
/branches/network/uspace/lib/libc/generic/vfs/vfs.c
0,0 → 1,619
/*
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
#include <vfs/vfs.h>
#include <vfs/canonify.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/types.h>
#include <ipc/ipc.h>
#include <ipc/services.h>
#include <async.h>
#include <atomic.h>
#include <futex.h>
#include <errno.h>
#include <string.h>
#include <ipc/devmap.h>
#include "../../srv/vfs/vfs.h"
 
int vfs_phone = -1;
futex_t vfs_phone_futex = FUTEX_INITIALIZER;
 
futex_t cwd_futex = FUTEX_INITIALIZER;
DIR *cwd_dir = NULL;
char *cwd_path = NULL;
size_t cwd_len = 0;
 
char *absolutize(const char *path, size_t *retlen)
{
char *ncwd_path;
char *ncwd_path_nc;
 
futex_down(&cwd_futex);
size_t len = strlen(path);
if (*path != '/') {
if (!cwd_path) {
futex_up(&cwd_futex);
return NULL;
}
ncwd_path_nc = malloc(cwd_len + 1 + len + 1);
if (!ncwd_path_nc) {
futex_up(&cwd_futex);
return NULL;
}
strcpy(ncwd_path_nc, cwd_path);
ncwd_path_nc[cwd_len] = '/';
ncwd_path_nc[cwd_len + 1] = '\0';
} else {
ncwd_path_nc = malloc(len + 1);
if (!ncwd_path_nc) {
futex_up(&cwd_futex);
return NULL;
}
ncwd_path_nc[0] = '\0';
}
strcat(ncwd_path_nc, path);
ncwd_path = canonify(ncwd_path_nc, retlen);
if (!ncwd_path) {
futex_up(&cwd_futex);
free(ncwd_path_nc);
return NULL;
}
/*
* We need to clone ncwd_path because canonify() works in-place and thus
* the address in ncwd_path need not be the same as ncwd_path_nc, even
* though they both point into the same dynamically allocated buffer.
*/
ncwd_path = strdup(ncwd_path);
free(ncwd_path_nc);
if (!ncwd_path) {
futex_up(&cwd_futex);
return NULL;
}
futex_up(&cwd_futex);
return ncwd_path;
}
 
static int vfs_connect(void)
{
if (vfs_phone < 0)
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
return vfs_phone;
}
 
static int device_get_handle(char *name, dev_handle_t *handle)
{
int phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CLIENT,
0);
if (phone < 0)
return phone;
ipc_call_t answer;
aid_t req = async_send_2(phone, DEVMAP_DEVICE_GET_HANDLE, 0, 0,
&answer);
ipcarg_t retval = ipc_data_write_start(phone, name, strlen(name) + 1);
 
if (retval != EOK) {
async_wait_for(req, NULL);
ipc_hangup(phone);
return retval;
}
 
async_wait_for(req, &retval);
 
if (handle != NULL)
*handle = -1;
if (retval == EOK) {
if (handle != NULL)
*handle = (dev_handle_t) IPC_GET_ARG1(answer);
}
ipc_hangup(phone);
return retval;
}
 
int mount(const char *fs_name, const char *mp, const char *dev)
{
int res;
ipcarg_t rc;
aid_t req;
dev_handle_t dev_handle;
res = device_get_handle(dev, &dev_handle);
if (res != EOK)
return res;
size_t mpa_len;
char *mpa = absolutize(mp, &mpa_len);
if (!mpa)
return ENOMEM;
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
free(mpa);
return res;
}
}
req = async_send_1(vfs_phone, VFS_MOUNT, dev_handle, NULL);
rc = ipc_data_write_start(vfs_phone, (void *)fs_name, strlen(fs_name));
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(mpa);
return (int) rc;
}
/* Ask VFS whether it likes fs_name. */
rc = async_req_0_0(vfs_phone, IPC_M_PING);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(mpa);
return (int) rc;
}
rc = ipc_data_write_start(vfs_phone, (void *)mpa, mpa_len);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(mpa);
return (int) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(mpa);
return (int) rc;
}
 
static int _open(const char *path, int lflag, int oflag, ...)
{
int res;
ipcarg_t rc;
ipc_call_t answer;
aid_t req;
size_t pa_len;
char *pa = absolutize(path, &pa_len);
if (!pa)
return ENOMEM;
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return res;
}
}
req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
rc = ipc_data_write_start(vfs_phone, pa, pa_len);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return (int) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
 
if (rc != EOK)
return (int) rc;
return (int) IPC_GET_ARG1(answer);
}
 
int open(const char *path, int oflag, ...)
{
return _open(path, L_FILE, oflag);
}
 
int close(int fildes)
{
int res;
ipcarg_t rc;
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
return res;
}
}
rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes);
 
async_serialize_end();
futex_up(&vfs_phone_futex);
return (int)rc;
}
 
ssize_t read(int fildes, void *buf, size_t nbyte)
{
int res;
ipcarg_t rc;
ipc_call_t answer;
aid_t req;
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
return res;
}
}
req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
return (ssize_t) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
futex_up(&vfs_phone_futex);
if (rc == EOK)
return (ssize_t) IPC_GET_ARG1(answer);
else
return rc;
}
 
ssize_t write(int fildes, const void *buf, size_t nbyte)
{
int res;
ipcarg_t rc;
ipc_call_t answer;
aid_t req;
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
return res;
}
}
req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer);
rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
return (ssize_t) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
futex_up(&vfs_phone_futex);
if (rc == EOK)
return (ssize_t) IPC_GET_ARG1(answer);
else
return -1;
}
 
off_t lseek(int fildes, off_t offset, int whence)
{
int res;
ipcarg_t rc;
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
return res;
}
}
off_t newoffs;
rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
(ipcarg_t)&newoffs);
 
async_serialize_end();
futex_up(&vfs_phone_futex);
 
if (rc != EOK)
return (off_t) -1;
return newoffs;
}
 
int ftruncate(int fildes, off_t length)
{
int res;
ipcarg_t rc;
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
return res;
}
}
rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
async_serialize_end();
futex_up(&vfs_phone_futex);
return (int) rc;
}
 
DIR *opendir(const char *dirname)
{
DIR *dirp = malloc(sizeof(DIR));
if (!dirp)
return NULL;
dirp->fd = _open(dirname, L_DIRECTORY, 0);
if (dirp->fd < 0) {
free(dirp);
return NULL;
}
return dirp;
}
 
struct dirent *readdir(DIR *dirp)
{
ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
if (len <= 0)
return NULL;
return &dirp->res;
}
 
void rewinddir(DIR *dirp)
{
(void) lseek(dirp->fd, 0, SEEK_SET);
}
 
int closedir(DIR *dirp)
{
(void) close(dirp->fd);
free(dirp);
return 0;
}
 
int mkdir(const char *path, mode_t mode)
{
int res;
ipcarg_t rc;
aid_t req;
size_t pa_len;
char *pa = absolutize(path, &pa_len);
if (!pa)
return ENOMEM;
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return res;
}
}
req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
rc = ipc_data_write_start(vfs_phone, pa, pa_len);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return (int) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return rc;
}
 
static int _unlink(const char *path, int lflag)
{
int res;
ipcarg_t rc;
aid_t req;
size_t pa_len;
char *pa = absolutize(path, &pa_len);
if (!pa)
return ENOMEM;
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return res;
}
}
req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
rc = ipc_data_write_start(vfs_phone, pa, pa_len);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return (int) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(pa);
return rc;
}
 
int unlink(const char *path)
{
return _unlink(path, L_NONE);
}
 
int rmdir(const char *path)
{
return _unlink(path, L_DIRECTORY);
}
 
int rename(const char *old, const char *new)
{
int res;
ipcarg_t rc;
aid_t req;
size_t olda_len;
char *olda = absolutize(old, &olda_len);
if (!olda)
return ENOMEM;
 
size_t newa_len;
char *newa = absolutize(new, &newa_len);
if (!newa) {
free(olda);
return ENOMEM;
}
 
futex_down(&vfs_phone_futex);
async_serialize_start();
if (vfs_phone < 0) {
res = vfs_connect();
if (res < 0) {
async_serialize_end();
futex_up(&vfs_phone_futex);
free(olda);
free(newa);
return res;
}
}
req = async_send_0(vfs_phone, VFS_RENAME, NULL);
rc = ipc_data_write_start(vfs_phone, olda, olda_len);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(olda);
free(newa);
return (int) rc;
}
rc = ipc_data_write_start(vfs_phone, newa, newa_len);
if (rc != EOK) {
async_wait_for(req, NULL);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(olda);
free(newa);
return (int) rc;
}
async_wait_for(req, &rc);
async_serialize_end();
futex_up(&vfs_phone_futex);
free(olda);
free(newa);
return rc;
}
 
int chdir(const char *path)
{
size_t pa_len;
char *pa = absolutize(path, &pa_len);
if (!pa)
return ENOMEM;
 
DIR *d = opendir(pa);
if (!d) {
free(pa);
return ENOENT;
}
 
futex_down(&cwd_futex);
if (cwd_dir) {
closedir(cwd_dir);
cwd_dir = NULL;
free(cwd_path);
cwd_path = NULL;
cwd_len = 0;
}
cwd_dir = d;
cwd_path = pa;
cwd_len = pa_len;
futex_up(&cwd_futex);
}
 
char *getcwd(char *buf, size_t size)
{
if (!size)
return NULL;
futex_down(&cwd_futex);
if (size < cwd_len + 1) {
futex_up(&cwd_futex);
return NULL;
}
strcpy(buf, cwd_path);
futex_up(&cwd_futex);
return buf;
}
 
/** @}
*/
/branches/network/uspace/lib/libc/generic/task.c
1,5 → 1,6
/*
* Copyright (c) 2006 Jakub Jermar
* Copyright (c) 2008 Jiri Svoboda
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
33,7 → 34,14
*/
 
#include <task.h>
#include <ipc/ipc.h>
#include <ipc/loader.h>
#include <libc.h>
#include <string.h>
#include <stdlib.h>
#include <async.h>
#include <errno.h>
#include <vfs/vfs.h>
 
task_id_t task_get_id(void)
{
44,5 → 52,136
return task_id;
}
 
static int task_spawn_loader(void)
{
int phone_id, rc;
 
rc = __SYSCALL1(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id);
if (rc != 0)
return rc;
 
return phone_id;
}
 
static int loader_set_args(int phone_id, const char *argv[])
{
aid_t req;
ipc_call_t answer;
ipcarg_t rc;
 
const char **ap;
char *dp;
char *arg_buf;
size_t buffer_size;
size_t len;
 
/*
* Serialize the arguments into a single array. First
* compute size of the buffer needed.
*/
ap = argv;
buffer_size = 0;
while (*ap != NULL) {
buffer_size += strlen(*ap) + 1;
++ap;
}
 
arg_buf = malloc(buffer_size);
if (arg_buf == NULL) return ENOMEM;
 
/* Now fill the buffer with null-terminated argument strings */
ap = argv;
dp = arg_buf;
while (*ap != NULL) {
strcpy(dp, *ap);
dp += strlen(*ap) + 1;
 
++ap;
}
 
/* Send serialized arguments to the loader */
 
req = async_send_0(phone_id, LOADER_SET_ARGS, &answer);
rc = ipc_data_write_start(phone_id, (void *)arg_buf, buffer_size);
if (rc != EOK) {
async_wait_for(req, NULL);
return rc;
}
 
async_wait_for(req, &rc);
if (rc != EOK) return rc;
 
/* Free temporary buffer */
free(arg_buf);
 
return EOK;
}
 
/** Create a new task by running an executable from VFS.
*
* @param path pathname of the binary to execute
* @param argv command-line arguments
* @return ID of the newly created task or zero on error.
*/
task_id_t task_spawn(const char *path, const char *argv[])
{
int phone_id;
ipc_call_t answer;
aid_t req;
int rc;
ipcarg_t retval;
 
char *pa;
size_t pa_len;
 
pa = absolutize(path, &pa_len);
if (!pa)
return 0;
 
/* Spawn a program loader */
phone_id = task_spawn_loader();
if (phone_id < 0)
return 0;
 
/*
* Say hello so that the loader knows the incoming connection's
* phone hash.
*/
rc = async_req_0_0(phone_id, LOADER_HELLO);
if (rc != EOK)
return 0;
 
/* Send program pathname */
req = async_send_0(phone_id, LOADER_SET_PATHNAME, &answer);
rc = ipc_data_write_start(phone_id, (void *)pa, pa_len);
if (rc != EOK) {
async_wait_for(req, NULL);
return 1;
}
 
async_wait_for(req, &retval);
if (retval != EOK)
goto error;
 
/* Send arguments */
rc = loader_set_args(phone_id, argv);
if (rc != EOK)
goto error;
 
/* Request loader to start the program */
rc = async_req_0_0(phone_id, LOADER_RUN);
if (rc != EOK)
goto error;
 
/* Success */
ipc_hangup(phone_id);
return 1;
 
/* Error exit */
error:
ipc_hangup(phone_id);
return 0;
}
 
/** @}
*/
/branches/network/uspace/lib/libc/generic/string.c
38,8 → 38,8
#include <limits.h>
#include <align.h>
#include <sys/types.h>
#include <malloc.h>
 
 
/* Dummy implementation of mem/ functions */
 
void *memset(void *s, int c, size_t n)
66,9 → 66,10
adst[i].n = asrc[i].n;
for (j = 0; j < n % sizeof(unsigned long); j++)
((unsigned char *) (((unsigned long *) dst) + i))[j] = ((unsigned char *) (((unsigned long *) src) + i))[j];
((unsigned char *) (((unsigned long *) dst) + i))[j] =
((unsigned char *) (((unsigned long *) src) + i))[j];
return (char *) src;
return (char *) dst;
}
 
void *memcpy(void *dst, const void *src, size_t n)
75,7 → 76,8
{
int i, j;
 
if (((long) dst & (sizeof(long) - 1)) || ((long) src & (sizeof(long) - 1)))
if (((long) dst & (sizeof(long) - 1)) ||
((long) src & (sizeof(long) - 1)))
return unaligned_memcpy(dst, src, n);
 
for (i = 0; i < n / sizeof(unsigned long); i++)
82,9 → 84,10
((unsigned long *) dst)[i] = ((unsigned long *) src)[i];
for (j = 0; j < n % sizeof(unsigned long); j++)
((unsigned char *) (((unsigned long *) dst) + i))[j] = ((unsigned char *) (((unsigned long *) src) + i))[j];
((unsigned char *) (((unsigned long *) dst) + i))[j] =
((unsigned char *) (((unsigned long *) src) + i))[j];
return (char *) src;
return (char *) dst;
}
 
void *memmove(void *dst, const void *src, size_t n)
95,22 → 98,23
return memcpy(dst, src, n);
 
for (j = (n % sizeof(unsigned long)) - 1; j >= 0; j--)
((unsigned char *) ((unsigned long *) dst))[j] = ((unsigned char *) ((unsigned long *) src))[j];
((unsigned char *) ((unsigned long *) dst))[j] =
((unsigned char *) ((unsigned long *) src))[j];
 
for (i = n / sizeof(unsigned long) - 1; i >=0 ; i--)
((unsigned long *) dst)[i] = ((unsigned long *) src)[i];
return (char *) src;
return (char *) dst;
}
 
/** Compare two memory areas.
*
* @param s1 Pointer to the first area to compare.
* @param s2 Pointer to the second area to compare.
* @param len Size of the first area in bytes. Both areas must have the same
* length.
* @return If len is 0, return zero. If the areas match, return zero.
* Otherwise return non-zero.
* @param s1 Pointer to the first area to compare.
* @param s2 Pointer to the second area to compare.
* @param len Size of the first area in bytes. Both areas must have
* the same length.
* @return If len is 0, return zero. If the areas match, return
* zero. Otherwise return non-zero.
*/
int bcmp(const char *s1, const char *s2, size_t len)
{
120,8 → 124,9
}
 
/** Count the number of characters in the string, not including terminating 0.
* @param str string
* @return number of characters in string.
*
* @param str String.
* @return Number of characters in string.
*/
size_t strlen(const char *str)
{
141,7 → 146,6
c++;
return (a[c] - b[c]);
}
 
int strncmp(const char *a, const char *b, size_t n)
155,10 → 159,22
}
 
/** Return pointer to the first occurence of character c in string
* @param str scanned string
* @param c searched character (taken as one byte)
* @return pointer to the matched character or NULL if it is not found in given string.
int stricmp(const char *a, const char *b)
{
int c = 0;
while (a[c] && b[c] && (!(tolower(a[c]) - tolower(b[c]))))
c++;
return (tolower(a[c]) - tolower(b[c]));
}
 
/** Return pointer to the first occurence of character c in string.
*
* @param str Scanned string.
* @param c Searched character (taken as one byte).
* @return Pointer to the matched character or NULL if it is not
* found in given string.
*/
char *strchr(const char *str, int c)
{
171,10 → 187,12
return NULL;
}
 
/** Return pointer to the last occurence of character c in string
* @param str scanned string
* @param c searched character (taken as one byte)
* @return pointer to the matched character or NULL if it is not found in given string.
/** Return pointer to the last occurence of character c in string.
*
* @param str Scanned string.
* @param c Searched character (taken as one byte).
* @return Pointer to the matched character or NULL if it is not
* found in given string.
*/
char *strrchr(const char *str, int c)
{
191,13 → 209,16
 
/** Convert string to a number.
* Core of strtol and strtoul functions.
* @param nptr pointer to string
* @param endptr if not NULL, function stores here pointer to the first invalid character
* @param base zero or number between 2 and 36 inclusive
* @param sgn its set to 1 if minus found
* @return result of conversion.
*
* @param nptr Pointer to string.
* @param endptr If not NULL, function stores here pointer to the first
* invalid character.
* @param base Zero or number between 2 and 36 inclusive.
* @param sgn It's set to 1 if minus found.
* @return Result of conversion.
*/
static unsigned long _strtoul(const char *nptr, char **endptr, int base, char *sgn)
static unsigned long
_strtoul(const char *nptr, char **endptr, int base, char *sgn)
{
unsigned char c;
unsigned long result = 0;
219,7 → 240,8
/* FIXME: set errno to EINVAL */
return 0;
}
if ((base == 16) && (*str == '0') && ((str[1] == 'x') || (str[1] == 'X'))) {
if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
(str[1] == 'X'))) {
str += 2;
}
} else {
238,7 → 260,8
 
while (*str) {
c = *str;
c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 : (c <= '9' ? c - '0' : 0xff)));
c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
(c <= '9' ? c - '0' : 0xff)));
if (c > base) {
break;
}
257,7 → 280,10
}
if (str == tmpptr) {
/* no number was found => first invalid character is the first character of the string */
/*
* No number was found => first invalid character is the first
* character of the string.
*/
/* FIXME: set errno to EINVAL */
str = nptr;
result = 0;
275,14 → 301,17
}
 
/** Convert initial part of string to long int according to given base.
* The number may begin with an arbitrary number of whitespaces followed by optional sign (`+' or `-').
* If the base is 0 or 16, the prefix `0x' may be inserted and the number will be taken as hexadecimal one.
* If the base is 0 and the number begin with a zero, number will be taken as octal one (as with base 8).
* Otherwise the base 0 is taken as decimal.
* @param nptr pointer to string
* @param endptr if not NULL, function stores here pointer to the first invalid character
* @param base zero or number between 2 and 36 inclusive
* @return result of conversion.
* The number may begin with an arbitrary number of whitespaces followed by
* optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
* inserted and the number will be taken as hexadecimal one. If the base is 0
* and the number begin with a zero, number will be taken as octal one (as with
* base 8). Otherwise the base 0 is taken as decimal.
*
* @param nptr Pointer to string.
* @param endptr If not NULL, function stores here pointer to the first
* invalid character.
* @param base Zero or number between 2 and 36 inclusive.
* @return Result of conversion.
*/
long int strtol(const char *nptr, char **endptr, int base)
{
305,14 → 334,17
 
 
/** Convert initial part of string to unsigned long according to given base.
* The number may begin with an arbitrary number of whitespaces followed by optional sign (`+' or `-').
* If the base is 0 or 16, the prefix `0x' may be inserted and the number will be taken as hexadecimal one.
* If the base is 0 and the number begin with a zero, number will be taken as octal one (as with base 8).
* Otherwise the base 0 is taken as decimal.
* @param nptr pointer to string
* @param endptr if not NULL, function stores here pointer to the first invalid character
* @param base zero or number between 2 and 36 inclusive
* @return result of conversion.
* The number may begin with an arbitrary number of whitespaces followed by
* optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
* inserted and the number will be taken as hexadecimal one. If the base is 0
* and the number begin with a zero, number will be taken as octal one (as with
* base 8). Otherwise the base 0 is taken as decimal.
*
* @param nptr Pointer to string.
* @param endptr If not NULL, function stores here pointer to the first
* invalid character
* @param base Zero or number between 2 and 36 inclusive.
* @return Result of conversion.
*/
unsigned long strtoul(const char *nptr, char **endptr, int base)
{
328,7 → 360,8
{
char *orig = dest;
while ((*(dest++) = *(src++)));
while ((*(dest++) = *(src++)))
;
return orig;
}
 
336,9 → 369,32
{
char *orig = dest;
while ((*(dest++) = *(src++)) && --n);
while ((*(dest++) = *(src++)) && --n)
;
return orig;
}
 
char *strcat(char *dest, const char *src)
{
char *orig = dest;
while (*dest++)
;
--dest;
while ((*dest++ = *src++))
;
return orig;
}
 
char * strdup(const char *s1)
{
size_t len = strlen(s1) + 1;
void *ret = malloc(len);
 
if (ret == NULL)
return (char *) NULL;
 
return (char *) memcpy(ret, s1, len);
}
 
/** @}
*/
/branches/network/uspace/lib/libc/generic/as.c
85,6 → 85,20
return __SYSCALL1(SYS_AS_AREA_DESTROY, (sysarg_t ) address);
}
 
/** Change address-space area flags.
*
* @param address Virtual address pointing into the address space area being
* modified.
* @param flags New flags describing type of the area.
*
* @return Zero on success or a code from @ref errno.h on failure.
*/
int as_area_change_flags(void *address, int flags)
{
return __SYSCALL2(SYS_AS_AREA_CHANGE_FLAGS, (sysarg_t) address,
(sysarg_t) flags);
}
 
static size_t heapsize = 0;
static size_t maxheapsize = (size_t) (-1);
 
/branches/network/uspace/lib/libc/generic/pcb.c
0,0 → 1,40
/*
* Copyright (c) 2008 Jiri Svoboda
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <loader/pcb.h>
 
pcb_t *__pcb;
 
/** @}
*/
/branches/network/uspace/lib/libc/generic/libc.c
48,8 → 48,10
#include <ipc/ipc.h>
#include <async.h>
#include <as.h>
#include <loader/pcb.h>
 
extern char _heap;
extern int main(int argc, char *argv[]);
 
void _exit(int status)
{
56,20 → 58,31
thread_exit(status);
}
 
void __main(void)
void __main(void *pcb_ptr)
{
fibril_t *f;
int argc;
char **argv;
 
(void) as_area_create(&_heap, 1, AS_AREA_WRITE | AS_AREA_READ);
_async_init();
f = fibril_setup();
__tcb_set(f->tcb);
}
open_console();
 
void __io_init(void)
{
open_stdin();
open_stdout();
/* Save the PCB pointer */
__pcb = (pcb_t *)pcb_ptr;
 
if (__pcb == NULL) {
argc = 0;
argv = NULL;
} else {
argc = __pcb->argc;
argv = __pcb->argv;
}
 
main(argc, argv);
}
 
void __exit(void)
/branches/network/uspace/lib/libc/generic/smc.c
0,0 → 1,45
/*
* Copyright (c) 2008 Jiri Svoboda
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <libc.h>
#include <sys/types.h>
 
int smc_coherence(void *address, size_t size)
{
return __SYSCALL2(SYS_SMC_COHERENCE, (sysarg_t) address,
(sysarg_t) size);
}
 
/** @}
*/
/branches/network/uspace/lib/libc/generic/async.c
1012,4 → 1012,3
 
/** @}
*/
 
/branches/network/uspace/lib/libc/generic/fibril.c
342,4 → 342,3
 
/** @}
*/
 
/branches/network/uspace/lib/libc/generic/libadt/hash_table.c
1,5 → 1,5
/*
* Copyright (c) 2006 Jakub Jermar
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
46,13 → 46,14
 
/** Create chained hash table.
*
* @param h Hash table structure. Will be initialized by this call.
* @param m Number of slots in the hash table.
* @param max_keys Maximal number of keys needed to identify an item.
* @param op Hash table operations structure.
* @return true on success
* @param h Hash table structure. Will be initialized by this call.
* @param m Number of hash table buckets.
* @param max_keys Maximal number of keys needed to identify an item.
* @param op Hash table operations structure.
* @return True on success
*/
int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys, hash_table_operations_t *op)
int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys,
hash_table_operations_t *op)
{
hash_count_t i;
 
76,12 → 77,23
return true;
}
 
/** Insert item into hash table.
/** Destroy a hash table instance.
*
* @param h Hash table.
* @param key Array of all keys necessary to compute hash index.
* @param item Item to be inserted into the hash table.
* @param h Hash table to be destroyed.
*/
void hash_table_destroy(hash_table_t *h)
{
assert(h);
assert(h->entry);
free(h->entry);
}
 
/** Insert item into a hash table.
*
* @param h Hash table.
* @param key Array of all keys necessary to compute hash index.
* @param item Item to be inserted into the hash table.
*/
void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item)
{
hash_index_t chain;
97,10 → 109,10
 
/** Search hash table for an item matching keys.
*
* @param h Hash table.
* @param key Array of all keys needed to compute hash index.
* @param h Hash table.
* @param key Array of all keys needed to compute hash index.
*
* @return Matching item on success, NULL if there is no such item.
* @return Matching item on success, NULL if there is no such item.
*/
link_t *hash_table_find(hash_table_t *h, unsigned long key[])
{
112,7 → 124,8
chain = h->op->hash(key);
assert(chain < h->entries);
for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
for (cur = h->entry[chain].next; cur != &h->entry[chain];
cur = cur->next) {
if (h->op->compare(key, h->max_keys, cur)) {
/*
* The entry is there.
128,9 → 141,10
*
* For each removed item, h->remove_callback() is called.
*
* @param h Hash table.
* @param key Array of keys that will be compared against items of the hash table.
* @param keys Number of keys in the 'key' array.
* @param h Hash table.
* @param key Array of keys that will be compared against items of
* the hash table.
* @param keys Number of keys in the 'key' array.
*/
void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys)
{
137,13 → 151,15
hash_index_t chain;
link_t *cur;
 
assert(h && h->op && h->op->hash && h->op->compare && h->op->remove_callback);
assert(h && h->op && h->op->hash && h->op->compare &&
h->op->remove_callback);
assert(keys <= h->max_keys);
if (keys == h->max_keys) {
 
/*
* All keys are known, hash_table_find() can be used to find the entry.
* All keys are known, hash_table_find() can be used to find the
* entry.
*/
cur = hash_table_find(h, key);
159,7 → 175,8
* Any partially matching entries are to be removed.
*/
for (chain = 0; chain < h->entries; chain++) {
for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
for (cur = h->entry[chain].next; cur != &h->entry[chain];
cur = cur->next) {
if (h->op->compare(key, keys, cur)) {
link_t *hlp;