init
This commit is contained in:
commit
4e11b595a3
9 changed files with 508 additions and 0 deletions
82
.clang-format
Normal file
82
.clang-format
Normal file
|
@ -0,0 +1,82 @@
|
|||
# CS 631 - Advanced Programming in the Unix Environment
|
||||
# clang-format source code format file
|
||||
# Author: Anthony Webster
|
||||
#
|
||||
# I created this file based on the criteria specified at <https://stevens.netmeister.org/631/style>.
|
||||
# I don't really care what you do with this file. I've just written this to (hopefully) be helpful.
|
||||
# But, because it's "the right thing to do", this file is licensed under the MIT license.
|
||||
#
|
||||
# Copyright (c) 2024 Anthony Webster
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
BasedOnStyle: LLVM
|
||||
# Despite my strong disagreement with using 80 columns, the style guide says we
|
||||
# should try to keep code within 80 columns. So I guess we have to set this to 80.
|
||||
ColumnLimit: 80
|
||||
TabWidth: 4
|
||||
IndentWidth: 4
|
||||
UseTab: AlignWithSpaces
|
||||
LineEnding: LF
|
||||
InsertBraces: true
|
||||
IndentCaseBlocks: false
|
||||
BreakBeforeBraces: Linux
|
||||
MaxEmptyLinesToKeep: 2
|
||||
IncludeBlocks: Regroup
|
||||
SortIncludes: CaseInsensitive
|
||||
IncludeCategories:
|
||||
# Kernel includes first
|
||||
- Regex: '^<sys/'
|
||||
Priority: 1
|
||||
SortPriority: 1
|
||||
CaseSensitive: false
|
||||
# Network includes after kernel includes, without a blank line
|
||||
- Regex: '^<(net|netinet|protocols)/'
|
||||
Priority: 1
|
||||
SortPriority: 2
|
||||
CaseSensitive: false
|
||||
# /usr includes next, separated by a blank line
|
||||
- Regex: '^<'
|
||||
Priority: 2
|
||||
SortPriority: 3
|
||||
CaseSensitive: false
|
||||
# And other includes after /usr, separated by a blank line
|
||||
- Regex: '^"'
|
||||
Priority: 3
|
||||
SortPriority: 4
|
||||
CaseSensitive: false
|
||||
|
||||
# These aren't explicitly stated in the style guide but are derived from how the style guide is formatted.
|
||||
BitFieldColonSpacing: None
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
QualifierAlignment: Left
|
||||
PointerAlignment: Right
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AlwaysBreakAfterDefinitionReturnType: All
|
||||
SeparateDefinitionBlocks: Always
|
||||
SpaceAfterCStyleCast: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
ContinuationIndentWidth: 4
|
||||
|
||||
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.o
|
||||
ls
|
21
Makefile
Normal file
21
Makefile
Normal file
|
@ -0,0 +1,21 @@
|
|||
CC = gcc
|
||||
CFLAGS = -g -Wall -Werror -Wextra -Wformat=2 -Wjump-misses-init -Wlogical-op -Wpedantic -Wshadow
|
||||
#CFLAGS = -ansi -g -Wall -Werror -Wextra -Wformat=2 -Wjump-misses-init -Wlogical-op -Wpedantic -Wshadow
|
||||
#CFLAGS = -Wall -Werror -Wextra -Wpedantic
|
||||
EXECUTABLE = ls
|
||||
|
||||
SOURCES = ls.c
|
||||
OBJECTS = $(SOURCES:.c=.o)
|
||||
|
||||
all: $(EXECUTABLE)
|
||||
|
||||
$(EXECUTABLE): $(OBJECTS)
|
||||
$(CC) $(OBJECTS) -o $(EXECUTABLE) $(LDFLAGS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(EXECUTABLE)
|
||||
|
||||
.PHONY: all clean
|
88
checklist
Normal file
88
checklist
Normal file
|
@ -0,0 +1,88 @@
|
|||
For each assignment, copy this file into your homework
|
||||
submission directory and answer all questions.
|
||||
|
||||
Did I write all the code myself?
|
||||
- Don't copy and paste code from the internet, your
|
||||
classmates, sample solutions, or anywhere else.
|
||||
Review https://stevens.netmeister.org/631/#plagiarism
|
||||
|
||||
|
||||
Did I use any AI technologies? If so, did I properly
|
||||
acknowledge this help?
|
||||
- Review https://stevens.netmeister.org/631/use-of-ai.html
|
||||
|
||||
|
||||
Does my code follow the style guide?
|
||||
- Code is communication. Make sure your code is
|
||||
readable, well-structured, properly indented,
|
||||
with sensibily named variables and functions.
|
||||
|
||||
yes i use a clang formatter a classmate wrote
|
||||
|
||||
|
||||
Does my code compile without warnings or errors on a
|
||||
NetBSD 10.0 system?
|
||||
- Always use *at least* 'cc -Wall -Werror -Wextra',
|
||||
possibly
|
||||
'cc -ansi -g -Wall -Werror -Wextra -Wformat=2 -Wjump-misses-init -Wlogical-op -Wpedantic -Wshadow'.
|
||||
|
||||
yes
|
||||
|
||||
Did I provide a Makefile?
|
||||
- 'make' should use the above CFLAGS and produce an
|
||||
executable
|
||||
|
||||
yup
|
||||
|
||||
Did I provide a README to explain any problems or
|
||||
issues I encountered?
|
||||
- Make sure that your text is well-formatted, plain
|
||||
ASCII in proper English. Use a spell checker.
|
||||
|
||||
yes
|
||||
|
||||
Did I check the return value of all function calls?
|
||||
- Yes, that does include but is not limited to malloc(3).
|
||||
|
||||
for non atomic / fillable ones yes
|
||||
|
||||
Did I send error messages to stderr? Did I use
|
||||
strerror(3) or perror(3) etc. to print meaningful
|
||||
error messages?
|
||||
|
||||
yeah we have a unified err interface!!
|
||||
|
||||
Did I use only meaningful and necessary comments?
|
||||
- Your comments should explain the 'why', not the
|
||||
'what'.
|
||||
|
||||
yes
|
||||
|
||||
Does my program only generate meaningful output?
|
||||
Debugging information should be removed.
|
||||
|
||||
yes
|
||||
|
||||
Does my program return zero on success, non-zero otherwise?
|
||||
|
||||
yeah
|
||||
|
||||
|
||||
Did I make sure that my .h files only include function
|
||||
forward declarations, macros, etc., no function
|
||||
implementations or other code?
|
||||
|
||||
n/a
|
||||
|
||||
Did I check that I have avoided code duplication?
|
||||
Writing the same or very similar code multiple times
|
||||
is a sign that my program could benefit from being
|
||||
restructured.
|
||||
|
||||
yes
|
||||
|
||||
For any string manipulation, did I use size-bounded
|
||||
functions?
|
||||
- Use strlcat(3)/strlcpy(3) instead of
|
||||
strcat(3)/strcpy(3) etc.
|
||||
yeah
|
149
ls.c
Normal file
149
ls.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void ls_ent(const char *path);
|
||||
void do_regfile(const char *path, const struct stat *sb);
|
||||
void do_dir(const char *path, const struct stat *sb);
|
||||
void do_symlink(const char *path, const struct stat *sb);
|
||||
void do_blockdev(const char *path, const struct stat *sb);
|
||||
void do_char(const char *path, const struct stat *sb);
|
||||
void do_fifo(const char *path, const struct stat *sb);
|
||||
void do_socket(const char *path, const struct stat *sb);
|
||||
void do_unknown(const char *path, const struct stat *sb);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
if (argc == 1) {
|
||||
ls_ent(".");
|
||||
} else {
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
/* argparsing */
|
||||
} else {
|
||||
ls_ent(argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ls_ent(const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
if (lstat(path, &sb) == -1) {
|
||||
err(1, "Failed to stat %s", path);
|
||||
}
|
||||
switch (sb.st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
do_regfile(path, &sb);
|
||||
break;
|
||||
case S_IFDIR:
|
||||
do_dir(path, &sb);
|
||||
break;
|
||||
case S_IFLNK:
|
||||
do_symlink(path, &sb);
|
||||
break;
|
||||
case S_IFCHR:
|
||||
do_char(path, &sb);
|
||||
break;
|
||||
case S_IFIFO:
|
||||
do_fifo(path, &sb);
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
do_socket(path, &sb);
|
||||
break;
|
||||
default:
|
||||
do_unknown(path, &sb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
do_regfile(const char *path, const struct stat *sb)
|
||||
{
|
||||
(void)sb;
|
||||
printf("reg: %s\n", path);
|
||||
}
|
||||
|
||||
void
|
||||
do_dir(const char *path, const struct stat *sb)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
char full_path[PATH_MAX];
|
||||
|
||||
(void)sb;
|
||||
d = opendir(path);
|
||||
if (!d) {
|
||||
err(1, "Failed to open dir: %s", path);
|
||||
}
|
||||
printf("dir: %s\n", path);
|
||||
while ((dir = readdir(d))) {
|
||||
/* avoids infinite recursion :( */
|
||||
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", path, dir->d_name);
|
||||
ls_ent(full_path);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
void
|
||||
do_symlink(const char *path, const struct stat *sb)
|
||||
{
|
||||
(void)sb;
|
||||
printf("sym: %s\n", path);
|
||||
}
|
||||
|
||||
void
|
||||
do_blockdev(const char *path, const struct stat *sb)
|
||||
{
|
||||
(void)sb;
|
||||
printf("blk: %s\n", path);
|
||||
}
|
||||
|
||||
void
|
||||
do_char(const char *path, const struct stat *sb)
|
||||
{
|
||||
(void)sb;
|
||||
printf("char: %s\n", path);
|
||||
}
|
||||
|
||||
void
|
||||
do_fifo(const char *path, const struct stat *sb)
|
||||
{
|
||||
(void)sb;
|
||||
printf("fifo: %s\n", path);
|
||||
}
|
||||
|
||||
void
|
||||
do_socket(const char *path, const struct stat *sb)
|
||||
{
|
||||
(void)sb;
|
||||
printf("sock: %s\n", path);
|
||||
}
|
||||
|
||||
void
|
||||
do_unknown(const char *path, const struct stat *sb)
|
||||
{
|
||||
(void)sb;
|
||||
printf("wtf: %s\n", path);
|
||||
}
|
45
lstest.sh
Normal file
45
lstest.sh
Normal file
|
@ -0,0 +1,45 @@
|
|||
#! /bin/sh
|
||||
#set -e
|
||||
|
||||
COMMANDS="./ls
|
||||
./ls -l
|
||||
./ls -la
|
||||
./ls -lai
|
||||
./ls -lairt
|
||||
./ls -lairtus
|
||||
./ls -d
|
||||
./ls -d .
|
||||
./ls -d . .. /
|
||||
./ls -n /home
|
||||
./ls -l /dev
|
||||
./ls -lsh
|
||||
./ls -lF
|
||||
./ls -A ~/testdir
|
||||
./ls -w ~/testdir
|
||||
./ls ~/testdir | more
|
||||
./ls ~/testdir/d
|
||||
./ls -l ~/testdir/d
|
||||
./ls -la ~/testdir/d
|
||||
BLOCKSIZE=bacon ./ls -ls
|
||||
BLOCKSIZE=0 ./ls -ls
|
||||
BLOCKSIZE=2048 ./ls -ls
|
||||
BLOCKSIZE=-50 ./ls -ls
|
||||
BLOCKSIZE=50 ./ls -ls
|
||||
TZ=PST8PDT ./ls -lc
|
||||
TZ=bacon ./ls -lc
|
||||
./ls -lks
|
||||
./ls / /tmp ~ .
|
||||
./ls -?
|
||||
./ls /does/not/exit
|
||||
./ls /nowhere"
|
||||
|
||||
IFS="
|
||||
"
|
||||
|
||||
for c in ${COMMANDS}; do
|
||||
echo ${c}
|
||||
timeout --foreground 60 sh -c "eval ${c}" || echo timed out
|
||||
done
|
||||
|
||||
echo "./ls -lR /"
|
||||
timeout 600 ./ls -lR / || echo timed out
|
107
mktestdir.sh
Normal file
107
mktestdir.sh
Normal file
|
@ -0,0 +1,107 @@
|
|||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p testdir
|
||||
cd testdir
|
||||
|
||||
mkdir d
|
||||
touch empty
|
||||
mkfifo fifo
|
||||
echo file > file
|
||||
ln file file2
|
||||
ln -s "" emptylink
|
||||
ln -s /nowhere
|
||||
ln -s file2 symlink
|
||||
touch -a -t 201810012222 atime
|
||||
touch -t 196912010000 longago
|
||||
touch -t 300011111111 inthefuture
|
||||
mkdir subdir
|
||||
chmod 1755 subdir
|
||||
ln -s . subdir/loopdir
|
||||
touch executable
|
||||
chmod 755 executable
|
||||
touch suid:sgid
|
||||
chmod 6755 suid:sgid
|
||||
touch missing-exec
|
||||
chmod 4000 missing-exec
|
||||
touch " "
|
||||
touch " "
|
||||
touch "foo
bar"
|
||||
|
||||
su root -c "chown nobody:operator file"
|
||||
su root -c "chown games:daemon d"
|
||||
#sudo chown nobody:operator file
|
||||
#sudo chown games:daemon d
|
||||
#su root -c "cp /dev/wd0 ."
|
||||
touch noowner
|
||||
su root -c "chown 1234 noowner"
|
||||
#sudo chown 1234 noowner
|
||||
touch nogroup
|
||||
su root -c "chown :1234 nogroup"
|
||||
#sudo chown :1234 nogroup
|
||||
ln -s / "ls-LR"
|
||||
su root -c "cp -a /dev/null null"
|
||||
#sudo cp -a /dev/null null
|
||||
touch $(yes a | head -255 | tr -d '\n')
|
||||
|
||||
cat >hole.c <<EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
char buf1[] = "abcdefghij";
|
||||
char buf2[] = "ABCDEFGHIJ";
|
||||
|
||||
#define BIGNUM 10240000
|
||||
|
||||
int
|
||||
main(void) {
|
||||
int fd;
|
||||
|
||||
if ((fd = creat("file.hole", S_IRUSR | S_IWUSR)) < 0) {
|
||||
perror("creat error");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (write(fd, buf1, strlen(buf1)) != (ssize_t)strlen(buf1)) {
|
||||
perror("error writing buf1");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (lseek(fd, BIGNUM, SEEK_CUR) == -1) {
|
||||
perror("lseek error");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (write(fd, buf2, strlen(buf2)) != (ssize_t)strlen(buf2)) {
|
||||
perror("error writing buf2");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
EOF
|
||||
|
||||
cc -Wall -Werror hole.c
|
||||
./a.out
|
||||
|
||||
mkdir nested
|
||||
cd nested
|
||||
(
|
||||
for i in `jot 512`; do
|
||||
mkdir $i
|
||||
cd $i
|
||||
done
|
||||
)
|
||||
|
||||
(
|
||||
for i in `jot 30`; do
|
||||
mkdir `yes a | head -255 | tr -d '\n'`
|
||||
ln -s a* b
|
||||
cd b
|
||||
done
|
||||
)
|
6
readme.rst
Normal file
6
readme.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
==
|
||||
ls
|
||||
==
|
||||
|
||||
|
||||
above was spellchecked by claude3
|
8
shell.nix
Normal file
8
shell.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
{ pkgs ? import <nixpkgs> {}}:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
gcc
|
||||
clang-tools
|
||||
];
|
||||
}
|
Loading…
Reference in a new issue