Author: nieklinnenbank Date: Fri Jul 10 09:07:14 2009 New Revision: 225 Added: trunk/bin/sh/ChangeDirCommand.cpp trunk/bin/sh/ChangeDirCommand.h Modified: trunk/bin/ls/Main.cpp trunk/bin/sh/SConscript trunk/bin/sh/Shell.cpp trunk/lib/libposix/unistd.cpp trunk/lib/libposix/unistd.h trunk/srv/filesystem/FileSystem.h trunk/srv/filesystem/FileSystemMessage.h trunk/srv/filesystem/virtual/VirtualFileSystem.cpp trunk/srv/filesystem/virtual/VirtualFileSystem.h Log: Implemented the notion of current directory in the VirtualFileSystem. Additionally, a POSIX-1.2008 compliant getcwd() function has been added. Shell now using this information in the system prompt, and 'ls' defaults to the current directory if no argument is given. Modified: trunk/bin/ls/Main.cpp ============================================================================== --- trunk/bin/ls/Main.cpp (original) +++ trunk/bin/ls/Main.cpp Fri Jul 10 09:07:14 2009 @@ -20,25 +20,29 @@ #include <dirent.h> #include <string.h> #include <errno.h> +#include <unistd.h> #include <TerminalCodes.h> int main(int argc, char **argv) { DIR *d; struct dirent *dent; + char path[255]; - /* Verify command-line arguments. */ - if (argc <= 1) + /* Grab command-line arguments, if any */ + if (argc > 1) { - printf("usage: %s DIRECTORY\r\n", - argv[0]); - return EXIT_FAILURE; + strncpy(path, argv[1], sizeof(path)); + path[sizeof(path) - 1] = 0; } + else + getcwd(path, sizeof(path)); + /* Attempt to open the directory. */ - if (!(d = opendir(argv[1]))) + if (!(d = opendir(path))) { printf("%s: failed to open '%s': %s\r\n", - argv[0], argv[1], strerror(errno)); + argv[0], path, strerror(errno)); return EXIT_FAILURE; } /* Read directory. */ Added: trunk/bin/sh/ChangeDirCommand.cpp ============================================================================== --- (empty file) +++ trunk/bin/sh/ChangeDirCommand.cpp Fri Jul 10 09:07:14 2009 @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009 Niek Linnenbank + * + * This program 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <API/IPCMessage.h> +#include <FileSystem.h> +#include <FileSystemPath.h> +#include <FileSystemMessage.h> +#include <Config.h> +#include <Macros.h> +#include <String.h> +#include <List.h> +#include <ListIterator.h> +#include "ChangeDirCommand.h" +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <errno.h> + +int ChangeDirCommand::execute(Size nparams, char **params) +{ + FileSystemMessage msg; + FileSystemPath path; + String *last = ZERO; + List<String> lst; + char cwd[PATHLEN], buf[PATHLEN]; + struct stat st; + + /* First stat the file. */ + if (stat(params[0], &st) != 0) + { + printf("Failed to stat() `%s': %s\r\n", + params[0], strerror(errno)); + return errno; + } + /* Must be a directory. */ + if (!S_ISDIR(st.st_mode)) + { + printf("`%s' is not a directory\r\n", + params[0]); + return -1; + } + /* What's the current working dir? */ + getcwd(cwd, PATHLEN); + + /* Relative or absolute? */ + if (params[0][0] != '/') + { + snprintf(buf, sizeof(buf), "%s/%s", cwd, params[0]); + path.parse(buf); + memset(buf, 0, sizeof(buf)); + + /* Process '..' */ + for (ListIterator<String> i(path.split()); i.hasNext(); i++) + { + if ((**i.current())[0] != '.') + { + lst.insertTail(i.current()); + last = i.current(); + } + else if ((**i.current())[1] == '.' && last) + { + lst.remove(last); + } + } + /* Construct final path. */ + for (ListIterator<String> i(&lst); i.hasNext(); i++) + { + strcat(buf, "/"); + strcat(buf, **i.current()); + } + msg.buffer = buf; + } + else + msg.buffer = params[0]; + + /* Fall back to slash? */ + if (!buf[0]) + { + strcpy(buf, "/"); + } + /* Fill the message. */ + msg.action = SetCurrentDir; + msg.procID = getpid(); + + /* Ask VFS. */ + IPCMessage(VFSSRV_PID, SendReceive, &msg, sizeof(msg)); + + /* Done. */ + return msg.result; +} + +INITOBJ(ChangeDirCommand, cdCmd, LIBCRT_DEFAULT) Added: trunk/bin/sh/ChangeDirCommand.h ============================================================================== --- (empty file) +++ trunk/bin/sh/ChangeDirCommand.h Fri Jul 10 09:07:14 2009 @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Niek Linnenbank + * + * This program 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __SH_CHANGE_DIR_COMMAND +#define __SH_CHANGE_DIR_COMMAND + +#include <Factory.h> +#include <Types.h> +#include "ShellCommand.h" + +/** + * Change the current working directory. + */+class ChangeDirCommand : public ShellCommand, public Factory<ChangeDirCommand>
+{ + public: + + /** + * Constructor function. + */ + ChangeDirCommand() : ShellCommand("cd", 1) + { + } + + /** + * Get the help string for this command. + * @return Pointer to character string describing what the command does. + */ + const char * help() + { + return "Change the current working directory"; + } + + /** + * Executes the command. + * @param nparams Number of parameters given. + * @param params Array of parameters. + * @return Error code or zero on success. + */ + int execute(Size nparams, char **params); +}; + +#endif /* __SH_CHANGE_DIR_COMMAND */ Modified: trunk/bin/sh/SConscript ============================================================================== --- trunk/bin/sh/SConscript (original) +++ trunk/bin/sh/SConscript Fri Jul 10 09:07:14 2009 @@ -21,5 +21,6 @@ [ 'memory', 'filesystem', 'filesystem/virtual', 'terminal' ]) env.Program('sh', [ 'Main.cpp', 'Shell.cpp', 'HelpCommand.cpp', - 'ShellCommand.cpp', 'WriteCommand.cpp', 'ExitCommand.cpp' ], + 'ShellCommand.cpp', 'WriteCommand.cpp', 'ExitCommand.cpp', + 'ChangeDirCommand.cpp' ], LIBS = env['LIBS'], LIBPATH = env['LIBPATH']) Modified: trunk/bin/sh/Shell.cpp ============================================================================== --- trunk/bin/sh/Shell.cpp (original) +++ trunk/bin/sh/Shell.cpp Fri Jul 10 09:07:14 2009 @@ -143,13 +143,17 @@ void Shell::prompt() { - char tmp[128]; + char host[128], cwd[128]; /* Retrieve current hostname. */ - gethostname(tmp, sizeof(tmp)); + gethostname(host, sizeof(host)); + + /* Retrieve current working directory. */ + getcwd(cwd, sizeof(cwd)); /* Print out the prompt. */ - printf(WHITE "(" GREEN "%s" WHITE ") # ", tmp); + printf(WHITE "(" GREEN "%s" WHITE ") " BLUE "%s" WHITE " # ", + host, cwd); } Size Shell::parse(char *cmdline, char **argv, Size maxArgv) Modified: trunk/lib/libposix/unistd.cpp ============================================================================== --- trunk/lib/libposix/unistd.cpp (original) +++ trunk/lib/libposix/unistd.cpp Fri Jul 10 09:07:14 2009 @@ -152,3 +152,22 @@ strlcpy(name, "localhost", namelen); return 0; } + +char *getcwd(char *buf, size_t size) +{ + FileSystemMessage msg; + + /* Fill message. */ + msg.buffer = buf; + msg.procID = getpid(); + msg.action = GetCurrentDir; + + /* Ask VFS. */ + IPCMessage(VFSSRV_PID, SendReceive, &msg, sizeof(msg)); + + /* Set errno. */ + errno = msg.result; + + /* All done. */ + return errno == ESUCCESS ? buf : ZERO; +} Modified: trunk/lib/libposix/unistd.h ============================================================================== --- trunk/lib/libposix/unistd.h (original) +++ trunk/lib/libposix/unistd.h Fri Jul 10 09:07:14 2009 @@ -248,6 +248,23 @@ extern C int gethostname(char *name, size_t namelen); /** + * @brief Get the pathname of the current working directory. + * + * The getcwd() function shall place an absolute pathname of the + * current working directory in the array pointed to by buf, and + * return buf. The pathname shall contain no components that are + * dot or dot-dot, or are symbolic links. + * + * @param buf Output buffer, to store the current directory. + * @param size Size of the output buffer. + * @return Upon successful completion, getcwd() shall return + * the buf argument. Otherwise, getcwd() shall return + * a null pointer and set errno to indicate the error. + * The contents of the array pointed to by buf are then undefined. + */ +extern C char *getcwd(char *buf, size_t size); + +/** * @} */ Modified: trunk/srv/filesystem/FileSystem.h ============================================================================== --- trunk/srv/filesystem/FileSystem.h (original) +++ trunk/srv/filesystem/FileSystem.h Fri Jul 10 09:07:14 2009 @@ -142,10 +142,11 @@ */ void ioHandler(FileSystemMessage *msg) { + FileSystemMessage vfs; FileSystemPath path; FileCache *fc = ZERO; File *f = ZERO; - char buf[PATHLEN]; + char buf[PATHLEN], tmp[PATHLEN]; /* * Find the file, either in cache, storage or via @@ -159,15 +160,35 @@ /* Copy the path first. */ if (VMCopy(msg->procID, Read, (Address) buf, - (Address) msg->buffer + strlen(mountPath), PATHLEN) <= 0) + (Address) msg->buffer, PATHLEN) <= 0) { msg->error(EACCES, IODone); return; } else { - /* Parse the path. */ - path.parse(buf); + /* Is the path relative? */ + if (buf[0] != '/') + { + vfs.action = GetCurrentDir; + vfs.buffer = tmp; + vfs.procID = msg->procID; + + /* + * Ask for their current directory. + * TODO: this can be much more efficient, if we can + * map the user process table in our address space!+ * TODO: this is also buggy... what if VFS tries to contact us meanwhile...
+ */ + IPCMessage(VFSSRV_PID, SendReceive, &vfs, sizeof(vfs)); + + /* Reconstruct path. */ + snprintf(tmp, sizeof(tmp), "%s/%s", tmp, + buf); + path.parse(tmp); + } + else + path.parse(buf + strlen(mountPath)); /* No need to lookup caches for creation. */ if (msg->action == CreateFile) Modified: trunk/srv/filesystem/FileSystemMessage.h ============================================================================== --- trunk/srv/filesystem/FileSystemMessage.h (original) +++ trunk/srv/filesystem/FileSystemMessage.h Fri Jul 10 09:07:14 2009 @@ -31,20 +31,22 @@ */ typedef enum FileSystemAction { - CreateFile = 0, - OpenFile = 1, - ReadFile = 2, - WriteFile = 3, - SeekFile = 4, - StatFile = 5, - ChangeFile = 6, - CloseFile = 7, - Mount = 8, - Unmount = 9, - MountInfo = 10, - NewProcess = 11, - KillProcess = 12, - IODone = 13, + CreateFile = 0, + OpenFile = 1, + ReadFile = 2, + WriteFile = 3, + SeekFile = 4, + StatFile = 5, + ChangeFile = 6, + CloseFile = 7, + Mount = 8, + Unmount = 9, + MountInfo = 10, + NewProcess = 11, + KillProcess = 12, + IODone = 13, + GetCurrentDir = 14, + SetCurrentDir = 15, } FileSystemAction; Modified: trunk/srv/filesystem/virtual/VirtualFileSystem.cpp ============================================================================== --- trunk/srv/filesystem/virtual/VirtualFileSystem.cpp (original)+++ trunk/srv/filesystem/virtual/VirtualFileSystem.cpp Fri Jul 10 09:07:14 2009
@@ -44,6 +44,8 @@ addIPCHandler(MountInfo, &VirtualFileSystem::mountInfoHandler); addIPCHandler(NewProcess, &VirtualFileSystem::newProcessHandler); addIPCHandler(KillProcess, &VirtualFileSystem::killProcessHandler); + addIPCHandler(GetCurrentDir, &VirtualFileSystem::currentDirHandler); + addIPCHandler(SetCurrentDir, &VirtualFileSystem::currentDirHandler); /* Wait for process server to sync BootPrograms from BootImages. */ for (Size i = 0; i < info.moduleCount; i++) @@ -75,7 +77,6 @@ void VirtualFileSystem::ioHandler(FileSystemMessage *msg) { - char path[PATHLEN]; FileSystemMount *mount; FileDescriptor *fd; ProcessID fsID; @@ -95,15 +96,8 @@ case OpenFile: case StatFile: - /* Obtain full path first. */ - if ((msg->result = VMCopy(msg->from, Read, (Address) path, - (Address) msg->buffer, PATHLEN)) < 0) - { - msg->error(msg->result); - return; - } /* Retrieve mountpoint. */ - if (!(mount = findMount(path))) + if (!(mount = findMount(msg))) { msg->error(ENOENT); return; @@ -154,9 +148,7 @@ void VirtualFileSystem::ioDoneHandler(FileSystemMessage *msg) { FileDescriptor *fd; - char path[PATHLEN]; FileSystemMount *mount; - Error err; /* Retrieve correct mountpoint or filedescriptor. */ switch (msg->savedAction) @@ -164,15 +156,8 @@ case OpenFile: case StatFile: - /* Obtain full path first. */ - if ((err = VMCopy(msg->procID, Read, (Address) path, - (Address) msg->buffer, PATHLEN) < 0)) - { - msg->error(err, IODone, msg->procID); - return; - } /* Retrieve mountpoint. */ - if (!(mount = findMount(path))) + if (!(mount = findMount(msg))) { msg->error(ENOENT, IODone, msg->procID); return; @@ -255,17 +240,23 @@ void VirtualFileSystem::newProcessHandler(FileSystemMessage *msg) { - /* Fill in the new process. */ + /* Fill in identities. */ procs[msg->procID].userID = msg->userID; procs[msg->procID].groupID = msg->groupID; - /* Copy file descriptor from parent, if any. */ + /* Copy file descriptors, and current directory from parent, if any. */ if (msg->parentID != ANY) + { procs[msg->procID].files = new Array<FileDescriptor>( procs[msg->parentID].files); + strlcpy(procs[msg->procID].currentDir, + procs[msg->parentID].currentDir, PATHLEN); + } else + { procs[msg->procID].files = new Array<FileDescriptor>; - + strncpy(procs[msg->procID].currentDir, "/", PATHLEN); + } /* Success. */ msg->result = ESUCCESS; } @@ -283,6 +274,38 @@ msg->result = ESUCCESS; } +void VirtualFileSystem::currentDirHandler(FileSystemMessage *msg) +{ + /* Only allow same owner. */ + if (!(procs[msg->from].userID == 0 || + (procs[msg->from].userID == procs[msg->procID].userID))) + { + msg->result = EPERM; + return; + } + /* Handle request. */ + switch (msg->action) + { + case GetCurrentDir: + msg->result = VMCopy(msg->from, Write, + (Address) procs[msg->procID].currentDir, + (Address) msg->buffer, PATHLEN); + break; + + case SetCurrentDir: + msg->result = VMCopy(msg->from, Read, + (Address) procs[msg->procID].currentDir, + (Address) msg->buffer, PATHLEN); + default: + break; + } + /* Mark with ESUCCESS? */ + if (msg->result > 0) + { + msg->size = msg->result; + msg->result = ESUCCESS; + } +} void VirtualFileSystem::insertMount(char *path, ProcessID pid, ulong opts) { @@ -299,11 +322,28 @@ } } -FileSystemMount * VirtualFileSystem::findMount(char *path) +FileSystemMount * VirtualFileSystem::findMount(FileSystemMessage *msg) { - Size length = 0, len; FileSystemMount *m = ZERO; + Size length = 0, len; + char path[PATHLEN], tmp[PATHLEN]; + /* Obtain full path first. */ + if (VMCopy(msg->procID, Read, (Address) path, + (Address) msg->buffer, PATHLEN) < 0) + { + return ZERO; + } + /* Force string terminate. */ + path[PATHLEN-1] = ZERO; + + /* Is the path relative? */ + if (path[0] != '/') + { + snprintf(tmp, sizeof(tmp), "%s/%s", + procs[msg->procID].currentDir, path); + strlcpy(path, tmp, PATHLEN); + } /* Find the longest match. */ for (Size i = 0; i < MAX_MOUNTS; i++) { @@ -322,5 +362,6 @@ } } } + /* All done. */ return m; } Modified: trunk/srv/filesystem/virtual/VirtualFileSystem.h ============================================================================== --- trunk/srv/filesystem/virtual/VirtualFileSystem.h (original)+++ trunk/srv/filesystem/virtual/VirtualFileSystem.h Fri Jul 10 09:07:14 2009
@@ -90,13 +90,8 @@ /** Total number of open files. */ Size fileCount; - /** Current working directory. - char curdir[len]; - */ - - /** Root directory - char rootdir[len]; - */ + /** Current working directory. */ + char currentDir[PATHLEN]; } UserProcessFSEntry; @@ -151,6 +146,12 @@ void killProcessHandler(FileSystemMessage *msg); /** + * Get or set the current directory. + * @param msg Input message. + */ + void currentDirHandler(FileSystemMessage *msg); + + /** * Creats a new mount. * @param path Full path of the new mount. * @param pid Process which handles the mountpoint. @@ -160,10 +161,10 @@ /** * Lookup the mount for a given path. - * @param path Path of the mountpoint to find. + * @param msg Message containing a path pointer. * @return Pointer to mount if found, ZERO otherwise. */ - FileSystemMount * findMount(char *path); + FileSystemMount * findMount(FileSystemMessage *msg); /** Mounted filesystems. */ static FileSystemMount mounts[MAX_MOUNTS];