Merge nih
This commit is contained in:
commit
cb45fbc0c4
130
.gitignore
vendored
130
.gitignore
vendored
@ -1,94 +1,44 @@
|
||||
*.aux
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
*.log
|
||||
*.so
|
||||
*.a
|
||||
*.o
|
||||
*.out
|
||||
*.pdf
|
||||
*.swp
|
||||
*.swn
|
||||
*.toc
|
||||
*.ko
|
||||
*.img.gz
|
||||
|
||||
# Makefile magic
|
||||
/.compositor-check
|
||||
/.config
|
||||
/.passed
|
||||
/.userspace-check
|
||||
/.disk_size
|
||||
/.ramdisk_size
|
||||
/.toolchain
|
||||
|
||||
/util/*.img
|
||||
/util/*.vmdk
|
||||
/util/*.vdi
|
||||
/util/bin/
|
||||
|
||||
/hdd/bin/
|
||||
/hdd/boot/
|
||||
/hdd/home/local/
|
||||
/hdd/home/root/
|
||||
/hdd/etc/hostname
|
||||
|
||||
/hdd/lib
|
||||
/hdd/opt
|
||||
|
||||
/hdd/usr/bin
|
||||
/hdd/usr/etc
|
||||
/hdd/usr/i686-pc-toaru
|
||||
/hdd/usr/include
|
||||
/hdd/usr/lib
|
||||
/hdd/usr/libexec
|
||||
/hdd/usr/local
|
||||
/hdd/usr/man
|
||||
/hdd/usr/share/aclocal
|
||||
/hdd/usr/share/doc
|
||||
/hdd/usr/share/games
|
||||
/hdd/usr/share/gcc-4.6.*
|
||||
/hdd/usr/share/gtk-doc
|
||||
/hdd/usr/share/info
|
||||
/hdd/usr/share/locale
|
||||
/hdd/usr/share/man
|
||||
/hdd/usr/share/tabset
|
||||
/hdd/usr/share/terminfo
|
||||
/hdd/usr/share/vim
|
||||
/hdd/usr/share/icons/external
|
||||
/hdd/usr/share/fontconfig
|
||||
/hdd/usr/share/xml
|
||||
/hdd/usr/python
|
||||
/hdd/usr/gcc
|
||||
|
||||
# pseudo-submodules
|
||||
/toaru-pdfviewer
|
||||
/toaru-python
|
||||
/pycairo
|
||||
|
||||
# Generated files / targets
|
||||
/kernel/symbols.s
|
||||
/kernel/symbols.S
|
||||
/tags
|
||||
/toaruos-disk.img
|
||||
/toaruos-kernel
|
||||
/toaruos.iso
|
||||
/toaruos-big.iso
|
||||
/modpack.kop
|
||||
/cdrom/
|
||||
/kernel-headers.img
|
||||
|
||||
# Toolchain
|
||||
/toolchain/build
|
||||
/toolchain/local
|
||||
/toolchain/tarballs
|
||||
|
||||
# Tool-generated files
|
||||
/qemu-vlan0.pcap
|
||||
# gdb history can end up all sorts of places
|
||||
*.iso
|
||||
*.efi
|
||||
.gdb_history
|
||||
|
||||
/contrib
|
||||
/.make/*
|
||||
/base/bin/*
|
||||
/cdrom/kernel
|
||||
/cdrom/netinit
|
||||
/cdrom/mod/*
|
||||
/cdrom/ramdisk.img
|
||||
/cdrom/boot.sys
|
||||
/cdrom/fat.img
|
||||
/fatbase/kernel
|
||||
/fatbase/netinit
|
||||
/fatbase/mod/*
|
||||
/fatbase/ramdisk.img
|
||||
/fatbase/efi/boot/bootia32.efi
|
||||
/util/tarballs
|
||||
/util/build
|
||||
/util/local
|
||||
/util/devtable
|
||||
/util/tmp-gcc
|
||||
/kernel/symbols.S
|
||||
/base/usr/python
|
||||
/base/usr/bin/*
|
||||
/base/usr/lib/*
|
||||
/base/usr/share/python-demos
|
||||
/base/usr/share/help
|
||||
|
||||
# Vagrant configs shouldn't end up in git
|
||||
/.vagrant
|
||||
/Vagrantfile
|
||||
# Generic
|
||||
/base/usr/share/aclocal
|
||||
/base/usr/share/gtk-doc
|
||||
|
||||
# Freetype
|
||||
/base/usr/include/freetype2
|
||||
/base/usr/include/ft2build.h
|
||||
/base/usr/share/fonts
|
||||
|
||||
# Cairo + Pixman
|
||||
/base/usr/include/cairo
|
||||
/base/usr/include/pixman-1
|
||||
|
24
.travis.yml
24
.travis.yml
@ -1,24 +0,0 @@
|
||||
language: c
|
||||
script:
|
||||
- docker run -v `pwd`:/opt/tree -w /opt/tree -t toaruos/build-tools:test util/build-travis.sh
|
||||
sudo: required
|
||||
dist: trusty
|
||||
serivces:
|
||||
- docker
|
||||
before_install:
|
||||
- docker pull toaruos/build-tools:test
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- secure: "YIH2do6BypI1ZiXONyldvW/xt8O2j/PDb3sPzGUwJql08pItH3t3MPN3JHtKEBU7+/yFB58HbA2C8B1gu/oAGs2tqMCFYiapVUYYv5CudvMt+XkBzxgKRFwPcvPtz+lAjVbIM0SXDdlrfjczDGKPnEvCYBIu+ZYlz8dgn5DEVX8="
|
||||
use_notice: false
|
||||
skip_join: true
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: Lcs5kHe9HAwcVLdm8c0FkAb77U9yzUQdI5PmTU1AnFyHtrPmW1+9d6HeYSPLHm+cPAUdWKqouJNKW7s76Sqhz+4IDcwro7VkbV/fd9NFQCOf9Jb5QScmCZndmYVQUiUmy/7wVqGdy+vatKEsnngctT7aVVhJ5SrWoCPmcttUez8=
|
||||
file: toaruos.iso
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
on:
|
||||
tags: true
|
58
LICENSE
58
LICENSE
@ -1,35 +1,33 @@
|
||||
Copyright (c) 2011-2017 Kevin Lange. All rights reserved.
|
||||
|
||||
Dedicated to the memory of
|
||||
Dennis Ritchie
|
||||
1941-2011
|
||||
University of Illinois/NCSA Open Source License
|
||||
|
||||
Developed by: ToAruOS Kernel Development Team
|
||||
http://toaruos.org
|
||||
Copyright (c) 2011-2018 K Lange, et al. (hereafter [fullname]). All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal with 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:
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the names of the ToAruOS Kernel Development Team, Kevin Lange,
|
||||
nor the names of its contributors may be used to endorse
|
||||
or promote products derived from this Software without specific prior
|
||||
written permission.
|
||||
Developed by: ToaruOS (hereafter [project])
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal with 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 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
|
||||
CONTRIBUTORS 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
|
||||
WITH THE SOFTWARE.
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
Additional licenses are available from hdd/usr/share/help/licenses, or through
|
||||
the Help Browser > Contents > Licenses within the OS.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of [fullname], [project] nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this Software without specific prior written permission.
|
||||
|
||||
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
|
||||
CONTRIBUTORS 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 WITH
|
||||
THE SOFTWARE.
|
||||
|
756
Makefile
756
Makefile
@ -1,511 +1,377 @@
|
||||
# ToaruOS Build Scripts
|
||||
ifneq ($(MAKECMDGOALS),toolchain)
|
||||
ifeq ($(TOOLCHAIN),)
|
||||
$(error $(shell util/helpful-toolchain-error.sh))
|
||||
else
|
||||
$(shell util/cache-toolchain.sh)
|
||||
endif
|
||||
ifeq ($(TOOLCHAIN),)
|
||||
ifeq ($(shell util/check.sh),y)
|
||||
export PATH := $(shell util/activate.sh)
|
||||
else
|
||||
FOO := $(shell util/prompt.sh)
|
||||
ifeq ($(shell util/check.sh),y)
|
||||
export PATH := $(shell util/activate.sh)
|
||||
else
|
||||
$(error "No toolchain, and you did not ask to build it.")
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
KERNEL_TARGET=i686-elf
|
||||
USER_TARGET=i686-pc-toaru
|
||||
|
||||
# Pretty output utilities.
|
||||
BEG = util/mk-beg
|
||||
END = util/mk-end
|
||||
INFO = util/mk-info
|
||||
ERRORS = 2>>/tmp/.`whoami`-build-errors || util/mk-error
|
||||
ERRORSS = >>/tmp/.`whoami`-build-errors || util/mk-error
|
||||
BEGRM = util/mk-beg-rm
|
||||
ENDRM = util/mk-end-rm
|
||||
|
||||
# Rules start here.
|
||||
.PHONY: all system install test toolchain userspace modules cdrom fix-cd
|
||||
.PHONY: clean clean-soft clean-hard clean-user clean-mods clean-core clean-disk clean-once
|
||||
.PHONY: run vga term headless curses quick
|
||||
.PHONY: debug debug-vga debug-term debug-curses
|
||||
.PHONY: virtualbox virtualbox-cdrom run-cdrom
|
||||
|
||||
# Prevents Make from removing intermediary files on failure
|
||||
.SECONDARY:
|
||||
|
||||
# Disable built-in rules
|
||||
.SUFFIXES:
|
||||
|
||||
all: $(shell util/detect-make-all.sh)
|
||||
all: image.iso
|
||||
|
||||
toolchain:
|
||||
@cd toolchain; ./toolchain-build.sh
|
||||
TARGET_TRIPLET=i686-pc-toaru
|
||||
|
||||
###########################
|
||||
# Emulator Pseudo-targets #
|
||||
###########################
|
||||
# Userspace flags
|
||||
|
||||
# Specify which modules should be included on startup.
|
||||
# There are a few modules that are kinda required for a working system
|
||||
# such as all of the dependencies needed to mount the root partition.
|
||||
# We can also include things like the debug shell...
|
||||
# Note that ordering matters - list dependencies first.
|
||||
BOOT_MODULES := zero random serial
|
||||
BOOT_MODULES += procfs tmpfs ata
|
||||
#BOOT_MODULES += dospart
|
||||
BOOT_MODULES += ext2
|
||||
BOOT_MODULES += debug_shell
|
||||
BOOT_MODULES += ps2mouse ps2kbd
|
||||
BOOT_MODULES += lfbvideo
|
||||
BOOT_MODULES += vidset
|
||||
BOOT_MODULES += packetfs
|
||||
BOOT_MODULES += snd
|
||||
BOOT_MODULES += pcspkr
|
||||
BOOT_MODULES += ac97
|
||||
BOOT_MODULES += net rtl
|
||||
CC=$(TARGET_TRIPLET)-gcc
|
||||
AR=$(TARGET_TRIPLET)-ar
|
||||
AS=$(TARGET_TRIPLET)-as
|
||||
CFLAGS= -O3 -g -std=gnu99 -I. -Iapps -pipe -mmmx -msse -msse2 -fplan9-extensions -Wall -Wextra -Wno-unused-parameter
|
||||
|
||||
# This is kinda silly. We're going to form an -initrd argument..
|
||||
# which is basically -initrd "hdd/mod/%.ko,hdd/mod/%.ko..."
|
||||
# for each of the modules listed above in BOOT_MODULES
|
||||
COMMA := ,
|
||||
EMPTY :=
|
||||
SPACE := $(EMPTY) $(EMPTY)
|
||||
BOOT_MODULES_X = -initrd "$(subst $(SPACE),$(COMMA),$(foreach mod,$(BOOT_MODULES),hdd/mod/$(mod).ko))"
|
||||
##
|
||||
# C library objects from libc/ C sources (and setjmp, which is assembly)
|
||||
LIBC_OBJS = $(patsubst %.c,%.o,$(wildcard libc/*.c))
|
||||
LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/*/*.c))
|
||||
LIBC_OBJS += libc/setjmp.o
|
||||
LC=base/lib/libc.so
|
||||
|
||||
# QEMU Configuration
|
||||
EMU = qemu-system-i386
|
||||
##
|
||||
# APPS = C sources from apps/
|
||||
# APPS_X = binaries
|
||||
# APPS_Y = generated makefiles for binaries (except init)
|
||||
# APPS_SH = shell scripts to copy to base/bin/ and mark executable
|
||||
# APPS_SH_X = destinations for shell scripts
|
||||
APPS=$(patsubst apps/%.c,%,$(wildcard apps/*.c))
|
||||
APPS_X=$(foreach app,$(APPS),base/bin/$(app))
|
||||
APPS_Y=$(foreach app,$(filter-out init,$(APPS)),.make/$(app).mak)
|
||||
APPS_SH=$(patsubst apps/%.sh,%.sh,$(wildcard apps/*.sh))
|
||||
APPS_SH_X=$(foreach app,$(APPS_SH),base/bin/$(app))
|
||||
|
||||
# Force the SDL backend with no frame and English (US) keyboard.
|
||||
EMUARGS = -sdl -no-frame -k en-us
|
||||
# 1GB of RAM
|
||||
EMUARGS += -m 1024
|
||||
# Bochs VBE display device
|
||||
EMUARGS += -vga std
|
||||
# Realtime clock based on localtime (we don't NTP or support timezone configs yet)
|
||||
EMUARGS += -rtc base=localtime
|
||||
# Network hardware: RTL8139, usermode network emulation.
|
||||
EMUARGS += -net nic,model=rtl8139 -net user
|
||||
# Enable TCP dumps for monitoring.
|
||||
EMUARGS += -net dump
|
||||
# Sound hardware: Intel AC'97, PC beeper
|
||||
EMUARGS += -soundhw pcspk,ac97
|
||||
# Enable KVM if available, or fall back to TCG
|
||||
EMUARGS += -M accel=kvm:tcg
|
||||
##
|
||||
# LIBS = C sources from lib/
|
||||
# LIBS_X = Shared libraries (.so)
|
||||
# LIBS_Y = Generated makefiles for libraries
|
||||
LIBS=$(patsubst lib/%.c,%,$(wildcard lib/*.c))
|
||||
LIBS_X=$(foreach lib,$(LIBS),base/lib/libtoaru_$(lib).so)
|
||||
LIBS_Y=$(foreach lib,$(LIBS),.make/$(lib).lmak)
|
||||
|
||||
# For development images, load the kernel, modules, hard disk.
|
||||
EMUKARGS = -kernel toaruos-kernel
|
||||
EMUKARGS += $(BOOT_MODULES_X)
|
||||
EMUKARGS += -hda toaruos-disk.img
|
||||
##
|
||||
# Files that must be present in the ramdisk (apps, libraries)
|
||||
RAMDISK_FILES= ${APPS_X} ${APPS_SH_X} ${LIBS_X} base/lib/ld.so base/lib/libm.so
|
||||
|
||||
# These arguments are passed to the kernel command line.
|
||||
DISK_ROOT = root=/dev/hda
|
||||
VID_QEMU = vid=qemu,,1280,,720
|
||||
START_VGA = start=--vga
|
||||
START_SINGLE = start=--single
|
||||
START_LIVE = start=live-welcome
|
||||
WITH_LOGS = logtoserial=1
|
||||
# Kernel / module flags
|
||||
|
||||
# Various different quick options
|
||||
run: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(DISK_ROOT)"
|
||||
quick: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(DISK_ROOT) start=quick-launch"
|
||||
debug: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -serial stdio -append "$(VID_QEMU) $(WITH_LOGS) $(DISK_ROOT)"
|
||||
vga: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -append "$(START_VGA) $(DISK_ROOT)"
|
||||
debug-vga: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -serial stdio -append "$(WITH_LOGS) $(START_VGA) $(DISK_ROOT)"
|
||||
term: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(START_SINGLE) $(DISK_ROOT)"
|
||||
debug-term: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -serial stdio -append "$(VID_QEMU) $(START_SINGLE) $(WITH_LOGS) $(DISK_ROOT)"
|
||||
headless: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -display none -append "$(START_VGA) $(DISK_ROOT)"
|
||||
curses: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -curses -append "$(START_VGA) $(DISK_ROOT)"
|
||||
debug-curses: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -serial file:serial-debug.log -curses -append "$(WITH_LOGS) $(START_VGA) $(DISK_ROOT)"
|
||||
live: system
|
||||
${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(START_LIVE) $(DISK_ROOT)"
|
||||
KCC = $(TARGET_TRIPLET)-gcc
|
||||
KAS = $(TARGET_TRIPLET)-as
|
||||
KLD = $(TARGET_TRIPLET)-ld
|
||||
KNM = $(TARGET_TRIPLET)-nm
|
||||
|
||||
# Run the cdrom
|
||||
run-cdrom: toaruos.iso
|
||||
${EMU} ${EMUARGS} -cdrom toaruos.iso
|
||||
KCFLAGS = -O2 -std=c99
|
||||
KCFLAGS += -finline-functions -ffreestanding
|
||||
KCFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format
|
||||
KCFLAGS += -pedantic -fno-omit-frame-pointer
|
||||
KCFLAGS += -D_KERNEL_
|
||||
KCFLAGS += -DKERNEL_GIT_TAG=$(shell util/make-version)
|
||||
KASFLAGS = --32
|
||||
|
||||
# Run VirtualBox
|
||||
virtualbox: system
|
||||
util/run-virtualbox.sh
|
||||
virtualbox-cdrom: toaruos.iso
|
||||
util/run-virtualbox-cdrom.sh
|
||||
|
||||
# Run the test suite
|
||||
test: system
|
||||
expect util/test.exp
|
||||
|
||||
################
|
||||
# Kernel #
|
||||
################
|
||||
|
||||
# Kernel build flags
|
||||
CFLAGS = -O2 -std=c99
|
||||
CFLAGS += -finline-functions -ffreestanding
|
||||
CFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format
|
||||
CFLAGS += -pedantic -fno-omit-frame-pointer
|
||||
CFLAGS += -D_KERNEL_
|
||||
ASFLAGS = --32
|
||||
|
||||
# Build kernel with bare elf toolchain
|
||||
KCC = $(KERNEL_TARGET)-gcc
|
||||
KNM = $(KERNEL_TARGET)-nm
|
||||
KCXX= $(KERNEL_TARGET)-g++
|
||||
KAR = $(KERNEL_TARGET)-ar
|
||||
KAS = $(KERNEL_TARGET)-as
|
||||
KSTRIP = $(KERNEL_TARGET)-strip
|
||||
|
||||
# Kernel autoversioning with git sha
|
||||
CFLAGS += -DKERNEL_GIT_TAG=`util/make-version`
|
||||
|
||||
# All of the core parts of the kernel are built directly.
|
||||
##
|
||||
# Kernel objects from kernel/ C sources
|
||||
KERNEL_OBJS = $(patsubst %.c,%.o,$(wildcard kernel/*.c))
|
||||
KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*.c))
|
||||
KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*/*.c))
|
||||
|
||||
##
|
||||
# Kernel objects from kernel/ assembly sources
|
||||
KERNEL_ASMOBJS = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/*.S)))
|
||||
|
||||
toaruos-kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o
|
||||
@${BEG} "CC" "$@"
|
||||
@${KCC} -T kernel/link.ld ${CFLAGS} -nostdlib -o toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o -lgcc ${ERRORS}
|
||||
@${END} "CC" "$@"
|
||||
@${INFO} "--" "Kernel is ready!"
|
||||
# Kernel
|
||||
|
||||
fatbase/kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o
|
||||
${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o $@ ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o -lgcc
|
||||
|
||||
##
|
||||
# Symbol table for the kernel. Instead of relying on getting
|
||||
# the symbol table from our bootloader (eg. through ELF
|
||||
# headers provided via multiboot structure), we have a dedicated
|
||||
# object that build with all the symbols. This allows us to
|
||||
# build the kernel as a flat binary or load it with less-capable
|
||||
# multiboot loaders and still get symbols, which we need to
|
||||
# load kernel modules and link them properly.
|
||||
kernel/symbols.o: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} util/generate_symbols.py
|
||||
@-rm -f kernel/symbols.o
|
||||
@${BEG} "NM" "Generating symbol list..."
|
||||
@${KCC} -T kernel/link.ld ${CFLAGS} -nostdlib -o toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} -lgcc ${ERRORS}
|
||||
@${KNM} toaruos-kernel -g | util/generate_symbols.py > kernel/symbols.S
|
||||
@${END} "NM" "Generated symbol list."
|
||||
@${BEG} "AS" "kernel/symbols.S"
|
||||
@${KAS} ${ASFLAGS} kernel/symbols.S -o $@ ${ERRORS}
|
||||
@${END} "AS" "kernel/symbols.S"
|
||||
-rm -f kernel/symbols.o
|
||||
${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o .toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} -lgcc
|
||||
${KNM} .toaruos-kernel -g | util/generate_symbols.py > kernel/symbols.S
|
||||
${KAS} ${KASFLAGS} kernel/symbols.S -o $@
|
||||
-rm -f .toaruos-kernel
|
||||
|
||||
##
|
||||
# version.o should be rebuilt whenever the kernel changes
|
||||
# in order to get fresh git commit hash information.
|
||||
kernel/sys/version.o: kernel/*/*.c kernel/*.c
|
||||
|
||||
hdd/mod:
|
||||
@mkdir -p hdd/mod
|
||||
kernel/%.o: kernel/%.S
|
||||
${KAS} ${ASFLAGS} $< -o $@
|
||||
|
||||
# Loadable modules
|
||||
MODULES = $(patsubst modules/%.c,hdd/mod/%.ko,$(wildcard modules/*.c))
|
||||
kernel/%.o: kernel/%.c ${HEADERS}
|
||||
${KCC} ${KCFLAGS} -nostdlib -g -c -o $@ $<
|
||||
|
||||
# We also want to rebuild when a header changes.
|
||||
# This is a naive approach, but it works...
|
||||
HEADERS = $(shell find kernel/include/ -type f -name '*.h')
|
||||
# Modules
|
||||
|
||||
hdd/mod/%.ko: modules/%.c ${HEADERS} | hdd/mod
|
||||
@${BEG} "CC" "$< [module]"
|
||||
@${KCC} -T modules/link.ld -I./kernel/include -nostdlib ${CFLAGS} -c -o $@ $< ${ERRORS}
|
||||
@${END} "CC" "$< [module]"
|
||||
fatbase/mod:
|
||||
@mkdir -p $@
|
||||
|
||||
##
|
||||
# Modules need to be installed on the boot image
|
||||
MODULES = $(patsubst modules/%.c,fatbase/mod/%.ko,$(wildcard modules/*.c))
|
||||
HEADERS = $(shell find base/usr/include/kernel -type f -name '*.h')
|
||||
|
||||
fatbase/mod/%.ko: modules/%.c ${HEADERS} | fatbase/mod
|
||||
${KCC} -T modules/link.ld -nostdlib ${KCFLAGS} -c -o $@ $<
|
||||
|
||||
modules: ${MODULES}
|
||||
|
||||
kernel/%.o: kernel/%.S
|
||||
@${BEG} "AS" "$<"
|
||||
@${KAS} ${ASFLAGS} $< -o $@ ${ERRORS}
|
||||
@${END} "AS" "$<"
|
||||
# Root Filesystem
|
||||
|
||||
kernel/%.o: kernel/%.c ${HEADERS}
|
||||
@${BEG} "CC" "$<"
|
||||
@${KCC} ${CFLAGS} -nostdlib -g -I./kernel/include -c -o $@ $< ${ERRORS}
|
||||
@${END} "CC" "$<"
|
||||
base/dev:
|
||||
mkdir -p $@
|
||||
base/tmp:
|
||||
mkdir -p $@
|
||||
base/proc:
|
||||
mkdir -p $@
|
||||
base/bin:
|
||||
mkdir -p $@
|
||||
base/lib:
|
||||
mkdir -p $@
|
||||
base/cdrom:
|
||||
mkdir -p $@
|
||||
fatbase/efi/boot:
|
||||
mkdir -p $@
|
||||
.make:
|
||||
mkdir -p .make
|
||||
dirs: base/dev base/tmp base/proc base/bin base/lib base/cdrom fatbase/efi/boot .make
|
||||
|
||||
system: toaruos-disk.img toaruos-kernel ${MODULES}
|
||||
# C Library
|
||||
|
||||
#############
|
||||
# Userspace #
|
||||
#############
|
||||
crts: base/lib/crt0.o base/lib/crti.o base/lib/crtn.o | dirs
|
||||
|
||||
# Userspace build flags
|
||||
USER_CFLAGS = -O3 -m32 -Wa,--32 -g -Iuserspace -std=c99 -U__STRICT_ANSI__ -Lhdd/usr/lib
|
||||
USER_CXXFLAGS = -O3 -m32 -Wa,--32 -g -Iuserspace
|
||||
USER_BINFLAGS =
|
||||
STRIP_LIBS = 1
|
||||
base/lib/crt%.o: libc/crt%.s
|
||||
yasm -f elf -o $@ $<
|
||||
|
||||
# We always build with our targetted cross-compiler
|
||||
CC = $(USER_TARGET)-gcc
|
||||
NM = $(USER_TARGET)-nm
|
||||
CXX= $(USER_TARGET)-g++
|
||||
AR = $(USER_TARGET)-ar
|
||||
AS = $(USER_TARGET)-as
|
||||
STRIP = $(USER_TARGET)-strip
|
||||
libc/setjmp.o: libc/setjmp.S
|
||||
$(AS) -o $@ $<
|
||||
|
||||
# Userspace binaries and libraries
|
||||
USER_CFILES = $(filter-out userspace/core/init.c,$(shell find userspace -not -wholename '*/lib/*' -not -wholename '*.static.*' -name '*.c'))
|
||||
USER_CXXFILES = $(shell find userspace -not -wholename '*/lib/*' -name '*.c++')
|
||||
USER_LIBFILES = $(shell find userspace -wholename '*/lib/*' -name '*.c')
|
||||
libc/%.o: libc/%.c
|
||||
$(CC) $(CFLAGS) -fPIC -c -o $@ $<
|
||||
|
||||
LIBC=hdd/usr/lib/libc.so
|
||||
base/lib/libc.a: ${LIBC_OBJS} | dirs crts
|
||||
$(AR) cr $@ $^
|
||||
|
||||
# PYthon sources
|
||||
PYTHON_LIBS = $(shell find userspace -wholename '*/lib/*' -name '*.py')
|
||||
PYTHON_BINS = $(shell find userspace -wholename '*/bin/*' -name '*.py')
|
||||
base/lib/libc.so: ${LIBC_OBJS} | dirs crts
|
||||
$(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc
|
||||
|
||||
PYTHON_FILES = $(foreach file,$(PYTHON_LIBS),$(patsubst %.py,hdd/usr/python/lib/python3.6/%.py,$(notdir ${file})))
|
||||
PYTHON_FILES += $(foreach file,$(PYTHON_BINS),$(patsubst %.py,hdd/bin/%.py,$(notdir ${file})))
|
||||
base/lib/libm.so: util/lm.c | dirs crts
|
||||
$(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc
|
||||
|
||||
# Userspace output files (so we can define metatargets)
|
||||
NONTEST_C = $(foreach f,$(USER_CFILES),$(if $(findstring /tests/,$f),,$f))
|
||||
NONTEST_CXX = $(foreach f,$(USER_CXXFILES),$(if $(findstring /tests/,$f),,$f))
|
||||
# Userspace Linker/Loader
|
||||
|
||||
NONTEST = $(foreach file,$(NONTEST_C),$(patsubst %.c,hdd/bin/%,$(notdir ${file})))
|
||||
NONTEST += $(foreach file,$(NONTEST_CXX),$(patsubst %.c++,hdd/bin/%,$(notdir ${file})))
|
||||
NONTEST += $(foreach file,$(USER_CSTATICFILES),$(patsubst %.static.c,hdd/bin/%,$(notdir ${file})))
|
||||
NONTEST += $(foreach file,$(USER_LIBFILES),$(patsubst %.c,hdd/usr/lib/libtoaru-%.so,$(notdir ${file})))
|
||||
NONTEST += $(LIBC) hdd/bin/init hdd/lib/ld.so
|
||||
base/lib/ld.so: linker/linker.c base/lib/libc.a | dirs
|
||||
$(CC) -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $<
|
||||
|
||||
USERSPACE = $(foreach file,$(USER_CFILES),$(patsubst %.c,hdd/bin/%,$(notdir ${file})))
|
||||
USERSPACE += $(foreach file,$(USER_CXXFILES),$(patsubst %.c++,hdd/bin/%,$(notdir ${file})))
|
||||
USERSPACE += $(foreach file,$(USER_CSTATICFILES),$(patsubst %.static.c,hdd/bin/%,$(notdir ${file})))
|
||||
USERSPACE += $(foreach file,$(USER_LIBFILES),$(patsubst %.c,hdd/usr/lib/libtoaru-%.so,$(notdir ${file})))
|
||||
USERSPACE += $(LIBC) hdd/bin/init hdd/lib/ld.so
|
||||
# Shared Libraries
|
||||
.make/%.lmak: lib/%.c util/auto-dep.py | dirs
|
||||
util/auto-dep.py --makelib $< > $@
|
||||
|
||||
userspace: ${USERSPACE}
|
||||
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
|
||||
-include ${LIBS_Y}
|
||||
endif
|
||||
|
||||
# Init must be built static at the moment.
|
||||
hdd/bin/init: userspace/core/init.c
|
||||
@${BEG} "CC" "$< (static)"
|
||||
@${CC} -o $@ -static -Wl,-static $(USER_CFLAGS) $(USER_BINFLAGS) $< ${ERRORS}
|
||||
@${END} "CC" "$< (static)"
|
||||
# Init (static)
|
||||
|
||||
# Libraries
|
||||
define user-c-rule
|
||||
$1: $2 $(shell util/auto-dep.py --deps $2) $(LIBC)
|
||||
@${BEG} "CCSO" "$$<"
|
||||
@${CC} -o $$@ $(USER_CFLAGS) -shared -fPIC $$(shell util/auto-dep.py --cflags $$<) $$< $$(shell util/auto-dep.py --libs $$<) -lc ${ERRORS}
|
||||
@if [ "x$(STRIP_LIBS)" = "x1" ]; then ${STRIP} $$@; fi
|
||||
@${END} "CCSO" "$$<"
|
||||
endef
|
||||
$(foreach file,$(USER_LIBFILES),$(eval $(call user-c-rule,$(patsubst %.c,hdd/usr/lib/libtoaru-%.so,$(notdir ${file})),${file})))
|
||||
base/bin/init: apps/init.c base/lib/libc.a | dirs
|
||||
$(CC) -static -Wl,-static $(CFLAGS) -o $@ $<
|
||||
|
||||
# Binaries from C sources
|
||||
define user-c-rule
|
||||
$1: $2 $(shell util/auto-dep.py --deps $2) $(LIBC)
|
||||
@${BEG} "CC" "$$<"
|
||||
@${CC} -o $$@ $(USER_CFLAGS) $(USER_BINFLAGS) -fPIE $$(shell util/auto-dep.py --cflags $$<) $$< $$(shell util/auto-dep.py --libs $$<) -lc ${ERRORS}
|
||||
@${END} "CC" "$$<"
|
||||
endef
|
||||
$(foreach file,$(USER_CFILES),$(eval $(call user-c-rule,$(patsubst %.c,hdd/bin/%,$(notdir ${file})),${file})))
|
||||
fatbase/netinit: util/netinit.c base/lib/libc.a | dirs
|
||||
$(CC) -static -Wl,-static $(CFLAGS) -o $@ $<
|
||||
|
||||
# Binaries from C++ sources
|
||||
define user-cxx-rule
|
||||
$1: $2 $(shell util/auto-dep.py --deps $2) $(LIBC)
|
||||
@${BEG} "C++" "$$<"
|
||||
@${CXX} -o $$@ $(USER_CXXFLAGS) $(USER_BINFLAGS) $$(shell util/auto-dep.py --cflags $$<) $$< $$(shell util/auto-dep.py --libs $$<) -lc ${ERRORS}
|
||||
@${END} "C++" "$$<"
|
||||
endef
|
||||
$(foreach file,$(USER_CXXFILES),$(eval $(call user-cxx-rule,$(patsubst %.c++,hdd/bin/%,$(notdir ${file})),${file})))
|
||||
# Userspace applications
|
||||
|
||||
hdd/usr/lib:
|
||||
@mkdir -p hdd/usr/lib
|
||||
.make/%.mak: apps/%.c util/auto-dep.py | dirs
|
||||
util/auto-dep.py --make $< > $@
|
||||
|
||||
# Bad implementations of shared libraries
|
||||
hdd/usr/lib/libc.so: ${TOOLCHAIN}/lib/libc.a | hdd/usr/lib
|
||||
@${BEG} "SO" "$@"
|
||||
@cp ${TOARU_SYSROOT}/usr/lib/libc.a libc.a
|
||||
@# init and fini don't belong in our shared object
|
||||
@ar d libc.a lib_a-init.o
|
||||
@ar d libc.a lib_a-fini.o
|
||||
@# Remove references to newlib's reentrant malloc
|
||||
@ar d libc.a lib_a-callocr.o
|
||||
@ar d libc.a lib_a-cfreer.o
|
||||
@ar d libc.a lib_a-freer.o
|
||||
@ar d libc.a lib_a-malignr.o
|
||||
@ar d libc.a lib_a-mallinfor.o
|
||||
@ar d libc.a lib_a-mallocr.o
|
||||
@ar d libc.a lib_a-malloptr.o
|
||||
@ar d libc.a lib_a-msizer.o
|
||||
@ar d libc.a lib_a-mallstatsr.o
|
||||
@ar d libc.a lib_a-pvallocr.o
|
||||
@ar d libc.a lib_a-vallocr.o
|
||||
@ar d libc.a lib_a-reallocr.o
|
||||
@ar d libc.a lib_a-realloc.o
|
||||
@ar d libc.a lib_a-calloc.o
|
||||
@ar d libc.a lib_a-reallo.o
|
||||
@${CC} -shared -o libc.so -Wl,--whole-archive libc.a -Wl,--no-whole-archive ${ERRORS}
|
||||
@mv libc.so hdd/usr/lib/libc.so
|
||||
@if [ "x$(STRIP_LIBS)" = "x1" ]; then ${STRIP} $@; fi
|
||||
@rm libc.a
|
||||
@${END} "SO" "$@"
|
||||
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
|
||||
-include ${APPS_Y}
|
||||
endif
|
||||
|
||||
base/bin/%.sh: apps/%.sh
|
||||
cp $< $@
|
||||
chmod +x $@
|
||||
|
||||
# Ramdisk
|
||||
|
||||
util/devtable: ${RAMDISK_FILES} $(shell find base) util/update-devtable.py
|
||||
util/update-devtable.py
|
||||
|
||||
fatbase/ramdisk.img: ${RAMDISK_FILES} $(shell find base) Makefile util/devtable | dirs
|
||||
genext2fs -B 4096 -d base -D util/devtable -U -b `util/calc-size.sh` -N 2048 $@
|
||||
|
||||
# CD image
|
||||
|
||||
ifeq (,$(wildcard /usr/lib32/crt0-efi-ia32.o))
|
||||
$(error Missing GNU-EFI.)
|
||||
endif
|
||||
|
||||
EFI_XORRISO=-eltorito-alt-boot -e fat.img -no-emul-boot -isohybrid-gpt-basdat
|
||||
EFI_BOOT=cdrom/fat.img
|
||||
EFI_UPDATE=util/update-extents.py
|
||||
|
||||
image.iso: ${EFI_BOOT} cdrom/boot.sys fatbase/netinit ${MODULES} util/update-extents.py
|
||||
xorriso -as mkisofs -R -J -c bootcat \
|
||||
-b boot.sys -no-emul-boot -boot-load-size 24 \
|
||||
${EFI_XORRISO} \
|
||||
-o image.iso cdrom
|
||||
${EFI_UPDATE}
|
||||
|
||||
# Boot loader
|
||||
|
||||
##
|
||||
# FAT EFI payload
|
||||
# This is the filesystem the EFI loaders see, so it must contain
|
||||
# the kernel, modules, and ramdisk, plus anything else we want
|
||||
# available to the bootloader (eg., netinit).
|
||||
cdrom/fat.img: fatbase/ramdisk.img ${MODULES} fatbase/kernel fatbase/netinit fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi util/mkdisk.sh
|
||||
util/mkdisk.sh $@ fatbase
|
||||
|
||||
##
|
||||
# For EFI, we build two laoders: ia32 and x64
|
||||
# We build them as ELF shared objects and the use objcopy to convert
|
||||
# them to PE executables / DLLs (as expected by EFI).
|
||||
EFI_CFLAGS=-fno-stack-protector -fpic -DEFI_PLATFORM -ffreestanding -fshort-wchar -I /usr/include/efi -mno-red-zone
|
||||
EFI_SECTIONS=-j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc
|
||||
|
||||
# ia32
|
||||
boot/efi.so: boot/cstuff.c boot/*.h
|
||||
$(CC) ${EFI_CFLAGS} -I /usr/include/efi/ia32 -c -o boot/efi.o $<
|
||||
$(LD) boot/efi.o /usr/lib32/crt0-efi-ia32.o -nostdlib -znocombreloc -T /usr/lib32/elf_ia32_efi.lds -shared -Bsymbolic -L /usr/lib32 -lefi -lgnuefi -o boot/efi.so
|
||||
|
||||
fatbase/efi/boot/bootia32.efi: boot/efi.so
|
||||
objcopy ${EFI_SECTIONS} --target=efi-app-ia32 $< $@
|
||||
|
||||
# x64
|
||||
boot/efi64.so: boot/cstuff.c boot/*.h
|
||||
gcc ${EFI_CFLAGS} -I /usr/include/efi/x86_64 -DEFI_FUNCTION_WRAPPER -c -o boot/efi64.o $<
|
||||
$(LD) boot/efi64.o /usr/lib/crt0-efi-x86_64.o -nostdlib -znocombreloc -T /usr/lib/elf_x86_64_efi.lds -shared -Bsymbolic -L /usr/lib -lefi -lgnuefi -o boot/efi64.so
|
||||
|
||||
fatbase/efi/boot/bootx64.efi: boot/efi64.so
|
||||
objcopy ${EFI_SECTIONS} --target=efi-app-x86_64 $< $@
|
||||
|
||||
# BIOS loader
|
||||
cdrom/boot.sys: boot/boot.o boot/cstuff.o boot/link.ld | dirs
|
||||
${KLD} -T boot/link.ld -o $@ boot/boot.o boot/cstuff.o
|
||||
|
||||
boot/cstuff.o: boot/cstuff.c boot/*.h
|
||||
${KCC} -c -Os -o $@ $<
|
||||
|
||||
boot/boot.o: boot/boot.s
|
||||
yasm -f elf -o $@ $<
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f base/lib/*.so
|
||||
rm -f base/lib/libc.a
|
||||
rm -f ${APPS_X} ${APPS_SH_X}
|
||||
rm -f libc/*.o libc/*/*.o
|
||||
rm -f image.iso
|
||||
rm -f fatbase/ramdisk.img
|
||||
rm -f cdrom/boot.sys
|
||||
rm -f boot/*.o
|
||||
rm -f boot/*.efi
|
||||
rm -f boot/*.so
|
||||
rm -f cdrom/fat.img cdrom/kernel cdrom/mod/* cdrom/ramdisk.img
|
||||
rm -f fatbase/kernel fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi
|
||||
rm -f cdrom/netinit fatbase/netinit
|
||||
rm -f ${KERNEL_OBJS} ${KERNEL_ASMOBJS} kernel/symbols.o kernel/symbols.S
|
||||
rm -f base/lib/crt*.o
|
||||
rm -f ${MODULES}
|
||||
rm -f ${APPS_Y} ${LIBS_Y} ${EXT_LIBS_Y}
|
||||
|
||||
ifneq (,$(findstring Microsoft,$(shell uname -r)))
|
||||
QEMU_ARGS=-serial mon:stdio -m 1G -rtc base=localtime -vnc :0
|
||||
else
|
||||
ifeq (,${NO_KVM})
|
||||
KVM=-enable-kvm
|
||||
else
|
||||
KVM=
|
||||
endif
|
||||
QEMU_ARGS=-serial mon:stdio -m 1G -soundhw ac97,pcspk ${KVM} -rtc base=localtime
|
||||
endif
|
||||
|
||||
|
||||
hdd/lib:
|
||||
@mkdir -p hdd/lib
|
||||
.PHONY: run
|
||||
run: image.iso
|
||||
qemu-system-i386 -cdrom $< ${QEMU_ARGS}
|
||||
|
||||
hdd/lib/ld.so: linker/linker.c | hdd/lib
|
||||
@${BEG} "CC" "$<"
|
||||
@${CC} -static -Wl,-static -std=c99 -g -U__STRICT_ANSI__ -o $@ -Os -T linker/link.ld $< ${ERRORS}
|
||||
@${END} "CC" "$<"
|
||||
.PHONY: fast
|
||||
fast: image.iso
|
||||
qemu-system-i386 -cdrom $< ${QEMU_ARGS} \
|
||||
-fw_cfg name=opt/org.toaruos.bootmode,string=normal
|
||||
|
||||
define basic-so-wrapper
|
||||
hdd/usr/lib/lib$(1).so: ${TOOLCHAIN}/lib/lib$(1).a
|
||||
@${BEG} "SO" "$$@"
|
||||
@${CC} -shared -Wl,-soname,lib$(1).so -o lib$(1).so -Lhdd/usr/lib -Wl,--whole-archive ${TOOLCHAIN}/lib/lib$(1).a -Wl,--no-whole-archive $2 -lgcc
|
||||
@mv lib$(1).so hdd/usr/lib/lib$(1).so
|
||||
@if [ "x$(STRIP_LIBS)" = "x1" ]; then ${STRIP} $$@; fi
|
||||
@${END} "SO" "$$@"
|
||||
.PHONY: headless
|
||||
headless: image.iso
|
||||
@qemu-system-i386 -cdrom $< ${QEMU_ARGS} \
|
||||
-nographic -no-reboot \
|
||||
-fw_cfg name=opt/org.toaruos.bootmode,string=headless
|
||||
|
||||
.PHONY: shell
|
||||
shell: image.iso
|
||||
@qemu-system-i386 -cdrom $< ${QEMU_ARGS} \
|
||||
-nographic -no-reboot \
|
||||
-fw_cfg name=opt/org.toaruos.bootmode,string=headless \
|
||||
-fw_cfg name=opt/org.toaruos.forceuser,string=local
|
||||
|
||||
.PHONY: efi64
|
||||
efi64: image.iso
|
||||
qemu-system-x86_64 -cdrom $< ${QEMU_ARGS} \
|
||||
-bios /usr/share/qemu/OVMF.fd
|
||||
|
||||
|
||||
VMNAME=ToaruOS-NIH CD
|
||||
|
||||
define virtualbox-runner =
|
||||
.PHONY: $1
|
||||
$1: image.iso
|
||||
-VBoxManage unregistervm "$(VMNAME)" --delete
|
||||
VBoxManage createvm --name "$(VMNAME)" --ostype $2 --register
|
||||
VBoxManage modifyvm "$(VMNAME)" --memory 1024 --vram 32 --audio pulse --audiocontroller ac97 --bioslogodisplaytime 1 --bioslogofadeout off --bioslogofadein off --biosbootmenu disabled $3
|
||||
VBoxManage storagectl "$(VMNAME)" --add ide --name "IDE"
|
||||
VBoxManage storageattach "$(VMNAME)" --storagectl "IDE" --port 0 --device 0 --medium $$(shell pwd)/image.iso --type dvddrive
|
||||
VBoxManage setextradata "$(VMNAME)" GUI/DefaultCloseAction PowerOff
|
||||
VBoxManage startvm "$(VMNAME)" --type separate
|
||||
endef
|
||||
|
||||
$(eval $(call basic-so-wrapper,gcc,))
|
||||
$(eval $(call basic-so-wrapper,m,))
|
||||
$(eval $(call basic-so-wrapper,z,))
|
||||
$(eval $(call basic-so-wrapper,ncurses,))
|
||||
$(eval $(call basic-so-wrapper,panel,-lncurses))
|
||||
$(eval $(call basic-so-wrapper,png15,-lz))
|
||||
$(eval $(call basic-so-wrapper,freetype,-lz))
|
||||
$(eval $(call basic-so-wrapper,pixman-1,-lm))
|
||||
$(eval $(call basic-so-wrapper,cairo,-lpixman-1 -lpng15 -lfreetype))
|
||||
$(eval $(call virtualbox-runner,virtualbox,"Other",))
|
||||
$(eval $(call virtualbox-runner,virtualbox-efi,"Other",--firmware efi))
|
||||
$(eval $(call virtualbox-runner,virtualbox-efi64,"Other_64",--firmware efi))
|
||||
|
||||
# Python parts of userspace
|
||||
##
|
||||
# Optional Extensions
|
||||
#
|
||||
# These optional extension libraries require third-party components to build,
|
||||
# but allow the native applications to make use of functionality such as
|
||||
# TrueType fonts or PNG images. You must have the necessary elements to build
|
||||
# these already installed into your sysroot for this to work.
|
||||
EXT_LIBS=$(patsubst ext/%.c,%,$(wildcard ext/*.c))
|
||||
EXT_LIBS_X=$(foreach lib,$(EXT_LIBS),base/lib/libtoaru_$(lib).so)
|
||||
EXT_LIBS_Y=$(foreach lib,$(EXT_LIBS),.make/$(lib).elmak)
|
||||
|
||||
hdd/usr/python/lib/python3.6:
|
||||
@mkdir -p $@
|
||||
.make/%.elmak: ext/%.c util/auto-dep.py | dirs
|
||||
util/auto-dep.py --makelib $< > $@
|
||||
|
||||
hdd/bin/%.py: userspace/py/bin/%.py
|
||||
@cp $< $@
|
||||
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
|
||||
-include ${EXT_LIBS_Y}
|
||||
endif
|
||||
|
||||
hdd/usr/python/lib/python3.6/%.py: userspace/py/lib/%.py hdd/usr/python/lib/python3.6
|
||||
@cp $< $@
|
||||
# Freetype: Terminal text rendering backend
|
||||
ext-freetype: base/lib/libtoaru_ext_freetype_fonts.so
|
||||
|
||||
####################
|
||||
# Hard Disk Images #
|
||||
####################
|
||||
|
||||
# Hard disk image generation
|
||||
GENEXT = genext2fs
|
||||
DISK_SIZE = `util/disk_size.sh`
|
||||
|
||||
toaruos-disk.img: ${USERSPACE} util/devtable ${PYTHON_FILES}
|
||||
@${BEG} "hdd" "Generating a Hard Disk image..."
|
||||
@-rm -f toaruos-disk.img
|
||||
@${GENEXT} -B 4096 -d hdd -D util/devtable -U -b ${DISK_SIZE} -N 4096 toaruos-disk.img ${ERRORS}
|
||||
@${END} "hdd" "Generated Hard Disk image"
|
||||
@${INFO} "--" "Hard disk image is ready!"
|
||||
|
||||
#############
|
||||
# CD Images #
|
||||
#############
|
||||
|
||||
cdrom: toaruos.iso
|
||||
|
||||
hdd/usr/share/terminfo/t/toaru: util/toaru.tic
|
||||
@mkdir -p hdd/usr/share/terminfo/t
|
||||
@cp $< $@
|
||||
|
||||
FORCE:
|
||||
|
||||
_cdrom: FORCE | ${NONTEST} toaruos-kernel
|
||||
@-rm -rf _cdrom
|
||||
@cp -r util/cdrom _cdrom
|
||||
|
||||
_cdrom/mod: ${MODULES} _cdrom
|
||||
@mv hdd/mod $@
|
||||
|
||||
_cdrom/kernel: toaruos-kernel _cdrom
|
||||
@cp $< $@
|
||||
|
||||
BLACKLIST = hdd/usr/share/wallpapers/grandcanyon.png
|
||||
BLACKLIST += hdd/usr/share/wallpapers/paris.png
|
||||
BLACKLIST += hdd/usr/share/wallpapers/southbay.png
|
||||
BLACKLIST += hdd/usr/share/wallpapers/yokohama.png
|
||||
BLACKLIST += hdd/usr/share/wallpapers/yosemite.png
|
||||
BLACKLIST += hdd/usr/share/wallpapers/fuji.png
|
||||
|
||||
_cdrom/ramdisk.img: ${NONTEST} hdd/usr/share/wallpapers util/devtable hdd/usr/share/terminfo/t/toaru _cdrom _cdrom/mod ${PYTHON_FILES}
|
||||
@${BEG} "ext" "Generating a ramdisk image..."
|
||||
@rm -f $(filter-out ${NONTEST},${USERSPACE})
|
||||
@rm -f ${BLACKLIST}
|
||||
@${STRIP} ${NONTEST}
|
||||
@${GENEXT} -B 4096 -d hdd -D util/devtable -U -b 16384 -N 2048 $@
|
||||
@${END} "ext" "Generated ramdisk image"
|
||||
|
||||
_cdrom/ramdisk.img.gz: _cdrom/ramdisk.img
|
||||
@gzip $<
|
||||
|
||||
define fixup-cd
|
||||
@git checkout hdd/usr/share/wallpapers
|
||||
@mv _cdrom/mod hdd/mod
|
||||
@rm -r _cdrom
|
||||
endef
|
||||
|
||||
toaruos.iso: _cdrom/ramdisk.img.gz _cdrom/kernel
|
||||
@${BEG} "ISO" "Building a CD image"
|
||||
@if [ -e /etc/lsb-release ] && grep precise /etc/lsb-release; then grub-mkrescue -o $@ _cdrom; else grub-mkrescue -d /usr/lib/grub/i386-pc --compress=xz -o $@ _cdrom 2> /dev/null; fi
|
||||
@${END} "ISO" "Building a CD image"
|
||||
$(call fixup-cd)
|
||||
@${INFO} "--" "CD generated"
|
||||
|
||||
netboot.img.gz: _cdrom/ramdisk.img.gz
|
||||
cp _cdrom/ramdisk.img.gz netboot.img.gz
|
||||
$(call fixup-cd)
|
||||
|
||||
fix-cd:
|
||||
$(call fixup-cd)
|
||||
|
||||
|
||||
##############
|
||||
# packages #
|
||||
##############
|
||||
|
||||
kernel-headers.img.gz: kernel/include
|
||||
@${BEG} "pack" "$@"
|
||||
@rm -rf _kernel
|
||||
@mkdir _kernel
|
||||
@cp -rL kernel/include/* _kernel/
|
||||
@${GENEXT} -B 4096 -d _kernel -U -b 170 $@ ${ERRORS}
|
||||
@rm -r _kernel
|
||||
@${END} "pack" "$@"
|
||||
|
||||
##############
|
||||
# ctags #
|
||||
##############
|
||||
tags: kernel/*/*.c kernel/*.c userspace/**/*.c modules/*.c linker/*.c
|
||||
@${BEG} "ctag" "Generating CTags..."
|
||||
@-ctags -R --c++-kinds=+p --fields=+iaS --extra=+q kernel userspace modules util linker ${ERRORS}
|
||||
@${END} "ctag" "Generated CTags."
|
||||
|
||||
###############
|
||||
# clean #
|
||||
###############
|
||||
|
||||
clean-soft:
|
||||
@${BEGRM} "RM" "Cleaning kernel objects..."
|
||||
@-rm -f kernel/*.o
|
||||
@-rm -f kernel/*/*.o
|
||||
@-rm -f ${KERNEL_OBJS}
|
||||
@${ENDRM} "RM" "Cleaned kernel objects"
|
||||
|
||||
clean-user:
|
||||
@${BEGRM} "RM" "Cleaning userspace products..."
|
||||
@-rm -f ${USERSPACE}
|
||||
@${ENDRM} "RM" "Cleaned userspace products"
|
||||
|
||||
clean-mods:
|
||||
@${BEGRM} "RM" "Cleaning kernel modules..."
|
||||
@-rm -f hdd/mod/*
|
||||
@${ENDRM} "RM" "Cleaned kernel modules"
|
||||
|
||||
clean-core:
|
||||
@${BEGRM} "RM" "Cleaning final output..."
|
||||
@-rm -f toaruos-kernel
|
||||
@${ENDRM} "RM" "Cleaned final output"
|
||||
|
||||
clean-disk:
|
||||
@${BEGRM} "RM" "Deleting hard disk image..."
|
||||
@-rm -f toaruos-disk.img
|
||||
@${ENDRM} "RM" "Deleted hard disk image"
|
||||
|
||||
clean: clean-soft clean-core
|
||||
@${INFO} "--" "Finished soft cleaning"
|
||||
|
||||
clean-hard: clean clean-user clean-mods
|
||||
@${INFO} "--" "Finished hard cleaning"
|
||||
|
||||
|
||||
# vim:noexpandtab
|
||||
# vim:tabstop=4
|
||||
# vim:shiftwidth=4
|
||||
# Cairo: Compositor rendering backend
|
||||
ext-cairo: base/lib/libtoaru_ext_cairo_renderer.so
|
||||
|
168
README.md
168
README.md
@ -1,24 +1,166 @@
|
||||
# ToaruOS
|
||||
# ToaruOS-NIH
|
||||
|
||||
ToaruOS is a hobby x86 operating system, built mostly from scratch.
|
||||
![screenshot](https://i.imgur.com/DqXLxaT.png)
|
||||
|
||||
This project has been deprecated and development has moved to [ToaruOS-NIH](https://gitlab.com/toaruos/toaru-nih), with the goal of changing the "mostly" above to "completely".
|
||||
ToaruOS-NIH is a distribution of ToaruOS which contains no third-party components. Its bootloader, kernel, modules, C library, and userspace applications and libraries are all written by the ToaruOS development team and direct contributors.
|
||||
|
||||
## Differences between ToaruOS and ToaruOS-NIH
|
||||
This distribution aims to eventually replace the core of the mainline ToaruOS, with the various third-party components building against our own C library. This is a long-term project, and developing the C library to the point where it is useful for this purpose is not expected to be completed for quite some time.
|
||||
|
||||
This is the traditional - or "mainline" - distribution of ToaruOS. The kernel is mostly the same, though some features have been added in ToaruOS-NIH that have not been backported here. The bulk of the differences between ToaruOS "mainline" and ToaruOS-NIH are found in the userspace.
|
||||
## Features
|
||||
|
||||
Fundamentally, mainline ToaruOS is built using Newlib. The use of a third-party, relatively complete C standard library means that mainline ToaruOS is able to support a larger collection of third-party software. ToaruOS-NIH, on the other hand, has its own C standard library. While Python 3.6 has been ported to both distributions, ToaruOS-NIH core policy of not including third-party components means that applications written in Python are not part of the "core" experience. As such, several applications which were written in Python for mainline ToaruOS are in the process of being ported to C, allowing them to remain part of the core experience of the OS. This has the added benefit of making these applications much more performant than their Python counterparts.
|
||||
ToaruOS-NIH comes with a graphical desktop environment with a compositing window manager, a featureful terminal emulator, a shell, several command-line tools, a text editor (with syntax highlighting), a dynamic loader, and can host Python 3.6 (which is included in pre-built CD releases). The kernel and included drivers support ATA hard disks and CD drives, ext2 filesystems, ISO 9660 filesystems, PS/2 mice and keyboards, RS232 serial, Intel e1000, RTL8139, and AMD PCNet-series network chipsets, TCP/IPv4, several virtual graphical framebuffers (including Bochs/QEMU and VMware, and support for framebuffers initialized by EFI), advanced VM integration (including absolute pointing devices in VMware, QEMU, and VirtualBox, as well as automatic display resizing, "Seamless Desktop" and hardware cursors in VirtualBox specifically), an implementation of the `/proc` virtual filesystem, Unix-style pipes and TTYs, shared memory, in-memory read-write temporary filesystem, Intel AC'97 audio (with a mixer), and more.
|
||||
|
||||
The use of Newlib and allowance of third-party libraries in mainline ToaruOS also means that the core UI is built on top of libraries like Cairo, libpng, and freetype, which ToaruOS-NIH uses its own graphical libraries.
|
||||
## Pre-Built Images
|
||||
|
||||
## Phasing out mainline ToaruOS
|
||||
Releases are occasionally posted on [GitHub](https://github.com/klange/toaru-nih/releases), and nightlies are available [from toaruos.org](https://toaruos.org/nih.iso).
|
||||
|
||||
As ToaruOS-NIH reaches a state of feature completeness, and libraries which had previously been ported to mainline ToaruOS are also ported to ToaruOS-NIH's C library, the mainline distribution will be discontinued and ToaruOS-NIH will become the only distribution of ToaruOS.
|
||||
### Running ToaruOS-NIH
|
||||
|
||||
There are many obstacles to tackle on the way to making ToaruOS-NIH the core ToaruOS distribution:
|
||||
It is recommended that you run ToaruOS-NIH in an emulator - specifically Qemu or VirtualBox, though some testing has been done in VMware Workstation (reasonable, but missing driver support) and Bochs (not recommended).
|
||||
|
||||
- Implementing enough C standard library functionality to port key applications and libraries from the mainline distribution, such as GCC, Vim, libpng, freetype, and Cairo.
|
||||
- Implementing plugin architectures so that applications can use either native libraries or these third-party libraries for graphics, font rendering, and so on.
|
||||
- Development of a package manager using only in-house components, so that the third-party libraries and applications may be installed.
|
||||
#### QEMU
|
||||
|
||||
1GB of RAM and an Intel AC'97 sound chip are recommended:
|
||||
|
||||
```
|
||||
qemu-system-i386 -cdrom image.iso -serial mon:stdio -m 1G -soundhw ac97,pcspk -enable-kvm -rtc base=localtime
|
||||
```
|
||||
|
||||
You may also use OVMF with the appropriate QEMU system target. Our EFI loader supports both IA32 and X64 EFIs:
|
||||
|
||||
```
|
||||
qemu-system-x86_64 -cdrom image.iso -serial mon:stdio -m 1G -soundhw ac97,pcspk -enable-kvm -rtc base=localtime \
|
||||
-bios /usr/share/qemu/OVMF.fd
|
||||
```
|
||||
|
||||
```
|
||||
qemu-system-i386 -cdrom image.iso -serial mon:stdio -m 1G -soundhw ac97,pcspk -enable-kvm -rtc base=localtime \
|
||||
-bios /path/to/OVMFia32.fd
|
||||
```
|
||||
|
||||
#### VirtualBox
|
||||
|
||||
ToaruOS should function either as an "Other/Unknown" guest or an "Other/Uknown 64-bit" guest with EFI.
|
||||
|
||||
All network chipset options should work except for `virtio-net` (work on virtio drivers has not yet begun).
|
||||
|
||||
It is highly recommended, due to the existence of Guest Additions drivers, that you provide your VM with at least 32MB of video memory to support larger display resolutions - especially if you are using a 4K display.
|
||||
|
||||
Ensure that the audio controller is set to ICH AC97 and that audio output is enabled (as it is disabled by default in some versions of VirtualBox).
|
||||
|
||||
Keep the system chipset set to PIIX3 for best compatibility. 1GB of RAM is recommended.
|
||||
|
||||
#### VMWare
|
||||
|
||||
Support for VMWare is experimental.
|
||||
|
||||
As of writing, the following configuration has been tested as functioning:
|
||||
|
||||
- Create a virtual machine for a 64-bit guest. (ToaruOS-NIH is 32-bit, but this configuration selects some hardware defaults that are desirable)
|
||||
- Ensure the VM has 1GB of RAM.
|
||||
- It is recommended you remove the hard disk and the audio device.
|
||||
- For network settings, the NAT option is recommended.
|
||||
|
||||
#### Bochs
|
||||
|
||||
Using Bochs to run ToaruOS is not advised; however the following configuration options are recommended if you wish to try it:
|
||||
|
||||
- Attach the CD and set it as a boot device.
|
||||
- Ensure that the `pcivga` device is enabled or ToaruOS will not be able to find the video card through PCI.
|
||||
- Provide at least 512MB of RAM to the guest.
|
||||
- If available, enable the `e1000` network device using the `slirp` backend.
|
||||
- Clock settings of `sync=realtime, time0=local, rtc_sync=1` are recommended.
|
||||
|
||||
## Implementation Details
|
||||
|
||||
All source code for the entire operating system is included in this repository.
|
||||
|
||||
### Kernel
|
||||
|
||||
The NIH kernel is essentially the same as the mainline kernel, though the PCI vendor and device ID list has been replaced with our own slimmed down version. This was the only third-party element of the ToaruOS kernel. Additionally, the headers for the kernel have been relocated from their original directories to facilitate a cleaner build. The NIH kernel should be considered the latest version of the ToaruOS kernel.
|
||||
|
||||
### Bootloader
|
||||
|
||||
Mainline ToaruOS shipped with GRUB, which provided a multiboot-compatible ELF loader. To that end, our native bootloader also implements multiboot. However, as writing a feature-complete bootloader is not a goal of this project, the native bootloader is very limited, supporting only ATAPI CDs on systems with El Torito "no-emulation" support. It is not guaranteed to work on real hardware, but has been tested in QEMU, Bochs, VirtualBox, and VMware Player.
|
||||
|
||||
### Userspace
|
||||
|
||||
The userspace includes a work-in-progress C standard library, the ToaruOS native libraries, the compositor (using only in-house graphics routines), and various other first-party utilities and applications.
|
||||
|
||||
#### Notable Components
|
||||
|
||||
- **Yutani** (window compositor), [apps/compositor.c](apps/compositor.c), manages window buffers, layout, and input routing.
|
||||
- **Bim** (text editor), [apps/bim.c](apps/bim.c), is a vim-inspired editor with syntax highlighting.
|
||||
- **Terminal**, [apps/terminal.c](apps/terminal.c), xterm-esque terminal emulator with 256 and 24-bit color support.
|
||||
- **ld.so** (dynamic linker/loader), [linker/linker.c](linker/linker.c), loads dynamically-linked ELF binaries.
|
||||
- **Esh** (shell), [apps/sh.c](apps/sh.c), supports pipes, redirections, variables, and more.
|
||||
|
||||
## Building
|
||||
|
||||
First, ensure you have the necessary build tools, which are mostly the same as mainline ToaruOS: `yasm`, `xorriso`, `genext2fs` (with Debian patches), `python`, `mtools` (for building FAT EFI payloads) and `gnu-efi` to build the EFI bootloader (I'll explore implementing necessary headers and functionality myself in the future, but for now just pull in gnu-efi and make my life easier).
|
||||
|
||||
Run `make` and you will be prompted to build a toolchain. Reply `y` and allow the toolchain to build.
|
||||
|
||||
### Third-Party Ports
|
||||
|
||||
#### Python
|
||||
|
||||
There are instructions on building Python 3.6 available from [the gitlab wiki](https://gitlab.com/toaruos/toaru-nih/wikis/Installing-Python).
|
||||
|
||||
#### Freetype
|
||||
|
||||
Currently only the Terminal supports using Freetype as a text rendering backend, but this will be expanded in the future.
|
||||
|
||||
Freetype should mostly build as-is, though libtool needs to be taught how to build a shared object for ToaruOS called `libfreetype.so` - this is left as an exercise for the reader until I've had time to formalize the process.
|
||||
|
||||
Once freetype is built and installed to `base/usr`, `make ext-freetype` will build the extension library. Place the required fonts, which you can get from maineline ToaruOS, in `base/usr/share/fonts`.
|
||||
|
||||
With fonts available, the build scripts will build larger ramdisks to accomodate the additional files. The font server will automatically run on startup if a GUI boot target is selected, and the Terminal will automatically use the Freetype backend if it loads.
|
||||
|
||||
#### Cairo / Pixman
|
||||
|
||||
The compositor can use Cairo for rendering, which improves performance over the naïve in-house SSE-accelerated blitter.
|
||||
|
||||
## Backwards Compatibility Notes
|
||||
|
||||
No ABI or API compatibility is guaranteed through the development of ToaruOS-NIH. Until a larger corpus of third-party software is ported to our new C library, APIs may change to improve or simplify library use, or to fix bugs. Even kernel ABI compatibility is not guaranteed as system calls are improved or made more compliant with expectations of POSIX or the C standard.
|
||||
|
||||
## Rationale
|
||||
|
||||
ToaruOS's kernel is entirely in-house. Its userspace, however, is built on several third-party libraries and tools, such as the Newlib C library, Freetype, Cairo, libpng, and most notably Python. While the decision to build ToaruOS on these technologies is not at all considered a mistake, the possibility remains to build a userspace entirely from scratch.
|
||||
|
||||
## Goals
|
||||
|
||||
Many of our initial goals have been met, including sufficient C library support to port Python 3.6.
|
||||
|
||||
Our current unmet goals include:
|
||||
|
||||
- Enough C library support to port binutils/gcc (needs enough C to get libstdc++ working)
|
||||
- Plugin systems for the compositor and general graphics APIs to support third-party libraries in the future (including support for Cairo as a backend for the compositor, PNG support in the graphics sprite API, Truetype rendering support through FreeType in the text rendering engine).
|
||||
- Porting the complete native desktop experience from ToaruOS mainline (which mostly means porting Python prototype applications and libraries to C).
|
||||
|
||||
## Project Layout
|
||||
|
||||
- **apps** - Userspace applications, all first-party.
|
||||
- **base** - Ramdisk root filesystem staging directory. Includes C headers in `base/usr/include`, as well as graphical resources for the compositor and window decorator.
|
||||
- **boot** - Bootloader, including BIOS and EFI IA32 and X64 support.
|
||||
- **cdrom** - Staging area for ISO9660 CD image, containing mostly blank shadow files for the FAT image.
|
||||
- **ext** - Optional runtime-loaded bindings for third-party libraries.
|
||||
- **fatbase** - Staging area for FAT image used by EFI.
|
||||
- **kernel** - The ToaruOS kernel.
|
||||
- **lib** - Userspace libraries.
|
||||
- **libc** - C standard library implementation.
|
||||
- **linker** - Userspace dynamic linker/loader, implements shared library support.
|
||||
- **modules** - Kernel modules/drivers.
|
||||
- **util** - Utility scripts, staging directory for the toolchain (binutils/gcc).
|
||||
- **.make** - Generated Makefiles.
|
||||
|
||||
## Mirrors
|
||||
|
||||
ToaruOS-NIH is regularly mirrored to multiple Git hosting sites. The recommended source is [Gitlab](https://gitlab.com/toaruos/toaru-nih).
|
||||
|
||||
- Gitlab: [toaruos/toaru-nih](https://gitlab.com/toaruos/toaru-nih)
|
||||
- GitHub: [klange/toaru-nih](https://github.com/klange/toaru-nih)
|
||||
- Bitbucket: [klange/toaru-nih](https://bitbucket.org/klange/toaru-nih)
|
||||
- ToaruOS.org: [klange/toaru-nih](https://git.toaruos.org/klange/toaru-nih)
|
||||
|
||||
|
@ -1,65 +0,0 @@
|
||||
![](https://i.imgur.com/QGVoRJD.png)
|
||||
![](https://i.imgur.com/MlAxGpj.png)
|
||||
![](https://i.imgur.com/OpMGfHP.png)
|
||||
|
||||
# ToaruOS (とあるOS) #
|
||||
|
||||
とあるOS (ToaruOS) is a hobby operating system built mostly from scratch, including both a kernel and userspace.
|
||||
|
||||
This repository contains the kernel, modules, and core userspace applications and libraries. Some third-party libraries and utilities are required to build a working system.
|
||||
|
||||
## Build Instructions ##
|
||||
|
||||
If you just want to build the kernel and userspace and get a working CD image, you can use Docker:
|
||||
|
||||
docker pull toaruos/build-tools:test
|
||||
docker run -v `pwd`:/opt/tree -w /opt/tree -t toaruos/build-tools:test util/build-travis.sh
|
||||
|
||||
To build a full toolchain locally, set up [a supported environment](https://github.com/klange/toaruos/wiki/Testing-and-Building#requirements) and run:
|
||||
|
||||
make toolchain
|
||||
|
||||
You may be prompted to enter your password for `sudo` to install required packages. The toolchain build scripts will then build several dependencies for building ToaruOS such as a GCC cross compiler and a few libraries used by the userspace. This may take around thirty minutes to an hour to complete, depending on your hardware. Once it is done, verify there were no errors and then follow the instructions provided to continue with the build.
|
||||
|
||||
If you experience issues, please join our [IRC channel](#irc) for help.
|
||||
|
||||
## History ##
|
||||
|
||||
ToaruOS started as a side project at the University of Illinois at Urbana-Champaign. For several months in late 2011 and early 2012, the University's [SIGOps](http://www.acm.uiuc.edu/sigops/) chapter managed development efforts focused on building the original compositing GUI. Since then, the project has mostly been a one-man effort with a handful of third party contributions.
|
||||
|
||||
## Kernel ##
|
||||
|
||||
The Toaru kernel provides a basic Unix-like environment. The kernel uses a hybrid modular architecture, with loadable modules providing most device driver support. The core kernel includes support for Unix pipes and TTYs, a virtual file system, multitasking, ELF binary support, and various core platform features on x86 systems.
|
||||
|
||||
Modules provide support for disk drives, ext2 filesystems, serial, keyboards and mice, a `/proc` filesystem similar to the one found in Linux, as well as an expanding collection of other device drivers.
|
||||
|
||||
## Userspace ##
|
||||
|
||||
ToaruOS's userspace is focused on a rich graphical environment, backed by an in-house compositing window manager. ToaruOS's terminal emulator supports xterm-compatible 256-color modes, as well as Konsole 24-bit color modes and anti-aliased text with basic Unicode support. Program binaries are dynamically linked. Several graphical demos are provided, alongside a number of command-line applications. A port of SDL targetting the native graphical environment is also available.
|
||||
|
||||
### Third-Party Software ###
|
||||
|
||||
The userspace depends on a number of third-party libraries which are outside of the development scope of the project. Additionally, several third-party applications and libraries have been integrated into ToaruOS's core userspace, or otherwise ported to ToaruOS.
|
||||
|
||||
License for the included third-party tools and libraries can be found [here](hdd/usr/share/help/licenses).
|
||||
|
||||
## Community ##
|
||||
|
||||
### Git ###
|
||||
|
||||
ToaruOS is hosted across multiple social git hosting sites:
|
||||
|
||||
- [Gitlab](https://gitlab.com/toaruos/toaruos)
|
||||
- [Github](https://github.com/klange/toaruos)
|
||||
- [Bitbucket](https://bitbucket.org/klange/toaruos)
|
||||
- [git.toaruos.org](https://git.toaruos.org/klange/toaruos)
|
||||
|
||||
### Wiki ###
|
||||
|
||||
For additional screenshots, see [Screenshots](https://github.com/klange/toaruos/wiki/Screenshots).
|
||||
|
||||
For instructions on building, see [Testing and Building](https://github.com/klange/toaruos/wiki/Testing-and-Building).
|
||||
|
||||
### IRC ###
|
||||
|
||||
For help building the kernel and userspace, join us in `#toaruos` on Freenode (`irc.freenode.net`).
|
223
apps/about.c
Normal file
223
apps/about.c
Normal file
@ -0,0 +1,223 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* about - Show an "About <Application>" dialog.
|
||||
*
|
||||
* By default, shows "About ToaruOS", suitable for use as an application
|
||||
* menu entry. Optionally, takes arguments specifying another application
|
||||
* to describe, suitable for the "Help > About" menu bar entry.
|
||||
*/
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/decorations.h>
|
||||
#include <toaru/sdf.h>
|
||||
#include <toaru/menu.h>
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * window = NULL;
|
||||
static gfx_context_t * ctx = NULL;
|
||||
static sprite_t logo;
|
||||
|
||||
static int32_t width = 350;
|
||||
static int32_t height = 250;
|
||||
static char * version_str;
|
||||
|
||||
static char * icon_path;
|
||||
static char * title_str;
|
||||
static char * version_str;
|
||||
static char * copyright_str[20] = {NULL};
|
||||
|
||||
static int center_x(int x) {
|
||||
return (width - x) / 2;
|
||||
}
|
||||
|
||||
static void draw_string(int y, const char * string, int font, uint32_t color) {
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(window, &bounds);
|
||||
|
||||
draw_sdf_string(ctx, bounds.left_width + center_x(draw_sdf_string_width(string, 16, font)), bounds.top_height + 10 + logo.height + 10 + y, string, 16, color, font);
|
||||
}
|
||||
|
||||
static void redraw(void) {
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(window, &bounds);
|
||||
|
||||
draw_fill(ctx, rgb(204,204,204));
|
||||
draw_sprite(ctx, &logo, bounds.left_width + center_x(logo.width), bounds.top_height + 10);
|
||||
|
||||
draw_string(0, version_str, SDF_FONT_BOLD, rgb(0,0,0));
|
||||
|
||||
int offset = 20;
|
||||
|
||||
for (char ** copy_str = copyright_str; *copy_str; ++copy_str) {
|
||||
if (**copy_str == '-') {
|
||||
offset += 10;
|
||||
} else if (**copy_str == '%') {
|
||||
draw_string(offset, *copy_str+1, SDF_FONT_THIN, rgb(0,0,255));
|
||||
offset += 20;
|
||||
} else {
|
||||
draw_string(offset, *copy_str, SDF_FONT_THIN, rgb(0,0,0));
|
||||
offset += 20;
|
||||
}
|
||||
}
|
||||
|
||||
window->decorator_flags |= DECOR_FLAG_NO_MAXIMIZE;
|
||||
render_decorations(window, ctx, title_str);
|
||||
|
||||
flip(ctx);
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
|
||||
static void init_default(void) {
|
||||
title_str = "About ToaruOS-NIH";
|
||||
icon_path = "/usr/share/logo_login.bmp";
|
||||
|
||||
{
|
||||
version_str = malloc(100);
|
||||
struct utsname u;
|
||||
uname(&u);
|
||||
char * tmp = strstr(u.release, "-");
|
||||
if (tmp) {
|
||||
*tmp = '\0';
|
||||
}
|
||||
sprintf(version_str, "ToaruOS-NIH %s", u.release);
|
||||
}
|
||||
|
||||
copyright_str[0] = "(C) 2011-2018 K. Lange, et al.";
|
||||
copyright_str[1] = "-";
|
||||
copyright_str[2] = "ToaruOS is free software released under the";
|
||||
copyright_str[3] = "NCSA/University of Illinois license.";
|
||||
copyright_str[4] = "-";
|
||||
copyright_str[5] = "%https://toaruos.org";
|
||||
copyright_str[6] = "%https://gitlab.com/toaruos";
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int req_center_x, req_center_y;
|
||||
yctx = yutani_init();
|
||||
if (!yctx) {
|
||||
fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_decorations();
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(NULL, &bounds);
|
||||
|
||||
window = yutani_window_create(yctx, width + bounds.width, height + bounds.height);
|
||||
req_center_x = yctx->display_width / 2;
|
||||
req_center_y = yctx->display_height / 2;
|
||||
|
||||
if (argc < 2) {
|
||||
init_default();
|
||||
} else if (argc < 5) {
|
||||
fprintf(stderr, "Invalid arguments.\n");
|
||||
return 1;
|
||||
} else {
|
||||
title_str = argv[1];
|
||||
icon_path = argv[2];
|
||||
version_str = argv[3];
|
||||
|
||||
int i = 0;
|
||||
char * me = argv[4], * end;
|
||||
do {
|
||||
copyright_str[i] = me;
|
||||
i++;
|
||||
end = strchr(me,'\n');
|
||||
if (end) {
|
||||
*end = '\0';
|
||||
me = end+1;
|
||||
}
|
||||
} while (end);
|
||||
|
||||
if (argc > 6) {
|
||||
req_center_x = atoi(argv[5]);
|
||||
req_center_y = atoi(argv[6]);
|
||||
}
|
||||
}
|
||||
|
||||
yutani_window_move(yctx, window, req_center_x - window->width / 2, req_center_y - window->height / 2);
|
||||
|
||||
yutani_window_advertise_icon(yctx, window, title_str, "star");
|
||||
|
||||
ctx = init_graphics_yutani_double_buffer(window);
|
||||
load_sprite(&logo, icon_path);
|
||||
logo.alpha = ALPHA_EMBEDDED;
|
||||
|
||||
redraw();
|
||||
|
||||
int playing = 1;
|
||||
while (playing) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
while (m) {
|
||||
if (menu_process_event(yctx, m)) {
|
||||
redraw();
|
||||
}
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
playing = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win) {
|
||||
win->focused = wf->focused;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
resize_finish(wr->width, wr->height);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
int result = decor_handle_event(yctx, m);
|
||||
switch (result) {
|
||||
case DECOR_CLOSE:
|
||||
playing = 0;
|
||||
break;
|
||||
case DECOR_RIGHT:
|
||||
/* right click in decoration, show appropriate menu */
|
||||
decor_show_default_menu(window, window->x + me->new_x, window->y + me->new_y);
|
||||
break;
|
||||
default:
|
||||
/* Other actions */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_CLOSE:
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
playing = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
}
|
||||
|
||||
yutani_close(yctx, window);
|
||||
|
||||
return 0;
|
||||
}
|
173
apps/background.c
Normal file
173
apps/background.c
Normal file
@ -0,0 +1,173 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* background - Draw a desktop wallpaper.
|
||||
*
|
||||
* TODO: This is a very minimal wallpaper renderer.
|
||||
* ToaruOS-mainline, before it went all Python,
|
||||
* included a more complete wallpaper application,
|
||||
* which supported icons and config files.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/fswait.h>
|
||||
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/menu.h>
|
||||
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * wallpaper_window;
|
||||
static gfx_context_t * wallpaper_ctx;
|
||||
static sprite_t * wallpaper;
|
||||
static struct MenuList * _rc_menu = NULL;
|
||||
|
||||
static void draw_background(int width, int height) {
|
||||
|
||||
float x = (float)wallpaper_window->width / (float)wallpaper->width;
|
||||
float y = (float)wallpaper_window->height / (float)wallpaper->height;
|
||||
|
||||
int nh = (int)(x * (float)wallpaper->height);
|
||||
int nw = (int)(y * (float)wallpaper->width);
|
||||
|
||||
if (nw == wallpaper->width && nh == wallpaper->height) {
|
||||
// special case
|
||||
draw_sprite(wallpaper_ctx, wallpaper, 0, 0);
|
||||
} else if (nw >= width) {
|
||||
draw_sprite_scaled(wallpaper_ctx, wallpaper, ((int)wallpaper_window->width - nw) / 2, 0, nw+2, wallpaper_window->height);
|
||||
} else {
|
||||
draw_sprite_scaled(wallpaper_ctx, wallpaper, 0, ((int)wallpaper_window->height - nh) / 2, wallpaper_window->width+2, nh);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_right_click_menu(int x, int y) {
|
||||
if (_rc_menu->window) return; /* Already shown */
|
||||
|
||||
menu_show(_rc_menu, yctx);
|
||||
if (x + _rc_menu->window->width > yctx->display_width) {
|
||||
yutani_window_move(yctx, _rc_menu->window, x - _rc_menu->window->width, y);
|
||||
} else {
|
||||
yutani_window_move(yctx, _rc_menu->window, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void resize_finish_wallpaper(int width, int height) {
|
||||
yutani_window_resize_accept(yctx, wallpaper_window, width, height);
|
||||
reinit_graphics_yutani(wallpaper_ctx, wallpaper_window);
|
||||
draw_background(width, height);
|
||||
yutani_window_resize_done(yctx, wallpaper_window);
|
||||
yutani_flip(yctx, wallpaper_window);
|
||||
}
|
||||
|
||||
static void launch_application(char * app) {
|
||||
if (!fork()) {
|
||||
printf("Starting %s\n", app);
|
||||
char * args[] = {"/bin/sh", "-c", app, NULL};
|
||||
execvp(args[0], args);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void launch_application_menu(struct MenuEntry * self) {
|
||||
struct MenuEntry_Normal * _self = (void *)self;
|
||||
launch_application((char *)_self->action);
|
||||
}
|
||||
|
||||
static void check_click(struct yutani_msg_window_mouse_event * evt) {
|
||||
if (evt->wid == wallpaper_window->wid) {
|
||||
if (evt->buttons & YUTANI_MOUSE_BUTTON_RIGHT) {
|
||||
show_right_click_menu(evt->new_x, evt->new_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sig_usr2(int sig) {
|
||||
yutani_set_stack(yctx, wallpaper_window, YUTANI_ZORDER_BOTTOM);
|
||||
yutani_flip(yctx, wallpaper_window);
|
||||
}
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
|
||||
if (argc < 2 || strcmp(argv[1],"--really")) {
|
||||
fprintf(stderr,
|
||||
"%s: Desktop environment wallpaper\n"
|
||||
"\n"
|
||||
" Renders the desktop wallpaper. You probably don't want\n"
|
||||
" to be running this directly - it is started by the\n"
|
||||
" session manager along with the panel.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
signal(SIGUSR2, sig_usr2);
|
||||
|
||||
wallpaper = malloc(sizeof(sprite_t));
|
||||
load_sprite(wallpaper, "/usr/share/wallpaper.bmp");
|
||||
wallpaper->alpha = 0;
|
||||
|
||||
yctx = yutani_init();
|
||||
if (!yctx) {
|
||||
fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
_rc_menu = menu_create();
|
||||
menu_insert(_rc_menu, menu_create_normal("utilities-terminal", "terminal", "Open Terminal", launch_application_menu));
|
||||
|
||||
/* wallpaper */
|
||||
wallpaper_window = yutani_window_create(yctx, yctx->display_width, yctx->display_height);
|
||||
yutani_window_move(yctx, wallpaper_window, 0, 0);
|
||||
yutani_set_stack(yctx, wallpaper_window, YUTANI_ZORDER_BOTTOM);
|
||||
|
||||
wallpaper_ctx = init_graphics_yutani(wallpaper_window);
|
||||
draw_background(yctx->display_width, yctx->display_height);
|
||||
yutani_flip(yctx, wallpaper_window);
|
||||
|
||||
int should_exit = 0;
|
||||
|
||||
while (!should_exit) {
|
||||
int fds[1] = {fileno(yctx->sock)};
|
||||
int index = fswait2(1,fds,200);
|
||||
if (index == 0) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
while (m) {
|
||||
menu_process_event(yctx, m);
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_WELCOME:
|
||||
yutani_window_resize_offer(yctx, wallpaper_window, yctx->display_width, yctx->display_height);
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
if (wr->wid == wallpaper_window->wid) {
|
||||
resize_finish_wallpaper(wr->width, wr->height);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
check_click((struct yutani_msg_window_mouse_event *)m->data);
|
||||
break;
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
should_exit = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
} else {
|
||||
/* Perform timer events here. Animations? */
|
||||
waitpid(-1, NULL, WNOHANG);
|
||||
}
|
||||
}
|
||||
|
||||
yutani_close(yctx, wallpaper_window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014 Kevin Lange
|
||||
* Copyright (C) 2014 K. Lange
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
5999
apps/bim.c
Normal file
5999
apps/bim.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,17 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2016 Kevin Lange
|
||||
* Copyright (C) 2016-2018 K. Lange
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "lib/graphics.h"
|
||||
#include "gui/terminal/lib/termemu.h"
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/termemu.h>
|
||||
|
||||
void get_cell_sizes(int * w, int * h) {
|
||||
struct winsize wsz;
|
||||
@ -45,6 +46,7 @@ int usage(char * argv[]) {
|
||||
"\n"
|
||||
" -n \033[3mdon't print a new line after image\033[0m\n"
|
||||
" -s \033[3mscale to cell height (up or down)\033[0m\n"
|
||||
" -w \033[3mscale to terminal width (up or down)\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
return 1;
|
||||
@ -59,14 +61,18 @@ int main (int argc, char * argv[]) {
|
||||
int opt;
|
||||
int no_newline = 0;
|
||||
int scale_to_cell_height = 0;
|
||||
int scale_to_term_width = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "?ns")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "?nsw")) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
return usage(argv);
|
||||
case 'n':
|
||||
no_newline = 1;
|
||||
break;
|
||||
case 'w':
|
||||
scale_to_term_width = 1;
|
||||
break;
|
||||
case 's':
|
||||
scale_to_cell_height = 1;
|
||||
break;
|
||||
@ -84,11 +90,8 @@ int main (int argc, char * argv[]) {
|
||||
|
||||
while (optind < argc) {
|
||||
sprite_t * image = calloc(sizeof(sprite_t),1);
|
||||
if (load_sprite_png(image, argv[optind])) {
|
||||
free(image);
|
||||
optind++;
|
||||
continue;
|
||||
}
|
||||
load_sprite(image, argv[optind]);
|
||||
image->alpha = ALPHA_EMBEDDED;
|
||||
|
||||
sprite_t * source = image;
|
||||
|
||||
@ -101,6 +104,17 @@ int main (int argc, char * argv[]) {
|
||||
sprite_free(image);
|
||||
}
|
||||
|
||||
if (scale_to_term_width) {
|
||||
struct winsize w;
|
||||
ioctl(0, TIOCGWINSZ, &w);
|
||||
int new_height = (w.ws_xpixel * image->height) / image->width;
|
||||
source = create_sprite(w.ws_xpixel, new_height, 1);
|
||||
gfx_context_t * g = init_graphics_sprite(source);
|
||||
draw_fill(g, 0x00000000);
|
||||
draw_sprite_scaled(g, image, 0, 0, w.ws_xpixel, new_height);
|
||||
sprite_free(image);
|
||||
}
|
||||
|
||||
int width_in_cells = source->width / w;
|
||||
if (source->width % w) width_in_cells++;
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
* cat
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* cat - Concatenate files
|
||||
*
|
||||
* Concatenates files together to standard output.
|
||||
* In a supporting terminal, you can then pipe
|
||||
@ -14,6 +14,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define CHUNK_SIZE 4096
|
||||
|
||||
@ -35,8 +37,8 @@ int main(int argc, char ** argv) {
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
int fd = open(argv[i], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "%s: %s: no such file or directory\n", argv[0], argv[i]);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
@ -59,8 +61,3 @@ int main(int argc, char ** argv) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vim:tabstop=4
|
||||
* vim:noexpandtab
|
||||
* vim:shiftwidth=4
|
||||
*/
|
135
apps/chmod.c
Normal file
135
apps/chmod.c
Normal file
@ -0,0 +1,135 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* chmod - change file permissions
|
||||
*
|
||||
* Note: This implementation is likely non-compliant, though it does
|
||||
* attempt to look similar to the standard POSIX syntax,
|
||||
* supporting both octal mode setings and +/-rwx flavors.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
enum mode_set {
|
||||
MODE_SET,
|
||||
MODE_ADD,
|
||||
MODE_REMOVE,
|
||||
};
|
||||
|
||||
static int calc(int mode, int users) {
|
||||
int out = 0;
|
||||
if (users & 1) {
|
||||
out |= (mode << 6);
|
||||
}
|
||||
if (users & 2) {
|
||||
out |= (mode << 3);
|
||||
}
|
||||
if (users & 4) {
|
||||
out |= (mode << 0);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: %s OCTAL-MODE FILE...\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse mode */
|
||||
int mode = 0;
|
||||
enum mode_set mode_set = MODE_SET;
|
||||
char * c = argv[1];
|
||||
int user_modes = 0;
|
||||
int all_users = 7;
|
||||
|
||||
while (*c) {
|
||||
switch (*c) {
|
||||
case '0':
|
||||
c++; /* 0 */
|
||||
while (*c >= '0' || *c <= '7') {
|
||||
mode *= 8;
|
||||
mode += (*c - '0');
|
||||
c++;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
all_users = 0;
|
||||
user_modes |= 1;
|
||||
c++;
|
||||
break;
|
||||
case 'g':
|
||||
all_users = 0;
|
||||
user_modes |= 2;
|
||||
c++;
|
||||
break;
|
||||
case 'o':
|
||||
all_users = 0;
|
||||
user_modes |= 4;
|
||||
c++;
|
||||
break;
|
||||
case 'a':
|
||||
all_users = 7;
|
||||
user_modes = 7;
|
||||
c++;
|
||||
break;
|
||||
case '-':
|
||||
mode_set = MODE_REMOVE;
|
||||
c++;
|
||||
break;
|
||||
case '+':
|
||||
mode_set = MODE_ADD;
|
||||
c++;
|
||||
break;
|
||||
case '=':
|
||||
mode_set = MODE_SET;
|
||||
c++;
|
||||
break;
|
||||
case 'r':
|
||||
mode |= calc(S_IROTH, user_modes | all_users);
|
||||
c++;
|
||||
break;
|
||||
case 'w':
|
||||
mode |= calc(S_IWOTH, user_modes | all_users);
|
||||
c++;
|
||||
break;
|
||||
case 'x':
|
||||
mode |= calc(S_IXOTH, user_modes | all_users);
|
||||
c++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int i = 2;
|
||||
while (i < argc) {
|
||||
int actual_mode = 0;
|
||||
struct stat _stat;
|
||||
if (stat(argv[i], &_stat) < 0) {
|
||||
fprintf(stderr, "%s: %s: error with stat\n", argv[0], argv[i]);
|
||||
}
|
||||
|
||||
switch (mode_set) {
|
||||
case MODE_SET:
|
||||
actual_mode = mode;
|
||||
break;
|
||||
case MODE_ADD:
|
||||
actual_mode = _stat.st_mode | mode;
|
||||
break;
|
||||
case MODE_REMOVE:
|
||||
actual_mode = _stat.st_mode &= ~(mode);
|
||||
break;
|
||||
}
|
||||
|
||||
if (chmod(argv[i], actual_mode) < 0) {
|
||||
fprintf(stderr, "%s: %s: error with chmod\n", argv[0], argv[i]);
|
||||
return 1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
19
apps/clear.c
Normal file
19
apps/clear.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013 K. Lange
|
||||
*
|
||||
* clear - Clear the terminal
|
||||
*
|
||||
* Sends an escape code to clear the screen. Ideally, this should
|
||||
* come from a database of terminal escape codes (eg. terminfo),
|
||||
* but we don't have one of those yet, so just send a code that
|
||||
* makes sense for a lot of terminals.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
printf("\033[H\033[2J");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,21 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013 Kevin Lange
|
||||
* Copyright (C) 2013 K. Lange
|
||||
* Copyright (C) 2013 Tyler Bindon
|
||||
*/
|
||||
/*
|
||||
* cp
|
||||
*
|
||||
* cp - Copy files
|
||||
*
|
||||
* This is an incomplete implementation of `cp`. A more complete
|
||||
* version of recursive directory copying can be found in the
|
||||
* `migrate` sources, and should probably be imported here.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define CHUNK_SIZE 4096
|
||||
|
||||
@ -23,11 +29,14 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
fd = fopen(argv[1], "r");
|
||||
if (!fd) {
|
||||
fprintf(stderr, "%s: %s: no such file or directory\n", argv[0], argv[1]);
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct stat statbuf;
|
||||
stat(argv[1], &statbuf);
|
||||
int initial_mode = statbuf.st_mode;
|
||||
|
||||
stat(argv[2], &statbuf);
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
char *filename = strrchr(argv[1], '/');
|
||||
@ -44,6 +53,11 @@ int main(int argc, char ** argv) {
|
||||
fout = fopen( argv[2], "w" );
|
||||
}
|
||||
|
||||
if (!fout) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t length;
|
||||
|
||||
fseek(fd, 0, SEEK_END);
|
||||
@ -64,11 +78,10 @@ int main(int argc, char ** argv) {
|
||||
fclose(fd);
|
||||
fclose(fout);
|
||||
|
||||
if (chmod(argv[2], initial_mode) < 0) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[2], strerror(errno));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vim:tabstop=4
|
||||
* vim:noexpandtab
|
||||
* vim:shiftwidth=4
|
||||
*/
|
19
apps/cursor-off.c
Normal file
19
apps/cursor-off.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2016-2018 K. Lange
|
||||
*
|
||||
* cursor-off - Disables the VGA text mode cursor.
|
||||
*
|
||||
* This is an old tool that calls a special system call
|
||||
* to change the VGA text-mode cursor position. The VGA
|
||||
* terminal renders its own cursor in software, so we
|
||||
* try to move the hardware cursor off screen so it doesn't
|
||||
* interfere with the rest of the terminal and look weird.
|
||||
*/
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int x[] = {0xFF,0xFF};
|
||||
return syscall_system_function(13, (char **)x);
|
||||
}
|
59
apps/date.c
Normal file
59
apps/date.c
Normal file
@ -0,0 +1,59 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* date - Print the current date and time.
|
||||
*
|
||||
* TODO: The traditional POSIX version of this tool is supposed
|
||||
* to accept a format *and* allow you to set the time.
|
||||
* We currently lack system calls for setting the time,
|
||||
* but when we add those this should probably be updated.
|
||||
*
|
||||
* At the very least, improving this to print the "correct"
|
||||
* default format would be good.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static void show_usage(int argc, char * argv[]) {
|
||||
printf(
|
||||
"%s - print the time and day\n"
|
||||
"\n"
|
||||
"usage: %s [-?] +FORMAT\n"
|
||||
"\n"
|
||||
" Note: This implementation is not currently capable of\n"
|
||||
" setting the system time.\n"
|
||||
"\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0], argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
char * format = "%a %b %d %T %Y";
|
||||
struct tm * timeinfo;
|
||||
struct timeval now;
|
||||
char buf[BUFSIZ] = {0};
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc,argv,"?")) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
show_usage(argc,argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc && *argv[optind] == '+') {
|
||||
format = &argv[optind][1];
|
||||
}
|
||||
|
||||
gettimeofday(&now, NULL); //time(NULL);
|
||||
timeinfo = localtime((time_t *)&now.tv_sec);
|
||||
|
||||
strftime(buf,BUFSIZ,format,timeinfo);
|
||||
puts(buf);
|
||||
return 0;
|
||||
}
|
134
apps/drawlines.c
Normal file
134
apps/drawlines.c
Normal file
@ -0,0 +1,134 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* drawlines - Draw random lines into a GUI window
|
||||
*
|
||||
* The original compositor demo application, this dates all the
|
||||
* way back to the original pre-Yutani compositor. Opens a very
|
||||
* basic window (no decorations) and randomly fills it with
|
||||
* colorful lines in a separate thread from the listener.
|
||||
*
|
||||
* There's no good reason for this to use threads - it should use
|
||||
* `fswait2` to apply timeouts - but it demonstrates threading
|
||||
* so we'll leave it that way for now.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
|
||||
static int left, top, width, height;
|
||||
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * wina;
|
||||
static gfx_context_t * ctx;
|
||||
static int should_exit = 0;
|
||||
static int thick = 0;
|
||||
|
||||
void * draw_thread(void * garbage) {
|
||||
(void)garbage;
|
||||
while (!should_exit) {
|
||||
if (thick) {
|
||||
draw_line_aa(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255), (float)thick);
|
||||
} else {
|
||||
draw_line(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255));
|
||||
}
|
||||
yutani_flip(yctx, wina);
|
||||
usleep(16666);
|
||||
}
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void show_usage(char * argv[]) {
|
||||
printf(
|
||||
"drawlines - graphical demo, draws lines randomly\n"
|
||||
"\n"
|
||||
"usage: %s [-t thickness]\n"
|
||||
"\n"
|
||||
" -t \033[3mdraw with anti-aliasing and the specified thickness\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
left = 100;
|
||||
top = 100;
|
||||
width = 500;
|
||||
height = 500;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "t:?")) != -1) {
|
||||
switch (c) {
|
||||
case 't':
|
||||
thick = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
show_usage(argv);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
yctx = yutani_init();
|
||||
if (!yctx) {
|
||||
fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
wina = yutani_window_create(yctx, width, height);
|
||||
yutani_window_move(yctx, wina, left, top);
|
||||
yutani_window_advertise_icon(yctx, wina, "drawlines", "drawlines");
|
||||
|
||||
ctx = init_graphics_yutani(wina);
|
||||
draw_fill(ctx, rgb(0,0,0));
|
||||
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, NULL, draw_thread, NULL);
|
||||
|
||||
while (!should_exit) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
if (m) {
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
should_exit = 1;
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) {
|
||||
yutani_window_drag_start(yctx, wina);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_CLOSE:
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
should_exit = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(m);
|
||||
}
|
||||
|
||||
yutani_close(yctx, wina);
|
||||
|
||||
return 0;
|
||||
}
|
124
apps/echo.c
Normal file
124
apps/echo.c
Normal file
@ -0,0 +1,124 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* echo - Print arguments to stdout.
|
||||
*
|
||||
* Prints arguments to stdout, possibly interpreting escape
|
||||
* sequences in the arguments.
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void show_usage(char * argv[]) {
|
||||
printf(
|
||||
"echo - print arguments\n"
|
||||
"\n"
|
||||
"usage: %s [-ne] ARG...\n"
|
||||
"\n"
|
||||
" -n \033[3mdo not output a new line at the end\033[0m\n"
|
||||
" -e \033[3mprocess escape sequences\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int use_newline = 1;
|
||||
int process_escapes = 0;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "enh?")) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
case 'h':
|
||||
show_usage(argv);
|
||||
return 1;
|
||||
case 'n':
|
||||
use_newline = 0;
|
||||
break;
|
||||
case 'e':
|
||||
process_escapes = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = optind; i < argc; ++i) {
|
||||
if (process_escapes) {
|
||||
char * c = argv[i];
|
||||
while (*c) {
|
||||
if (*c == '\\') {
|
||||
c++;
|
||||
switch (*c) {
|
||||
case '\\':
|
||||
putchar('\\');
|
||||
break;
|
||||
case 'a':
|
||||
putchar('\a');
|
||||
break;
|
||||
case 'b':
|
||||
putchar('\b');
|
||||
break;
|
||||
case 'c':
|
||||
return 0;
|
||||
case 'e':
|
||||
putchar('\033');
|
||||
break;
|
||||
case 'f':
|
||||
putchar('\f');
|
||||
break;
|
||||
case 'n':
|
||||
putchar('\n');
|
||||
break;
|
||||
case 't':
|
||||
putchar('\t');
|
||||
break;
|
||||
case 'v':
|
||||
putchar('\v');
|
||||
break;
|
||||
case '0':
|
||||
{
|
||||
int i = 0;
|
||||
if (!isdigit(*(c+1)) || *(c+1) > '7') {
|
||||
break;
|
||||
}
|
||||
c++;
|
||||
i = *c - '0';
|
||||
if (isdigit(*(c+1)) && *(c+1) <= '7') {
|
||||
c++;
|
||||
i = (i << 3) | (*c - '0');
|
||||
if (isdigit(*(c+1)) && *(c+1) <= '7') {
|
||||
c++;
|
||||
i = (i << 3) | (*c - '0');
|
||||
}
|
||||
}
|
||||
putchar(i);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
putchar('\\');
|
||||
putchar(*c);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
putchar(*c);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
} else {
|
||||
printf("%s",argv[i]);
|
||||
}
|
||||
if (i != argc - 1) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
if (use_newline) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
49
apps/env.c
Normal file
49
apps/env.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* env - Print or set environment
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern int _environ_size;
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int start = 1;
|
||||
|
||||
if (start < argc && !strcmp(argv[start],"-i")) {
|
||||
for (int i = 0; i < _environ_size; ++i) {
|
||||
environ[i] = NULL;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
for (; start < argc; ++start) {
|
||||
if (!strchr(argv[start],'=')) {
|
||||
break;
|
||||
} else {
|
||||
putenv(argv[start]);
|
||||
}
|
||||
}
|
||||
|
||||
if (start < argc) {
|
||||
/* Execute command */
|
||||
if (execvp(argv[start], &argv[start])) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[start], strerror(errno));
|
||||
}
|
||||
} else {
|
||||
char ** env = environ;
|
||||
|
||||
while (*env) {
|
||||
printf("%s\n", *env);
|
||||
env++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
10
apps/false.c
Normal file
10
apps/false.c
Normal file
@ -0,0 +1,10 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* false - returns a failure status code.
|
||||
*/
|
||||
int main() {
|
||||
return 1;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* vim: ts=4 sw=4 noexpandtab
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2015 Kevin Lange
|
||||
* Copyright (C) 2015-2018 K. Lange
|
||||
*
|
||||
* fetch - Retreive documents from HTTP servers.
|
||||
*
|
||||
@ -15,7 +15,7 @@
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/http_parser.h"
|
||||
#include <toaru/hashmap.h>
|
||||
|
||||
#define SIZE 512
|
||||
#define BOUNDARY "------ToaruOSFetchUploadBoundary"
|
||||
@ -34,7 +34,6 @@ struct {
|
||||
const char * upload_file;
|
||||
char * password;
|
||||
int show_progress;
|
||||
int next_is_content_length;
|
||||
size_t content_length;
|
||||
size_t size;
|
||||
struct timeval start;
|
||||
@ -70,10 +69,10 @@ void parse_url(char * d, struct http_req * r) {
|
||||
void print_progress(void) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
fprintf(stderr,"\033[G%6dkB",fetch_options.size/1024);
|
||||
fprintf(stderr,"\033[G%6dkB",(int)fetch_options.size/1024);
|
||||
if (fetch_options.content_length) {
|
||||
int percent = (fetch_options.size * BAR_WIDTH) / (fetch_options.content_length);
|
||||
fprintf(stderr," / %6dkB [%.*s%.*s]", fetch_options.content_length/1024, percent,bar_perc,BAR_WIDTH-percent,bar_spac);
|
||||
fprintf(stderr," / %6dkB [%.*s%.*s]", (int)fetch_options.content_length/1024, percent,bar_perc,BAR_WIDTH-percent,bar_spac);
|
||||
}
|
||||
|
||||
double timediff = (double)(now.tv_sec - fetch_options.start.tv_sec) + (double)(now.tv_usec - fetch_options.start.tv_usec)/1000000.0;
|
||||
@ -98,45 +97,23 @@ void print_progress(void) {
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
int callback_header_field (http_parser *p, const char *buf, size_t len) {
|
||||
if (fetch_options.show_headers) {
|
||||
fprintf(stderr, "Header field: %.*s\n", len, buf);
|
||||
}
|
||||
if (!strncmp(buf,"Content-Length",len)) {
|
||||
fetch_options.next_is_content_length = 1;
|
||||
} else {
|
||||
fetch_options.next_is_content_length = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int callback_header_value (http_parser *p, const char *buf, size_t len) {
|
||||
if (fetch_options.show_headers) {
|
||||
fprintf(stderr, "Header value: %.*s\n", len, buf);
|
||||
}
|
||||
if (fetch_options.next_is_content_length) {
|
||||
char tmp[len+1];
|
||||
memcpy(tmp,buf,len);
|
||||
tmp[len] = '\0';
|
||||
fetch_options.content_length = atoi(tmp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int callback_body (http_parser *p, const char *buf, size_t len) {
|
||||
fwrite(buf, 1, len, fetch_options.out);
|
||||
fetch_options.size += len;
|
||||
if (fetch_options.show_progress) {
|
||||
print_progress();
|
||||
}
|
||||
if (fetch_options.machine_readable && fetch_options.content_length) {
|
||||
fprintf(stdout,"%d %d\n",fetch_options.size, fetch_options.content_length);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usage(char * argv[]) {
|
||||
fprintf(stderr, "Usage: %s [-h] [-c cookie] [-o file] url\n", argv[0]);
|
||||
fprintf(stderr,
|
||||
"fetch - download files over HTTP\n"
|
||||
"\n"
|
||||
"usage: %s [-hOvmp?] [-c cookie] [-o file] [-u file] [-s speed] URL\n"
|
||||
"\n"
|
||||
" -h \033[3mshow headers\033[0m\n"
|
||||
" -O \033[3msave the file based on the filename in the URL\033[0m\n"
|
||||
" -v \033[3mshow progress\033[0m\n"
|
||||
" -m \033[3mmachine readable output\033[0m\n"
|
||||
" -p \033[3mprompt for password\033[0m\n"
|
||||
" -c ... \033[3mset cookies\033[0m\n"
|
||||
" -o ... \033[3msave to the specified file\033[0m\n"
|
||||
" -u ... \033[3mupload the specified file\033[0m\n"
|
||||
" -s ... \033[3mspecify the speed for uploading slowly\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -155,6 +132,111 @@ int collect_password(char * password) {
|
||||
password[strlen(password)-1] = '\0';
|
||||
tcsetattr(fileno(stdin), TCSAFLUSH, &old);
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void read_http_line(char * buf, FILE * f) {
|
||||
memset(buf, 0x00, 256);
|
||||
|
||||
fgets(buf, 255, f);
|
||||
char * _r = strchr(buf, '\r');
|
||||
if (_r) {
|
||||
*_r = '\0';
|
||||
}
|
||||
if (!_r) {
|
||||
_r = strchr(buf, '\n'); /* that's not right, but, whatever */
|
||||
if (_r) {
|
||||
*_r = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bad_response(void) {
|
||||
fprintf(stderr, "Bad response.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int http_fetch(FILE * f) {
|
||||
hashmap_t * headers = hashmap_create(10);
|
||||
|
||||
/* Parse response */
|
||||
{
|
||||
char buf[256];
|
||||
read_http_line(buf, f);
|
||||
|
||||
char * elements[3];
|
||||
|
||||
elements[0] = buf;
|
||||
elements[1] = strchr(elements[0], ' ');
|
||||
if (!elements[1]) bad_response();
|
||||
*elements[1] = '\0';
|
||||
elements[1]++;
|
||||
|
||||
elements[2] = strchr(elements[1], ' ');
|
||||
if (!elements[2]) bad_response();
|
||||
*elements[2] = '\0';
|
||||
elements[2]++;
|
||||
|
||||
if (strcmp(elements[1], "200")) {
|
||||
fprintf(stderr, "Bad response code: %s\n", elements[1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse headers */
|
||||
while (1) {
|
||||
char buf[256];
|
||||
read_http_line(buf, f);
|
||||
|
||||
if (!*buf) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Split */
|
||||
char * name = buf;
|
||||
char * value = strstr(buf, ": ");
|
||||
if (!value) bad_response();
|
||||
*value = '\0';
|
||||
value += 2;
|
||||
|
||||
hashmap_set(headers, name, strdup(value));
|
||||
}
|
||||
|
||||
if (fetch_options.show_headers) {
|
||||
list_t * hash_keys = hashmap_keys(headers);
|
||||
foreach(_key, hash_keys) {
|
||||
char * key = (char *)_key->value;
|
||||
fprintf(stderr, "[%s] = %s\n", key, (char*)hashmap_get(headers, key));
|
||||
}
|
||||
list_free(hash_keys);
|
||||
free(hash_keys);
|
||||
}
|
||||
|
||||
/* determine how many bytes we should read now */
|
||||
if (!hashmap_has(headers, "Content-Length")) {
|
||||
fprintf(stderr, "Don't know how much to read.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bytes_to_read = atoi(hashmap_get(headers, "Content-Length"));
|
||||
fetch_options.content_length = bytes_to_read;
|
||||
|
||||
while (bytes_to_read > 0) {
|
||||
char buf[1024];
|
||||
size_t r = fread(buf, 1, bytes_to_read < 1024 ? bytes_to_read : 1024, f);
|
||||
fwrite(buf, 1, r, fetch_options.out);
|
||||
fetch_options.size += r;
|
||||
if (fetch_options.show_progress) {
|
||||
print_progress();
|
||||
}
|
||||
if (fetch_options.machine_readable && fetch_options.content_length) {
|
||||
fprintf(stdout,"%d %d\n",(int)fetch_options.size, (int)fetch_options.content_length);
|
||||
}
|
||||
bytes_to_read -= r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@ -216,7 +298,7 @@ int main(int argc, char * argv[]) {
|
||||
|
||||
fetch_options.out = stdout;
|
||||
if (fetch_options.output_file) {
|
||||
fetch_options.out = fopen(fetch_options.output_file, "w");
|
||||
fetch_options.out = fopen(fetch_options.output_file, "w+");
|
||||
}
|
||||
|
||||
FILE * f = fopen(file,"r+");
|
||||
@ -268,7 +350,7 @@ int main(int argc, char * argv[]) {
|
||||
"Accept: */*\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: multipart/form-data; boundary=" BOUNDARY "%08x\r\n"
|
||||
"\r\n", my_req.path, my_req.domain, out_size, boundary_fuzz);
|
||||
"\r\n", my_req.path, my_req.domain, (int)out_size, boundary_fuzz);
|
||||
|
||||
fprintf(f,"%s",tmp);
|
||||
fprintf(f,
|
||||
@ -309,22 +391,7 @@ int main(int argc, char * argv[]) {
|
||||
"\r\n", my_req.path, my_req.domain);
|
||||
}
|
||||
|
||||
http_parser_settings settings;
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
settings.on_header_field = callback_header_field;
|
||||
settings.on_header_value = callback_header_value;
|
||||
settings.on_body = callback_body;
|
||||
|
||||
http_parser parser;
|
||||
http_parser_init(&parser, HTTP_RESPONSE);
|
||||
|
||||
gettimeofday(&fetch_options.start, NULL);
|
||||
while (!feof(f)) {
|
||||
char buf[10240];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
size_t r = fread(buf, 1, 10240, f);
|
||||
http_parser_execute(&parser, &settings, buf, r);
|
||||
}
|
||||
http_fetch(f);
|
||||
|
||||
fflush(fetch_options.out);
|
||||
|
45
apps/fgrep.c
Normal file
45
apps/fgrep.c
Normal file
@ -0,0 +1,45 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014-2018 K. Lange
|
||||
*
|
||||
* fgrep - dump grep
|
||||
*
|
||||
* Locates strings in files and prints the lines containing them,
|
||||
* with extra color identification if stdout is a tty.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LINE_SIZE 4096
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s thing-to-grep-for\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * needle = argv[1];
|
||||
char buf[LINE_SIZE];
|
||||
int ret = 1;
|
||||
int is_tty = isatty(STDOUT_FILENO);
|
||||
|
||||
while (fgets(buf, LINE_SIZE, stdin)) {
|
||||
char * found = strstr(buf, needle);
|
||||
if (found) {
|
||||
if (is_tty) {
|
||||
*found = '\0';
|
||||
found += strlen(needle);
|
||||
fprintf(stdout, "%s\033[1;31m%s\033[0m%s", buf, needle, found);
|
||||
} else {
|
||||
fprintf(stdout, "%s", buf);
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
510
apps/file-browser.c
Normal file
510
apps/file-browser.c
Normal file
@ -0,0 +1,510 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* file-browser - Show directory listings.
|
||||
*
|
||||
* This is a basic graphical file navigator. It's based somewhat
|
||||
* on the original Python implementation. There's still a lot
|
||||
* of work to do here presentation-wise.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/decorations.h>
|
||||
#include <toaru/menu.h>
|
||||
#include <toaru/icon_cache.h>
|
||||
#include <toaru/list.h>
|
||||
#include <toaru/sdf.h>
|
||||
|
||||
#define APPLICATION_TITLE "File Browser"
|
||||
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * main_window;
|
||||
static gfx_context_t * ctx;
|
||||
|
||||
#define SCROLL_AMOUNT 20
|
||||
static int application_running = 1;
|
||||
static int show_hidden = 1;
|
||||
static int scroll_offset = 0;
|
||||
static int available_height = 0;
|
||||
|
||||
static struct menu_bar menu_bar = {0};
|
||||
static struct menu_bar_entries menu_entries[] = {
|
||||
{"File", "file"},
|
||||
{"Go", "go"},
|
||||
{"Help", "help"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static void _menu_action_exit(struct MenuEntry * entry) {
|
||||
application_running = 0;
|
||||
}
|
||||
|
||||
struct File {
|
||||
char name[256];
|
||||
char icon[256];
|
||||
char date[256];
|
||||
int type;
|
||||
};
|
||||
|
||||
static gfx_context_t * contents = NULL;
|
||||
static sprite_t * contents_sprite = NULL;
|
||||
static char * last_directory = NULL;
|
||||
static int hilighted_offset = -1;
|
||||
static struct File ** file_pointers = NULL;
|
||||
static ssize_t file_pointers_len = 0;
|
||||
|
||||
static int _close_enough(struct yutani_msg_window_mouse_event * me) {
|
||||
if (me->command == YUTANI_MOUSE_EVENT_RAISE && sqrt(pow(me->new_x - me->old_x, 2) + pow(me->new_y - me->old_y, 2)) < 10) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clear_offset(int offset) {
|
||||
draw_rectangle(contents, 0, offset * 24, contents->width, 24, rgb(255,255,255));
|
||||
}
|
||||
|
||||
static void draw_file(struct File * f, int offset) {
|
||||
sprite_t * icon = icon_get_16(f->icon);
|
||||
draw_sprite(contents, icon, 2, offset * 24 + 2);
|
||||
if (offset == hilighted_offset) {
|
||||
draw_sprite_alpha_paint(contents, icon, 2, offset * 24 + 2, 0.5, rgb(72,167,255));
|
||||
draw_sdf_string(contents, 30, offset * 24, f->name, 16, rgb(72,167,255), SDF_FONT_THIN);
|
||||
} else {
|
||||
draw_sdf_string(contents, 30, offset * 24, f->name, 16, rgb(0,0,0), SDF_FONT_THIN);
|
||||
}
|
||||
}
|
||||
|
||||
static struct File * get_file_at_offset(int offset) {
|
||||
if (offset >= 0 && offset < file_pointers_len) {
|
||||
return file_pointers[offset];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void redraw_files(void) {
|
||||
for (int i = 0; i < file_pointers_len; ++i) {
|
||||
draw_file(file_pointers[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
static void load_directory(const char * path) {
|
||||
if (file_pointers) {
|
||||
for (int i = 0; i < file_pointers_len; ++i) {
|
||||
free(file_pointers[i]);
|
||||
}
|
||||
free(file_pointers);
|
||||
}
|
||||
|
||||
DIR * dirp = opendir(path);
|
||||
|
||||
if (!dirp) {
|
||||
/* Failed to open directory. Throw up a warning? */
|
||||
file_pointers = NULL;
|
||||
file_pointers_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_directory) {
|
||||
free(last_directory);
|
||||
}
|
||||
|
||||
last_directory = strdup(path);
|
||||
|
||||
/* Get the current time */
|
||||
#if 0
|
||||
struct tm * timeinfo;
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL); //time(NULL);
|
||||
timeinfo = localtime((time_t *)&now.tv_sec);
|
||||
int this_year = timeinfo->tm_year;
|
||||
#endif
|
||||
|
||||
list_t * file_list = list_create();
|
||||
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (ent->d_name[0] == '.' &&
|
||||
(ent->d_name[1] == '\0' ||
|
||||
(ent->d_name[1] == '.' &&
|
||||
ent->d_name[2] == '\0'))) {
|
||||
/* skip . and .. */
|
||||
ent = readdir(dirp);
|
||||
continue;
|
||||
}
|
||||
if (show_hidden || (ent->d_name[0] != '.')) {
|
||||
|
||||
struct File * f = malloc(sizeof(struct File));
|
||||
sprintf(f->name, "%s", ent->d_name); /* snprintf? copy min()? */
|
||||
|
||||
struct stat statbuf;
|
||||
//struct stat statbufl;
|
||||
//char * link;
|
||||
|
||||
char tmp[strlen(path)+strlen(ent->d_name)+2];
|
||||
sprintf(tmp, "%s/%s", path, ent->d_name);
|
||||
lstat(tmp, &statbuf);
|
||||
#if 0
|
||||
if (S_ISLNK(statbuf.st_mode)) {
|
||||
stat(tmp, &statbufl);
|
||||
f->link = malloc(4096);
|
||||
readlink(tmp, f->link, 4096);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
sprintf(f->icon, "folder");
|
||||
f->type = 1;
|
||||
} else {
|
||||
sprintf(f->icon, "file");
|
||||
f->type = 0;
|
||||
}
|
||||
|
||||
list_insert(file_list, f);
|
||||
}
|
||||
ent = readdir(dirp);
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
/* create a an array to hold the files */
|
||||
file_pointers = malloc(sizeof(struct File *) * file_list->length);
|
||||
file_pointers_len = file_list->length;
|
||||
int i = 0;
|
||||
foreach (node, file_list) {
|
||||
file_pointers[i] = node->value;
|
||||
i++;
|
||||
}
|
||||
|
||||
list_free(file_list);
|
||||
free(file_list);
|
||||
|
||||
/* Sort files */
|
||||
int comparator(const void * c1, const void * c2) {
|
||||
const struct File * f1 = *(const struct File **)(c1);
|
||||
const struct File * f2 = *(const struct File **)(c2);
|
||||
if (f1->type == 1 && f2->type == 0) return -1;
|
||||
if (f1->type == 0 && f2->type == 1) return 1;
|
||||
return strcmp(f1->name, f2->name);
|
||||
}
|
||||
qsort(file_pointers, file_pointers_len, sizeof(struct File *), comparator);
|
||||
|
||||
scroll_offset = 0;
|
||||
}
|
||||
|
||||
static void reinitialize_contents(void) {
|
||||
if (contents) {
|
||||
free(contents);
|
||||
}
|
||||
|
||||
if (contents_sprite) {
|
||||
sprite_free(contents_sprite);
|
||||
}
|
||||
|
||||
/* Calculate height for current directory */
|
||||
int calculated_height = file_pointers_len * 24;
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(main_window, &bounds);
|
||||
|
||||
contents_sprite = create_sprite(main_window->width - bounds.width, calculated_height, ALPHA_EMBEDDED);
|
||||
contents = init_graphics_sprite(contents_sprite);
|
||||
|
||||
draw_fill(contents, rgb(255,255,255));
|
||||
|
||||
/* Draw file entries */
|
||||
redraw_files();
|
||||
}
|
||||
|
||||
static void redraw_window(void) {
|
||||
draw_fill(ctx, rgb(255,255,255));
|
||||
|
||||
render_decorations(main_window, ctx, APPLICATION_TITLE);
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(main_window, &bounds);
|
||||
|
||||
menu_bar.x = bounds.left_width;
|
||||
menu_bar.y = bounds.top_height;
|
||||
menu_bar.width = ctx->width - bounds.width;
|
||||
menu_bar.window = main_window;
|
||||
menu_bar_render(&menu_bar, ctx);
|
||||
|
||||
gfx_clear_clip(ctx);
|
||||
gfx_add_clip(ctx, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT, ctx->width - bounds.width, available_height);
|
||||
draw_sprite(ctx, contents_sprite, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT - scroll_offset);
|
||||
gfx_clear_clip(ctx);
|
||||
gfx_add_clip(ctx, 0, 0, ctx->width, ctx->height);
|
||||
|
||||
|
||||
flip(ctx);
|
||||
yutani_flip(yctx, main_window);
|
||||
}
|
||||
|
||||
static void resize_finish(int w, int h) {
|
||||
int width_changed = (main_window->width != (unsigned int)w);
|
||||
|
||||
yutani_window_resize_accept(yctx, main_window, w, h);
|
||||
reinit_graphics_yutani(ctx, main_window);
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(main_window, &bounds);
|
||||
|
||||
available_height = ctx->height - MENU_BAR_HEIGHT - bounds.height;
|
||||
|
||||
if (width_changed) {
|
||||
reinitialize_contents();
|
||||
}
|
||||
|
||||
if (available_height > contents->height) {
|
||||
scroll_offset = 0;
|
||||
} else {
|
||||
if (scroll_offset > contents->height - available_height) {
|
||||
scroll_offset = contents->height - available_height;
|
||||
}
|
||||
}
|
||||
|
||||
redraw_window();
|
||||
yutani_window_resize_done(yctx, main_window);
|
||||
|
||||
yutani_flip(yctx, main_window);
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
#if 0
|
||||
static void _menu_action_input_path(struct MenuEntry * entry) {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _menu_action_navigate(struct MenuEntry * entry) {
|
||||
/* go to entry->action */
|
||||
struct MenuEntry_Normal * _entry = (void*)entry;
|
||||
load_directory(_entry->action);
|
||||
reinitialize_contents();
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
static void _menu_action_up(struct MenuEntry * entry) {
|
||||
/* go up */
|
||||
char tmp[1024];
|
||||
sprintf(tmp, "%s/..", last_directory);
|
||||
load_directory(tmp);
|
||||
reinitialize_contents();
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
static void _menu_action_help(struct MenuEntry * entry) {
|
||||
/* show help documentation */
|
||||
system("help-browser file-browser.trt &");
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
static void _menu_action_about(struct MenuEntry * entry) {
|
||||
/* Show About dialog */
|
||||
char about_cmd[1024] = "\0";
|
||||
strcat(about_cmd, "about \"About File Browser\" /usr/share/icons/48/folder.bmp \"ToaruOS File Browser\" \"(C) 2018 K. Lange\n-\nPart of ToaruOS, which is free software\nreleased under the NCSA/University of Illinois\nlicense.\n-\n%https://toaruos.org\n%https://gitlab.com/toaruos\" ");
|
||||
char coords[100];
|
||||
sprintf(coords, "%d %d &", (int)main_window->x + (int)main_window->width / 2, (int)main_window->y + (int)main_window->height / 2);
|
||||
strcat(about_cmd, coords);
|
||||
system(about_cmd);
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
yctx = yutani_init();
|
||||
init_decorations();
|
||||
main_window = yutani_window_create(yctx, 800, 600);
|
||||
yutani_window_move(yctx, main_window, yctx->display_width / 2 - main_window->width / 2, yctx->display_height / 2 - main_window->height / 2);
|
||||
ctx = init_graphics_yutani_double_buffer(main_window);
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(main_window, &bounds);
|
||||
|
||||
yutani_window_advertise_icon(yctx, main_window, APPLICATION_TITLE, "folder");
|
||||
|
||||
menu_bar.entries = menu_entries;
|
||||
menu_bar.redraw_callback = redraw_window;
|
||||
|
||||
menu_bar.set = menu_set_create();
|
||||
|
||||
struct MenuList * m = menu_create(); /* File */
|
||||
menu_insert(m, menu_create_normal("exit",NULL,"Exit", _menu_action_exit));
|
||||
menu_set_insert(menu_bar.set, "file", m);
|
||||
|
||||
m = menu_create(); /* Go */
|
||||
/* TODO implement input dialog for Path... */
|
||||
#if 0
|
||||
menu_insert(m, menu_create_normal("open",NULL,"Path...", _menu_action_input_path));
|
||||
menu_insert(m, menu_create_separator());
|
||||
#endif
|
||||
menu_insert(m, menu_create_normal("home",getenv("HOME"),"Home",_menu_action_navigate));
|
||||
menu_insert(m, menu_create_normal(NULL,"/","File System",_menu_action_navigate));
|
||||
menu_insert(m, menu_create_normal("up",NULL,"Up",_menu_action_up));
|
||||
menu_set_insert(menu_bar.set, "go", m);
|
||||
|
||||
m = menu_create();
|
||||
menu_insert(m, menu_create_normal("help",NULL,"Contents",_menu_action_help));
|
||||
menu_insert(m, menu_create_separator());
|
||||
menu_insert(m, menu_create_normal("star",NULL,"About " APPLICATION_TITLE,_menu_action_about));
|
||||
menu_set_insert(menu_bar.set, "help", m);
|
||||
|
||||
available_height = ctx->height - MENU_BAR_HEIGHT - bounds.height;
|
||||
load_directory("/usr/share");
|
||||
reinitialize_contents();
|
||||
redraw_window();
|
||||
|
||||
while (application_running) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
while (m) {
|
||||
if (menu_process_event(yctx, m)) {
|
||||
redraw_window();
|
||||
}
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
_menu_action_exit(NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win == main_window) {
|
||||
win->focused = wf->focused;
|
||||
redraw_window();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
if (wr->wid == main_window->wid) {
|
||||
resize_finish(wr->width, wr->height);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid);
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(win, &bounds);
|
||||
|
||||
if (win == main_window) {
|
||||
int result = decor_handle_event(yctx, m);
|
||||
switch (result) {
|
||||
case DECOR_CLOSE:
|
||||
_menu_action_exit(NULL);
|
||||
break;
|
||||
case DECOR_RIGHT:
|
||||
/* right click in decoration, show appropriate menu */
|
||||
decor_show_default_menu(main_window, main_window->x + me->new_x, main_window->y + me->new_y);
|
||||
break;
|
||||
default:
|
||||
/* Other actions */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Menu bar */
|
||||
menu_bar_mouse_event(yctx, main_window, &menu_bar, me, me->new_x, me->new_y);
|
||||
|
||||
if (me->new_y > (int)(bounds.top_height + MENU_BAR_HEIGHT) &&
|
||||
me->new_y < (int)(main_window->height - bounds.bottom_height) &&
|
||||
me->new_x > (int)(bounds.left_width) &&
|
||||
me->new_x < (int)(main_window->width - bounds.right_width)) {
|
||||
if (me->buttons & YUTANI_MOUSE_SCROLL_UP) {
|
||||
/* Scroll up */
|
||||
scroll_offset -= SCROLL_AMOUNT;
|
||||
if (scroll_offset < 0) {
|
||||
scroll_offset = 0;
|
||||
}
|
||||
redraw_window();
|
||||
} else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) {
|
||||
if (available_height > contents->height) {
|
||||
scroll_offset = 0;
|
||||
} else {
|
||||
scroll_offset += SCROLL_AMOUNT;
|
||||
if (scroll_offset > contents->height - available_height) {
|
||||
scroll_offset = contents->height - available_height;
|
||||
}
|
||||
}
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
/* Get offset into contents */
|
||||
int y_into = me->new_y - bounds.top_height - MENU_BAR_HEIGHT + scroll_offset;
|
||||
int offset = y_into / 24;
|
||||
if (offset != hilighted_offset) {
|
||||
int old_offset = hilighted_offset;
|
||||
hilighted_offset = offset;
|
||||
if (old_offset != -1) {
|
||||
clear_offset(old_offset);
|
||||
struct File * f = get_file_at_offset(old_offset);
|
||||
if (f) {
|
||||
clear_offset(old_offset);
|
||||
draw_file(f, old_offset);
|
||||
}
|
||||
}
|
||||
struct File * f = get_file_at_offset(hilighted_offset);
|
||||
if (f) {
|
||||
clear_offset(hilighted_offset);
|
||||
draw_file(f, hilighted_offset);
|
||||
}
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
if (me->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(me)) {
|
||||
struct File * f = get_file_at_offset(hilighted_offset);
|
||||
if (f && f->type == 1) {
|
||||
char tmp[1024];
|
||||
sprintf(tmp,"%s/%s", last_directory, f->name);
|
||||
load_directory(tmp);
|
||||
reinitialize_contents();
|
||||
redraw_window();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
int old_offset = hilighted_offset;
|
||||
hilighted_offset = -1;
|
||||
if (old_offset != -1) {
|
||||
clear_offset(old_offset);
|
||||
struct File * f = get_file_at_offset(old_offset);
|
||||
if (f) {
|
||||
clear_offset(old_offset);
|
||||
draw_file(f, old_offset);
|
||||
}
|
||||
redraw_window();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_CLOSE:
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
_menu_action_exit(NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
}
|
||||
}
|
97
apps/font-server.c
Normal file
97
apps/font-server.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* font-server - Provides shared-memory fonts.
|
||||
*
|
||||
* This is an implementation of the shared memory font server
|
||||
* from Yutani in mainline ToaruOS. In theory, with the fonts
|
||||
* installed, this could be used to provide fonts for legacy
|
||||
* mainline applications in ToaruOS-NIH, but this is untested.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#if 0
|
||||
#include <toaru/trace.h>
|
||||
#define TRACE_APP_NAME "font-server"
|
||||
#else
|
||||
#define TRACE(...)
|
||||
#endif
|
||||
|
||||
#define FONT_PATH "/usr/share/fonts/"
|
||||
#define FONT(a,b) {a, FONT_PATH b}
|
||||
|
||||
struct font_def {
|
||||
char * identifier;
|
||||
char * path;
|
||||
};
|
||||
|
||||
static struct font_def fonts[] = {
|
||||
FONT("sans-serif", "DejaVuSans.ttf"),
|
||||
FONT("sans-serif.bold", "DejaVuSans-Bold.ttf"),
|
||||
FONT("sans-serif.italic", "DejaVuSans-Oblique.ttf"),
|
||||
FONT("sans-serif.bolditalic", "DejaVuSans-BoldOblique.ttf"),
|
||||
FONT("monospace", "DejaVuSansMono.ttf"),
|
||||
FONT("monospace.bold", "DejaVuSansMono-Bold.ttf"),
|
||||
FONT("monospace.italic", "DejaVuSansMono-Oblique.ttf"),
|
||||
FONT("monospace.bolditalic", "DejaVuSansMono-BoldOblique.ttf"),
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Preload a font into the font cache.
|
||||
*/
|
||||
static char * precache_shmfont(char * ident, char * name) {
|
||||
FILE * f = fopen(name, "r");
|
||||
if (!f) return NULL;
|
||||
size_t s = 0;
|
||||
fseek(f, 0, SEEK_END);
|
||||
s = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
size_t shm_size = s;
|
||||
char * font = (char *)syscall_shm_obtain(ident, &shm_size);
|
||||
assert((shm_size >= s) && "shm_obtain returned too little memory to load a font into!");
|
||||
|
||||
fread(font, s, 1, f);
|
||||
|
||||
fclose(f);
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all of the fonts into the cache.
|
||||
*/
|
||||
static void load_fonts(char * server) {
|
||||
int i = 0;
|
||||
while (fonts[i].identifier) {
|
||||
char tmp[100];
|
||||
sprintf(tmp, "sys.%s.fonts.%s", server, fonts[i].identifier);
|
||||
TRACE("Loading font %s -> %s", fonts[i].path, tmp);
|
||||
if (!precache_shmfont(tmp, fonts[i].path)) {
|
||||
TRACE(" ... failed.");
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
/* Daemonize */
|
||||
if (!fork()) {
|
||||
load_fonts("fonts");
|
||||
|
||||
while (1) {
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2015 Kevin Lange
|
||||
* Copyright (C) 2015-2018 K. Lange
|
||||
*
|
||||
* free - Show free / used / total RAM
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void show_usage(int argc, char * argv[]) {
|
||||
printf(
|
||||
@ -27,23 +28,21 @@ int main(int argc, char * argv[]) {
|
||||
int use_kilobytes = 0;
|
||||
int show_total = 0;
|
||||
|
||||
if (argc > 1) {
|
||||
int index, c;
|
||||
while ((c = getopt(argc, argv, "ktu?")) != -1) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
show_used = 1;
|
||||
break;
|
||||
case 't':
|
||||
show_total = 1;
|
||||
break;
|
||||
case 'k':
|
||||
use_kilobytes = 1;
|
||||
break;
|
||||
case '?':
|
||||
show_usage(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "utk?")) != -1) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
show_used = 1;
|
||||
break;
|
||||
case 't':
|
||||
show_total = 1;
|
||||
break;
|
||||
case 'k':
|
||||
use_kilobytes = 1;
|
||||
break;
|
||||
case '?':
|
||||
show_usage(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +52,24 @@ int main(int argc, char * argv[]) {
|
||||
if (!f) return 1;
|
||||
|
||||
int total, free, used;
|
||||
fscanf(f, "MemTotal: %d kB\nMemFree: %d kB\n", &total, &free);
|
||||
char buf[1024] = {0};
|
||||
fgets(buf, 1024, f);
|
||||
char * a, * b;
|
||||
|
||||
a = strchr(buf, ' ');
|
||||
a++;
|
||||
b = strchr(a, '\n');
|
||||
*b = '\0';
|
||||
total = atoi(a);
|
||||
|
||||
fgets(buf, 1024, f);
|
||||
a = strchr(buf, ' ');
|
||||
a++;
|
||||
b = strchr(a, '\n');
|
||||
*b = '\0';
|
||||
free = atoi(a);
|
||||
|
||||
//fscanf(f, "MemTotal: %d kB\nMemFree: %d kB\n", &total, &free);
|
||||
used = total - free;
|
||||
|
||||
if (!use_kilobytes) {
|
96
apps/getty.c
Normal file
96
apps/getty.c
Normal file
@ -0,0 +1,96 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* getty - Manage a TTY.
|
||||
*
|
||||
* Wraps a serial port (or other dumb connection) with a pty
|
||||
* and manages a login for it.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <pty.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/fswait.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int fd_master, fd_slave, fd_serial;
|
||||
char * file = "/dev/ttyS0";
|
||||
char * user = NULL;
|
||||
|
||||
if (getuid() != 0) {
|
||||
fprintf(stderr, "%s: only root can do that\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "a:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
user = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
file = argv[optind];
|
||||
}
|
||||
|
||||
openpty(&fd_master, &fd_slave, NULL, NULL, NULL);
|
||||
fd_serial = open(file, O_RDWR);
|
||||
|
||||
pid_t child = fork();
|
||||
|
||||
if (!child) {
|
||||
dup2(fd_slave, 0);
|
||||
dup2(fd_slave, 1);
|
||||
dup2(fd_slave, 2);
|
||||
|
||||
system("ttysize -q");
|
||||
|
||||
char * tokens[] = {"/bin/login",NULL,NULL,NULL};
|
||||
|
||||
if (user) {
|
||||
tokens[1] = "-f";
|
||||
tokens[2] = user;
|
||||
}
|
||||
|
||||
execvp(tokens[0], tokens);
|
||||
exit(1);
|
||||
} else {
|
||||
|
||||
int fds[2] = {fd_serial, fd_master};
|
||||
|
||||
while (1) {
|
||||
int index = fswait2(2,fds,200);
|
||||
char buf[1024];
|
||||
int r;
|
||||
switch (index) {
|
||||
case 0: /* fd_serial */
|
||||
r = read(fd_serial, buf, 1);
|
||||
write(fd_master, buf, 1);
|
||||
break;
|
||||
case 1: /* fd_master */
|
||||
r = read(fd_master, buf, 1024);
|
||||
write(fd_serial, buf, r);
|
||||
break;
|
||||
default: /* timeout */
|
||||
{
|
||||
int result = waitpid(child, NULL, WNOHANG);
|
||||
if (result > 0) {
|
||||
/* Child login shell has returned (session ended) */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
589
apps/glogin-provider.c
Normal file
589
apps/glogin-provider.c
Normal file
@ -0,0 +1,589 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2015 K. Lange
|
||||
*/
|
||||
/*
|
||||
* glogin
|
||||
*
|
||||
* Graphical Login screen
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/kbd.h>
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/auth.h>
|
||||
#include <toaru/confreader.h>
|
||||
#include <toaru/sdf.h>
|
||||
|
||||
#include <toaru/trace.h>
|
||||
#define TRACE_APP_NAME "glogin-provider"
|
||||
|
||||
static sprite_t logo;
|
||||
|
||||
static gfx_context_t * ctx;
|
||||
|
||||
static uint16_t win_width;
|
||||
static uint16_t win_height;
|
||||
|
||||
static int uid = 0;
|
||||
|
||||
#define USERNAME_BOX 1
|
||||
#define PASSWORD_BOX 2
|
||||
|
||||
static int LOGO_FINAL_OFFSET = 100;
|
||||
static int BOX_WIDTH = 272;
|
||||
static int BOX_HEIGHT = 104;
|
||||
static int BOX_ROUNDNESS = 8;
|
||||
static int CENTER_BOX_X=1;
|
||||
static int CENTER_BOX_Y=1;
|
||||
static int BOX_LEFT=-1;
|
||||
static int BOX_RIGHT=-1;
|
||||
static int BOX_TOP=-1;
|
||||
static int BOX_BOTTOM=-1;
|
||||
static int BOX_COLOR_R=0;
|
||||
static int BOX_COLOR_G=0;
|
||||
static int BOX_COLOR_B=0;
|
||||
static int BOX_COLOR_A=127;
|
||||
static char * WALLPAPER = "/usr/share/wallpaper.bmp";
|
||||
static char * LOGO = "/usr/share/logo_login.bmp";
|
||||
|
||||
#define TEXTBOX_INTERIOR_LEFT 4
|
||||
#define EXTRA_TEXT_OFFSET 15
|
||||
|
||||
int center_x(int x) {
|
||||
return (win_width - x) / 2;
|
||||
}
|
||||
|
||||
int center_y(int y) {
|
||||
return (win_height - y) / 2;
|
||||
}
|
||||
|
||||
#define INPUT_SIZE 1024
|
||||
int buffer_put(char * input_buffer, char c) {
|
||||
int input_collected = strlen(input_buffer);
|
||||
if (c == 8) {
|
||||
/* Backspace */
|
||||
if (input_collected > 0) {
|
||||
input_collected--;
|
||||
input_buffer[input_collected] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (c < 10 || (c > 10 && c < 32) || c > 126) {
|
||||
return 0;
|
||||
}
|
||||
input_buffer[input_collected] = c;
|
||||
input_collected++;
|
||||
input_buffer[input_collected] = '\0';
|
||||
if (input_collected == INPUT_SIZE - 1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct text_box {
|
||||
int x;
|
||||
int y;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
||||
uint32_t text_color;
|
||||
|
||||
struct login_container * parent;
|
||||
|
||||
int is_focused:1;
|
||||
int is_password:1;
|
||||
|
||||
unsigned int cursor;
|
||||
char * buffer;
|
||||
|
||||
char * placeholder;
|
||||
};
|
||||
|
||||
struct login_container {
|
||||
int x;
|
||||
int y;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
||||
struct text_box * username_box;
|
||||
struct text_box * password_box;
|
||||
|
||||
int show_error:1;
|
||||
};
|
||||
|
||||
void draw_text_box(gfx_context_t * ctx, struct text_box * tb) {
|
||||
int x = tb->parent->x + tb->x;
|
||||
int y = tb->parent->y + tb->y;
|
||||
|
||||
int text_offset = 15;
|
||||
if (tb->is_focused) {
|
||||
draw_rounded_rectangle(ctx, 1 + x, 1 + y, tb->width - 2, tb->height - 2, 4, rgb(8,193,236));
|
||||
draw_rounded_rectangle(ctx, 2 + x, 2 + y, tb->width - 4, tb->height - 4, 4, rgb(244,244,244));
|
||||
} else {
|
||||
draw_rounded_rectangle(ctx, 1 + x, 1 + y, tb->width - 2, tb->height - 2, 4, rgb(158,169,177));
|
||||
}
|
||||
/* Line width 2? */
|
||||
char * text = tb->buffer;
|
||||
char password_circles[512];
|
||||
uint32_t color = tb->text_color;
|
||||
|
||||
if (strlen(tb->buffer) == 0 && !tb->is_focused) {
|
||||
text = tb->placeholder;
|
||||
color = rgba(0,0,0,127);
|
||||
} else if (tb->is_password) {
|
||||
strcpy(password_circles, "");
|
||||
for (unsigned int i = 0; i < strlen(tb->buffer); ++i) {
|
||||
strcat(password_circles, "\007");
|
||||
}
|
||||
text = password_circles;
|
||||
}
|
||||
|
||||
draw_sdf_string(ctx, x + TEXTBOX_INTERIOR_LEFT, y + text_offset - 12, text, 15, color, SDF_FONT_THIN);
|
||||
|
||||
if (tb->is_focused) {
|
||||
int width = draw_sdf_string_width(text, 15, SDF_FONT_THIN) + 2;
|
||||
draw_line(ctx, x + TEXTBOX_INTERIOR_LEFT + width, x + TEXTBOX_INTERIOR_LEFT + width, y + 2, y + text_offset + 1, tb->text_color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void draw_login_container(gfx_context_t * ctx, struct login_container * lc) {
|
||||
|
||||
|
||||
/* Draw rounded rectangle */
|
||||
draw_rounded_rectangle(ctx, lc->x, lc->y, lc->width, lc->height, BOX_ROUNDNESS, rgba(BOX_COLOR_R,BOX_COLOR_G,BOX_COLOR_B,BOX_COLOR_A));
|
||||
|
||||
/* Draw labels */
|
||||
if (lc->show_error) {
|
||||
char * error_message = "Incorrect username or password.";
|
||||
|
||||
//set_font_size(11);
|
||||
//draw_string(ctx, lc->x + (lc->width - draw_string_width(error_message)) / 2, lc->y + 6 + EXTRA_TEXT_OFFSET, rgb(240, 20, 20), error_message);
|
||||
draw_sdf_string(ctx, lc->x + (lc->width - draw_sdf_string_width(error_message, 14, SDF_FONT_THIN)) / 2, lc->y + 6 + EXTRA_TEXT_OFFSET - 14, error_message, 14, rgb(240,20,20), SDF_FONT_THIN);
|
||||
}
|
||||
|
||||
draw_text_box(ctx, lc->username_box);
|
||||
draw_text_box(ctx, lc->password_box);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hostname information updated with the current time.
|
||||
*
|
||||
* @param hostname
|
||||
*/
|
||||
static void get_updated_hostname_with_time_info(char hostname[]) {
|
||||
// get hostname
|
||||
char _hostname[256];
|
||||
gethostname(_hostname, 255);
|
||||
|
||||
// get current time
|
||||
struct tm * timeinfo;
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL); //time(NULL);
|
||||
timeinfo = localtime((time_t *)&now.tv_sec);
|
||||
|
||||
// format the hostname info
|
||||
char _date[256];
|
||||
strftime(_date, 256, "%a %B %d %Y", timeinfo);
|
||||
sprintf(hostname, "%s // %s", _hostname, _date);
|
||||
}
|
||||
|
||||
static void draw_sdf_string_shadow(gfx_context_t * ctx, char * string, int font_size, int left, int top, uint32_t text_color, uint32_t shadow_color, int blur, int font) {
|
||||
int w = draw_sdf_string_width(string, font_size, font);
|
||||
sprite_t * _tmp_s = create_sprite(w + blur * 2, font_size + blur * 2, ALPHA_EMBEDDED);
|
||||
gfx_context_t * _tmp = init_graphics_sprite(_tmp_s);
|
||||
draw_fill(_tmp, rgba(0,0,0,0));
|
||||
draw_sdf_string(_tmp, blur, blur, string, font_size, shadow_color, font);
|
||||
blur_context_box(_tmp, blur);
|
||||
free(_tmp);
|
||||
draw_sprite(ctx, _tmp_s, left - blur, top - blur);
|
||||
sprite_free(_tmp_s);
|
||||
draw_sdf_string(ctx, left, top, string, 14, text_color, font);
|
||||
}
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (getuid() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Hello\n");
|
||||
|
||||
yutani_t * y = yutani_init();
|
||||
|
||||
if (!y) {
|
||||
fprintf(stderr, "[glogin] Connection to server failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load config */
|
||||
{
|
||||
confreader_t * conf = confreader_load("/etc/glogin.conf");
|
||||
|
||||
LOGO_FINAL_OFFSET = confreader_intd(conf, "style", "logo_padding", LOGO_FINAL_OFFSET);
|
||||
BOX_WIDTH = confreader_intd(conf, "style", "box_width", BOX_WIDTH);
|
||||
BOX_HEIGHT = confreader_intd(conf, "style", "box_height", BOX_HEIGHT);
|
||||
BOX_ROUNDNESS = confreader_intd(conf, "style", "box_roundness", BOX_ROUNDNESS);
|
||||
CENTER_BOX_X = confreader_intd(conf, "style", "center_box_x", CENTER_BOX_X);
|
||||
CENTER_BOX_Y = confreader_intd(conf, "style", "center_box_y", CENTER_BOX_Y);
|
||||
BOX_LEFT = confreader_intd(conf, "style", "box_left", BOX_LEFT);
|
||||
BOX_RIGHT = confreader_intd(conf, "style", "box_right", BOX_RIGHT);
|
||||
BOX_TOP = confreader_intd(conf, "style", "box_top", BOX_TOP);
|
||||
BOX_BOTTOM = confreader_intd(conf, "style", "box_bottom", BOX_BOTTOM);
|
||||
BOX_COLOR_R = confreader_intd(conf, "style", "box_color_r", BOX_COLOR_R);
|
||||
BOX_COLOR_G = confreader_intd(conf, "style", "box_color_g", BOX_COLOR_G);
|
||||
BOX_COLOR_B = confreader_intd(conf, "style", "box_color_b", BOX_COLOR_B);
|
||||
BOX_COLOR_A = confreader_intd(conf, "style", "box_color_a", BOX_COLOR_A);
|
||||
|
||||
WALLPAPER = confreader_getd(conf, "image", "wallpaper", WALLPAPER);
|
||||
LOGO = confreader_getd(conf, "image", "logo", LOGO);
|
||||
|
||||
confreader_free(conf);
|
||||
|
||||
TRACE("Loading complete");
|
||||
}
|
||||
|
||||
TRACE("Loading logo...");
|
||||
load_sprite(&logo, LOGO);
|
||||
logo.alpha = ALPHA_EMBEDDED;
|
||||
TRACE("... done.");
|
||||
|
||||
/* Generate surface for background */
|
||||
sprite_t * bg_sprite;
|
||||
|
||||
int width = y->display_width;
|
||||
int height = y->display_height;
|
||||
int skip_animation = 0;
|
||||
|
||||
/* Do something with a window */
|
||||
TRACE("Connecting to window server...");
|
||||
yutani_window_t * wina = yutani_window_create(y, width, height);
|
||||
assert(wina);
|
||||
yutani_set_stack(y, wina, 0);
|
||||
ctx = init_graphics_yutani_double_buffer(wina);
|
||||
draw_fill(ctx, rgba(0,0,0,255));
|
||||
yutani_flip(y, wina);
|
||||
TRACE("... done.");
|
||||
|
||||
|
||||
redo_everything:
|
||||
win_width = width;
|
||||
win_height = height;
|
||||
|
||||
#if 0
|
||||
cairo_surface_t * cs = cairo_image_surface_create_for_data((void*)ctx->backbuffer, CAIRO_FORMAT_ARGB32, ctx->width, ctx->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ctx->width));
|
||||
cairo_t * cr = cairo_create(cs);
|
||||
#endif
|
||||
|
||||
|
||||
TRACE("Loading wallpaper...");
|
||||
{
|
||||
sprite_t * wallpaper = malloc(sizeof(sprite_t));
|
||||
load_sprite(wallpaper, WALLPAPER);
|
||||
|
||||
float x = (float)width / (float)wallpaper->width;
|
||||
float y = (float)height / (float)wallpaper->height;
|
||||
|
||||
int nh = (int)(x * (float)wallpaper->height);
|
||||
int nw = (int)(y * (float)wallpaper->width);;
|
||||
|
||||
bg_sprite = create_sprite(width, height, ALPHA_OPAQUE);
|
||||
gfx_context_t * bg = init_graphics_sprite(bg_sprite);
|
||||
|
||||
if (nw > width) {
|
||||
draw_sprite_scaled(bg, wallpaper, (width - nw) / 2, 0, nw, height);
|
||||
} else {
|
||||
draw_sprite_scaled(bg, wallpaper, 0, (height - nh) / 2, width, nh);
|
||||
}
|
||||
|
||||
/* Three box blurs = good enough approximation of a guassian, but faster*/
|
||||
blur_context_box(bg, 20);
|
||||
blur_context_box(bg, 20);
|
||||
blur_context_box(bg, 20);
|
||||
|
||||
free(bg);
|
||||
free(wallpaper);
|
||||
}
|
||||
TRACE("... done.");
|
||||
|
||||
while (1) {
|
||||
|
||||
yutani_set_stack(y, wina, 0);
|
||||
yutani_focus_window(y, wina->wid);
|
||||
|
||||
draw_fill(ctx, rgb(0,0,0));
|
||||
draw_sprite(ctx, bg_sprite, center_x(width), center_y(height));
|
||||
flip(ctx);
|
||||
yutani_flip(y, wina);
|
||||
|
||||
char * foo = malloc(sizeof(uint32_t) * width * height);
|
||||
memcpy(foo, ctx->backbuffer, sizeof(uint32_t) * width * height);
|
||||
|
||||
TRACE("Begin animation.");
|
||||
if (!skip_animation) {
|
||||
struct timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
|
||||
while (1) {
|
||||
uint32_t tick;
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
|
||||
uint32_t sec_diff = t.tv_sec - start.tv_sec;
|
||||
uint32_t usec_diff = t.tv_usec - start.tv_usec;
|
||||
|
||||
if (t.tv_usec < start.tv_usec) {
|
||||
sec_diff -= 1;
|
||||
usec_diff = (1000000 + t.tv_usec) - start.tv_usec;
|
||||
}
|
||||
|
||||
tick = (uint32_t)(sec_diff * 1000 + usec_diff / 1000);
|
||||
int i = (float)LOGO_FINAL_OFFSET * (float)tick / 700.0f;
|
||||
if (i >= LOGO_FINAL_OFFSET) break;
|
||||
|
||||
memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height);
|
||||
draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - i);
|
||||
flip(ctx);
|
||||
yutani_flip_region(y, wina, center_x(logo.width), center_y(logo.height) - i, logo.width, logo.height + 5);
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
TRACE("End animation.");
|
||||
skip_animation = 0;
|
||||
|
||||
char username[INPUT_SIZE] = {0};
|
||||
char password[INPUT_SIZE] = {0};
|
||||
char hostname[512];
|
||||
|
||||
// we do it here to calculate the final string position
|
||||
get_updated_hostname_with_time_info(hostname);
|
||||
|
||||
char kernel_v[512];
|
||||
|
||||
{
|
||||
struct utsname u;
|
||||
uname(&u);
|
||||
char * os_name_ = "ToaruOS";
|
||||
snprintf(kernel_v, 512, "%s %s", os_name_, u.release);
|
||||
}
|
||||
|
||||
uid = 0;
|
||||
|
||||
int box_x, box_y;
|
||||
|
||||
if (CENTER_BOX_X) {
|
||||
box_x = center_x(BOX_WIDTH);
|
||||
} else if (BOX_LEFT == -1) {
|
||||
box_x = win_width - BOX_RIGHT - BOX_WIDTH;
|
||||
} else {
|
||||
box_x = BOX_LEFT;
|
||||
}
|
||||
if (CENTER_BOX_Y) {
|
||||
box_y = center_y(0) + 8;
|
||||
} else if (BOX_TOP == -1) {
|
||||
box_y = win_width - BOX_BOTTOM - BOX_HEIGHT;
|
||||
} else {
|
||||
box_y = BOX_TOP;
|
||||
}
|
||||
|
||||
int focus = 0;
|
||||
|
||||
//set_font_size(11);
|
||||
int hostname_label_left = width - 10 - draw_sdf_string_width(hostname, 14, SDF_FONT_BOLD);
|
||||
int kernel_v_label_left = 10;
|
||||
|
||||
struct text_box username_box = { (BOX_WIDTH - 170) / 2, 30, 170, 20, rgb(0,0,0), NULL, 0, 0, 0, username, "Username" };
|
||||
struct text_box password_box = { (BOX_WIDTH - 170) / 2, 58, 170, 20, rgb(0,0,0), NULL, 0, 1, 0, password, "Password" };
|
||||
|
||||
struct login_container lc = { box_x, box_y, BOX_WIDTH, BOX_HEIGHT, &username_box, &password_box, 0 };
|
||||
|
||||
username_box.parent = &lc;
|
||||
password_box.parent = &lc;
|
||||
|
||||
while (1) {
|
||||
focus = 0;
|
||||
memset(username, 0x0, INPUT_SIZE);
|
||||
memset(password, 0x0, INPUT_SIZE);
|
||||
|
||||
while (1) {
|
||||
|
||||
// update time info
|
||||
get_updated_hostname_with_time_info(hostname);
|
||||
|
||||
memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height);
|
||||
draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - LOGO_FINAL_OFFSET);
|
||||
|
||||
draw_sdf_string_shadow(ctx, hostname, 14, hostname_label_left, height - 22, rgb(255,255,255), rgb(0,0,0), 4, SDF_FONT_BOLD);
|
||||
draw_sdf_string_shadow(ctx, kernel_v, 14, kernel_v_label_left, height - 22, rgb(255,255,255), rgb(0,0,0), 4, SDF_FONT_BOLD);
|
||||
|
||||
if (focus == USERNAME_BOX) {
|
||||
username_box.is_focused = 1;
|
||||
password_box.is_focused = 0;
|
||||
} else if (focus == PASSWORD_BOX) {
|
||||
username_box.is_focused = 0;
|
||||
password_box.is_focused = 1;
|
||||
} else {
|
||||
username_box.is_focused = 0;
|
||||
password_box.is_focused = 0;
|
||||
}
|
||||
|
||||
draw_login_container(ctx, &lc);
|
||||
|
||||
flip(ctx);
|
||||
yutani_flip(y, wina);
|
||||
|
||||
struct yutani_msg_key_event kbd;
|
||||
struct yutani_msg_window_mouse_event mou;
|
||||
int msg_type = 0;
|
||||
collect_events:
|
||||
do {
|
||||
yutani_msg_t * msg = yutani_poll(y);
|
||||
switch (msg->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)msg->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN) {
|
||||
memcpy(&kbd, ke, sizeof(struct yutani_msg_key_event));
|
||||
msg_type = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)msg->data;
|
||||
memcpy(&mou, me, sizeof(struct yutani_msg_mouse_event));
|
||||
msg_type = 2;
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WELCOME:
|
||||
{
|
||||
struct yutani_msg_welcome * mw = (void*)msg->data;
|
||||
yutani_window_resize(y, wina, mw->display_width, mw->display_height);
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)msg->data;
|
||||
width = wr->width;
|
||||
height = wr->height;
|
||||
yutani_window_resize_accept(y, wina, width, height);
|
||||
reinit_graphics_yutani(ctx, wina);
|
||||
yutani_window_resize_done(y, wina);
|
||||
|
||||
sprite_free(bg_sprite);
|
||||
//cairo_destroy(cr);
|
||||
//cairo_surface_destroy(cs);
|
||||
|
||||
skip_animation = 1;
|
||||
goto redo_everything;
|
||||
}
|
||||
break;
|
||||
}
|
||||
free(msg);
|
||||
} while (!msg_type);
|
||||
|
||||
if (msg_type == 1) {
|
||||
|
||||
if (kbd.event.keycode == '\n') {
|
||||
if (focus == USERNAME_BOX) {
|
||||
focus = PASSWORD_BOX;
|
||||
continue;
|
||||
} else if (focus == PASSWORD_BOX) {
|
||||
break;
|
||||
} else {
|
||||
focus = USERNAME_BOX;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (kbd.event.keycode == '\t') {
|
||||
if (focus == USERNAME_BOX) {
|
||||
focus = PASSWORD_BOX;
|
||||
} else {
|
||||
focus = USERNAME_BOX;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kbd.event.key) {
|
||||
|
||||
if (!focus) {
|
||||
focus = USERNAME_BOX;
|
||||
}
|
||||
|
||||
if (focus == USERNAME_BOX) {
|
||||
buffer_put(username, kbd.event.key);
|
||||
} else if (focus == PASSWORD_BOX) {
|
||||
buffer_put(password, kbd.event.key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (msg_type == 2) {
|
||||
|
||||
if ((mou.command == YUTANI_MOUSE_EVENT_DOWN
|
||||
&& mou.buttons & YUTANI_MOUSE_BUTTON_LEFT)
|
||||
|| (mou.command == YUTANI_MOUSE_EVENT_CLICK)) {
|
||||
/* Determine if we were inside of a text box */
|
||||
|
||||
if (mou.new_x >= (int)lc.x + (int)username_box.x &&
|
||||
mou.new_x <= (int)lc.x + (int)username_box.x + (int)username_box.width &&
|
||||
mou.new_y >= (int)lc.y + (int)username_box.y &&
|
||||
mou.new_y <= (int)lc.y + (int)username_box.y + (int)username_box.height) {
|
||||
/* Ensure this box is focused. */
|
||||
focus = USERNAME_BOX;
|
||||
continue;
|
||||
} else if (
|
||||
(int)mou.new_x >= (int)lc.x + (int)password_box.x &&
|
||||
(int)mou.new_x <= (int)lc.x + (int)password_box.x + (int)password_box.width &&
|
||||
(int)mou.new_y >= (int)lc.y + (int)password_box.y &&
|
||||
(int)mou.new_y <= (int)lc.y + (int)password_box.y + (int)password_box.height) {
|
||||
/* Ensure this box is focused. */
|
||||
focus = PASSWORD_BOX;
|
||||
continue;
|
||||
} else {
|
||||
focus = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
goto collect_events;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fprintf(stdout, "USER %s\n", username);
|
||||
fprintf(stdout, "PASS %s\n", password);
|
||||
fprintf(stdout, "AUTH\n");
|
||||
|
||||
char tmp[1024];
|
||||
fgets(tmp, 1024, stdin);
|
||||
if (!strcmp(tmp,"FAIL\n")) {
|
||||
lc.show_error = 1;
|
||||
continue;
|
||||
} else if (!strcmp(tmp,"SUCC\n")) {
|
||||
fprintf(stderr,"Success!\n");
|
||||
goto _success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_success:
|
||||
yutani_close(y, wina);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2015 Kevin Lange
|
||||
* Copyright (C) 2013-2015 K. Lange
|
||||
*
|
||||
* Graphical login daemon.
|
||||
*
|
||||
@ -17,17 +17,20 @@
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "lib/toaru_auth.h"
|
||||
|
||||
#include "lib/trace.h"
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/auth.h>
|
||||
#include <toaru/trace.h>
|
||||
#define TRACE_APP_NAME "glogin"
|
||||
|
||||
#undef TRACE
|
||||
#define TRACE(msg,...)
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (getuid() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Ensure a somewhat sane environment going in */
|
||||
TRACE("Graphical login starting.");
|
||||
yutani_init();
|
||||
|
||||
setenv("USER", "root", 1);
|
||||
setenv("HOME", "/", 1);
|
||||
setenv("SHELL", "/bin/sh", 1);
|
||||
@ -52,7 +55,7 @@ int main (int argc, char ** argv) {
|
||||
close(com_pipe[0]);
|
||||
close(rep_pipe[1]);
|
||||
TRACE("In client...");
|
||||
char * args[] = {"/bin/login.py", NULL};
|
||||
char * args[] = {"/bin/glogin-provider", NULL};
|
||||
execvp(args[0], args);
|
||||
TRACE("Exec failure?");
|
||||
exit(1);
|
||||
@ -67,7 +70,6 @@ int main (int argc, char ** argv) {
|
||||
while (!feof(com)) {
|
||||
char buf[1024]; /* line length? */
|
||||
char * cmd = fgets(buf, sizeof(buf), com);
|
||||
TRACE("cmd = %p", cmd);
|
||||
size_t r = strlen(cmd);
|
||||
if (cmd && r) {
|
||||
if (cmd[r-1] == '\n') {
|
||||
@ -119,12 +121,13 @@ int main (int argc, char ** argv) {
|
||||
if (!_session_pid) {
|
||||
setuid(uid);
|
||||
toaru_auth_set_vars();
|
||||
char * args[] = {"/bin/gsession", NULL};
|
||||
char * args[] = {"/bin/session", NULL};
|
||||
execvp(args[0], args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
waitpid(_session_pid, NULL, 0);
|
||||
TRACE("Session ended.");
|
||||
}
|
||||
|
||||
return 0;
|
@ -1,7 +1,7 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014-2017 Kevin Lange
|
||||
* Copyright (C) 2014-2017 K. Lange
|
||||
*
|
||||
* gsudo - graphical implementation of sudo
|
||||
*
|
||||
@ -11,16 +11,18 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib/toaru_auth.h"
|
||||
#include "lib/yutani.h"
|
||||
#include "lib/graphics.h"
|
||||
#include "lib/shmemfonts.h"
|
||||
#include <toaru/auth.h>
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/sdf.h>
|
||||
|
||||
#define FONT_SIZE_MAIN 20
|
||||
#define FONT_SIZE_PASSWD 25
|
||||
|
||||
uint32_t child = 0;
|
||||
|
||||
@ -40,7 +42,6 @@ int main(int argc, char ** argv) {
|
||||
int error = 0;
|
||||
|
||||
yutani_t * yctx = yutani_init();
|
||||
init_shmemfonts();
|
||||
|
||||
int left = (yctx->display_width - width) / 2;
|
||||
int top = (yctx->display_height - height) / 2;
|
||||
@ -50,7 +51,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
gfx_context_t * ctx = init_graphics_yutani_double_buffer(window);
|
||||
|
||||
|
||||
while (1) {
|
||||
char * username = getenv("USER");
|
||||
char * password = calloc(sizeof(char) * 1024,1);
|
||||
@ -67,27 +67,23 @@ int main(int argc, char ** argv) {
|
||||
|
||||
char prompt_message[512];
|
||||
sprintf(prompt_message, "Enter password for '%s'", username);
|
||||
set_font_size(13);
|
||||
draw_string(ctx, (width - draw_string_width(prompt_message)) / 2, 20, rgb(255, 255, 255), prompt_message);
|
||||
draw_sdf_string(ctx, (width - draw_sdf_string_width(prompt_message, FONT_SIZE_MAIN, SDF_FONT_THIN)) / 2, 20, prompt_message, FONT_SIZE_MAIN, rgb(255, 255, 255), SDF_FONT_THIN);
|
||||
|
||||
sprintf(prompt_message, "requested by %s", argv[1]);
|
||||
set_font_size(13);
|
||||
draw_string(ctx, (width - draw_string_width(prompt_message)) / 2, 190, rgb(255, 255, 255), prompt_message);
|
||||
draw_sdf_string(ctx, (width - draw_sdf_string_width(prompt_message, FONT_SIZE_MAIN, SDF_FONT_THIN)) / 2, 150, prompt_message, FONT_SIZE_MAIN, rgb(255, 255, 255), SDF_FONT_THIN);
|
||||
|
||||
if (error) {
|
||||
sprintf(prompt_message, "Try again. %d failures.", fails);
|
||||
set_font_size(13);
|
||||
draw_string(ctx, (width - draw_string_width(prompt_message)) / 2, 35, rgb(255, 0, 0), prompt_message);
|
||||
draw_sdf_string(ctx, (width - draw_sdf_string_width(prompt_message, FONT_SIZE_MAIN, SDF_FONT_THIN)) / 2, 50, prompt_message, FONT_SIZE_MAIN, rgb(255, 0, 0), SDF_FONT_THIN);
|
||||
|
||||
}
|
||||
|
||||
char password_circles[512] = {0};;
|
||||
strcpy(password_circles, "");
|
||||
for (int i = 0; i < strlen(password) && i < 512/4; ++i) {
|
||||
strcat(password_circles, "⚫");
|
||||
for (unsigned int i = 0; i < strlen(password) && i < 512/4; ++i) {
|
||||
strcat(password_circles, "\007");
|
||||
}
|
||||
set_font_size(15);
|
||||
draw_string(ctx, (width - draw_string_width(password_circles)) / 2, 100, rgb(255, 255, 255), password_circles);
|
||||
draw_sdf_string(ctx, (width - draw_sdf_string_width(password_circles, FONT_SIZE_PASSWD, SDF_FONT_THIN)) / 2, 80, password_circles, FONT_SIZE_PASSWD, rgb(255, 255, 255), SDF_FONT_THIN);
|
||||
|
||||
flip(ctx);
|
||||
yutani_flip(yctx, window);
|
||||
@ -131,9 +127,7 @@ _done:
|
||||
}
|
||||
|
||||
char ** args = &argv[1];
|
||||
int j = execvp(args[0], args);
|
||||
|
||||
return 1;
|
||||
return execvp(args[0], args);
|
||||
}
|
||||
|
||||
return 1;
|
72
apps/head.c
Normal file
72
apps/head.c
Normal file
@ -0,0 +1,72 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* head - Print the first `n` lines of a file.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int n = 10;
|
||||
int opt;
|
||||
int print_names = 0;
|
||||
int retval = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "n:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
n = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind + 1) {
|
||||
/* Multiple files */
|
||||
print_names = 1;
|
||||
}
|
||||
|
||||
if (argc == optind) {
|
||||
/* This is silly, but should work due to reasons. */
|
||||
argv[optind] = "-";
|
||||
argc++;
|
||||
}
|
||||
|
||||
for (int i = optind; i < argc; ++i) {
|
||||
FILE * f = (!strcmp(argv[i],"-")) ? stdin : fopen(argv[i],"r");
|
||||
if (!f) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
|
||||
retval = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (print_names) {
|
||||
fprintf(stdout, "==> %s <==\n", (f == stdin) ? "standard input" : argv[i]);
|
||||
}
|
||||
|
||||
int line = 1;
|
||||
|
||||
while (!feof(f)) {
|
||||
int c = fgetc(f);
|
||||
if (c >= 0) {
|
||||
fputc(c, stdout);
|
||||
|
||||
if (c == '\n') {
|
||||
line++;
|
||||
if (line > n) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (f != stdin) {
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
13
apps/hello.c
Normal file
13
apps/hello.c
Normal file
@ -0,0 +1,13 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2011~2018 K. Lange
|
||||
*
|
||||
* hello - Prints "Hello, world."
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
puts("Hello, world.");
|
||||
return 0;
|
||||
}
|
242
apps/help-browser.c
Normal file
242
apps/help-browser.c
Normal file
@ -0,0 +1,242 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* help-browser - Display documentation.
|
||||
*
|
||||
* This is a work-in-progress reimplementation of the help browser
|
||||
* from mainline ToaruOS. It is currently incomplete.
|
||||
*
|
||||
* Eventually, this should be a rich text document browser, almost
|
||||
* akin to a web browser. Right now it just says "Hello, world."
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/decorations.h>
|
||||
#include <toaru/menu.h>
|
||||
#include <toaru/sdf.h>
|
||||
|
||||
#define APPLICATION_TITLE "Help Browser"
|
||||
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * main_window;
|
||||
static gfx_context_t * ctx;
|
||||
|
||||
static int application_running = 1;
|
||||
|
||||
static gfx_context_t * contents = NULL;
|
||||
static sprite_t * contents_sprite = NULL;
|
||||
|
||||
static struct menu_bar menu_bar = {0};
|
||||
static struct menu_bar_entries menu_entries[] = {
|
||||
{"File", "file"},
|
||||
{"Go", "go"},
|
||||
{"Help", "help"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static void _menu_action_exit(struct MenuEntry * entry) {
|
||||
application_running = 0;
|
||||
}
|
||||
|
||||
static void redraw_text(void) {
|
||||
draw_sdf_string(contents, 30, 30, "Hello, world.", 16, rgb(0,0,0), SDF_FONT_THIN);
|
||||
}
|
||||
|
||||
static void reinitialize_contents(void) {
|
||||
if (contents) {
|
||||
free(contents);
|
||||
}
|
||||
|
||||
if (contents_sprite) {
|
||||
sprite_free(contents_sprite);
|
||||
}
|
||||
|
||||
/* Calculate height for current directory */
|
||||
int calculated_height = 200;
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(main_window, &bounds);
|
||||
|
||||
contents_sprite = create_sprite(main_window->width - bounds.width, calculated_height, ALPHA_EMBEDDED);
|
||||
contents = init_graphics_sprite(contents_sprite);
|
||||
|
||||
draw_fill(contents, rgb(255,255,255));
|
||||
|
||||
/* Draw file entries */
|
||||
redraw_text();
|
||||
}
|
||||
|
||||
static void redraw_window(void) {
|
||||
draw_fill(ctx, rgb(255,255,255));
|
||||
|
||||
render_decorations(main_window, ctx, APPLICATION_TITLE);
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(main_window, &bounds);
|
||||
|
||||
menu_bar.x = bounds.left_width;
|
||||
menu_bar.y = bounds.top_height;
|
||||
menu_bar.width = ctx->width - bounds.width;
|
||||
menu_bar.window = main_window;
|
||||
menu_bar_render(&menu_bar, ctx);
|
||||
|
||||
gfx_clear_clip(ctx);
|
||||
gfx_add_clip(ctx, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT, ctx->width - bounds.width, ctx->height - MENU_BAR_HEIGHT - bounds.height);
|
||||
draw_sprite(ctx, contents_sprite, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT);
|
||||
gfx_clear_clip(ctx);
|
||||
gfx_add_clip(ctx, 0, 0, ctx->width, ctx->height);
|
||||
|
||||
flip(ctx);
|
||||
yutani_flip(yctx, main_window);
|
||||
}
|
||||
|
||||
static void resize_finish(int w, int h) {
|
||||
int height_changed = (main_window->width != (unsigned int)w);
|
||||
|
||||
yutani_window_resize_accept(yctx, main_window, w, h);
|
||||
reinit_graphics_yutani(ctx, main_window);
|
||||
|
||||
if (height_changed) {
|
||||
reinitialize_contents();
|
||||
}
|
||||
|
||||
redraw_window();
|
||||
yutani_window_resize_done(yctx, main_window);
|
||||
|
||||
yutani_flip(yctx, main_window);
|
||||
}
|
||||
|
||||
static void _menu_action_navigate(struct MenuEntry * entry) {
|
||||
/* go to entry->action */
|
||||
}
|
||||
|
||||
static void _menu_action_back(struct MenuEntry * entry) {
|
||||
/* go back */
|
||||
}
|
||||
|
||||
static void _menu_action_forward(struct MenuEntry * entry) {
|
||||
/* go forward */
|
||||
}
|
||||
|
||||
static void _menu_action_about(struct MenuEntry * entry) {
|
||||
/* Show About dialog */
|
||||
char about_cmd[1024] = "\0";
|
||||
strcat(about_cmd, "about \"About Help Browser\" /usr/share/icons/48/help.bmp \"ToaruOS Help Browser\" \"(C) 2018 K. Lange\n-\nPart of ToaruOS, which is free software\nreleased under the NCSA/University of Illinois\nlicense.\n-\n%https://toaruos.org\n%https://gitlab.com/toarus\" ");
|
||||
char coords[100];
|
||||
sprintf(coords, "%d %d &", (int)main_window->x + (int)main_window->width / 2, (int)main_window->y + (int)main_window->height / 2);
|
||||
strcat(about_cmd, coords);
|
||||
system(about_cmd);
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
yctx = yutani_init();
|
||||
init_decorations();
|
||||
main_window = yutani_window_create(yctx, 640, 480);
|
||||
yutani_window_move(yctx, main_window, yctx->display_width / 2 - main_window->width / 2, yctx->display_height / 2 - main_window->height / 2);
|
||||
ctx = init_graphics_yutani_double_buffer(main_window);
|
||||
|
||||
yutani_window_advertise_icon(yctx, main_window, APPLICATION_TITLE, "help");
|
||||
|
||||
menu_bar.entries = menu_entries;
|
||||
menu_bar.redraw_callback = redraw_window;
|
||||
|
||||
menu_bar.set = menu_set_create();
|
||||
|
||||
struct MenuList * m = menu_create(); /* File */
|
||||
menu_insert(m, menu_create_normal("exit",NULL,"Exit", _menu_action_exit));
|
||||
menu_set_insert(menu_bar.set, "file", m);
|
||||
|
||||
m = menu_create(); /* Go */
|
||||
menu_insert(m, menu_create_normal("home","0_index.trt","Home",_menu_action_navigate));
|
||||
menu_insert(m, menu_create_normal("bookmark","special:contents","Topics",_menu_action_navigate));
|
||||
menu_insert(m, menu_create_separator());
|
||||
menu_insert(m, menu_create_normal("back",NULL,"Back",_menu_action_back));
|
||||
menu_insert(m, menu_create_normal("forward",NULL,"Forward",_menu_action_forward));
|
||||
menu_set_insert(menu_bar.set, "go", m);
|
||||
|
||||
m = menu_create();
|
||||
menu_insert(m, menu_create_normal("help","help_browser.trt","Contents",_menu_action_navigate));
|
||||
menu_insert(m, menu_create_separator());
|
||||
menu_insert(m, menu_create_normal("star",NULL,"About " APPLICATION_TITLE,_menu_action_about));
|
||||
menu_set_insert(menu_bar.set, "help", m);
|
||||
|
||||
reinitialize_contents();
|
||||
redraw_window();
|
||||
|
||||
while (application_running) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
while (m) {
|
||||
if (menu_process_event(yctx, m)) {
|
||||
redraw_window();
|
||||
}
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
_menu_action_exit(NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win == main_window) {
|
||||
win->focused = wf->focused;
|
||||
redraw_window();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
if (wr->wid == main_window->wid) {
|
||||
resize_finish(wr->width, wr->height);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid);
|
||||
|
||||
if (win == main_window) {
|
||||
int result = decor_handle_event(yctx, m);
|
||||
switch (result) {
|
||||
case DECOR_CLOSE:
|
||||
_menu_action_exit(NULL);
|
||||
break;
|
||||
case DECOR_RIGHT:
|
||||
/* right click in decoration, show appropriate menu */
|
||||
decor_show_default_menu(main_window, main_window->x + me->new_x, main_window->y + me->new_y);
|
||||
break;
|
||||
default:
|
||||
/* Other actions */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Menu bar */
|
||||
menu_bar_mouse_event(yctx, main_window, &menu_bar, me, me->new_x, me->new_y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_CLOSE:
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
_menu_action_exit(NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
}
|
||||
}
|
199
apps/hexify.c
Normal file
199
apps/hexify.c
Normal file
@ -0,0 +1,199 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* hexify - Convert binary to hex.
|
||||
*
|
||||
* This is based on the output of xxd.
|
||||
* Does NOT a hex-to-bin option - something to consider.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
void print_line(unsigned char * buf, unsigned int width, unsigned int sizer, unsigned int offset) {
|
||||
fprintf(stdout, "%08x: ", sizer);
|
||||
for (unsigned int i = 0; i < width; ) {
|
||||
if (i >= offset) {
|
||||
fprintf(stdout, " ");
|
||||
} else {
|
||||
fprintf(stdout, "%02x", buf[i]);
|
||||
}
|
||||
i++;
|
||||
if (i == width) break; /* in case of odd width */
|
||||
if (i >= offset) {
|
||||
fprintf(stdout, " ");
|
||||
} else {
|
||||
fprintf(stdout, "%02x ", buf[i]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
fprintf(stdout, " ");
|
||||
for (unsigned int i = 0; i < width; i++) {
|
||||
if (i >= offset) {
|
||||
fprintf(stdout, " ");
|
||||
} else {
|
||||
if (isprint(buf[i])) {
|
||||
fprintf(stdout, "%c", buf[i]);
|
||||
} else {
|
||||
fprintf(stdout, ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
static int stoih(int w, char c[w], unsigned int *out) {
|
||||
*out = 0;
|
||||
for (int i = 0; i < w; ++i) {
|
||||
(*out) <<= 4;
|
||||
if (c[i] >= '0' && c[i] <= '9') {
|
||||
*out |= (c[i] - '0');
|
||||
} else if (c[i] >= 'A' && c[i] <= 'F') {
|
||||
*out |= (c[i] - 'A' + 0xA);
|
||||
} else if (c[i] >= 'a' && c[i] <= 'f') {
|
||||
*out |= (c[i] - 'a' + 0xA);
|
||||
} else {
|
||||
*out = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
unsigned int width = 16; /* TODO make configurable */
|
||||
int opt;
|
||||
int direction = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "?w:d")) != -1) {
|
||||
switch (opt) {
|
||||
default:
|
||||
case '?':
|
||||
fprintf(stderr, "%s: convert to/from hexadecimal dump\n", argv[0]);
|
||||
return 1;
|
||||
case 'w':
|
||||
width = atoi(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
direction = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FILE * f;
|
||||
char * name;
|
||||
|
||||
if (optind < argc) {
|
||||
f = fopen(argv[optind], "r");
|
||||
name = argv[optind];
|
||||
if (!f) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
|
||||
}
|
||||
} else {
|
||||
name = "[stdin]";
|
||||
f = stdin;
|
||||
}
|
||||
|
||||
if (direction == 0) {
|
||||
/* Convert to hexadecimal */
|
||||
|
||||
unsigned int sizer = 0;
|
||||
unsigned int offset = 0;
|
||||
unsigned char buf[width];
|
||||
while (!feof(f)) {
|
||||
unsigned int r = fread(buf+offset, 1, width-offset, f);
|
||||
offset += r;
|
||||
|
||||
if (offset == width) {
|
||||
print_line(buf, width, sizer, offset);
|
||||
offset = 0;
|
||||
sizer += width;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset != 0) {
|
||||
print_line(buf, width, sizer, offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Convert from hexify's output format */
|
||||
unsigned int eoffset = 0;
|
||||
unsigned int lineno = 1;
|
||||
while (!feof(f)) {
|
||||
/* Read offset */
|
||||
char offset_bytes[8];
|
||||
fread(&offset_bytes, 1, 8, f);
|
||||
|
||||
/* Convert offset for verification */
|
||||
unsigned int offset;
|
||||
if (stoih(8, offset_bytes, &offset)) {
|
||||
fprintf(stderr, "%s: %s: syntax error (bad offset) on line %d\n", argv[0], name, lineno);
|
||||
fprintf(stderr, "offset bytes: %8s\n", offset_bytes);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (offset != eoffset) {
|
||||
fprintf(stderr, "%s: %s: offset mismatch on line %d\n", argv[0], name, lineno);
|
||||
fprintf(stderr, "expected 0x%x, got 0x%x\n", offset, eoffset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read ": " */
|
||||
char tmp[2];
|
||||
fread(&tmp, 1, 2, f);
|
||||
|
||||
if (tmp[0] != ':' || tmp[1] != ' ') {
|
||||
fprintf(stderr, "%s: %s: syntax error (unexpected characters after offset) on line %d\n", argv[0], name, lineno);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read [width] characters */
|
||||
for (unsigned int i = 0; i < width; ) {
|
||||
unsigned int byte = 0;
|
||||
for (unsigned int j = 0; i < width && j < 2; ++j, ++i) {
|
||||
fread(&tmp, 1, 2, f);
|
||||
if (tmp[0] == ' ' && tmp[1] == ' ') {
|
||||
/* done; return */
|
||||
return 0;
|
||||
}
|
||||
if (stoih(2, tmp, &byte)) {
|
||||
fprintf(stderr, "%s: %s: syntax error (bad byte) on line %d\n", argv[0], name, lineno);
|
||||
fprintf(stderr, "byte bytes: %2s\n", tmp);
|
||||
return 1;
|
||||
}
|
||||
fwrite(&byte, 1, 1, stdout);
|
||||
}
|
||||
/* Read space */
|
||||
fread(&tmp, 1, 1, f);
|
||||
if (tmp[0] != ' ') {
|
||||
fprintf(stderr, "%s: %s: syntax error (unexpected characters after byte) on line %d\n", argv[0], name, lineno);
|
||||
fprintf(stderr, "unexpected character: %c\n", tmp[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fread(&tmp, 1, 1, f);
|
||||
if (tmp[0] != ' ') {
|
||||
fprintf(stderr, "%s: %s: syntax error (unexpected characters after bytes) on line %d\n", argv[0], name, lineno);
|
||||
}
|
||||
|
||||
/* Read correct number of characters, plus line feed */
|
||||
char tmp2[width+2];
|
||||
fread(&tmp2, 1, width+1, f);
|
||||
tmp2[width+1] = '\0';
|
||||
if (tmp2[width] != '\n') {
|
||||
fprintf(stderr, "%s: %s: syntax error: expected end of line, got garbage on line %d\n", argv[0], name, lineno);
|
||||
fprintf(stderr, "eol data: %s\n", tmp2);
|
||||
}
|
||||
|
||||
lineno++;
|
||||
eoffset += width;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,30 +1,28 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
*/
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* hostname
|
||||
*
|
||||
* Prints or sets the system hostname.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#define ROOT_UID 0
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if ((argc > 1 && argv[1][0] == '-') || (argc < 2)) {
|
||||
char tmp[256];
|
||||
syscall_gethostname(tmp);
|
||||
char tmp[256] = {0};
|
||||
gethostname(tmp, 255);
|
||||
printf("%s\n", tmp);
|
||||
return 0;
|
||||
} else {
|
||||
if (syscall_getuid() != ROOT_UID) {
|
||||
if (getuid() != 0) {
|
||||
fprintf(stderr,"Must be root to set hostname.\n");
|
||||
return 1;
|
||||
} else {
|
||||
syscall_sethostname(argv[1]);
|
||||
sethostname(argv[1], strlen(argv[1]));
|
||||
FILE * file = fopen("/etc/hostname", "w");
|
||||
if (!file) {
|
||||
return 1;
|
235
apps/imgviewer.c
Normal file
235
apps/imgviewer.c
Normal file
@ -0,0 +1,235 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* imgviewer - Display bitmaps in a graphical window.
|
||||
*
|
||||
* This is probably the 4th time I've (re)written a version of
|
||||
* this application... This uses the libtoaru_graphics sprite
|
||||
* functionality to load images, so it will support whatever
|
||||
* that ends up supporting - which at the time of writing is
|
||||
* just bitmaps of various types.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/decorations.h>
|
||||
#include <toaru/menu.h>
|
||||
|
||||
/* Pointer to graphics memory */
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * window = NULL;
|
||||
static gfx_context_t * ctx = NULL;
|
||||
|
||||
static int decor_left_width = 0;
|
||||
static int decor_top_height = 0;
|
||||
static int decor_right_width = 0;
|
||||
static int decor_bottom_height = 0;
|
||||
static int decor_width = 0;
|
||||
static int decor_height = 0;
|
||||
|
||||
int left = 40;
|
||||
int top = 40;
|
||||
int width = 300;
|
||||
int height = 300;
|
||||
|
||||
sprite_t img = {0};
|
||||
|
||||
#define APPLICATION_TITLE "Image Viewer"
|
||||
|
||||
void usage(char * argv[]) {
|
||||
printf(
|
||||
"Image Viewer - Shows images.\n"
|
||||
"\n"
|
||||
"usage: %s \033[3mimage\033[0m\n"
|
||||
"\n"
|
||||
" -? --help \033[3mShow this help message.\033[0m\n",
|
||||
argv[0]);
|
||||
}
|
||||
|
||||
static void decors() {
|
||||
render_decorations(window, ctx, APPLICATION_TITLE);
|
||||
}
|
||||
|
||||
void redraw() {
|
||||
static double r = 0.0;
|
||||
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
GFX(ctx,x+decor_left_width,y+decor_top_height) = (((y / 10) % 2 == 0) ^ ((x / 10) % 2 == 0)) ? rgb(107,107,107) : rgb(147,147,147);
|
||||
}
|
||||
}
|
||||
|
||||
draw_sprite(ctx, &img, decor_left_width + width/2 - img.width/2, decor_top_height + height/2 - img.height/2);
|
||||
decors();
|
||||
flip(ctx);
|
||||
r += 0.02;
|
||||
}
|
||||
|
||||
void resize_finish(int w, int h) {
|
||||
yutani_window_resize_accept(yctx, window, w, h);
|
||||
reinit_graphics_yutani(ctx, window);
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(window, &bounds);
|
||||
|
||||
decor_left_width = bounds.left_width;
|
||||
decor_top_height = bounds.top_height;
|
||||
decor_right_width = bounds.right_width;
|
||||
decor_bottom_height = bounds.bottom_height;
|
||||
decor_width = bounds.width;
|
||||
decor_height = bounds.height;
|
||||
|
||||
width = w - decor_left_width - decor_right_width;
|
||||
height = h - decor_top_height - decor_bottom_height;
|
||||
|
||||
redraw();
|
||||
yutani_window_resize_done(yctx, window);
|
||||
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
static struct option long_opts[] = {
|
||||
{"help", no_argument, 0, '?'},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
if (argc > 1) {
|
||||
/* Read some arguments */
|
||||
int index, c;
|
||||
while ((c = getopt_long(argc, argv, "h", long_opts, &index)) != -1) {
|
||||
if (!c) {
|
||||
if (long_opts[index].flag == 0) {
|
||||
c = long_opts[index].val;
|
||||
}
|
||||
}
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv);
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yctx = yutani_init();
|
||||
if (!yctx) {
|
||||
fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_decorations();
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(NULL, &bounds);
|
||||
|
||||
decor_left_width = bounds.left_width;
|
||||
decor_top_height = bounds.top_height;
|
||||
decor_right_width = bounds.right_width;
|
||||
decor_bottom_height = bounds.bottom_height;
|
||||
decor_width = bounds.width;
|
||||
decor_height = bounds.height;
|
||||
|
||||
load_sprite(&img, argv[optind]);
|
||||
if (!img.width) {
|
||||
fprintf(stderr, "%s: failed to open image %s\n", argv[0], argv[optind]);
|
||||
return 1;
|
||||
}
|
||||
img.alpha = ALPHA_EMBEDDED;
|
||||
|
||||
width = img.width;
|
||||
height = img.height;
|
||||
|
||||
window = yutani_window_create(yctx, width + decor_width, height + decor_height);
|
||||
yutani_window_move(yctx, window, left, top);
|
||||
|
||||
yutani_window_advertise_icon(yctx, window, APPLICATION_TITLE, "imgviewer");
|
||||
|
||||
ctx = init_graphics_yutani_double_buffer(window);
|
||||
|
||||
redraw();
|
||||
yutani_flip(yctx, window);
|
||||
|
||||
int playing = 1;
|
||||
while (playing) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
while (m) {
|
||||
if (menu_process_event(yctx, m)) {
|
||||
/* just decorations should be fine */
|
||||
decors();
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
playing = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win && win == window) {
|
||||
win->focused = wf->focused;
|
||||
decors();
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
resize_finish(wr->width, wr->height);
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
int result = decor_handle_event(yctx, m);
|
||||
switch (result) {
|
||||
case DECOR_CLOSE:
|
||||
playing = 0;
|
||||
break;
|
||||
case DECOR_RIGHT:
|
||||
/* right click in decoration, show appropriate menu */
|
||||
decor_show_default_menu(window, window->x + me->new_x, window->y + me->new_y);
|
||||
break;
|
||||
default:
|
||||
/* Other actions */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_CLOSE:
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
playing = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
}
|
||||
|
||||
yutani_close(yctx, window);
|
||||
|
||||
return 0;
|
||||
}
|
146
apps/init.c
Normal file
146
apps/init.c
Normal file
@ -0,0 +1,146 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* init - First process.
|
||||
*
|
||||
* `init` calls startup scripts and then waits for them to complete.
|
||||
* It also waits for orphaned proceses so they can be collected.
|
||||
*
|
||||
* `init` itself is statically-linked, so minimizing libc dependencies
|
||||
* is worthwhile as it reduces to the total size of init itself, which
|
||||
* remains in memory throughout the entire lifetime of the OS.
|
||||
*
|
||||
* Startup scripts for init are stored in /etc/startup.d and are run
|
||||
* in sorted alphabetical order. It is generally recommended that these
|
||||
* startup scripts be named with numbers at the front to ensure easy
|
||||
* ordering. This system of running a set of scripts on startup is
|
||||
* somewhat similar to how sysvinit worked, but no claims of
|
||||
* compatibility are made.
|
||||
*
|
||||
* Startup scripts can be any executable binary. Shell scripts are
|
||||
* generally used to allow easy editing, but you could also use
|
||||
* a binary (even a dynamically linked one) as a startup script.
|
||||
* `init` will wait for each startup script (that is, it will wait for
|
||||
* the original process it started to exit) before running the next one.
|
||||
* So if you wish to run daemons, be sure to fork them off and then
|
||||
* exit so that the rest of the startup process can continue.
|
||||
*
|
||||
* When the last startup script finishes, `init` will reboot the system.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <wait.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define INITD_PATH "/etc/startup.d"
|
||||
|
||||
/* Initialize fd 0, 1, 2 */
|
||||
void set_console(void) {
|
||||
/* default to /dev/ttyS0 (serial COM1) */
|
||||
int _stdin = syscall_open("/dev/ttyS0", 0, 0);
|
||||
if (_stdin < 0) {
|
||||
/* if /dev/ttyS0 failed to open, fall back to /dev/null */
|
||||
syscall_open("/dev/null", 0, 0);
|
||||
syscall_open("/dev/null", 1, 0);
|
||||
syscall_open("/dev/null", 1, 0);
|
||||
} else {
|
||||
/* otherwise also use /dev/ttyS0 for stdout, stderr */
|
||||
syscall_open("/dev/ttyS0", 1, 0);
|
||||
syscall_open("/dev/ttyS0", 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run a startup script and wait for it to finish */
|
||||
int start_options(char * args[]) {
|
||||
|
||||
/* Fork child to run script */
|
||||
int cpid = syscall_fork();
|
||||
|
||||
/* Child process... */
|
||||
if (!cpid) {
|
||||
/* Pass environment from init to child */
|
||||
syscall_execve(args[0], args, environ);
|
||||
/* exec failed, exit this subprocess */
|
||||
syscall_exit(0);
|
||||
}
|
||||
|
||||
/* Wait for the child process to finish */
|
||||
int pid = 0;
|
||||
do {
|
||||
/*
|
||||
* Wait, ignoring kernel threads
|
||||
* (which also end up as children to init)
|
||||
*/
|
||||
pid = waitpid(-1, NULL, WNOKERN);
|
||||
|
||||
if (pid == -1 && errno == ECHILD) {
|
||||
/* There are no more children */
|
||||
break;
|
||||
}
|
||||
|
||||
if (pid == cpid) {
|
||||
/* The child process finished */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Continue while no error (or error was "interrupted") */
|
||||
} while ((pid > 0) || (pid == -1 && errno == EINTR));
|
||||
|
||||
return cpid;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
/* Initialize stdin/out/err */
|
||||
set_console();
|
||||
|
||||
/* Get directory listing for /etc/startup.d */
|
||||
int initd_dir = syscall_open(INITD_PATH, 0, 0);
|
||||
if (initd_dir < 0) {
|
||||
/* No init scripts; try to start getty as a fallback */
|
||||
start_options((char *[]){"/bin/getty",NULL});
|
||||
} else {
|
||||
int count = 0, i = 0, ret = 0;
|
||||
|
||||
/* Figure out how many entries we have with a dry run */
|
||||
do {
|
||||
struct dirent ent;
|
||||
ret = syscall_readdir(initd_dir, ++count, &ent);
|
||||
} while (ret > 0);
|
||||
|
||||
/* Read each directory entry */
|
||||
struct dirent entries[count];
|
||||
do {
|
||||
syscall_readdir(initd_dir, i, &entries[i]);
|
||||
i++;
|
||||
} while (i < count);
|
||||
|
||||
/* Sort the directory entries */
|
||||
int comparator(const void * c1, const void * c2) {
|
||||
const struct dirent * d1 = c1;
|
||||
const struct dirent * d2 = c2;
|
||||
return strcmp(d1->d_name, d2->d_name);
|
||||
}
|
||||
qsort(entries, count, sizeof(struct dirent), comparator);
|
||||
|
||||
/* Run scripts */
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (entries[i].d_name[0] != '.') {
|
||||
char path[256];
|
||||
sprintf(path, "/etc/startup.d/%s", entries[i].d_name);
|
||||
start_options((char *[]){path, NULL});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Self-explanatory */
|
||||
syscall_reboot();
|
||||
return 0;
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2016 Kevin Lange
|
||||
* Copyright (C) 2016 K. Lange
|
||||
*
|
||||
* insmod - Load kernel module
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <syscall.h>
|
542
apps/irc.c
Normal file
542
apps/irc.c
Normal file
@ -0,0 +1,542 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* irc - Internet Relay Chat client
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <va_list.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <sys/fswait.h>
|
||||
|
||||
#define _ITALIC "\033[3m"
|
||||
#define _END "\033[0m\n"
|
||||
|
||||
#define VERSION_STRING "0.3.0"
|
||||
|
||||
/* Theming */
|
||||
#define TIME_FMT "%02d:%02d:%02d"
|
||||
#define TIME_ARGS hr, min, sec
|
||||
|
||||
static char * nick = "toaru-user";
|
||||
static char * host = NULL;
|
||||
static char * pass = NULL;
|
||||
static unsigned short port = 6667;
|
||||
|
||||
static char * channel = NULL;
|
||||
|
||||
static int sock_fd;
|
||||
static FILE * sock_r;
|
||||
static FILE * sock_w;
|
||||
|
||||
struct color_pair {
|
||||
int fg;
|
||||
int bg;
|
||||
};
|
||||
|
||||
static void show_usage(int argc, char * argv[]) {
|
||||
fprintf(stderr,
|
||||
"irc - Terminal IRC client.\n"
|
||||
"\n"
|
||||
"usage: %s [-h] [-p port] [-n nick] host\n"
|
||||
"\n"
|
||||
" -p port " _ITALIC "Specify port to connect to" _END
|
||||
" -P pass " _ITALIC "Password for server connection" _END
|
||||
" -n nick " _ITALIC "Specify a nick to use" _END
|
||||
" -h " _ITALIC "Print this help message" _END
|
||||
"\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static struct termios old;
|
||||
|
||||
static void set_unbuffered() {
|
||||
tcgetattr(fileno(stdin), &old);
|
||||
struct termios new = old;
|
||||
new.c_lflag &= (~ICANON & ~ECHO);
|
||||
tcsetattr(fileno(stdin), TCSAFLUSH, &new);
|
||||
}
|
||||
|
||||
static void set_buffered() {
|
||||
tcsetattr(fileno(stdin), TCSAFLUSH, &old);
|
||||
}
|
||||
|
||||
static int user_color(char * user) {
|
||||
int i = 0;
|
||||
while (*user) {
|
||||
i += *user;
|
||||
user++;
|
||||
}
|
||||
i = i % 5;
|
||||
switch (i) {
|
||||
case 0: return 2;
|
||||
case 1: return 3;
|
||||
case 2: return 4;
|
||||
case 3: return 6;
|
||||
case 4: return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct color_pair irc_color_to_pair(int fg, int bg) {
|
||||
int _fg = 0;
|
||||
int _bg = 0;
|
||||
if (fg == -1) {
|
||||
_fg = -1;
|
||||
} else {
|
||||
fg = fg % 16;
|
||||
switch (fg) {
|
||||
case 0: _fg = 15; break;
|
||||
case 1: _fg = 0; break;
|
||||
case 2: _fg = 4; break;
|
||||
case 3: _fg = 2; break;
|
||||
case 4: _fg = 9; break;
|
||||
case 5: _fg = 1; break;
|
||||
case 6: _fg = 5; break;
|
||||
case 7: _fg = 3; break;
|
||||
case 8: _fg = 11; break;
|
||||
case 9: _fg = 10; break;
|
||||
case 10: _fg = 6; break;
|
||||
case 11: _fg = 14; break;
|
||||
case 12: _fg = 12; break;
|
||||
case 13: _fg = 13; break;
|
||||
case 14: _fg = 8; break;
|
||||
case 15: _fg = 7; break;
|
||||
}
|
||||
}
|
||||
if (bg == -1) {
|
||||
_bg = -1;
|
||||
} else {
|
||||
bg = bg % 16;
|
||||
switch (bg) {
|
||||
case 0: _bg = 15; break;
|
||||
case 1: _bg = 0; break;
|
||||
case 2: _bg = 4; break;
|
||||
case 3: _bg = 2; break;
|
||||
case 4: _bg = 9; break;
|
||||
case 5: _bg = 1; break;
|
||||
case 6: _bg = 5; break;
|
||||
case 7: _bg = 3; break;
|
||||
case 8: _bg = 11; break;
|
||||
case 9: _bg = 10; break;
|
||||
case 10: _bg = 6; break;
|
||||
case 11: _bg = 14; break;
|
||||
case 12: _bg = 12; break;
|
||||
case 13: _bg = 13; break;
|
||||
case 14: _bg = 8; break;
|
||||
case 15: _bg = 7; break;
|
||||
}
|
||||
}
|
||||
return (struct color_pair){_fg, _bg};
|
||||
}
|
||||
|
||||
static void get_time(int * h, int * m, int * s) {
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
struct tm *tm_struct = localtime(&rawtime);
|
||||
|
||||
*h = tm_struct->tm_hour;
|
||||
*m = tm_struct->tm_min;
|
||||
*s = tm_struct->tm_sec;
|
||||
}
|
||||
|
||||
static void print_color(struct color_pair t) {
|
||||
fprintf(stdout, "\033[");
|
||||
if (t.fg == -1) {
|
||||
fprintf(stdout,"39");
|
||||
} else if (t.fg > 15) {
|
||||
/* TODO */
|
||||
} else if (t.fg > 7) {
|
||||
fprintf(stdout,"9%d", t.fg - 8);
|
||||
} else {
|
||||
fprintf(stdout,"3%d", t.fg);
|
||||
}
|
||||
fprintf(stdout, ";");
|
||||
if (t.bg == -1) {
|
||||
fprintf(stdout, "49");
|
||||
} else if (t.bg > 15) {
|
||||
/* TODO */
|
||||
} else if (t.bg > 7) {
|
||||
fprintf(stdout,"10%d", t.bg - 8);
|
||||
} else {
|
||||
fprintf(stdout,"4%d", t.bg);
|
||||
}
|
||||
fprintf(stdout, "m");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void WRITE(const char * fmt, ...) {
|
||||
|
||||
int bold_on = 0;
|
||||
int italic_on = 0;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char * tmp;
|
||||
vasprintf(&tmp, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
struct winsize w;
|
||||
ioctl(0, TIOCGWINSZ, &w);
|
||||
fprintf(stdout,"\033[%d;1H\033[K", w.ws_row);
|
||||
|
||||
int line_feed_pending = 0;
|
||||
char * c = tmp;
|
||||
|
||||
while (*c) {
|
||||
if (*c == '\n') {
|
||||
if (line_feed_pending) {
|
||||
/* Print line feed */
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
line_feed_pending = 1;
|
||||
c++;
|
||||
continue;
|
||||
} else {
|
||||
if (line_feed_pending) {
|
||||
line_feed_pending = 0;
|
||||
/* Print line feed */
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
if (*c == 0x03) {
|
||||
c++;
|
||||
int i = -1;
|
||||
int j = -1;
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
i = (*c - '0');
|
||||
c++;
|
||||
}
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
i *= 10;
|
||||
i += (*c - '0');
|
||||
c++;
|
||||
}
|
||||
if (*c == ',') {
|
||||
c++;
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
j = (*c - '0');
|
||||
c++;
|
||||
}
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
j *= 10;
|
||||
j = (*c - '0');
|
||||
c++;
|
||||
}
|
||||
}
|
||||
struct color_pair t = irc_color_to_pair(i, j);
|
||||
print_color(t);
|
||||
continue;
|
||||
}
|
||||
if (*c == 0x02) {
|
||||
if (bold_on) {
|
||||
fprintf(stdout,"\033[22m");
|
||||
bold_on = 0;
|
||||
} else {
|
||||
fprintf(stdout,"\033[1m");
|
||||
bold_on = 1;
|
||||
}
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
if (*c == 0x16) {
|
||||
if (italic_on) {
|
||||
fprintf(stdout,"\033[23m");
|
||||
italic_on = 0;
|
||||
} else {
|
||||
fprintf(stdout,"\033[3m");
|
||||
italic_on = 1;
|
||||
}
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
if (*c == 0x0f) {
|
||||
fprintf(stdout, "\033[0m");
|
||||
c++;
|
||||
bold_on = 0;
|
||||
italic_on = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stdout, "%c", *c);
|
||||
c++;
|
||||
}
|
||||
if (line_feed_pending) {
|
||||
fprintf(stdout, "\033[0m\033[K\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void handle(char * line) {
|
||||
char * c = line;
|
||||
while (c < line + strlen(line)) {
|
||||
char * e = strstr(c, "\r\n");
|
||||
if (e > line + strlen(line)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!e) {
|
||||
/* Write c */
|
||||
WRITE(c);
|
||||
goto next;
|
||||
}
|
||||
|
||||
*e = '\0';
|
||||
|
||||
if (strstr(c, "PING") == c) {
|
||||
char * t = strstr(c, ":");
|
||||
fprintf(sock_w, "PONG %s\r\n", t);
|
||||
fflush(sock_w);
|
||||
goto next;
|
||||
}
|
||||
|
||||
char * user, * command, * channel, * message;
|
||||
|
||||
user = c;
|
||||
if (user[0] == ':') {
|
||||
user++;
|
||||
}
|
||||
|
||||
command = strstr(user, " ");
|
||||
if (!command) {
|
||||
WRITE("%s\n", user);
|
||||
goto next;
|
||||
}
|
||||
command[0] = '\0';
|
||||
command++;
|
||||
|
||||
channel = strstr(command, " ");
|
||||
if (!channel) {
|
||||
WRITE("%s %s\n", user, command);
|
||||
goto next;
|
||||
}
|
||||
channel[0] = '\0';
|
||||
channel++;
|
||||
|
||||
message = strstr(channel, " ");
|
||||
if (message) {
|
||||
message[0] = '\0';
|
||||
message++;
|
||||
if (message[0] == ':') {
|
||||
message++;
|
||||
}
|
||||
}
|
||||
|
||||
int hr, min, sec;
|
||||
get_time(&hr, &min, &sec);
|
||||
|
||||
if (!strcmp(command, "PRIVMSG")) {
|
||||
if (!message) continue;
|
||||
char * t = strstr(user, "!");
|
||||
if (t) { t[0] = '\0'; }
|
||||
t = strstr(user, "@");
|
||||
if (t) { t[0] = '\0'; }
|
||||
|
||||
if (strstr(message, "\001ACTION ") == message) {
|
||||
message = message + 8;
|
||||
char * x = strstr(message, "\001");
|
||||
if (x) *x = '\0';
|
||||
WRITE(TIME_FMT " \002* \003%d%s\003\002 %s\n", TIME_ARGS, user_color(user), user, message);
|
||||
} else {
|
||||
WRITE(TIME_FMT " \00314<\003%d%s\00314>\003 %s\n", TIME_ARGS, user_color(user), user, message);
|
||||
}
|
||||
} else if (!strcmp(command, "332")) {
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
/* Topic */
|
||||
} else if (!strcmp(command, "JOIN")) {
|
||||
char * t = strstr(user, "!");
|
||||
if (t) { t[0] = '\0'; }
|
||||
t = strstr(user, "@");
|
||||
if (t) { t[0] = '\0'; }
|
||||
if (channel[0] == ':') { channel++; }
|
||||
|
||||
WRITE(TIME_FMT " \00312-\003!\00312-\00311 %s\003 has joined \002%s\n", TIME_ARGS, user, channel);
|
||||
} else if (!strcmp(command, "PART")) {
|
||||
char * t = strstr(user, "!");
|
||||
if (t) { t[0] = '\0'; }
|
||||
t = strstr(user, "@");
|
||||
if (t) { t[0] = '\0'; }
|
||||
if (channel[0] == ':') { channel++; }
|
||||
|
||||
WRITE(TIME_FMT " \00312-\003!\00312\003-\00310 %s\003 has left \002%s\n", TIME_ARGS, user, channel);
|
||||
} else if (!strcmp(command, "372")) {
|
||||
WRITE(TIME_FMT " \00314%s\003 %s\n", TIME_ARGS, user, message ? message : "");
|
||||
} else if (!strcmp(command, "376")) {
|
||||
/* End of MOTD */
|
||||
WRITE(TIME_FMT " \00314%s (end of MOTD)\n", TIME_ARGS, user);
|
||||
} else {
|
||||
WRITE(TIME_FMT " \00310%s %s %s %s\n", TIME_ARGS, user, command, channel, message ? message : "");
|
||||
}
|
||||
|
||||
next:
|
||||
if (!e) break;
|
||||
c = e + 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void redraw_buffer(char * buf) {
|
||||
struct winsize w;
|
||||
ioctl(0, TIOCGWINSZ, &w);
|
||||
fprintf(stdout,"\033[%d;1H [%s] ", w.ws_row, channel ? channel : "(status)");
|
||||
fprintf(stdout,"%s\033[K", buf);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void handle_input(char * buf) {
|
||||
fflush(stdout);
|
||||
if (strstr(buf, "/help") == buf) {
|
||||
WRITE("[help] help text goes here\n");
|
||||
} else if (strstr(buf, "/quit") == buf) {
|
||||
char * m = strstr(buf, " "); if (m) m++;
|
||||
fprintf(sock_w, "QUIT :%s\r\n", m ? m : "https://gitlab.com/toaruos");
|
||||
fflush(sock_w);
|
||||
fprintf(stderr,"\033[0m\n");
|
||||
set_buffered();
|
||||
exit(0);
|
||||
} else if (strstr(buf,"/part") == buf) {
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Not in a channel.\n");
|
||||
return;
|
||||
}
|
||||
char * m = strstr(buf, " "); if (m) m++;
|
||||
fprintf(sock_w, "PART %s%s%s\r\n", channel, m ? " :" : "", m ? m : "");
|
||||
fflush(sock_w);
|
||||
free(channel);
|
||||
channel = NULL;
|
||||
} else if (strstr(buf,"/join ") == buf) {
|
||||
char * m = strstr(buf, " "); if (m) m++;
|
||||
fprintf(sock_w, "JOIN %s\r\n", m);
|
||||
fflush(sock_w);
|
||||
channel = strdup(m);
|
||||
} else if (strstr(buf, "/") == buf) {
|
||||
WRITE("[system] Unknown command: %s\n", buf);
|
||||
} else {
|
||||
int hr, min, sec;
|
||||
get_time(&hr, &min, &sec);
|
||||
WRITE("%02d:%02d:%02d \00314<\003\002%s\002\00314>\003 %s\n", hr, min, sec, nick, buf);
|
||||
fprintf(sock_w, "PRIVMSG %s :%s\r\n", channel, buf);
|
||||
}
|
||||
redraw_buffer("");
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
/* Option parsing */
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "?hp:n:P:")) != -1) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
nick = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
pass = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
show_usage(argc, argv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
show_usage(argc, argv);
|
||||
}
|
||||
|
||||
host = argv[optind];
|
||||
|
||||
/* Connect */
|
||||
{
|
||||
char tmphost[512];
|
||||
sprintf(tmphost, "/dev/net/%s:%d", host, port);
|
||||
sock_fd = open(tmphost, O_RDWR);
|
||||
if (sock_fd < 0) {
|
||||
fprintf(stderr, "%s: Connection failed or network not available.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
sock_r = fdopen(sock_fd, "r");
|
||||
sock_w = fdopen(sock_fd, "w");
|
||||
}
|
||||
|
||||
set_unbuffered();
|
||||
|
||||
fprintf(stdout, " - Toaru IRC v %s - \n", VERSION_STRING);
|
||||
fprintf(stdout, " Copyright 2015-2018 K. Lange\n");
|
||||
fprintf(stdout, " https://toaruos.org - https://gitlab.com/toaruos\n");
|
||||
fprintf(stdout, " \n");
|
||||
fprintf(stdout, " For help, type /help\n");
|
||||
|
||||
if (pass) {
|
||||
fprintf(sock_w, "PASS %s\r\n", pass);
|
||||
}
|
||||
fprintf(sock_w, "NICK %s\r\nUSER %s * 0 :%s\r\n", nick, nick, nick);
|
||||
fflush(sock_w);
|
||||
|
||||
int fds[] = {sock_fd, STDIN_FILENO, sock_fd};
|
||||
|
||||
char net_buf[2048];
|
||||
memset(net_buf, 0, 2048);
|
||||
int net_buf_p = 0;
|
||||
|
||||
char buf[1024] = {0};
|
||||
int buf_p = 0;
|
||||
|
||||
while (1) {
|
||||
int index = fswait2(2,fds,200);
|
||||
|
||||
if (index == 1) {
|
||||
/* stdin */
|
||||
int c = fgetc(stdin);
|
||||
if (c < 0) {
|
||||
continue;
|
||||
}
|
||||
if (c == 0x08) {
|
||||
/* Remove from buffer */
|
||||
if (buf_p) {
|
||||
buf[buf_p-1] = '\0';
|
||||
buf_p--;
|
||||
redraw_buffer(buf);
|
||||
}
|
||||
} else if (c == '\n') {
|
||||
/* Send buffer */
|
||||
handle_input(buf);
|
||||
memset(buf, 0, 1024);
|
||||
buf_p = 0;
|
||||
} else {
|
||||
/* Append buffer, or check special keys */
|
||||
buf[buf_p] = c;
|
||||
buf_p++;
|
||||
redraw_buffer(buf);
|
||||
}
|
||||
} else if (index == 0) {
|
||||
/* network */
|
||||
do {
|
||||
int c = fgetc(sock_r);
|
||||
if (c < 0) continue;
|
||||
net_buf[net_buf_p] = c;
|
||||
net_buf_p++;
|
||||
if (c == '\n' || net_buf_p == 2046) {
|
||||
handle(net_buf);
|
||||
net_buf_p = 0;
|
||||
memset(net_buf, 0, 2048);
|
||||
redraw_buffer(buf);
|
||||
}
|
||||
} while (!_fwouldblock(sock_r));
|
||||
} else {
|
||||
/* timer */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
* Julia Fractal Generator
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* julia - Julia Fractal Generator
|
||||
*
|
||||
* This is the updated windowed version of the
|
||||
* julia fractal generator demo.
|
||||
@ -11,31 +11,32 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "lib/yutani.h"
|
||||
#include "lib/graphics.h"
|
||||
#include "lib/decorations.h"
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/decorations.h>
|
||||
#include <toaru/menu.h>
|
||||
|
||||
#define DIRECT_OFFSET(x,y) ((x) + (y) * window->width)
|
||||
|
||||
/*
|
||||
* Macros make verything easier.
|
||||
*/
|
||||
#define SPRITE(sprite,x,y) sprite->bitmap[sprite->width * (y) + (x)]
|
||||
|
||||
#define GFX_(xpt, ypt) ((uint32_t *)window->buffer)[DIRECT_OFFSET(xpt+decor_left_width,ypt+decor_top_height)]
|
||||
#define GFX_(xpt, ypt) (GFX(ctx,xpt+decor_left_width,ypt+decor_top_height))
|
||||
|
||||
/* Pointer to graphics memory */
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * window = NULL;
|
||||
static gfx_context_t * ctx = NULL;
|
||||
|
||||
static int decor_left_width = 0;
|
||||
static int decor_top_height = 0;
|
||||
static int decor_right_width = 0;
|
||||
static int decor_bottom_height = 0;
|
||||
static int decor_width = 0;
|
||||
static int decor_height = 0;
|
||||
|
||||
|
||||
/* Julia fractals elements */
|
||||
float conx = -0.74; /* real part of c */
|
||||
float cony = 0.1; /* imag part of c */
|
||||
@ -159,6 +160,7 @@ void redraw() {
|
||||
newcolor = lastcolor;
|
||||
i+= 2;
|
||||
} while ( i < width );
|
||||
yutani_flip(yctx, window);
|
||||
++j;
|
||||
} while ( j < height );
|
||||
}
|
||||
@ -167,12 +169,25 @@ void resize_finish(int w, int h) {
|
||||
yutani_window_resize_accept(yctx, window, w, h);
|
||||
reinit_graphics_yutani(ctx, window);
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(window, &bounds);
|
||||
|
||||
decor_left_width = bounds.left_width;
|
||||
decor_top_height = bounds.top_height;
|
||||
decor_right_width = bounds.right_width;
|
||||
decor_bottom_height = bounds.bottom_height;
|
||||
decor_width = bounds.width;
|
||||
decor_height = bounds.height;
|
||||
|
||||
width = w - decor_left_width - decor_right_width;
|
||||
height = h - decor_top_height - decor_bottom_height;
|
||||
|
||||
draw_fill(ctx, rgb(0,0,0));
|
||||
decors();
|
||||
yutani_window_resize_done(yctx, window);
|
||||
|
||||
redraw();
|
||||
|
||||
yutani_window_resize_done(yctx, window);
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
|
||||
@ -237,9 +252,23 @@ int main(int argc, char * argv[]) {
|
||||
}
|
||||
|
||||
yctx = yutani_init();
|
||||
if (!yctx) {
|
||||
fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_decorations();
|
||||
|
||||
window = yutani_window_create(yctx, width + decor_width(), height + decor_height());
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(NULL, &bounds);
|
||||
|
||||
decor_left_width = bounds.left_width;
|
||||
decor_top_height = bounds.top_height;
|
||||
decor_right_width = bounds.right_width;
|
||||
decor_bottom_height = bounds.bottom_height;
|
||||
decor_width = bounds.width;
|
||||
decor_height = bounds.height;
|
||||
|
||||
window = yutani_window_create(yctx, width + decor_width, height + decor_height);
|
||||
yutani_window_move(yctx, window, left, top);
|
||||
|
||||
yutani_window_advertise_icon(yctx, window, "Julia Fractals", "julia");
|
||||
@ -252,7 +281,12 @@ int main(int argc, char * argv[]) {
|
||||
int playing = 1;
|
||||
while (playing) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
if (m) {
|
||||
while (m) {
|
||||
if (menu_process_event(yctx, m)) {
|
||||
/* just decorations should be fine */
|
||||
decors();
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
@ -266,7 +300,7 @@ int main(int argc, char * argv[]) {
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win) {
|
||||
if (win && win == window) {
|
||||
win->focused = wf->focused;
|
||||
decors();
|
||||
yutani_flip(yctx, window);
|
||||
@ -281,25 +315,32 @@ int main(int argc, char * argv[]) {
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
int result = decor_handle_event(yctx, m);
|
||||
switch (result) {
|
||||
case DECOR_CLOSE:
|
||||
playing = 0;
|
||||
break;
|
||||
case DECOR_RIGHT:
|
||||
/* right click in decoration, show appropriate menu */
|
||||
decor_show_default_menu(window, window->x + me->new_x, window->y + me->new_y);
|
||||
break;
|
||||
default:
|
||||
/* Other actions */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_CLOSE:
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
playing = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
free(m);
|
||||
}
|
||||
|
||||
yutani_close(yctx, window);
|
138
apps/kcmdline.c
Normal file
138
apps/kcmdline.c
Normal file
@ -0,0 +1,138 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* kcmdline - Parse /proc/cmdline usefully.
|
||||
*
|
||||
* Parses /proc/cmdline and provides an interface for querying
|
||||
* whether an argument was present, and its value if applicable.
|
||||
*
|
||||
* Also converts ASCII field separators to spaces so that cmdline
|
||||
* arguments can have spaces in them.
|
||||
*
|
||||
* Useful for shell scripts.
|
||||
*
|
||||
* TODO: This should probably be a library we can use in other
|
||||
* applications...
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <toaru/hashmap.h>
|
||||
|
||||
hashmap_t * args_map = NULL;
|
||||
|
||||
int tokenize(char * str, char * sep, char **buf) {
|
||||
char * pch_i;
|
||||
char * save_i;
|
||||
int argc = 0;
|
||||
pch_i = strtok_r(str,sep,&save_i);
|
||||
if (!pch_i) { return 0; }
|
||||
while (pch_i != NULL) {
|
||||
buf[argc] = (char *)pch_i;
|
||||
++argc;
|
||||
pch_i = strtok_r(NULL,sep,&save_i);
|
||||
}
|
||||
buf[argc] = NULL;
|
||||
return argc;
|
||||
}
|
||||
|
||||
void args_parse(char * _arg) {
|
||||
char * arg = strdup(_arg);
|
||||
char * argv[1024];
|
||||
int argc = tokenize(arg, " ", argv);
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
char * c = strdup(argv[i]);
|
||||
|
||||
char * name;
|
||||
char * value;
|
||||
|
||||
name = c;
|
||||
value = NULL;
|
||||
/* Find the first = and replace it with a null */
|
||||
char * v = c;
|
||||
while (*v) {
|
||||
if (*v == '=') {
|
||||
*v = '\0';
|
||||
v++;
|
||||
value = v;
|
||||
char * tmp = value;
|
||||
/* scan it for \037 and replace with spaces */
|
||||
while (*tmp) {
|
||||
if (*tmp == '\037') {
|
||||
*tmp = ' ';
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
goto _break;
|
||||
}
|
||||
v++;
|
||||
}
|
||||
|
||||
_break:
|
||||
hashmap_set(args_map, name, value);
|
||||
}
|
||||
|
||||
free(arg);
|
||||
}
|
||||
|
||||
void show_usage(int argc, char * argv[]) {
|
||||
printf(
|
||||
"kcmdline - query the kernel command line\n"
|
||||
"\n"
|
||||
"usage: %s -g ARG...\n"
|
||||
" %s -q ARG...\n"
|
||||
"\n"
|
||||
" -g \033[3mprint the value for the requested argument\033[0m\n"
|
||||
" -q \033[3mquery whether the requested argument is present (0 = yes)\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0], argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
/* Open */
|
||||
FILE * f = fopen("/proc/cmdline", "r");
|
||||
if (!f) return 1;
|
||||
|
||||
/* Read */
|
||||
char * cmdline = malloc(4096); /* cmdline can't be longer than that */
|
||||
memset(cmdline, 0, 4096);
|
||||
size_t size = fread(cmdline, 1, 4096, f);
|
||||
if (cmdline[size-1] == '\n') cmdline[size-1] = '\0';
|
||||
fclose(f);
|
||||
|
||||
/* Parse */
|
||||
args_map = hashmap_create(10);
|
||||
args_parse(cmdline);
|
||||
|
||||
/* Figure out what we're doing */
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?g:q:s")) != -1) {
|
||||
switch (opt) {
|
||||
case 'g':
|
||||
if (hashmap_has(args_map, optarg)) {
|
||||
char * tmp = (char*)hashmap_get(args_map, optarg);
|
||||
if (!tmp) {
|
||||
printf("%s\n", optarg); /* special case = present but not set should yield name of variable */
|
||||
} else {
|
||||
printf("%s\n", tmp);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
case 'q':
|
||||
return !hashmap_has(args_map,optarg);
|
||||
case 's':
|
||||
return size;
|
||||
case '?':
|
||||
show_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "%s\n", cmdline);
|
||||
}
|
16
apps/kdebug.c
Normal file
16
apps/kdebug.c
Normal file
@ -0,0 +1,16 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014-2018 K. Lange
|
||||
*
|
||||
* kdebug - Launch kernel shell
|
||||
*/
|
||||
#include <syscall.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
syscall_system_function(7, NULL);
|
||||
int status;
|
||||
wait(&status);
|
||||
return WEXITSTATUS(status);
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2017 Kevin Lange
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* kill
|
||||
* kill - Send a signal to a process
|
||||
*
|
||||
* Send a signal to another process
|
||||
* Supports signal names like any mature `kill` should.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -59,14 +60,14 @@ struct sig_def signals[] = {
|
||||
|
||||
void usage(char * argv[]) {
|
||||
printf(
|
||||
"kill - send a signal to another process\n"
|
||||
"%s - send a signal to another process\n"
|
||||
"\n"
|
||||
"usage: %s [-\033[3mx\033[0m] \033[3mprocess\033[0m\n"
|
||||
"\n"
|
||||
" -h --help \033[3mShow this help message.\033[0m\n"
|
||||
" -\033[3mx\033[0m \033[3mSignal number to send\033[0m\n"
|
||||
"\n",
|
||||
argv[0]);
|
||||
argv[0], argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@ -81,7 +82,7 @@ int main(int argc, char * argv[]) {
|
||||
if (argc > 2) {
|
||||
if (argv[1][0] == '-') {
|
||||
signum = -1;
|
||||
if (strlen(argv[1]+1) > 3 && !strncmp(argv[1]+1,"SIG",3)) {
|
||||
if (strlen(argv[1]+1) > 3 && strstr(argv[1]+1,"SIG") == (argv[1]+1)) {
|
||||
struct sig_def * s = signals;
|
||||
while (s->name) {
|
||||
if (!strcmp(argv[1]+4,s->name)) {
|
222
apps/killall.c
Normal file
222
apps/killall.c
Normal file
@ -0,0 +1,222 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* killall - Send signals to processes matching name
|
||||
*
|
||||
* Find processes by name and send them signals.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <getopt.h>
|
||||
|
||||
typedef struct process {
|
||||
int pid;
|
||||
int ppid;
|
||||
int tgid;
|
||||
char name[100];
|
||||
char path[200];
|
||||
} p_t;
|
||||
|
||||
#define LINE_LEN 4096
|
||||
|
||||
p_t * build_entry(struct dirent * dent) {
|
||||
char tmp[256];
|
||||
FILE * f;
|
||||
char line[LINE_LEN];
|
||||
|
||||
sprintf(tmp, "/proc/%s/status", dent->d_name);
|
||||
f = fopen(tmp, "r");
|
||||
|
||||
p_t * proc = malloc(sizeof(p_t));
|
||||
|
||||
while (fgets(line, LINE_LEN, f) != NULL) {
|
||||
char * n = strstr(line,"\n");
|
||||
if (n) { *n = '\0'; }
|
||||
char * tab = strstr(line,"\t");
|
||||
if (tab) {
|
||||
*tab = '\0';
|
||||
tab++;
|
||||
}
|
||||
if (strstr(line, "Pid:") == line) {
|
||||
proc->pid = atoi(tab);
|
||||
} else if (strstr(line, "PPid:") == line) {
|
||||
proc->ppid = atoi(tab);
|
||||
} else if (strstr(line, "Tgid:") == line) {
|
||||
proc->tgid = atoi(tab);
|
||||
} else if (strstr(line, "Name:") == line) {
|
||||
strcpy(proc->name, tab);
|
||||
} else if (strstr(line, "Path:") == line) {
|
||||
strcpy(proc->path, tab);
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(proc->name,"python") == proc->name) {
|
||||
char * name = proc->path + strlen(proc->path) - 1;
|
||||
|
||||
while (1) {
|
||||
if (*name == '/') {
|
||||
name++;
|
||||
break;
|
||||
}
|
||||
if (name == proc->name) break;
|
||||
name--;
|
||||
}
|
||||
|
||||
memcpy(proc->name, name, strlen(name)+1);
|
||||
}
|
||||
|
||||
if (proc->tgid != proc->pid) {
|
||||
char tmp[100] = {0};
|
||||
sprintf(tmp, "{%s}", proc->name);
|
||||
memcpy(proc->name, tmp, strlen(tmp)+1);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
void show_usage(int argc, char * argv[]) {
|
||||
printf(
|
||||
"killall - send signal to processes with given name\n"
|
||||
"\n"
|
||||
"usage: %s [-s SIG] name\n"
|
||||
"\n"
|
||||
" -s \033[3msignal to send\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
}
|
||||
|
||||
struct sig_def {
|
||||
int sig;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
struct sig_def signals[] = {
|
||||
{SIGHUP,"HUP"},
|
||||
{SIGINT,"INT"},
|
||||
{SIGQUIT,"QUIT"},
|
||||
{SIGILL,"ILL"},
|
||||
{SIGTRAP,"TRAP"},
|
||||
{SIGABRT,"ABRT"},
|
||||
{SIGEMT,"EMT"},
|
||||
{SIGFPE,"FPE"},
|
||||
{SIGKILL,"KILL"},
|
||||
{SIGBUS,"BUS"},
|
||||
{SIGSEGV,"SEGV"},
|
||||
{SIGSYS,"SYS"},
|
||||
{SIGPIPE,"PIPE"},
|
||||
{SIGALRM,"ALRM"},
|
||||
{SIGTERM,"TERM"},
|
||||
{SIGUSR1,"USR1"},
|
||||
{SIGUSR2,"USR2"},
|
||||
{SIGCHLD,"CHLD"},
|
||||
{SIGPWR,"PWR"},
|
||||
{SIGWINCH,"WINCH"},
|
||||
{SIGURG,"URG"},
|
||||
{SIGPOLL,"POLL"},
|
||||
{SIGSTOP,"STOP"},
|
||||
{SIGTSTP,"TSTP"},
|
||||
{SIGCONT,"CONT"},
|
||||
{SIGTTIN,"TTIN"},
|
||||
{SIGTTOUT,"TTOUT"},
|
||||
{SIGVTALRM,"VTALRM"},
|
||||
{SIGPROF,"PROF"},
|
||||
{SIGXCPU,"XCPU"},
|
||||
{SIGXFSZ,"XFSZ"},
|
||||
{SIGWAITING,"WAITING"},
|
||||
{SIGDIAF,"DIAF"},
|
||||
{SIGHATE,"HATE"},
|
||||
{SIGWINEVENT,"WINEVENT"},
|
||||
{SIGCAT,"CAT"},
|
||||
{0,NULL},
|
||||
};
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
|
||||
int signum = SIGTERM;
|
||||
|
||||
/* Open the directory */
|
||||
DIR * dirp = opendir("/proc");
|
||||
|
||||
char c;
|
||||
while ((c = getopt(argc, argv, "s:?")) != -1) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
{
|
||||
signum = -1;
|
||||
if (strlen(optarg) > 3 && strstr(optarg,"SIG") == (optarg)) {
|
||||
struct sig_def * s = signals;
|
||||
while (s->name) {
|
||||
if (!strcmp(optarg+3,s->name)) {
|
||||
signum = s->sig;
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
} else {
|
||||
if (optarg[0] < '0' || optarg[0] > '9') {
|
||||
struct sig_def * s = signals;
|
||||
while (s->name) {
|
||||
if (!strcmp(optarg,s->name)) {
|
||||
signum = s->sig;
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
} else {
|
||||
signum = atoi(optarg);
|
||||
}
|
||||
}
|
||||
if (signum == -1) {
|
||||
fprintf(stderr,"%s: %s: invalid signal specification\n",argv[0],optarg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
show_usage(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
show_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int killed_something = 0;
|
||||
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') {
|
||||
p_t * proc = build_entry(ent);
|
||||
|
||||
if (!strcmp(proc->name, argv[optind])) {
|
||||
kill(proc->pid, signum);
|
||||
killed_something = 1;
|
||||
}
|
||||
}
|
||||
ent = readdir(dirp);
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
if (!killed_something) {
|
||||
fprintf(stderr, "%s: no process found\n", argv[optind]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
61
apps/live-session.c
Normal file
61
apps/live-session.c
Normal file
@ -0,0 +1,61 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* live-session - Run live CD user session.
|
||||
*
|
||||
* Launches the general session manager as 'local', waits for the
|
||||
* session to end, then launches the login manager.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <toaru/auth.h>
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/trace.h>
|
||||
#define TRACE_APP_NAME "live-session"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int pid;
|
||||
|
||||
if (getuid() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _session_pid = fork();
|
||||
if (!_session_pid) {
|
||||
setuid(1000);
|
||||
toaru_auth_set_vars();
|
||||
|
||||
char * args[] = {"/bin/session", NULL};
|
||||
execvp(args[0], args);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dummy session for live-session prevents compositor from killing itself
|
||||
* when the main session dies the first time. */
|
||||
yutani_init();
|
||||
|
||||
do {
|
||||
pid = wait(NULL);
|
||||
} while ((pid > 0 && pid != _session_pid) || (pid == -1 && errno == EINTR));
|
||||
|
||||
TRACE("Live session has ended, launching graphical login.");
|
||||
int _glogin_pid = fork();
|
||||
if (!_glogin_pid) {
|
||||
char * args[] = {"/bin/glogin",NULL};
|
||||
execvp(args[0],args);
|
||||
system("reboot");
|
||||
}
|
||||
|
||||
do {
|
||||
pid = wait(NULL);
|
||||
} while ((pid > 0 && pid != _glogin_pid) || (pid == -1 && errno == EINTR));
|
||||
|
||||
return 0;
|
||||
}
|
@ -2,11 +2,13 @@
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2015 Mike Gerow
|
||||
* 2018 K. Lange
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const char usage[] =
|
||||
"Usage: %s [-s] TARGET NAME\n"
|
||||
@ -39,15 +41,20 @@ int main(int argc, char * argv[]) {
|
||||
|
||||
if (symlink_flag) {
|
||||
if(symlink(target, name) < 0) {
|
||||
perror("symlink");
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], name, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef link
|
||||
if (link(target, name) < 0) {
|
||||
perror("link");
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], name, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "%s: %s: hard link not supported\n", argv[0], name);
|
||||
#endif
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
32
apps/login-loop.c
Normal file
32
apps/login-loop.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* login-loop - Continuously call `login`
|
||||
*
|
||||
* Used by the VGA terminal to provide interactive login sessions.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
while (1) {
|
||||
pid_t f = fork();
|
||||
if (!f) {
|
||||
char * args[] = {
|
||||
"login",
|
||||
NULL
|
||||
};
|
||||
execvp(args[0], args);
|
||||
} else {
|
||||
int result;
|
||||
do {
|
||||
result = waitpid(f, NULL, 0);
|
||||
} while (result < 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
* Copyright (C) 2013-2014 K. Lange
|
||||
*
|
||||
* Login Service
|
||||
*
|
||||
@ -11,7 +11,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -19,10 +18,11 @@
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "lib/toaru_auth.h"
|
||||
#include <toaru/auth.h>
|
||||
|
||||
#define LINE_LEN 1024
|
||||
|
||||
@ -44,6 +44,30 @@ void sig_segv(int sig) {
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
char * user = NULL;
|
||||
int uid;
|
||||
pid_t pid, f;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "f:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
user = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (user) {
|
||||
struct passwd * pw = getpwnam(user);
|
||||
if (pw) {
|
||||
uid = pw->pw_uid;
|
||||
goto do_fork;
|
||||
} else {
|
||||
fprintf(stderr, "%s: no such user\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
system("uname -a");
|
||||
printf("\n");
|
||||
@ -53,12 +77,13 @@ int main(int argc, char ** argv) {
|
||||
signal(SIGSEGV, sig_segv);
|
||||
|
||||
while (1) {
|
||||
char * username = malloc(sizeof(char) * 1024);
|
||||
char * password = malloc(sizeof(char) * 1024);
|
||||
|
||||
char username[1024] = {0};
|
||||
char password[1024] = {0};
|
||||
|
||||
/* TODO: gethostname() */
|
||||
char _hostname[256];
|
||||
syscall_gethostname(_hostname);
|
||||
gethostname(_hostname, 255);
|
||||
|
||||
fprintf(stdout, "%s login: ", _hostname);
|
||||
fflush(stdout);
|
||||
@ -72,6 +97,11 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
username[strlen(username)-1] = '\0';
|
||||
|
||||
if (!strcmp(username, "reboot")) {
|
||||
/* Quick hack so vga text mode login can exit */
|
||||
system("reboot");
|
||||
}
|
||||
|
||||
fprintf(stdout, "password: ");
|
||||
fflush(stdout);
|
||||
|
||||
@ -95,7 +125,7 @@ int main(int argc, char ** argv) {
|
||||
tcsetattr(fileno(stdin), TCSAFLUSH, &old);
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
int uid = toaru_auth_check_pass(username, password);
|
||||
uid = toaru_auth_check_pass(username, password);
|
||||
|
||||
if (uid < 0) {
|
||||
sleep(2);
|
||||
@ -103,30 +133,31 @@ int main(int argc, char ** argv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
system("cat /etc/motd");
|
||||
|
||||
pid_t pid = getpid();
|
||||
|
||||
pid_t f = fork();
|
||||
if (getpid() != pid) {
|
||||
setuid(uid);
|
||||
toaru_auth_set_vars();
|
||||
char * args[] = {
|
||||
getenv("SHELL"),
|
||||
NULL
|
||||
};
|
||||
int i = execvp(args[0], args);
|
||||
} else {
|
||||
child = f;
|
||||
int result;
|
||||
do {
|
||||
result = waitpid(f, NULL, 0);
|
||||
} while (result < 0);
|
||||
}
|
||||
child = 0;
|
||||
free(username);
|
||||
free(password);
|
||||
break;
|
||||
}
|
||||
|
||||
system("cat /etc/motd");
|
||||
|
||||
do_fork:
|
||||
pid = getpid();
|
||||
f = fork();
|
||||
if (getpid() != pid) {
|
||||
setuid(uid);
|
||||
toaru_auth_set_vars();
|
||||
char * args[] = {
|
||||
getenv("SHELL"),
|
||||
NULL
|
||||
};
|
||||
execvp(args[0], args);
|
||||
return 1;
|
||||
} else {
|
||||
child = f;
|
||||
int result;
|
||||
do {
|
||||
result = waitpid(f, NULL, 0);
|
||||
} while (result < 0);
|
||||
}
|
||||
child = 0;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* ls
|
||||
*
|
||||
@ -15,17 +15,21 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "lib/list.h"
|
||||
#define TRACE_APP_NAME "ls"
|
||||
//#include "lib/trace.h"
|
||||
#define TRACE(...)
|
||||
|
||||
#include <toaru/list.h>
|
||||
|
||||
#define MIN_COL_SPACING 2
|
||||
|
||||
@ -49,7 +53,6 @@
|
||||
static int human_readable = 0;
|
||||
static int stdout_is_tty = 1;
|
||||
static int this_year = 0;
|
||||
static int explicit_path_set = 0;
|
||||
static int show_hidden = 0;
|
||||
static int long_mode = 0;
|
||||
static int print_dir = 0;
|
||||
@ -95,6 +98,7 @@ static int filecmp(const void * c1, const void * c2) {
|
||||
if (a == b) return strcmp(d1->name, d2->name);
|
||||
else if (a < b) return -1;
|
||||
else if (a > b) return 1;
|
||||
return 0; /* impossible ? */
|
||||
}
|
||||
|
||||
static int filecmp_notypesort(const void * c1, const void * c2) {
|
||||
@ -122,12 +126,15 @@ static void print_entry(struct tfile * file, int colwidth) {
|
||||
|
||||
static int print_username(char * _out, int uid) {
|
||||
|
||||
TRACE("getpwuid");
|
||||
struct passwd * p = getpwuid(uid);
|
||||
int out = 0;
|
||||
|
||||
if (p) {
|
||||
TRACE("p is set");
|
||||
out = sprintf(_out, "%s", p->pw_name);
|
||||
} else {
|
||||
TRACE("p is not set");
|
||||
out = sprintf(_out, "%d", uid);
|
||||
}
|
||||
|
||||
@ -139,12 +146,12 @@ static int print_username(char * _out, int uid) {
|
||||
static int print_human_readable_size(char * _out, size_t s) {
|
||||
if (s >= 1<<20) {
|
||||
size_t t = s / (1 << 20);
|
||||
return sprintf(_out, "%d.%1dM", t, (s - t * (1 << 20)) / ((1 << 20) / 10));
|
||||
return sprintf(_out, "%d.%1dM", (int)t, (int)(s - t * (1 << 20)) / ((1 << 20) / 10));
|
||||
} else if (s >= 1<<10) {
|
||||
size_t t = s / (1 << 10);
|
||||
return sprintf(_out, "%d.%1dK", t, (s - t * (1 << 10)) / ((1 << 10) / 10));
|
||||
return sprintf(_out, "%d.%1dK", (int)t, (int)(s - t * (1 << 10)) / ((1 << 10) / 10));
|
||||
} else {
|
||||
return sprintf(_out, "%d", s);
|
||||
return sprintf(_out, "%d", (int)s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,22 +160,26 @@ static void update_column_widths(int * widths, struct tfile * file) {
|
||||
int n;
|
||||
|
||||
/* Links */
|
||||
TRACE("links");
|
||||
n = sprintf(tmp, "%d", file->statbuf.st_nlink);
|
||||
if (n > widths[0]) widths[0] = n;
|
||||
|
||||
/* User */
|
||||
TRACE("user");
|
||||
n = print_username(tmp, file->statbuf.st_uid);
|
||||
if (n > widths[1]) widths[1] = n;
|
||||
|
||||
/* Group */
|
||||
TRACE("group");
|
||||
n = print_username(tmp, file->statbuf.st_gid);
|
||||
if (n > widths[2]) widths[2] = n;
|
||||
|
||||
/* File size */
|
||||
TRACE("file size");
|
||||
if (human_readable) {
|
||||
n = print_human_readable_size(tmp, file->statbuf.st_size);
|
||||
} else {
|
||||
n = sprintf(tmp, "%d", file->statbuf.st_size);
|
||||
n = sprintf(tmp, "%d", (int)file->statbuf.st_size);
|
||||
}
|
||||
if (n > widths[3]) widths[3] = n;
|
||||
}
|
||||
@ -208,11 +219,11 @@ static void print_entry_long(int * widths, struct tfile * file) {
|
||||
print_human_readable_size(tmp, file->statbuf.st_size);
|
||||
printf("%*s ", widths[3], tmp);
|
||||
} else {
|
||||
printf("%*d ", widths[3], file->statbuf.st_size);
|
||||
printf("%*d ", widths[3], (int)file->statbuf.st_size);
|
||||
}
|
||||
|
||||
char time_buf[80];
|
||||
struct tm * timeinfo = localtime(&file->statbuf.st_mtime);
|
||||
struct tm * timeinfo = localtime((time_t*)&file->statbuf.st_mtime);
|
||||
if (timeinfo->tm_year == this_year) {
|
||||
strftime(time_buf, 80, "%b %d %H:%M", timeinfo);
|
||||
} else {
|
||||
@ -252,10 +263,12 @@ static void show_usage(int argc, char * argv[]) {
|
||||
|
||||
static void display_tfiles(struct tfile ** ents_array, int numents) {
|
||||
if (long_mode) {
|
||||
TRACE("long mode display, column lengths");
|
||||
int widths[4] = {0,0,0,0};
|
||||
for (int i = 0; i < numents; i++) {
|
||||
update_column_widths(widths, ents_array[i]);
|
||||
}
|
||||
TRACE("actual printing");
|
||||
for (int i = 0; i < numents; i++) {
|
||||
print_entry_long(widths, ents_array[i]);
|
||||
}
|
||||
@ -263,7 +276,7 @@ static void display_tfiles(struct tfile ** ents_array, int numents) {
|
||||
/* Determine the gridding dimensions */
|
||||
int ent_max_len = 0;
|
||||
for (int i = 0; i < numents; i++) {
|
||||
ent_max_len = MAX(ent_max_len, strlen(ents_array[i]->name));
|
||||
ent_max_len = MAX(ent_max_len, (int)strlen(ents_array[i]->name));
|
||||
}
|
||||
|
||||
int col_ext = ent_max_len + MIN_COL_SPACING;
|
||||
@ -300,6 +313,7 @@ static int display_dir(char * p) {
|
||||
/* Read the entries in the directory */
|
||||
list_t * ents_list = list_create();
|
||||
|
||||
TRACE("reading entries");
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (show_hidden || (ent->d_name[0] != '.')) {
|
||||
@ -307,9 +321,9 @@ static int display_dir(char * p) {
|
||||
|
||||
f->name = strdup(ent->d_name);
|
||||
|
||||
char tmp[strlen(p)+strlen(ent->d_name)+1];
|
||||
char tmp[strlen(p)+strlen(ent->d_name)+2];
|
||||
sprintf(tmp, "%s/%s", p, ent->d_name);
|
||||
int t = lstat(tmp, &f->statbuf);
|
||||
lstat(tmp, &f->statbuf);
|
||||
if (S_ISLNK(f->statbuf.st_mode)) {
|
||||
stat(tmp, &f->statbufl);
|
||||
f->link = malloc(4096);
|
||||
@ -322,8 +336,12 @@ static int display_dir(char * p) {
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
TRACE("copying");
|
||||
|
||||
/* Now, copy those entries into an array (for sorting) */
|
||||
|
||||
if (!ents_list->length) return 0;
|
||||
|
||||
struct tfile ** file_arr = malloc(sizeof(struct tfile *) * ents_list->length);
|
||||
int index = 0;
|
||||
foreach(node, ents_list) {
|
||||
@ -332,8 +350,10 @@ static int display_dir(char * p) {
|
||||
|
||||
list_free(ents_list);
|
||||
|
||||
TRACE("sorting");
|
||||
qsort(file_arr, index, sizeof(struct tfile *), filecmp_notypesort);
|
||||
|
||||
TRACE("displaying");
|
||||
display_tfiles(file_arr, index);
|
||||
|
||||
free(file_arr);
|
||||
@ -347,7 +367,7 @@ int main (int argc, char * argv[]) {
|
||||
char * p = ".";
|
||||
|
||||
if (argc > 1) {
|
||||
int index, c;
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "ahl?")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
@ -373,6 +393,7 @@ int main (int argc, char * argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stdout_is_tty = isatty(STDOUT_FILENO);
|
||||
|
||||
if (long_mode) {
|
||||
@ -384,6 +405,7 @@ int main (int argc, char * argv[]) {
|
||||
}
|
||||
|
||||
if (stdout_is_tty) {
|
||||
TRACE("getting display size");
|
||||
struct winsize w;
|
||||
ioctl(1, TIOCGWINSZ, &w);
|
||||
term_width = w.ws_col;
|
||||
@ -394,6 +416,7 @@ int main (int argc, char * argv[]) {
|
||||
int out = 0;
|
||||
|
||||
if (argc == 1 || optind == argc) {
|
||||
TRACE("no file to look up");
|
||||
display_dir(p);
|
||||
} else {
|
||||
list_t * files = list_create();
|
||||
@ -416,6 +439,11 @@ int main (int argc, char * argv[]) {
|
||||
else p = argv[optind];
|
||||
}
|
||||
|
||||
if (!files->length) {
|
||||
/* No valid entries */
|
||||
return out;
|
||||
}
|
||||
|
||||
struct tfile ** file_arr = malloc(sizeof(struct tfile *) * files->length);
|
||||
int index = 0;
|
||||
foreach(node, files) {
|
132
apps/lspci.c
Normal file
132
apps/lspci.c
Normal file
@ -0,0 +1,132 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* lspci - Print information about connected PCI devices.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
struct device_class {
|
||||
char * code;
|
||||
char * name;
|
||||
} device_classes[] = {
|
||||
{"0101", "IDE interface"},
|
||||
{"0102", "Floppy disk controller"},
|
||||
{"0105", "ATA controller"},
|
||||
{"0106", "SATA controller"},
|
||||
{"0200", "Ethernet controller"},
|
||||
{"0280", "Network controller"},
|
||||
{"0300", "VGA compatible controller"},
|
||||
{"0380", "Display controller"},
|
||||
{"0401", "Multimedia audio controller"},
|
||||
{"0403", "Audio device"},
|
||||
{"0480", "Multimedia controller"},
|
||||
{"0600", "Host bridge"},
|
||||
{"0601", "ISA bridge"},
|
||||
{"0604", "PCI bridge"},
|
||||
{"0680", "Bridge"},
|
||||
{"0880", "System peripheral"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static void show_usage(char * argv[]) {
|
||||
fprintf(stderr,
|
||||
"lspci - show information about PCI devices\n"
|
||||
"\n"
|
||||
"usage: %s [-n]\n"
|
||||
"\n"
|
||||
" -n \033[3mshow numeric device codes\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int numeric = 0;
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "n?")) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
show_usage(argv);
|
||||
return 0;
|
||||
case 'n':
|
||||
numeric = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FILE * f = fopen("/proc/pci","r");
|
||||
if (!f) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], "/proc/pci", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (!feof(f)) {
|
||||
char line[1024];
|
||||
fgets(line, 1024, f);
|
||||
if (line[0] == ' ') {
|
||||
/* Skip; don't care about this information */
|
||||
continue;
|
||||
}
|
||||
/* Read bus, etc. verbatim */
|
||||
char * device_bus = line;
|
||||
|
||||
/* Read device class */
|
||||
char * device_class = strstr(line," (");
|
||||
if (!device_class) {
|
||||
fprintf(stderr, "%s: parse error\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
*device_class = '\0';
|
||||
device_class++; /* space */
|
||||
device_class++; /* ( */
|
||||
|
||||
char * device_vendor = strstr(device_class, ", ");
|
||||
if (!device_vendor) {
|
||||
fprintf(stderr, "%s: parse error\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
*device_vendor = '\0';
|
||||
device_vendor++; /* comma */
|
||||
device_vendor++; /* space */
|
||||
|
||||
char * device_code = strstr(device_vendor, ":");
|
||||
if (!device_code) {
|
||||
fprintf(stderr, "%s: parse error\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
*device_code = '\0';
|
||||
device_code++; /* colon */
|
||||
|
||||
char * device_name = strstr(device_code, ") ");
|
||||
if (!device_name) {
|
||||
fprintf(stderr, "%s: parse error\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
*device_name = '\0';
|
||||
device_name++; /* ) */
|
||||
device_name++; /* space */
|
||||
|
||||
char * linefeed = strstr(device_name, "\n");
|
||||
if (linefeed) *linefeed = '\0';
|
||||
|
||||
if (numeric) {
|
||||
fprintf(stdout, "%s %s: %s:%s\n", device_bus, device_class, device_vendor, device_code);
|
||||
} else {
|
||||
for (struct device_class * c = device_classes; c->code; ++c) {
|
||||
if (!strcmp(device_class, c->code)) {
|
||||
device_class = c->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* TODO: We should also look up vendor + device names ourselves and possibly remove them from the kernel */
|
||||
fprintf(stdout, "%s %s: %s\n", device_bus, device_class, device_name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
56
apps/menu.c
Normal file
56
apps/menu.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* menu - Display a menu file and print actions
|
||||
*
|
||||
* This is a demo of the menu library, and can be used by scripts
|
||||
* to display menus. It may be broken without a root window for
|
||||
* the menus to display on, though?
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/sdf.h>
|
||||
#include <toaru/hashmap.h>
|
||||
#include <toaru/list.h>
|
||||
#include <toaru/menu.h>
|
||||
|
||||
static yutani_t * yctx;
|
||||
|
||||
static void _action_callback(struct MenuEntry * self) {
|
||||
struct MenuEntry_Normal * _self = (void *)self;
|
||||
|
||||
fprintf(stdout, "%s\n", _self->action);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
yctx = yutani_init();
|
||||
|
||||
/* Create menu from file. */
|
||||
struct MenuSet * menu = menu_set_from_description(argv[1], _action_callback);
|
||||
menu_show(menu_set_get_root(menu), yctx);
|
||||
|
||||
while (1) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
if (menu_process_event(yctx, m)) {
|
||||
return 1;
|
||||
}
|
||||
free(m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
240
apps/migrate.c
Normal file
240
apps/migrate.c
Normal file
@ -0,0 +1,240 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* migrate - Relocate root filesystem to tmpfs
|
||||
*
|
||||
* Run as part of system startup to move the ext2 root ramdisk
|
||||
* into a flexible in-memory temporary filesystem, which allows
|
||||
* file creation and editing and is much faster than the using
|
||||
* the ext2 driver against the static in-memory ramdisk.
|
||||
*
|
||||
* Based on the original Python implementation.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <toaru/trace.h>
|
||||
#include <toaru/hashmap.h>
|
||||
#define TRACE_APP_NAME "migrate"
|
||||
|
||||
#define TRACE_(...) do { if (_debug) { TRACE(__VA_ARGS__); } } while (0)
|
||||
|
||||
#define CHUNK_SIZE 4096
|
||||
|
||||
static int _debug = 0;
|
||||
|
||||
int tokenize(char * str, char * sep, char **buf) {
|
||||
char * pch_i;
|
||||
char * save_i;
|
||||
int argc = 0;
|
||||
pch_i = strtok_r(str,sep,&save_i);
|
||||
if (!pch_i) { return 0; }
|
||||
while (pch_i != NULL) {
|
||||
buf[argc] = (char *)pch_i;
|
||||
++argc;
|
||||
pch_i = strtok_r(NULL,sep,&save_i);
|
||||
}
|
||||
buf[argc] = NULL;
|
||||
return argc;
|
||||
}
|
||||
|
||||
void copy_link(char * source, char * dest, int mode, int uid, int gid) {
|
||||
//fprintf(stderr, "need to copy link %s to %s\n", source, dest);
|
||||
char tmp[1024];
|
||||
readlink(source, tmp, 1024);
|
||||
symlink(tmp, dest);
|
||||
chmod(dest, mode);
|
||||
chown(dest, uid, gid);
|
||||
}
|
||||
|
||||
void copy_file(char * source, char * dest, int mode,int uid, int gid) {
|
||||
//fprintf(stderr, "need to copy file %s to %s %x\n", source, dest, mode);
|
||||
|
||||
int d_fd = open(dest, O_WRONLY | O_CREAT, mode);
|
||||
int s_fd = open(source, O_RDONLY);
|
||||
|
||||
ssize_t length;
|
||||
|
||||
length = lseek(s_fd, 0, SEEK_END);
|
||||
lseek(s_fd, 0, SEEK_SET);
|
||||
|
||||
//fprintf(stderr, "%d bytes to copy\n", length);
|
||||
|
||||
char buf[CHUNK_SIZE];
|
||||
|
||||
while (length > 0) {
|
||||
size_t r = read(s_fd, buf, length < CHUNK_SIZE ? length : CHUNK_SIZE);
|
||||
//fprintf(stderr, "copying %d bytes from %s to %s\n", r, source, dest);
|
||||
write(d_fd, buf, r);
|
||||
length -= r;
|
||||
//fprintf(stderr, "%d bytes remaining\n", length);
|
||||
}
|
||||
|
||||
close(s_fd);
|
||||
close(d_fd);
|
||||
|
||||
chown(dest, uid, gid);
|
||||
}
|
||||
|
||||
void copy_directory(char * source, char * dest, int mode, int uid, int gid) {
|
||||
DIR * dirp = opendir(source);
|
||||
if (dirp == NULL) {
|
||||
fprintf(stderr, "Failed to copy directory %s\n", source);
|
||||
return;
|
||||
}
|
||||
|
||||
//fprintf(stderr, "Creating %s\n", dest);
|
||||
if (!strcmp(dest, "/")) {
|
||||
dest = "";
|
||||
} else {
|
||||
mkdir(dest, mode);
|
||||
}
|
||||
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (!strcmp(ent->d_name,".") || !strcmp(ent->d_name,"..")) {
|
||||
//fprintf(stderr, "Skipping %s\n", ent->d_name);
|
||||
ent = readdir(dirp);
|
||||
continue;
|
||||
}
|
||||
//fprintf(stderr, "not skipping %s/%s → %s/%s\n", source, ent->d_name, dest, ent->d_name);
|
||||
struct stat statbuf;
|
||||
char tmp[strlen(source)+strlen(ent->d_name)+2];
|
||||
sprintf(tmp, "%s/%s", source, ent->d_name);
|
||||
char tmp2[strlen(dest)+strlen(ent->d_name)+2];
|
||||
sprintf(tmp2, "%s/%s", dest, ent->d_name);
|
||||
//fprintf(stderr,"%s → %s\n", tmp, tmp2);
|
||||
lstat(tmp,&statbuf);
|
||||
if (S_ISLNK(statbuf.st_mode)) {
|
||||
copy_link(tmp, tmp2, statbuf.st_mode & 07777, statbuf.st_uid, statbuf.st_gid);
|
||||
} else if (S_ISDIR(statbuf.st_mode)) {
|
||||
copy_directory(tmp, tmp2, statbuf.st_mode & 07777, statbuf.st_uid, statbuf.st_gid);
|
||||
} else if (S_ISREG(statbuf.st_mode)) {
|
||||
copy_file(tmp, tmp2, statbuf.st_mode & 07777, statbuf.st_uid, statbuf.st_gid);
|
||||
} else {
|
||||
fprintf(stderr, " %s is not any of the required file types?\n", tmp);
|
||||
}
|
||||
ent = readdir(dirp);
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
chown(dest, uid, gid);
|
||||
}
|
||||
|
||||
void free_ramdisk(char * path) {
|
||||
int fd = open(path, O_RDONLY);
|
||||
ioctl(fd, 0x4001, NULL);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
hashmap_t * get_cmdline(void) {
|
||||
int fd = open("/proc/cmdline", O_RDONLY);
|
||||
char * out = malloc(1024);
|
||||
size_t r = read(fd, out, 1024);
|
||||
out[r] = '\0';
|
||||
if (out[r-1] == '\n') {
|
||||
out[r-1] = '\0';
|
||||
}
|
||||
|
||||
char * arg = strdup(out);
|
||||
char * argv[1024];
|
||||
int argc = tokenize(arg, " ", argv);
|
||||
|
||||
/* New let's parse the tokens into the arguments list so we can index by key */
|
||||
|
||||
hashmap_t * args = hashmap_create(10);
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
char * c = strdup(argv[i]);
|
||||
|
||||
char * name;
|
||||
char * value;
|
||||
|
||||
name = c;
|
||||
value = NULL;
|
||||
/* Find the first = and replace it with a null */
|
||||
char * v = c;
|
||||
while (*v) {
|
||||
if (*v == '=') {
|
||||
*v = '\0';
|
||||
v++;
|
||||
value = v;
|
||||
goto _break;
|
||||
}
|
||||
v++;
|
||||
}
|
||||
|
||||
_break:
|
||||
hashmap_set(args, name, value);
|
||||
}
|
||||
|
||||
free(arg);
|
||||
free(out);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
hashmap_t * cmdline = get_cmdline();
|
||||
|
||||
if (hashmap_has(cmdline, "logtoserial")) {
|
||||
_debug = 1;
|
||||
}
|
||||
|
||||
if (hashmap_has(cmdline, "root")) {
|
||||
TRACE_("Original root was %s", hashmap_get(cmdline, "root"));
|
||||
} else if (hashmap_has(cmdline,"init") && !strcmp(hashmap_get(cmdline,"init"),"/dev/ram0")) {
|
||||
TRACE_("Init is ram0, so this is probably a netboot image, going to assume root is /tmp/netboot.img");
|
||||
hashmap_set(cmdline,"root","/tmp/netboot.img");
|
||||
} else {
|
||||
TRACE_("Fatal: Don't know how to boot this. No root set.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * root = hashmap_get(cmdline,"root");
|
||||
|
||||
char * start = hashmap_get(cmdline,"_start");
|
||||
if (!start) {
|
||||
start = "";
|
||||
}
|
||||
char * root_type = hashmap_get(cmdline,"root_type");
|
||||
if (!root_type) {
|
||||
root_type = "ext2";
|
||||
}
|
||||
|
||||
char tmp[1024];
|
||||
|
||||
TRACE_("Remounting root to /dev/base");
|
||||
sprintf(tmp, "mount %s %s /dev/base", root_type, root);
|
||||
system(tmp);
|
||||
|
||||
TRACE_("Mounting tmpfs to /");
|
||||
system("mount tmpfs x /");
|
||||
|
||||
TRACE_("Migrating root...");
|
||||
copy_directory("/dev/base","/",0660,0,0);
|
||||
system("mount tmpfs x /dev/base");
|
||||
|
||||
if (strstr(root, "/dev/ram") != NULL) {
|
||||
char * tmp = strdup(root);
|
||||
char * c = strchr(tmp, ',');
|
||||
if (c) {
|
||||
*c = '\0';
|
||||
}
|
||||
TRACE_("Freeing ramdisk at %s", tmp);
|
||||
free_ramdisk(tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -10,21 +10,24 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/sound.h"
|
||||
#include <kernel/mod/sound.h>
|
||||
|
||||
static const char usage[] =
|
||||
static char usage[] =
|
||||
"%s - Control audio mixer settings.\n"
|
||||
"\n"
|
||||
"Usage %s [-d device_id] -l\n"
|
||||
" %s [-d device_id] [-k knob_id] -r\n"
|
||||
" %s [-d device_id] [-k knob_id] -w knob_value\n"
|
||||
" %s -h\n"
|
||||
" -d: Device id to address. Defaults to the main sound device.\n"
|
||||
" -l: List the knobs on a device.\n"
|
||||
" -k: Knob id to address. Defaults to the device's master knob.\n"
|
||||
" -r: Perform a read on the given device's knob. Defaults to the device's\n"
|
||||
" master knob.\n"
|
||||
" -w: Perform a write on the given device's knob. The value should be a\n"
|
||||
" float from 0.0 to 1.0.\n"
|
||||
" -h: Print this help message and exit.\n";
|
||||
"\n"
|
||||
" -d: \033[3mDevice id to address. Defaults to the main sound device.\033[0m\n"
|
||||
" -l: \033[3mList the knobs on a device.\033[0m\n"
|
||||
" -k: \033[3mKnob id to address. Defaults to the device's master knob.\033[0m\n"
|
||||
" -r: \033[3mPerform a read on the given device's knob. Defaults to the device's\n"
|
||||
" master knob.\033[0m\n"
|
||||
" -w: \033[3mPerform a write on the given device's knob. The value should be a\n"
|
||||
" float from 0.0 to 1.0.\033[0m\n"
|
||||
" -h: \033[3mPrint this help message and exit.\033[0m\n";
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
uint32_t device_id = SND_DEVICE_MAIN;
|
||||
@ -36,16 +39,16 @@ int main(int argc, char * argv[]) {
|
||||
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "d:lk:rw:h")) != -1) {
|
||||
while ((c = getopt(argc, argv, "d:lk:rw:h?")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
device_id = atol(optarg);
|
||||
device_id = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
list_flag = 1;
|
||||
break;
|
||||
case 'k':
|
||||
knob_id = atol(optarg);
|
||||
knob_id = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
read_flag = 1;
|
||||
@ -59,17 +62,16 @@ int main(int argc, char * argv[]) {
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
fprintf(stdout, usage, argv[0], argv[0], argv[0], argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
default:
|
||||
fprintf(stderr, usage, argv[0], argv[0], argv[0], argv[0]);
|
||||
fprintf(stderr, usage, argv[0], argv[0], argv[0], argv[0], argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int mixer = open("/dev/mixer", O_RDONLY);
|
||||
if (mixer < 1) {
|
||||
perror("open");
|
||||
//perror("open");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -88,7 +90,7 @@ int main(int argc, char * argv[]) {
|
||||
perror("ioctl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fprintf(stdout, "%d: %s\n", info.id, info.name);
|
||||
fprintf(stdout, "%d: %s\n", (unsigned int)info.id, info.name);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
71
apps/mkdir.c
Normal file
71
apps/mkdir.c
Normal file
@ -0,0 +1,71 @@
|
||||
/* vim:tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 K. Lange
|
||||
*
|
||||
* mkdir
|
||||
*
|
||||
* Create a directory.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int makedir(const char * dir, int mask, int parents) {
|
||||
if (!parents) return mkdir(dir,mask);
|
||||
|
||||
char * tmp = strdup(dir);
|
||||
char * c = tmp;
|
||||
while ((c = strchr(c+1,'/'))) {
|
||||
*c = '\0';
|
||||
if (mkdir(tmp,mask) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
*c = '/';
|
||||
continue;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*c = '/';
|
||||
continue;
|
||||
}
|
||||
|
||||
return mkdir(tmp, mask);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int retval = 0;
|
||||
int parents = 0;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "m:p")) != -1) {
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
fprintf(stderr, "%s: -m unsupported\n", argv[0]);
|
||||
return 1;
|
||||
case 'p':
|
||||
parents = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = optind; i < argc; ++i) {
|
||||
if (makedir(argv[i], 0777, parents) < 0) {
|
||||
if (parents && errno == EEXIST) continue;
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
|
||||
retval = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014 Kevin Lange
|
||||
* Copyright (C) 2014-2018 K. Lange
|
||||
*
|
||||
* mount
|
||||
*
|
||||
@ -9,9 +9,8 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Probably should go somewhere */
|
||||
extern int mount(char* src,char* tgt,char* typ,unsigned long,void*);
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
if (argc < 4) {
|
||||
@ -19,9 +18,11 @@ int main(int argc, char ** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mount(argv[2], argv[3], argv[1], 0, NULL) < 0) {
|
||||
perror("mount");
|
||||
return 1;
|
||||
int ret = mount(argv[2], argv[3], argv[1], 0, NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "%s: %s\n", argv[0], strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
41
apps/mv.c
Normal file
41
apps/mv.c
Normal file
@ -0,0 +1,41 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* DUMMY mv implementation that calls cp + rm
|
||||
*
|
||||
* TODO: Actually implement the plumbing for mv!
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static int call(char * args[]) {
|
||||
pid_t pid = fork();
|
||||
if (!pid) {
|
||||
execvp(args[0], args);
|
||||
exit(1);
|
||||
} else {
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "%s: missing operand\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(argv[1], argv[2])) {
|
||||
fprintf(stderr, "%s: %s and %s are the same file\n", argv[0], argv[1], argv[2]);
|
||||
return 1;
|
||||
}
|
||||
/* TODO stat magic for other ways to reference the same file */
|
||||
if (call((char *[]){"/bin/cp",argv[1],argv[2],NULL})) return 1;
|
||||
if (call((char *[]){"/bin/rm",argv[1],NULL})) return 1;
|
||||
return 0;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* vim: ts=4 sw=4 noexpandtab
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2016 Kevin Lange
|
||||
* Copyright (C) 2016-2018 K. Lange
|
||||
*
|
||||
* nslookup - perform nameserver lookups
|
||||
*
|
||||
@ -11,15 +11,14 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "lib/network.h"
|
||||
#include <sys/socket.h>
|
||||
|
||||
static void ip_ntoa(uint32_t src_addr, char * out) {
|
||||
sprintf(out, "%d.%d.%d.%d",
|
||||
(src_addr & 0xFF000000) >> 24,
|
||||
(src_addr & 0xFF0000) >> 16,
|
||||
(src_addr & 0xFF00) >> 8,
|
||||
(src_addr & 0xFF));
|
||||
(unsigned int)((src_addr & 0xFF000000) >> 24),
|
||||
(unsigned int)((src_addr & 0xFF0000) >> 16),
|
||||
(unsigned int)((src_addr & 0xFF00) >> 8),
|
||||
(unsigned int)((src_addr & 0xFF)));
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2013 Kevin Lange. All rights reserved.
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Copyright (c) 2011-2018 K. Lange. All rights reserved.
|
||||
*
|
||||
* Developed by: Kevin Lange
|
||||
* http://github.com/klange/nyancat
|
||||
* Developed by: K. Lange
|
||||
* http://gitlab.com/klange/nyancat
|
||||
* http://nyancat.dakko.us
|
||||
*
|
||||
* 40-column support by: Peter Hazenberg
|
||||
@ -35,7 +35,7 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimers in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the Association for Computing Machinery, Kevin
|
||||
* 3. Neither the names of the Association for Computing Machinery, K.
|
||||
* Lange, nor the names of its contributors may be used to endorse
|
||||
* or promote products derived from this Software without specific prior
|
||||
* written permission.
|
||||
@ -77,13 +77,13 @@
|
||||
* (it surprises some people that telnet is, really,
|
||||
* a protocol, and not just raw text transmission)
|
||||
*/
|
||||
#include "telnet.h"
|
||||
#include "nyancat/telnet.h"
|
||||
|
||||
/*
|
||||
* The animation frames are stored separately in
|
||||
* this header so they don't clutter the core source
|
||||
*/
|
||||
#include "animation.h"
|
||||
#include "nyancat/animation.h"
|
||||
|
||||
/*
|
||||
* Color palette to use for final output
|
||||
@ -193,12 +193,14 @@ void SIGINT_handler(int sig){
|
||||
* Handle the alarm which breaks us off of options
|
||||
* handling if we didn't receive a terminal
|
||||
*/
|
||||
#if 0
|
||||
void SIGALRM_handler(int sig) {
|
||||
(void)sig;
|
||||
alarm(0);
|
||||
longjmp(environment, 1);
|
||||
/* Unreachable */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle the loss of stdout, as would be the case when
|
||||
@ -239,12 +241,12 @@ void newline(int n) {
|
||||
/* We will send `n` linefeeds to the client */
|
||||
if (telnet) {
|
||||
/* Send the telnet newline sequence */
|
||||
putc('\r', stdout);
|
||||
putc(0, stdout);
|
||||
putc('\n', stdout);
|
||||
fputc('\r', stdout);
|
||||
fputc(0, stdout);
|
||||
fputc('\n', stdout);
|
||||
} else {
|
||||
/* Send a regular line feed */
|
||||
putc('\n', stdout);
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -317,6 +319,13 @@ void send_command(int cmd, int opt) {
|
||||
}
|
||||
}
|
||||
|
||||
static int _tolower(int c) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
return c - 'A' + 'a';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the usage / help text describing options
|
||||
*/
|
||||
@ -348,10 +357,10 @@ int main(int argc, char ** argv) {
|
||||
char term[1024] = {'a','n','s','i', 0};
|
||||
unsigned int k;
|
||||
int ttype;
|
||||
uint32_t option = 0, done = 0, sb_mode = 0;
|
||||
//uint32_t option = 0, done = 0, sb_mode = 0;
|
||||
/* Various pieces for the telnet communication */
|
||||
char sb[1024] = {0};
|
||||
unsigned short sb_len = 0;
|
||||
//char sb[1024] = {0};
|
||||
//unsigned short sb_len = 0;
|
||||
|
||||
/* Whether or not to show the MOTD intro */
|
||||
char show_intro = 0;
|
||||
@ -435,6 +444,7 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
(void)skip_intro;
|
||||
#if 0
|
||||
if (telnet) {
|
||||
/* Telnet mode */
|
||||
@ -577,7 +587,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
/* Convert the entire terminal string to lower case */
|
||||
for (k = 0; k < strlen(term); ++k) {
|
||||
term[k] = tolower(term[k]);
|
||||
term[k] = _tolower(term[k]);
|
||||
}
|
||||
|
||||
/* Do our terminal detection */
|
||||
@ -599,7 +609,7 @@ int main(int argc, char ** argv) {
|
||||
ttype = 3; /* Accepts LINUX mode */
|
||||
} else if (strstr(term, "vt100") && terminal_width == 40) {
|
||||
ttype = 7; /* No color support, only 40 columns */
|
||||
} else if (!strncmp(term, "st", 2)) {
|
||||
} else if (strstr(term, "st") == term) {
|
||||
ttype = 1; /* suckless simple terminal is xterm-256color-compatible */
|
||||
} else {
|
||||
ttype = 2; /* Everything else */
|
||||
@ -773,7 +783,7 @@ int main(int argc, char ** argv) {
|
||||
newline(3);
|
||||
printf(" \033[1mNyancat Telnet Server\033[0m");
|
||||
newline(2);
|
||||
printf(" written and run by \033[1;32mKevin Lange\033[1;34m @kevinlange\033[0m");
|
||||
printf(" written and run by \033[1;32mK. Lange\033[1;34m @_klange\033[0m");
|
||||
newline(2);
|
||||
printf(" If things don't look right, try:");
|
||||
newline(1);
|
||||
@ -891,7 +901,8 @@ int main(int argc, char ** argv) {
|
||||
* The \033[0m prevents the Apple ][ from flipping everything, but
|
||||
* makes the whole nyancat less bright on the vt220
|
||||
*/
|
||||
printf("\033[1;37mYou have nyaned for %0.0f seconds!\033[J\033[0m", diff);
|
||||
//printf("\033[1;37mYou have nyaned for %0.0f seconds!\033[J\033[0m", diff);
|
||||
printf("\033[1;37mYou have nyaned for %d seconds!\033[J\033[0m", (int)diff);
|
||||
}
|
||||
/* Reset the last color so that the escape sequences rewrite */
|
||||
last = 0;
|
1288
apps/panel.c
Normal file
1288
apps/panel.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,9 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014 Kevin Lange
|
||||
* Copyright (C) 2014-2018 K. Lange
|
||||
*
|
||||
* piano - Interactively make beeping noises
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@ -45,8 +48,9 @@ int main(int argc, char * argv[]) {
|
||||
set_unbuffered();
|
||||
|
||||
char c;
|
||||
while (c = fgetc(stdin)) {
|
||||
while ((c = fgetc(stdin))) {
|
||||
switch (c) {
|
||||
case 'q': return 0;
|
||||
case 'z': return 0;
|
||||
case 'a': note(10, 1308); break;
|
||||
case 'w': note(10, 1386); break;
|
120
apps/pidof.c
Normal file
120
apps/pidof.c
Normal file
@ -0,0 +1,120 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* pidof - Find and print process IDs
|
||||
*
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#include <sys/signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct process {
|
||||
int pid;
|
||||
int ppid;
|
||||
int tgid;
|
||||
char name[100];
|
||||
char path[200];
|
||||
} p_t;
|
||||
|
||||
#define LINE_LEN 4096
|
||||
|
||||
p_t * build_entry(struct dirent * dent) {
|
||||
char tmp[256];
|
||||
FILE * f;
|
||||
char line[LINE_LEN];
|
||||
|
||||
sprintf(tmp, "/proc/%s/status", dent->d_name);
|
||||
f = fopen(tmp, "r");
|
||||
|
||||
p_t * proc = malloc(sizeof(p_t));
|
||||
|
||||
while (fgets(line, LINE_LEN, f) != NULL) {
|
||||
char * n = strstr(line,"\n");
|
||||
if (n) { *n = '\0'; }
|
||||
char * tab = strstr(line,"\t");
|
||||
if (tab) {
|
||||
*tab = '\0';
|
||||
tab++;
|
||||
}
|
||||
if (strstr(line, "Pid:") == line) {
|
||||
proc->pid = atoi(tab);
|
||||
} else if (strstr(line, "PPid:") == line) {
|
||||
proc->ppid = atoi(tab);
|
||||
} else if (strstr(line, "Tgid:") == line) {
|
||||
proc->tgid = atoi(tab);
|
||||
} else if (strstr(line, "Name:") == line) {
|
||||
strcpy(proc->name, tab);
|
||||
} else if (strstr(line, "Path:") == line) {
|
||||
strcpy(proc->path, tab);
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(proc->name,"python") == proc->name) {
|
||||
char * name = proc->path + strlen(proc->path) - 1;
|
||||
|
||||
while (1) {
|
||||
if (*name == '/') {
|
||||
name++;
|
||||
break;
|
||||
}
|
||||
if (name == proc->name) break;
|
||||
name--;
|
||||
}
|
||||
|
||||
memcpy(proc->name, name, strlen(name)+1);
|
||||
}
|
||||
|
||||
if (proc->tgid != proc->pid) {
|
||||
char tmp[100] = {0};
|
||||
sprintf(tmp, "{%s}", proc->name);
|
||||
memcpy(proc->name, tmp, strlen(tmp)+1);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
|
||||
if (argc < 2) return 1;
|
||||
|
||||
int space = 0;
|
||||
|
||||
/* Open the directory */
|
||||
DIR * dirp = opendir("/proc");
|
||||
|
||||
int found_something = 0;
|
||||
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') {
|
||||
p_t * proc = build_entry(ent);
|
||||
|
||||
if (!strcmp(proc->name, argv[optind])) {
|
||||
if (space++) printf(" ");
|
||||
printf("%d", proc->pid);
|
||||
found_something = 1;
|
||||
}
|
||||
}
|
||||
ent = readdir(dirp);
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
if (!found_something) {
|
||||
return 1;
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,23 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
* test-gfx
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* plasma - Draw animated plasma in a window
|
||||
*
|
||||
* Windowed graphical test application.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <syscall.h>
|
||||
#include <wait.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include "lib/yutani.h"
|
||||
#include "lib/graphics.h"
|
||||
#include "lib/decorations.h"
|
||||
#include "lib/pthread.h"
|
||||
#include "lib/spinlock.h"
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/decorations.h>
|
||||
#include <toaru/spinlock.h>
|
||||
#include <toaru/menu.h>
|
||||
|
||||
#define dist(a,b,c,d) sqrt((double)(((a) - (c)) * ((a) - (c)) + ((b) - (d)) * ((b) - (d))))
|
||||
|
||||
@ -35,7 +36,7 @@ static int volatile draw_lock = 0;
|
||||
gfx_context_t * ctx;
|
||||
|
||||
void redraw_borders() {
|
||||
render_decorations(wina, ctx, "🔥 Plasma 🔥");
|
||||
render_decorations(wina, ctx, "Plasma");
|
||||
}
|
||||
|
||||
uint32_t hsv_to_rgb(int h, float s, float v) {
|
||||
@ -69,9 +70,6 @@ void * draw_thread(void * garbage) {
|
||||
|
||||
time += 1.0;
|
||||
|
||||
int w = win_width;
|
||||
int h = win_height;
|
||||
|
||||
spin_lock(&draw_lock);
|
||||
for (int x = 0; x < win_width; ++x) {
|
||||
for (int y = 0; y < win_height; ++y) {
|
||||
@ -86,35 +84,51 @@ void * draw_thread(void * garbage) {
|
||||
flip(ctx);
|
||||
yutani_flip(yctx, wina);
|
||||
spin_unlock(&draw_lock);
|
||||
syscall_yield();
|
||||
sched_yield();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void resize_finish(int w, int h) {
|
||||
yutani_window_resize_accept(yctx, wina, w, h);
|
||||
reinit_graphics_yutani(ctx, wina);
|
||||
|
||||
win_width = w - decor_width();
|
||||
win_height = h - decor_height();
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(wina, &bounds);
|
||||
|
||||
win_width = w - bounds.width;
|
||||
win_height = h - bounds.height;
|
||||
off_x = bounds.left_width;
|
||||
off_y = bounds.top_height;
|
||||
|
||||
yutani_window_resize_done(yctx, wina);
|
||||
}
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
yctx = yutani_init();
|
||||
if (!yctx) {
|
||||
fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
win_width = 100;
|
||||
win_height = 100;
|
||||
win_width = 300;
|
||||
win_height = 300;
|
||||
|
||||
init_decorations();
|
||||
|
||||
off_x = decor_left_width;
|
||||
off_y = decor_top_height;
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(NULL, &bounds);
|
||||
|
||||
/* Do something with a window */
|
||||
wina = yutani_window_create(yctx, win_width + decor_width(), win_height + decor_height());
|
||||
wina = yutani_window_create(yctx, win_width + bounds.width, win_height + bounds.height);
|
||||
yutani_window_move(yctx, wina, 300, 300);
|
||||
|
||||
decor_get_bounds(wina, &bounds);
|
||||
off_x = bounds.left_width;
|
||||
off_y = bounds.top_height;
|
||||
win_width = wina->width - bounds.width;
|
||||
win_height = wina->height - bounds.height;
|
||||
|
||||
ctx = init_graphics_yutani_double_buffer(wina);
|
||||
|
||||
draw_fill(ctx, rgb(0,0,0));
|
||||
@ -129,7 +143,8 @@ int main (int argc, char ** argv) {
|
||||
|
||||
while (!should_exit) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
if (m) {
|
||||
while (m) {
|
||||
menu_process_event(yctx, m);
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
@ -143,34 +158,48 @@ int main (int argc, char ** argv) {
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win) {
|
||||
if (win && win == wina) {
|
||||
win->focused = wf->focused;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_CLOSE:
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
should_exit = 1;
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
spin_lock(&draw_lock);
|
||||
resize_finish(wr->width, wr->height);
|
||||
spin_unlock(&draw_lock);
|
||||
if (wr->wid == wina->wid) {
|
||||
spin_lock(&draw_lock);
|
||||
resize_finish(wr->width, wr->height);
|
||||
spin_unlock(&draw_lock);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
if (decor_handle_event(yctx, m) == DECOR_CLOSE) {
|
||||
should_exit = 1;
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
switch (decor_handle_event(yctx, m)) {
|
||||
case DECOR_CLOSE:
|
||||
should_exit = 1;
|
||||
break;
|
||||
case DECOR_RIGHT:
|
||||
decor_show_default_menu(wina, wina->x + me->new_x, wina->y + me->new_y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
m = yutani_poll_async(yctx);
|
||||
}
|
||||
}
|
||||
|
||||
wait(NULL);
|
||||
|
||||
yutani_close(yctx, wina);
|
||||
return 0;
|
||||
}
|
@ -1,6 +1,12 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2015 Kevin Lange
|
||||
* Copyright (C) 2015-2018 K. Lange
|
||||
*
|
||||
* play - Play back PCM samples
|
||||
*
|
||||
* This needs very specifically-formatted PCM data to function
|
||||
* properly - 16-bit, signed, stereo, little endian, and 48KHz.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -31,7 +37,7 @@ int main(int argc, char * argv[]) {
|
||||
|
||||
char buf[0x1000];
|
||||
int r;
|
||||
while (r = read(song, buf, sizeof(buf))) {
|
||||
while ((r = read(song, buf, sizeof(buf)))) {
|
||||
write(spkr, buf, r);
|
||||
}
|
||||
return 0;
|
@ -1,8 +1,9 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2015 Kevin Lange
|
||||
* Copyright (C) 2015 K. Lange
|
||||
*
|
||||
* Window Manager Pong
|
||||
* pong - Window Manager Pong
|
||||
*
|
||||
* Play pong where the paddles and ball are all windows.
|
||||
* Use the WM bindings to drag the left paddle to play.
|
||||
@ -23,14 +24,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
#include "lib/yutani.h"
|
||||
#include "lib/graphics.h"
|
||||
#include "lib/pthread.h"
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
|
||||
#define GAME_PATH "/usr/share/pong"
|
||||
|
||||
@ -98,7 +96,7 @@ static uint32_t current_time() {
|
||||
uint32_t sec_diff = t.tv_sec - start_time;
|
||||
uint32_t usec_diff = t.tv_usec - start_subtime;
|
||||
|
||||
if (t.tv_usec < start_subtime) {
|
||||
if (t.tv_usec < (int)start_subtime) {
|
||||
sec_diff -= 1;
|
||||
usec_diff = (1000000 + t.tv_usec) - start_subtime;
|
||||
}
|
||||
@ -233,9 +231,13 @@ int main (int argc, char ** argv) {
|
||||
ball.vel_y = ((double)rand() / RAND_MAX) * 6.0 - 3.0;
|
||||
ball.vel_x = -10.0;
|
||||
|
||||
load_sprite_png(&left.sprite, GAME_PATH "/paddle-red.png");
|
||||
load_sprite_png(&right.sprite,GAME_PATH "/paddle-blue.png");
|
||||
load_sprite_png(&ball.sprite, GAME_PATH "/ball.png");
|
||||
fprintf(stderr, "Loading sprites...\n");
|
||||
load_sprite(&left.sprite, GAME_PATH "/paddle-red.bmp");
|
||||
left.sprite.alpha = ALPHA_EMBEDDED;
|
||||
load_sprite(&right.sprite,GAME_PATH "/paddle-blue.bmp");
|
||||
right.sprite.alpha = ALPHA_EMBEDDED;
|
||||
load_sprite(&ball.sprite, GAME_PATH "/ball.bmp");
|
||||
ball.sprite.alpha = ALPHA_EMBEDDED;
|
||||
|
||||
redraw();
|
||||
update_left();
|
||||
@ -294,7 +296,7 @@ int main (int argc, char ** argv) {
|
||||
}
|
||||
free(m);
|
||||
} else {
|
||||
syscall_yield();
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
289
apps/ps.c
Normal file
289
apps/ps.c
Normal file
@ -0,0 +1,289 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* ps
|
||||
*
|
||||
* print a list of running processes
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <toaru/list.h>
|
||||
|
||||
#define LINE_LEN 4096
|
||||
|
||||
static int show_all = 0;
|
||||
static int show_threads = 0;
|
||||
static int show_username = 0;
|
||||
static int show_mem = 0;
|
||||
static int collect_commandline = 0;
|
||||
|
||||
static int widths[] = {3,3,4,3,3,4};
|
||||
|
||||
struct process {
|
||||
int uid;
|
||||
int pid;
|
||||
int tid;
|
||||
int mem;
|
||||
int vsz;
|
||||
int shm;
|
||||
char * process;
|
||||
char * command_line;
|
||||
};
|
||||
|
||||
void print_username(int uid) {
|
||||
struct passwd * p = getpwuid(uid);
|
||||
|
||||
if (p) {
|
||||
printf("%-8s", p->pw_name);
|
||||
} else {
|
||||
printf("%-8d", uid);
|
||||
}
|
||||
|
||||
endpwent();
|
||||
}
|
||||
|
||||
struct process * process_entry(struct dirent *dent) {
|
||||
char tmp[256];
|
||||
FILE * f;
|
||||
char line[LINE_LEN];
|
||||
|
||||
int pid = 0, uid = 0, tgid = 0, mem = 0, shm = 0, vsz = 0;
|
||||
char name[100];
|
||||
|
||||
sprintf(tmp, "/proc/%s/status", dent->d_name);
|
||||
f = fopen(tmp, "r");
|
||||
|
||||
if (!f) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
line[0] = 0;
|
||||
|
||||
while (fgets(line, LINE_LEN, f) != NULL) {
|
||||
char * n = strstr(line,"\n");
|
||||
if (n) { *n = '\0'; }
|
||||
char * tab = strstr(line,"\t");
|
||||
if (tab) {
|
||||
*tab = '\0';
|
||||
tab++;
|
||||
}
|
||||
if (strstr(line, "Pid:") == line) {
|
||||
pid = atoi(tab);
|
||||
} else if (strstr(line, "Uid:") == line) {
|
||||
uid = atoi(tab);
|
||||
} else if (strstr(line, "Tgid:") == line) {
|
||||
tgid = atoi(tab);
|
||||
} else if (strstr(line, "Name:") == line) {
|
||||
strcpy(name, tab);
|
||||
} else if (strstr(line, "VmSize:") == line) {
|
||||
vsz = atoi(tab);
|
||||
} else if (strstr(line, "RssShmem:") == line) {
|
||||
shm = atoi(tab);
|
||||
} else if (strstr(line, "MemPermille:") == line) {
|
||||
mem = atoi(tab);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (!show_all) {
|
||||
/* Filter not ours */
|
||||
if (uid != getuid()) return NULL;
|
||||
}
|
||||
|
||||
if (!show_threads) {
|
||||
if (tgid != pid) return NULL;
|
||||
}
|
||||
|
||||
struct process * out = malloc(sizeof(struct process));
|
||||
out->uid = uid;
|
||||
out->pid = tgid;
|
||||
out->tid = pid;
|
||||
out->mem = mem;
|
||||
out->shm = shm;
|
||||
out->vsz = vsz;
|
||||
out->process = strdup(name);
|
||||
out->command_line = NULL;
|
||||
|
||||
char garbage[1024];
|
||||
int len;
|
||||
|
||||
if ((len = sprintf(garbage, "%d", out->pid)) > widths[0]) widths[0] = len;
|
||||
if ((len = sprintf(garbage, "%d", out->tid)) > widths[1]) widths[1] = len;
|
||||
if ((len = sprintf(garbage, "%d", out->vsz)) > widths[3]) widths[3] = len;
|
||||
if ((len = sprintf(garbage, "%d", out->shm)) > widths[4]) widths[4] = len;
|
||||
if ((len = sprintf(garbage, "%d.%01d", out->mem / 10, out->mem % 10)) > widths[5]) widths[5] = len;
|
||||
|
||||
struct passwd * p = getpwuid(out->uid);
|
||||
if (p) {
|
||||
if ((len = strlen(p->pw_name)) > widths[2]) widths[2] = len;
|
||||
} else {
|
||||
if ((len = sprintf(garbage, "%d", out->uid)) > widths[2]) widths[2] = len;
|
||||
}
|
||||
endpwent();
|
||||
|
||||
if (collect_commandline) {
|
||||
sprintf(tmp, "/proc/%s/cmdline", dent->d_name);
|
||||
f = fopen(tmp, "r");
|
||||
char foo[1024];
|
||||
int s = fread(foo, 1, 1024, f);
|
||||
if (s > 0) {
|
||||
out->command_line = malloc(s + 1);
|
||||
memset(out->command_line, 0, s + 1);
|
||||
memcpy(out->command_line, foo, s);
|
||||
|
||||
for (int i = 0; i < s; ++i) {
|
||||
if (out->command_line[i] == 30) {
|
||||
out->command_line[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void print_header(void) {
|
||||
if (show_username) {
|
||||
printf("%-*s ", widths[2], "USER");
|
||||
}
|
||||
printf("%*s ", widths[0], "PID");
|
||||
if (show_threads) {
|
||||
printf("%*s ", widths[1], "TID");
|
||||
}
|
||||
if (show_mem) {
|
||||
printf("%*s ", widths[5], "MEM%");
|
||||
printf("%*s ", widths[3], "VSZ");
|
||||
printf("%*s ", widths[4], "SHM");
|
||||
}
|
||||
printf("CMD\n");
|
||||
}
|
||||
|
||||
void print_entry(struct process * out) {
|
||||
if (show_username) {
|
||||
struct passwd * p = getpwuid(out->uid);
|
||||
if (p) {
|
||||
printf("%-*s ", widths[2], p->pw_name);
|
||||
} else {
|
||||
printf("%-*d ", widths[2], out->uid);
|
||||
}
|
||||
endpwent();
|
||||
}
|
||||
printf("%*d ", widths[0], out->pid);
|
||||
if (show_threads) {
|
||||
printf("%*d ", widths[1], out->tid);
|
||||
}
|
||||
if (show_mem) {
|
||||
char tmp[6];
|
||||
sprintf(tmp, "%*d.%01d", widths[5]-2, out->mem / 10, out->mem % 10);
|
||||
printf("%*s ", widths[5], tmp);
|
||||
printf("%*d ", widths[3], out->vsz);
|
||||
printf("%*d ", widths[4], out->shm);
|
||||
}
|
||||
if (out->command_line) {
|
||||
printf("%s\n", out->command_line);
|
||||
} else {
|
||||
printf("%s\n", out->process);
|
||||
}
|
||||
}
|
||||
|
||||
void show_usage(int argc, char * argv[]) {
|
||||
printf(
|
||||
"ps - list running processes\n"
|
||||
"\n"
|
||||
"usage: %s [-A] [format]\n"
|
||||
"\n"
|
||||
" -A \033[3mshow other users' processes\033[0m\n"
|
||||
" -T \033[3mshow threads\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n"
|
||||
" [format] supports some BSD options:\n"
|
||||
"\n"
|
||||
" a \033[3mshow full command line\033[0m\n"
|
||||
" u \033[3muse 'user-oriented' format\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
}
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
|
||||
/* Parse arguments */
|
||||
char c;
|
||||
while ((c = getopt(argc, argv, "AT?")) != -1) {
|
||||
switch (c) {
|
||||
case 'A':
|
||||
show_all = 1;
|
||||
break;
|
||||
case 'T':
|
||||
show_threads = 1;
|
||||
break;
|
||||
case '?':
|
||||
show_usage(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
char * show = argv[optind];
|
||||
while (*show) {
|
||||
switch (*show) {
|
||||
case 'u':
|
||||
show_username = 1;
|
||||
show_mem = 1;
|
||||
// fallthrough
|
||||
case 'a':
|
||||
collect_commandline = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
show++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the directory */
|
||||
DIR * dirp = opendir("/proc");
|
||||
|
||||
/* Read the entries in the directory */
|
||||
list_t * ents_list = list_create();
|
||||
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') {
|
||||
struct process * p = process_entry(ent);
|
||||
if (p) {
|
||||
list_insert(ents_list, (void *)p);
|
||||
}
|
||||
}
|
||||
|
||||
ent = readdir(dirp);
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
print_header();
|
||||
foreach(entry, ents_list) {
|
||||
print_entry(entry->value);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vim: tabstop=4
|
||||
* vim: shiftwidth=4
|
||||
* vim: noexpandtab
|
||||
*/
|
@ -1,26 +1,22 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
* pstree
|
||||
* Copyright (C) 2014-2018 K. Lange
|
||||
*
|
||||
* pstree - Display a tree of running process
|
||||
*
|
||||
* Prints running processes as a tree of
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "lib/list.h"
|
||||
#include "lib/tree.h"
|
||||
#include <toaru/list.h>
|
||||
#include <toaru/tree.h>
|
||||
|
||||
typedef struct process {
|
||||
int pid;
|
||||
@ -33,33 +29,37 @@ typedef struct process {
|
||||
#define LINE_LEN 4096
|
||||
|
||||
p_t * build_entry(struct dirent * dent) {
|
||||
char tmp[256], buf[4096];
|
||||
char tmp[256];
|
||||
FILE * f;
|
||||
int read = 1;
|
||||
char line[LINE_LEN];
|
||||
|
||||
int pid, uid;
|
||||
|
||||
snprintf(tmp, 256, "/proc/%s/status", dent->d_name);
|
||||
sprintf(tmp, "/proc/%s/status", dent->d_name);
|
||||
f = fopen(tmp, "r");
|
||||
|
||||
p_t * proc = malloc(sizeof(p_t));
|
||||
|
||||
while (fgets(line, LINE_LEN, f) != NULL) {
|
||||
char * n = strstr(line,"\n");
|
||||
if (n) { *n = '\0'; }
|
||||
char * tab = strstr(line,"\t");
|
||||
if (tab) {
|
||||
*tab = '\0';
|
||||
tab++;
|
||||
}
|
||||
if (strstr(line, "Pid:") == line) {
|
||||
sscanf(line, "%s %d", &buf, &proc->pid);
|
||||
proc->pid = atoi(tab);
|
||||
} else if (strstr(line, "PPid:") == line) {
|
||||
sscanf(line, "%s %d", &buf, &proc->ppid);
|
||||
proc->ppid = atoi(tab);
|
||||
} else if (strstr(line, "Tgid:") == line) {
|
||||
sscanf(line, "%s %d", &buf, &proc->tgid);
|
||||
proc->tgid = atoi(tab);
|
||||
} else if (strstr(line, "Name:") == line) {
|
||||
sscanf(line, "%s %s", &buf, &proc->name);
|
||||
strcpy(proc->name, tab);
|
||||
} else if (strstr(line, "Path:") == line) {
|
||||
sscanf(line, "%s %s", &buf, &proc->path);
|
||||
strcpy(proc->path, tab);
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(proc->name,"python",6)) {
|
||||
if (strstr(proc->name,"python") == proc->name) {
|
||||
char * name = proc->path + strlen(proc->path) - 1;
|
||||
|
||||
while (1) {
|
||||
@ -96,7 +96,7 @@ void print_process_tree_node(tree_node_t * node, size_t depth, int indented, int
|
||||
|
||||
p_t * proc = node->value;
|
||||
|
||||
for (int i = 0; i < strlen(proc->name)+3; ++i) {
|
||||
for (int i = 0; i < (int)strlen(proc->name)+3; ++i) {
|
||||
lines[depth+i] = 0;
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ void print_process_tree_node(tree_node_t * node, size_t depth, int indented, int
|
||||
}
|
||||
depth += 3;
|
||||
} else if (depth) {
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
for (int i = 0; i < (int)depth; ++i) {
|
||||
if (lines[i]) {
|
||||
printf("│");
|
||||
} else {
|
||||
@ -135,11 +135,12 @@ void print_process_tree_node(tree_node_t * node, size_t depth, int indented, int
|
||||
int t = 0;
|
||||
foreach(child, node->children) {
|
||||
/* Recursively print the children */
|
||||
print_process_tree_node(child->value, depth, !!(t++), ((t+1)!=node->children->length), lines);
|
||||
print_process_tree_node(child->value, depth, !!(t), ((t+1)!=(int)node->children->length), lines);
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < strlen(proc->name)+3; ++i) {
|
||||
for (int i = 0; i < (int)strlen(proc->name)+3; ++i) {
|
||||
lines[depth+i] = 0;
|
||||
}
|
||||
}
|
||||
@ -181,3 +182,4 @@ int main (int argc, char * argv[]) {
|
||||
* vim: shiftwidth=4
|
||||
* vim: noexpandtab
|
||||
*/
|
||||
|
19
apps/pwd.c
Normal file
19
apps/pwd.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* pwd - Print working directory
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
char tmp[1024];
|
||||
if (getcwd(tmp, 1023)) {
|
||||
puts(tmp);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
86
apps/qemu-display-hack.c
Normal file
86
apps/qemu-display-hack.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* qemu-display-hack - Manage display size under QEMU
|
||||
*
|
||||
* Communicates with a harness on the host running QEMU to
|
||||
* automatically update the display resolution when the
|
||||
* QEMU window size changes, similar to how VirtualBox's
|
||||
* display size changing works.
|
||||
*
|
||||
* This is automatically run at startup if the harness is
|
||||
* detected by the 90_qemu_hack.sh startup script.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <kernel/video.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
if (system("qemu-fwcfg -q opt/org.toaruos.displayharness") != 0) {
|
||||
fprintf(stderr, "%s: display harness not enabled\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = open("/dev/fb0", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "%s: failed to open framebuffer: %s\n", argv[0], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct vid_size s;
|
||||
|
||||
FILE * f = fopen("/dev/ttyS1","r+");
|
||||
if (!f) {
|
||||
fprintf(stderr, "%s: failed to open serial: %s\n", argv[0], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!fork()) {
|
||||
|
||||
while (!feof(f)) {
|
||||
char data[128];
|
||||
fgets(data, 128, f);
|
||||
|
||||
char * linefeed = strstr(data,"\n");
|
||||
if (linefeed) { *linefeed = '\0'; }
|
||||
|
||||
char * width;
|
||||
char * height;
|
||||
|
||||
width = strstr(data, " ");
|
||||
if (width) {
|
||||
*width = '\0';
|
||||
width++;
|
||||
} else {
|
||||
continue; /* bad line */
|
||||
}
|
||||
|
||||
height = strstr(width, " ");
|
||||
if (height) {
|
||||
*height = '\0';
|
||||
height++;
|
||||
} else {
|
||||
continue; /* bad line */
|
||||
}
|
||||
|
||||
s.width = atoi(width);
|
||||
s.height = atoi(height);
|
||||
|
||||
ioctl(fd, IO_VID_SET, &s);
|
||||
fprintf(f, "X");
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
187
apps/qemu-fwcfg.c
Normal file
187
apps/qemu-fwcfg.c
Normal file
@ -0,0 +1,187 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* qemu-fwcfg - Read QEMU fwcfg values.
|
||||
*
|
||||
* Provides easy access to values and files set by QEMU's -fw_cfg
|
||||
* flag. This is used by the QEMU harness, as well as the bootloader,
|
||||
* and can be used to provide files directly to the guest.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define FW_CFG_PORT_OUT 0x510
|
||||
#define FW_CFG_PORT_IN 0x511
|
||||
#define FW_CFG_SELECT_QEMU 0x0000
|
||||
#define FW_CFG_SELECT_LIST 0x0019
|
||||
|
||||
static int port_fd = -1;
|
||||
|
||||
/* outw / inb helper functions */
|
||||
static void outports(unsigned short _port, unsigned short _data) {
|
||||
lseek(port_fd, _port, SEEK_SET);
|
||||
write(port_fd, &_data, 2);
|
||||
}
|
||||
|
||||
static unsigned char inportb(unsigned short _port) {
|
||||
unsigned char out;
|
||||
lseek(port_fd, _port, SEEK_SET);
|
||||
read(port_fd, &out, 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Despite primarily emulating x86, these are all big-endian */
|
||||
static void swap_bytes(void * in, int count) {
|
||||
char * bytes = in;
|
||||
if (count == 4) {
|
||||
uint32_t * t = in;
|
||||
*t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3];
|
||||
} else if (count == 2) {
|
||||
uint16_t * t = in;
|
||||
*t = (bytes[0] << 8) | bytes[1];
|
||||
}
|
||||
}
|
||||
|
||||
/* Layout of the information returned from the fw_cfg port */
|
||||
struct fw_cfg_file {
|
||||
uint32_t size;
|
||||
uint16_t select;
|
||||
uint16_t reserved;
|
||||
char name[56];
|
||||
};
|
||||
|
||||
static int usage(char * argv[]) {
|
||||
printf(
|
||||
"Obtain QEMU fw_cfg values\n"
|
||||
"\n"
|
||||
"usage: %s [-?ln] [config name]\n"
|
||||
"\n"
|
||||
" -l \033[3mlist available config entries\033[0m\n"
|
||||
" -n \033[3mdon't print a new line after data\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sig_pass(int sig) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
uint32_t count = 0;
|
||||
uint8_t * bytes = (uint8_t *)&count;
|
||||
int found = 0;
|
||||
struct fw_cfg_file file;
|
||||
uint8_t * tmp = (uint8_t *)&file;
|
||||
|
||||
int opt = 0;
|
||||
int list = 0;
|
||||
int no_newline = 0;
|
||||
int query_quietly = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "?lnq")) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
return usage(argv);
|
||||
case 'n':
|
||||
no_newline = 1;
|
||||
break;
|
||||
case 'q':
|
||||
query_quietly = 1;
|
||||
break;
|
||||
case 'l':
|
||||
list = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc && !list) {
|
||||
return usage(argv);
|
||||
}
|
||||
|
||||
port_fd = open("/dev/port", O_RDWR);
|
||||
|
||||
if (port_fd < 0) {
|
||||
fprintf(stderr, "%s: could not open port IO device\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
signal(SIGILL, sig_pass);
|
||||
|
||||
/* First check for QEMU */
|
||||
outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_QEMU);
|
||||
if (inportb(FW_CFG_PORT_IN) != 'Q' ||
|
||||
inportb(FW_CFG_PORT_IN) != 'E' ||
|
||||
inportb(FW_CFG_PORT_IN) != 'M' ||
|
||||
inportb(FW_CFG_PORT_IN) != 'U') {
|
||||
fprintf(stderr, "%s: this doesn't seem to be qemu\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Then get the list of "files" so we can look at names */
|
||||
outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_LIST);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
bytes[i] = inportb(FW_CFG_PORT_IN);
|
||||
}
|
||||
swap_bytes(&count, sizeof(count));
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
|
||||
/* read one file entry */
|
||||
for (unsigned int j = 0; j < sizeof(struct fw_cfg_file); ++j) {
|
||||
tmp[j] = inportb(FW_CFG_PORT_IN);
|
||||
}
|
||||
|
||||
/* endian swap to get file size and selector ID */
|
||||
swap_bytes(&file.size, sizeof(file.size));
|
||||
swap_bytes(&file.select, sizeof(file.select));
|
||||
|
||||
if (list) {
|
||||
/* 0x0020 org/whatever (1234 bytes) */
|
||||
fprintf(stdout, "0x%04x %s (%d byte%s)\n", file.select, file.name, (int)file.size, file.size == 1 ? "" : "s");
|
||||
} else {
|
||||
if (!strcmp(file.name, argv[optind])) {
|
||||
/* found the requested file */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (query_quietly) {
|
||||
return !found;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
/* if we found the requested file, read it from the port */
|
||||
outports(FW_CFG_PORT_OUT, file.select);
|
||||
|
||||
for (unsigned int i = 0; i < file.size; ++i) {
|
||||
fputc(inportb(FW_CFG_PORT_IN), stdout);
|
||||
}
|
||||
|
||||
if (!no_newline) {
|
||||
fprintf(stdout, "\n");
|
||||
} else {
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
} else if (!list) {
|
||||
fprintf(stderr, "%s: config option not found\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,19 +1,20 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
* Copyright (C) 2013-2018 K Lange
|
||||
*
|
||||
* readelf - Show information about ELF objects
|
||||
*
|
||||
* This is a very custom implementation and nothing remotely
|
||||
* like the version that comes with binutils. Making it more
|
||||
* like that version might be worthwhile.
|
||||
*/
|
||||
/*
|
||||
* ToAruOS Miniature ELF Reader
|
||||
* (C) 2011 Kevin Lange
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* The Master ELF Header */
|
||||
#include "../../kernel/include/elf.h"
|
||||
#include <errno.h>
|
||||
#include <kernel/elf.h>
|
||||
|
||||
/**
|
||||
* Show usage for the readelf application.
|
||||
@ -40,12 +41,17 @@ int main(int argc, char ** argv) {
|
||||
size_t binary_size; /**< Size of the file */
|
||||
char * binary_buf; /**< Buffer to store the binary in memory */
|
||||
Elf32_Header * header; /**< ELF header */
|
||||
char * string_table; /**< The section header string table */
|
||||
char * sym_string_table; /**< The symbol string table */
|
||||
char * string_table = NULL; /**< The section header string table */
|
||||
char * sym_string_table = NULL; /**< The symbol string table */
|
||||
|
||||
/* Open the requested binary */
|
||||
binary = fopen(argv[1], "r");
|
||||
|
||||
if (!binary) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Jump to the end so we can get the size */
|
||||
fseek(binary, 0, SEEK_END);
|
||||
binary_size = ftell(binary);
|
||||
@ -117,17 +123,17 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
/* Entry point in memory */
|
||||
printf("Binary entry point in virtual memory is at 0x%x\n", header->e_entry);
|
||||
printf("Binary entry point in virtual memory is at 0x%x\n", (unsigned int)header->e_entry);
|
||||
|
||||
/* Program header table offset */
|
||||
printf("Program header table is at +0x%x and one entry is 0x%x bytes.\n"
|
||||
"There are %d total program headers.\n",
|
||||
header->e_phoff, header->e_phentsize, header->e_phnum);
|
||||
(unsigned int)header->e_phoff, (unsigned int)header->e_phentsize, (unsigned int)header->e_phnum);
|
||||
|
||||
/* Section header table offset */
|
||||
printf("Section header table is at +0x%x and one entry is 0x%x bytes.\n"
|
||||
"There are %d total section headers.\n",
|
||||
header->e_shoff, header->e_shentsize, header->e_shnum);
|
||||
(unsigned int)header->e_shoff, (unsigned int)header->e_shentsize, (unsigned int)header->e_shnum);
|
||||
|
||||
/* Read the program headers */
|
||||
printf("\033[1mProgram Headers\033[0m\n");
|
||||
@ -166,12 +172,17 @@ int main(int argc, char ** argv) {
|
||||
if (shdr->sh_type == SHT_STRTAB) {
|
||||
if (i == header->e_shstrndx) {
|
||||
string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset);
|
||||
printf("Found the section string table at 0x%x\n", shdr->sh_offset);
|
||||
printf("Found the section string table at 0x%x\n", (unsigned int)shdr->sh_offset);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!string_table) {
|
||||
printf("No string table, skipping rest of output.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find the (hopefully two) string tables */
|
||||
printf("\033[1mString Tables\033[0m\n");
|
||||
for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
|
||||
@ -183,13 +194,13 @@ int main(int argc, char ** argv) {
|
||||
if (shdr->sh_type == SHT_STRTAB) {
|
||||
if (!strcmp((char *)((uintptr_t)string_table + shdr->sh_name), ".strtab")) {
|
||||
sym_string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset);
|
||||
printf("Found the symbol string table at 0x%x\n", shdr->sh_offset);
|
||||
printf("Found the symbol string table at 0x%x\n", (unsigned int)shdr->sh_offset);
|
||||
}
|
||||
printf("Displaying string table at 0x%x\n", shdr->sh_offset);
|
||||
printf("Displaying string table at 0x%x\n", (unsigned int)shdr->sh_offset);
|
||||
char * _string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset);
|
||||
unsigned int j = 1;
|
||||
int k = 0;
|
||||
printf("%d\n", shdr->sh_size);
|
||||
printf("%d\n", (unsigned int)shdr->sh_size);
|
||||
while (j < shdr->sh_size) {
|
||||
int t = strlen((char *)((uintptr_t)_string_table + j));
|
||||
if (t) {
|
||||
@ -212,10 +223,10 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x));
|
||||
|
||||
printf("[%d] %s\n", shdr->sh_type, (char *)((uintptr_t)string_table + shdr->sh_name));
|
||||
printf("Section starts at 0x%x and is 0x%x bytes long.\n", shdr->sh_offset, shdr->sh_size);
|
||||
printf("[%d] %s\n", (unsigned int)shdr->sh_type, (char *)((uintptr_t)string_table + shdr->sh_name));
|
||||
printf("Section starts at 0x%x and is 0x%x bytes long.\n", (unsigned int)shdr->sh_offset, (unsigned int)shdr->sh_size);
|
||||
if (shdr->sh_addr) {
|
||||
printf("It should be loaded at 0x%x.\n", shdr->sh_addr);
|
||||
printf("It should be loaded at 0x%x.\n", (unsigned int)shdr->sh_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,7 +244,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
Elf32_Sym * table = (Elf32_Sym *)((uintptr_t)binary_buf + (shdr->sh_offset));
|
||||
while ((uintptr_t)table - ((uintptr_t)binary_buf + shdr->sh_offset) < shdr->sh_size) {
|
||||
printf("%s: 0x%x [0x%x]\n", (char *)((uintptr_t)sym_string_table + table->st_name), table->st_value, table->st_size);
|
||||
printf("%s: 0x%x [0x%x]\n", (char *)((uintptr_t)sym_string_table + table->st_name), (unsigned int)table->st_value, (unsigned int)table->st_size);
|
||||
table++;
|
||||
}
|
||||
}
|
||||
@ -243,8 +254,3 @@ int main(int argc, char ** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vim:noexpandtab
|
||||
* vim:tabstop=4
|
||||
* vim:shiftwidth=4
|
||||
*/
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define MAX_LINK_SIZE 4096
|
||||
|
||||
static const char usage[] =
|
||||
static char usage[] =
|
||||
"Usage: %s LINK\n";
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@ -21,7 +21,7 @@ int main(int argc, char * argv[]) {
|
||||
|
||||
char buf[MAX_LINK_SIZE];
|
||||
if (readlink(name, buf, sizeof(buf)) < 0) {
|
||||
perror("link");
|
||||
//perror("link");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fprintf(stdout, "%s\n", buf);
|
@ -1,11 +1,10 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
* reboot
|
||||
* Copyright (C) 2013-2014 K. Lange
|
||||
*
|
||||
* reboot - Reboot the system
|
||||
*
|
||||
* Reboot the system.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <syscall.h>
|
31
apps/rm.c
Normal file
31
apps/rm.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* rm - Unlink files
|
||||
*
|
||||
* TODO: Support recursive, directory removal, etc.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s FILE...\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (unlink(argv[i]) < 0) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
156
apps/sdf-demo.c
Normal file
156
apps/sdf-demo.c
Normal file
@ -0,0 +1,156 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* sdf-demo - SDF font rasterizer demo
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <toaru/yutani.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/decorations.h>
|
||||
#include <toaru/sdf.h>
|
||||
|
||||
/* Pointer to graphics memory */
|
||||
static yutani_t * yctx;
|
||||
static yutani_window_t * window = NULL;
|
||||
static gfx_context_t * ctx = NULL;
|
||||
|
||||
static int width = 500;
|
||||
static int height = 500;
|
||||
|
||||
static int left = 200;
|
||||
static int top = 200;
|
||||
|
||||
static int size = 16;
|
||||
|
||||
static void decors() {
|
||||
render_decorations(window, ctx, "SDF Demo");
|
||||
}
|
||||
|
||||
void redraw() {
|
||||
draw_fill(ctx, rgb(255,255,255));
|
||||
|
||||
decors();
|
||||
|
||||
draw_sdf_string(ctx, 30, 30, "ABCDEFGHIJKLMNOPQRSTUVWXYZABC", size, rgb(0,0,0), SDF_FONT_THIN);
|
||||
draw_sdf_string(ctx, 30, 60, "abcdefghijklmnopqrstuvwxyzabc", size, rgb(0,0,0), SDF_FONT_THIN);
|
||||
draw_sdf_string(ctx, 30, 90, "ABCDEFGHIJKLMNOPQRSTUVWXYZABC", size, rgb(0,0,0), SDF_FONT_BOLD);
|
||||
draw_sdf_string(ctx, 30,120, "abcdefghijklmnopqrstuvwxyzabc", size, rgb(0,0,0), SDF_FONT_BOLD);
|
||||
}
|
||||
|
||||
void resize_finish(int w, int h) {
|
||||
yutani_window_resize_accept(yctx, window, w, h);
|
||||
reinit_graphics_yutani(ctx, window);
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(window, &bounds);
|
||||
|
||||
width = w - bounds.left_width - bounds.right_width;
|
||||
height = h - bounds.top_height - bounds.bottom_height;
|
||||
|
||||
redraw();
|
||||
|
||||
yutani_window_resize_done(yctx, window);
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
yctx = yutani_init();
|
||||
if (!yctx) {
|
||||
fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_decorations();
|
||||
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(NULL, &bounds);
|
||||
|
||||
window = yutani_window_create(yctx, width + bounds.width, height + bounds.height);
|
||||
yutani_window_move(yctx, window, left, top);
|
||||
|
||||
yutani_window_advertise_icon(yctx, window, "SDF Demo", "sdf");
|
||||
|
||||
ctx = init_graphics_yutani(window);
|
||||
|
||||
redraw();
|
||||
yutani_flip(yctx, window);
|
||||
|
||||
int playing = 1;
|
||||
while (playing) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
if (m) {
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
playing = 0;
|
||||
} else if (ke->event.action == KEY_ACTION_DOWN) {
|
||||
if (size <= 20) {
|
||||
size += 1;
|
||||
} else if (size > 20) {
|
||||
size += 5;
|
||||
}
|
||||
if (size > 100) {
|
||||
size = 1;
|
||||
}
|
||||
redraw();
|
||||
yutani_flip(yctx,window);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win) {
|
||||
win->focused = wf->focused;
|
||||
decors();
|
||||
yutani_flip(yctx, window);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
resize_finish(wr->width, wr->height);
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
int result = decor_handle_event(yctx, m);
|
||||
switch (result) {
|
||||
case DECOR_CLOSE:
|
||||
playing = 0;
|
||||
break;
|
||||
default:
|
||||
/* Other actions */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
playing = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(m);
|
||||
}
|
||||
|
||||
yutani_close(yctx, window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
* Copyright (C) 2013-2014 K. Lange
|
||||
*
|
||||
* serial console
|
||||
*
|
||||
@ -12,11 +12,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <syscall.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/fswait.h>
|
||||
|
||||
int fd = 0;
|
||||
|
||||
@ -90,7 +91,7 @@ int main(int argc, char ** argv) {
|
||||
int fds[2] = {STDIN_FILENO, fd};
|
||||
|
||||
while (1) {
|
||||
int index = syscall_fswait(2, fds);
|
||||
int index = fswait(2, fds);
|
||||
|
||||
if (index == -1) {
|
||||
fprintf(stderr, "serial-console: fswait: erroneous file descriptor\n");
|
@ -1,30 +1,41 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* Graphical Session Manager
|
||||
* session - UI session manager
|
||||
*
|
||||
* Runs a background and panel for a single user and waits
|
||||
* for them to exit.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <syscall.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
/* Starts a graphical session and then spins waiting for a kill (logout) signal */
|
||||
|
||||
char path[1024];
|
||||
char * home = getenv("HOME");
|
||||
if (home) {
|
||||
sprintf(path, "%s/.yutanirc", home);
|
||||
char * args[] = {path, NULL};
|
||||
execvp(args[0], args);
|
||||
}
|
||||
|
||||
/* Fallback */
|
||||
|
||||
int _background_pid = fork();
|
||||
if (!_background_pid) {
|
||||
char * args[] = {"/bin/background", "--really", NULL};
|
||||
execvp(args[0], args);
|
||||
}
|
||||
|
||||
int _panel_pid = fork();
|
||||
if (!_panel_pid) {
|
||||
char * args[] = {"/bin/panel.py", NULL};
|
||||
execvp(args[0], args);
|
||||
}
|
||||
int _toastd_pid = fork();
|
||||
if (!_toastd_pid) {
|
||||
char * args[] = {"/bin/toastd.py", NULL};
|
||||
char * args[] = {"/bin/panel", "--really", NULL};
|
||||
execvp(args[0], args);
|
||||
}
|
||||
|
48
apps/set-resolution.c
Normal file
48
apps/set-resolution.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* set-resolution - Change the display resolution.
|
||||
*
|
||||
* Simple tool to interface with the IO_VID_SET ioctl.
|
||||
*
|
||||
* TODO: This is probably something we should request from the
|
||||
* compositor rather than a separate application...
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <kernel/video.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s width height\n", argv[0]);
|
||||
}
|
||||
|
||||
/* Open framebuffer */
|
||||
int fd = open("/dev/fb0", O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prepare ioctl from arguments */
|
||||
struct vid_size s;
|
||||
s.width = atoi(argv[1]);
|
||||
s.height = atoi(argv[2]);
|
||||
|
||||
/* Send ioctl */
|
||||
if (ioctl(fd, IO_VID_SET, &s) < 0) {
|
||||
perror("ioctl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
* Sleep
|
||||
* Copyright (C) 2013 K. Lange
|
||||
*
|
||||
* sleep - Do nothing, efficiently.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int ret = 0;
|
||||
@ -24,8 +25,3 @@ int main(int argc, char ** argv) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vim:tabstop=4
|
||||
* vim:noexpandtab
|
||||
* vim:shiftwidth=4
|
||||
*/
|
100
apps/sort.c
Normal file
100
apps/sort.c
Normal file
@ -0,0 +1,100 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* sort - Sort standard in or files.
|
||||
*
|
||||
* Currently implemented with a naive insertion sort.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <toaru/list.h>
|
||||
|
||||
int compare(const char * a, const char * b) {
|
||||
while (1) {
|
||||
while (*a == *b || tolower(*a) == tolower(*b)) {
|
||||
if (!*a) return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
while (*a && !isalnum(*a)) a++;
|
||||
while (*b && !isalnum(*b)) b++;
|
||||
|
||||
if (tolower(*a) == tolower(*b)) continue;
|
||||
|
||||
if (tolower(*a) < tolower(*b)) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int reverse = 0;
|
||||
int opt;
|
||||
|
||||
list_t * lines = list_create();
|
||||
list_t * files = list_create();
|
||||
|
||||
while ((opt = getopt(argc, argv, "r")) != -1) {
|
||||
switch (opt) {
|
||||
case 'r':
|
||||
reverse = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
/* No arguments */
|
||||
list_insert(files, stdin);
|
||||
} else {
|
||||
while (optind < argc) {
|
||||
FILE * f = fopen(argv[optind], "r");
|
||||
if (!f) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
|
||||
} else {
|
||||
list_insert(files, f);
|
||||
}
|
||||
optind++;
|
||||
}
|
||||
}
|
||||
|
||||
char line_buf[4096] = {0};
|
||||
foreach (node, files) {
|
||||
FILE * f = node->value;
|
||||
while (!feof(f)) {
|
||||
if (!fgets(line_buf, 4096, f)) {
|
||||
break;
|
||||
}
|
||||
if (!strchr(line_buf,'\n')) {
|
||||
fprintf(stderr, "%s: oversized line\n", argv[0]);
|
||||
}
|
||||
char * line = strdup(line_buf);
|
||||
node_t * next = NULL;
|
||||
foreach (lnode, lines) {
|
||||
char * cmp = lnode->value;
|
||||
if (reverse ? (compare(cmp, line) < 0) : (compare(line, cmp) < 0)) {
|
||||
next = lnode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (next) {
|
||||
list_insert_before(lines, next, line);
|
||||
} else {
|
||||
list_insert(lines, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (lnode, lines) {
|
||||
char * line = lnode->value;
|
||||
fprintf(stdout, "%s", line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
92
apps/stat.c
Normal file
92
apps/stat.c
Normal file
@ -0,0 +1,92 @@
|
||||
/* vim: ts=4 sw=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2018 K. Lange
|
||||
*
|
||||
* stat
|
||||
*
|
||||
* Display file status.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static void show_usage(int argc, char * argv[]) {
|
||||
printf(
|
||||
"stat - display file status\n"
|
||||
"\n"
|
||||
"usage: %s [-Lq] PATH\n"
|
||||
"\n"
|
||||
" -L \033[3mdereference symlinks\033[0m\n"
|
||||
" -q \033[3mdon't print anything, just return 0 if file exists\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int dereference = 0, quiet = 0;
|
||||
char * file;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "?Lq")) != -1) {
|
||||
switch (opt) {
|
||||
case 'L':
|
||||
dereference = 1;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case '?':
|
||||
show_usage(argc,argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
show_usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = argv[optind];
|
||||
|
||||
struct stat _stat;
|
||||
if (dereference) {
|
||||
if (stat(file, &_stat) < 0) return 1;
|
||||
} else {
|
||||
if (lstat(file, &_stat) < 0) return 1;
|
||||
}
|
||||
|
||||
if (quiet) return 0;
|
||||
|
||||
printf("0x%x bytes\n", (unsigned int)_stat.st_size);
|
||||
|
||||
if (S_ISDIR(_stat.st_mode)) {
|
||||
printf("Is a directory.\n");
|
||||
} else if (S_ISFIFO(_stat.st_mode)) {
|
||||
printf("Is a pipe.\n");
|
||||
} else if (S_ISLNK(_stat.st_mode)) {
|
||||
printf("Is a symlink.\n");
|
||||
} else if (_stat.st_mode & 0111) {
|
||||
printf("Is executable.\n");
|
||||
}
|
||||
|
||||
struct stat * f = &_stat;
|
||||
|
||||
printf("st_dev 0x%x %d\n", (unsigned int)f->st_dev , (unsigned int)sizeof(f->st_dev ));
|
||||
printf("st_ino 0x%x %d\n", (unsigned int)f->st_ino , (unsigned int)sizeof(f->st_ino ));
|
||||
printf("st_mode 0x%x %d\n", (unsigned int)f->st_mode , (unsigned int)sizeof(f->st_mode ));
|
||||
printf("st_nlink 0x%x %d\n", (unsigned int)f->st_nlink , (unsigned int)sizeof(f->st_nlink ));
|
||||
printf("st_uid 0x%x %d\n", (unsigned int)f->st_uid , (unsigned int)sizeof(f->st_uid ));
|
||||
printf("st_gid 0x%x %d\n", (unsigned int)f->st_gid , (unsigned int)sizeof(f->st_gid ));
|
||||
printf("st_rdev 0x%x %d\n", (unsigned int)f->st_rdev , (unsigned int)sizeof(f->st_rdev ));
|
||||
printf("st_size 0x%x %d\n", (unsigned int)f->st_size , (unsigned int)sizeof(f->st_size ));
|
||||
|
||||
printf("0x%x\n", (unsigned int)((uint32_t *)f)[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
330
apps/stty.c
Normal file
330
apps/stty.c
Normal file
@ -0,0 +1,330 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
static int hide_defaults = 1;
|
||||
static int printed = 0;
|
||||
|
||||
static void print_cc(struct termios * t, const char * lbl, int val, int def) {
|
||||
int c = t->c_cc[val];
|
||||
if (hide_defaults && c == def) return;
|
||||
if (!c) {
|
||||
fprintf(stdout, "%s = <undef>; ", lbl);
|
||||
} else if (c < 32) {
|
||||
fprintf(stdout, "%s = ^%c; ", lbl, '@' + c);
|
||||
} else {
|
||||
fprintf(stdout, "%s = %c; ", lbl, c);
|
||||
}
|
||||
printed = 1;
|
||||
}
|
||||
|
||||
static void print_(int flags, const char * lbl, int val, int def) {
|
||||
int c = !!(flags & val);
|
||||
if (!hide_defaults || c != def) {
|
||||
fprintf(stdout, "%s%s ", c ? "" : "-", lbl);
|
||||
printed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define print_cflag(lbl,val,def) print_(t.c_cflag, lbl, val, def)
|
||||
#define print_iflag(lbl,val,def) print_(t.c_iflag, lbl, val, def)
|
||||
#define print_oflag(lbl,val,def) print_(t.c_oflag, lbl, val, def)
|
||||
#define print_lflag(lbl,val,def) print_(t.c_lflag, lbl, val, def)
|
||||
|
||||
static void set_char_(struct termios *t, const char * lbl, int val, const char * cmp, const char * arg, int * i) {
|
||||
if (!strcmp(cmp, lbl)) {
|
||||
if (!arg) {
|
||||
fprintf(stderr, "%s: expected argument\n", lbl);
|
||||
exit(1);
|
||||
}
|
||||
/* Parse arg */
|
||||
if (strlen(arg) == 1) {
|
||||
/* Assume raw character */
|
||||
t->c_cc[val] = *arg;
|
||||
} else if (*arg == '^') { /* ^c, etc. */
|
||||
int v = toupper(arg[1]);
|
||||
t->c_cc[val] = v - '@';
|
||||
} else {
|
||||
/* Assume decimal for now */
|
||||
int v = atoi(arg);
|
||||
t->c_cc[val] = v;
|
||||
}
|
||||
(*i)++;
|
||||
}
|
||||
}
|
||||
|
||||
#define set_char(lbl,val) set_char_(&t, lbl, val, argv[i], argv[i+1], &i)
|
||||
|
||||
static void setunset_flag(tcflag_t * flag, const char * lbl, int val, const char * cmp) {
|
||||
if (*cmp == '-') {
|
||||
if (!strcmp(cmp+1, lbl)) {
|
||||
(*flag) = (*flag) & (~val);
|
||||
}
|
||||
} else {
|
||||
if (!strcmp(cmp, lbl)) {
|
||||
(*flag) = (*flag) | (val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define set_cflag(lbl,val) setunset_flag(&(t.c_cflag), lbl, val, argv[i])
|
||||
#define set_iflag(lbl,val) setunset_flag(&(t.c_iflag), lbl, val, argv[i])
|
||||
#define set_oflag(lbl,val) setunset_flag(&(t.c_oflag), lbl, val, argv[i])
|
||||
#define set_lflag(lbl,val) setunset_flag(&(t.c_lflag), lbl, val, argv[i])
|
||||
|
||||
static void set_toggle_(tcflag_t * flag, const char * lbl, int base, int val, const char * cmp) {
|
||||
if (!strcmp(cmp, lbl)) {
|
||||
(*flag) = (*flag) & ~(base);
|
||||
(*flag) = (*flag) | (val);
|
||||
}
|
||||
}
|
||||
|
||||
#define set_ctoggle(lbl,base,val) set_toggle_(&(t.c_cflag), lbl, base, val, argv[i])
|
||||
#define set_otoggle(lbl,base,val) set_toggle_(&(t.c_oflag), lbl, base, val, argv[i])
|
||||
|
||||
static int show_settings(int all) {
|
||||
/* Size */
|
||||
struct winsize w;
|
||||
ioctl(STDERR_FILENO, TIOCGWINSZ, &w);
|
||||
fprintf(stdout, "rows %d; columns %d; ypixels %d; xpixels %d;\n", w.ws_row, w.ws_col, w.ws_ypixel, w.ws_xpixel);
|
||||
printed = 0;
|
||||
|
||||
struct termios t;
|
||||
tcgetattr(STDERR_FILENO, &t);
|
||||
|
||||
/* Keys */
|
||||
print_cc(&t, "intr", VINTR, 3);
|
||||
print_cc(&t, "quit", VQUIT, 28);
|
||||
print_cc(&t, "erase", VERASE, '\b');
|
||||
print_cc(&t, "kill", VKILL, 21);
|
||||
print_cc(&t, "eof", VEOF, 4);
|
||||
print_cc(&t, "eol", VEOL, 0);
|
||||
if (printed) { fprintf(stdout, "\n"); printed = 0; }
|
||||
|
||||
print_cc(&t, "start", VSTART, 17);
|
||||
print_cc(&t, "stop", VSTOP, 19);
|
||||
print_cc(&t, "susp", VSUSP, 26);
|
||||
|
||||
/* MIN, TIME */
|
||||
if (!hide_defaults || t.c_cc[VMIN] != 1) { fprintf(stdout, "min = %d; ", t.c_cc[VMIN]); printed = 1; }
|
||||
if (!hide_defaults || t.c_cc[VTIME] != 0) { fprintf(stdout, "time = %d; ", t.c_cc[VTIME]); printed = 1; }
|
||||
if (printed) { fprintf(stdout, "\n"); printed = 0; }
|
||||
|
||||
switch ((t.c_cflag & CSIZE)) {
|
||||
case CS5: fprintf(stdout, "cs5 "); printed = 1; break;
|
||||
case CS6: fprintf(stdout, "cs6 "); printed = 1; break;
|
||||
case CS7: fprintf(stdout, "cs7 "); printed = 1; break;
|
||||
case CS8: if (!hide_defaults) { fprintf(stdout, "cs8 "); printed = 1; } break;
|
||||
}
|
||||
|
||||
print_cflag("cstopb", CSTOPB, 0);
|
||||
print_cflag("cread", CREAD, 1);
|
||||
print_cflag("parenb", PARENB, 0);
|
||||
print_cflag("parodd", PARODD, 0);
|
||||
print_cflag("hupcl", HUPCL, 0);
|
||||
print_cflag("clocal", CLOCAL, 0);
|
||||
if (printed) { fprintf(stdout, "\n"); printed = 0; }
|
||||
|
||||
print_iflag("brkint", BRKINT, 1);
|
||||
print_iflag("icrnl", ICRNL, 1);
|
||||
print_iflag("ignbrk", IGNBRK, 0);
|
||||
print_iflag("igncr", IGNCR, 0);
|
||||
print_iflag("ignpar", IGNPAR, 0);
|
||||
print_iflag("inlcr", INLCR, 0);
|
||||
print_iflag("inpck", INPCK, 0);
|
||||
print_iflag("istrip", ISTRIP, 0);
|
||||
print_iflag("ixany", IXANY, 0);
|
||||
print_iflag("ixoff", IXOFF, 0);
|
||||
print_iflag("ixon", IXON, 0);
|
||||
print_iflag("parmrk", PARMRK, 0);
|
||||
if (printed) { fprintf(stdout, "\n"); printed = 0; }
|
||||
|
||||
print_oflag("opost", OPOST, 1);
|
||||
print_oflag("olcuc", OLCUC, 0);
|
||||
print_oflag("onlcr", ONLCR, 1);
|
||||
print_oflag("ocrnl", OCRNL, 0);
|
||||
print_oflag("onocr", ONOCR, 0);
|
||||
print_oflag("onlret", ONLRET, 0);
|
||||
print_oflag("ofill", OFILL, 0);
|
||||
print_oflag("ofdel", OFDEL, 0);
|
||||
|
||||
switch ((t.c_oflag & CRDLY)) {
|
||||
case CR0: if (!hide_defaults) { fprintf(stdout, "cr0 "); printed = 1; } break;
|
||||
case CR1: fprintf(stdout, "cr1 "); printed = 1; break;
|
||||
case CR2: fprintf(stdout, "cr2 "); printed = 1; break;
|
||||
case CR3: fprintf(stdout, "cr3 "); printed = 1; break;
|
||||
}
|
||||
|
||||
switch ((t.c_oflag & NLDLY)) {
|
||||
case NL0: if (!hide_defaults) { fprintf(stdout, "nl0 "); printed = 1; } break;
|
||||
case NL1: fprintf(stdout, "nl1 "); printed = 1; break;
|
||||
}
|
||||
|
||||
switch ((t.c_oflag & TABDLY)) {
|
||||
case TAB0: if (!hide_defaults) { fprintf(stdout, "tab0 "); printed = 1; } break;
|
||||
case TAB1: fprintf(stdout, "tab1 "); printed = 1; break;
|
||||
case TAB2: fprintf(stdout, "tab2 "); printed = 1; break;
|
||||
case TAB3: fprintf(stdout, "tab3 "); printed = 1; break;
|
||||
}
|
||||
|
||||
switch ((t.c_oflag & BSDLY)) {
|
||||
case BS0: if (!hide_defaults) { fprintf(stdout, "bs0 "); printed = 1; } break;
|
||||
case BS1: fprintf(stdout, "bs1 "); printed = 1; break;
|
||||
}
|
||||
|
||||
switch ((t.c_oflag & FFDLY)) {
|
||||
case FF0: if (!hide_defaults) { fprintf(stdout, "ff0 "); printed = 1; } break;
|
||||
case FF1: fprintf(stdout, "ff1 "); printed = 1; break;
|
||||
}
|
||||
|
||||
switch ((t.c_oflag & VTDLY)) {
|
||||
case VT0: if (!hide_defaults) { fprintf(stdout, "vt0"); printed = 1; } break;
|
||||
case VT1: fprintf(stdout, "vt1"); printed = 1; break;
|
||||
}
|
||||
if (printed) { fprintf(stdout, "\n"); printed = 0; }
|
||||
|
||||
print_lflag("isig", ISIG, 1);
|
||||
print_lflag("icanon", ICANON, 1);
|
||||
print_lflag("xcase", XCASE, 0);
|
||||
print_lflag("echo", ECHO, 1);
|
||||
print_lflag("echoe", ECHOE, 1);
|
||||
print_lflag("echok", ECHOK, 1);
|
||||
print_lflag("echonl", ECHONL, 0);
|
||||
print_lflag("noflsh", NOFLSH, 0);
|
||||
print_lflag("tostop", TOSTOP, 0);
|
||||
print_lflag("iexten", IEXTEN, 1);
|
||||
if (printed) { fprintf(stdout, "\n"); printed = 0; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
int i = 1;
|
||||
|
||||
if (i < argc && !strcmp(argv[i], "-a")) {
|
||||
hide_defaults = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == argc) {
|
||||
return show_settings(0);
|
||||
}
|
||||
|
||||
struct termios t;
|
||||
tcgetattr(STDERR_FILENO, &t);
|
||||
|
||||
while (i < argc) {
|
||||
|
||||
if (!strcmp(argv[i], "sane")) {
|
||||
t.c_iflag = ICRNL | BRKINT;
|
||||
t.c_oflag = ONLCR | OPOST;
|
||||
t.c_lflag = ECHO | ECHOE | ECHOK | ICANON | ISIG | IEXTEN;
|
||||
t.c_cflag = CREAD | CS8;
|
||||
t.c_cc[VEOF] = 4; /* ^D */
|
||||
t.c_cc[VEOL] = 0; /* Not set */
|
||||
t.c_cc[VERASE] = '\b';
|
||||
t.c_cc[VINTR] = 3; /* ^C */
|
||||
t.c_cc[VKILL] = 21; /* ^U */
|
||||
t.c_cc[VMIN] = 1;
|
||||
t.c_cc[VQUIT] = 28; /* ^\ */
|
||||
t.c_cc[VSTART] = 17; /* ^Q */
|
||||
t.c_cc[VSTOP] = 19; /* ^S */
|
||||
t.c_cc[VSUSP] = 26; /* ^Z */
|
||||
t.c_cc[VTIME] = 0;
|
||||
}
|
||||
|
||||
set_char("eof", VEOF);
|
||||
set_char("eol", VEOL);
|
||||
set_char("erase", VERASE);
|
||||
set_char("intr", VINTR);
|
||||
set_char("kill", VKILL);
|
||||
set_char("quit", VQUIT);
|
||||
set_char("start", VSTART);
|
||||
set_char("stop", VSTOP);
|
||||
set_char("susp", VSUSP);
|
||||
|
||||
|
||||
set_cflag("parenb", PARENB);
|
||||
set_cflag("parodd", PARODD);
|
||||
set_cflag("hupcl", HUPCL);
|
||||
set_cflag("hup", HUPCL); /* alias */
|
||||
set_cflag("cstopb", CSTOPB);
|
||||
set_cflag("cread", CREAD);
|
||||
set_cflag("clocal", CLOCAL);
|
||||
|
||||
set_ctoggle("cs5", CSIZE, CS5);
|
||||
set_ctoggle("cs6", CSIZE, CS6);
|
||||
set_ctoggle("cs7", CSIZE, CS7);
|
||||
set_ctoggle("cs8", CSIZE, CS8);
|
||||
|
||||
set_iflag("ignbrk", IGNBRK);
|
||||
set_iflag("brkint", BRKINT);
|
||||
set_iflag("ignpar", IGNPAR);
|
||||
set_iflag("parmrk", PARMRK);
|
||||
set_iflag("inpck", INPCK);
|
||||
set_iflag("istrip", ISTRIP);
|
||||
set_iflag("inlcr", INLCR);
|
||||
set_iflag("igncr", IGNCR);
|
||||
set_iflag("icrnl", ICRNL);
|
||||
set_iflag("ixon", IXON);
|
||||
set_iflag("ixany", IXANY);
|
||||
set_iflag("ixoff", IXOFF);
|
||||
|
||||
set_oflag("olcuc", OLCUC);
|
||||
set_oflag("opost", OPOST);
|
||||
set_oflag("onlcr", ONLCR);
|
||||
set_oflag("ocrnl", OCRNL);
|
||||
set_oflag("onocr", ONOCR);
|
||||
set_oflag("onlret", ONLRET);
|
||||
set_oflag("ofill", OFILL);
|
||||
set_oflag("ofdel", OFDEL);
|
||||
|
||||
set_otoggle("cr0", CRDLY, CR0);
|
||||
set_otoggle("cr1", CRDLY, CR1);
|
||||
set_otoggle("cr2", CRDLY, CR2);
|
||||
set_otoggle("cr3", CRDLY, CR3);
|
||||
|
||||
set_otoggle("nl0", NLDLY, NL0);
|
||||
set_otoggle("nl1", NLDLY, NL1);
|
||||
|
||||
set_otoggle("tab0", TABDLY, TAB0);
|
||||
set_otoggle("tab1", TABDLY, TAB1);
|
||||
set_otoggle("tab2", TABDLY, TAB2);
|
||||
set_otoggle("tab3", TABDLY, TAB3);
|
||||
|
||||
set_otoggle("bs0", BSDLY, BS0);
|
||||
set_otoggle("bs1", BSDLY, BS1);
|
||||
|
||||
set_otoggle("ff0", FFDLY, FF0);
|
||||
set_otoggle("ff1", FFDLY, FF1);
|
||||
|
||||
set_otoggle("vt0", VTDLY, VT0);
|
||||
set_otoggle("vt1", VTDLY, VT1);
|
||||
|
||||
set_lflag("isig", ISIG);
|
||||
set_lflag("icanon", ICANON);
|
||||
set_lflag("iexten", IEXTEN);
|
||||
set_lflag("echo", ECHO);
|
||||
set_lflag("echoe", ECHOE);
|
||||
set_lflag("echok", ECHOK);
|
||||
set_lflag("echonl", ECHONL);
|
||||
set_lflag("noflsh", NOFLSH);
|
||||
set_lflag("tostop", TOSTOP);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
tcsetattr(STDERR_FILENO, TCSAFLUSH, &t);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014 Kevin Lange
|
||||
* Copyright (C) 2014 K. Lange
|
||||
*
|
||||
* sudo
|
||||
*
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -19,8 +18,7 @@
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "lib/toaru_auth.h"
|
||||
#include <toaru/auth.h>
|
||||
|
||||
uint32_t child = 0;
|
||||
|
||||
@ -73,8 +71,15 @@ int main(int argc, char ** argv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set username to root */
|
||||
putenv("USER=root");
|
||||
|
||||
if (!strcmp(argv[1], "-s")) {
|
||||
argv[1] = getenv("SHELL");
|
||||
}
|
||||
|
||||
char ** args = &argv[1];
|
||||
int i = execvp(args[0], args);
|
||||
execvp(args[0], args);
|
||||
|
||||
/* XXX: There are other things that can cause an exec to fail. */
|
||||
fprintf(stderr, "%s: %s: command not found\n", argv[0], args[0]);
|
@ -1,8 +1,7 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013 Kevin Lange
|
||||
*/
|
||||
/* vim:tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Copyright (C) 2013 K. Lange
|
||||
*
|
||||
* sysfunc
|
||||
*
|
@ -1,19 +1,21 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2015 Kevin Lange
|
||||
* Copyright (C) 2015-2018 K. Lange
|
||||
*
|
||||
* sysinfo - visually based on screenfetch
|
||||
*
|
||||
* Displays system information in a visually-pleasing format.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "lib/graphics.h"
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/termemu.h>
|
||||
|
||||
#include "gui/terminal/lib/termemu.h"
|
||||
#include "toaru_logo.h"
|
||||
|
||||
#define NUM_DATA_LINES 30
|
||||
@ -39,6 +41,8 @@ int main(int argc, char * argv[]) {
|
||||
/* Prepare data */
|
||||
char * user = getenv("USER");
|
||||
char * wm_theme = getenv("WM_THEME");
|
||||
char * term = getenv("TERM");
|
||||
int term_is_toaru = term && !strcmp(term,"toaru");
|
||||
|
||||
int i = 0;
|
||||
prog_lines[i] = "hostname";
|
||||
@ -55,8 +59,10 @@ int main(int argc, char * argv[]) {
|
||||
sprintf(data_lines[i++], C_A "Resolution: " C_O);
|
||||
sprintf(data_lines[i++], C_A "WM: " C_O "Yutani");
|
||||
sprintf(data_lines[i++], C_A "WM Theme: " C_O "%s", wm_theme);
|
||||
#if 0
|
||||
prog_lines[i] = "yutani-query -m";
|
||||
sprintf(data_lines[i++], C_A "Font: " C_O);
|
||||
#endif
|
||||
//sprintf(data_lines[i++], C_A "CPU: " C_O "(query cpudet)");
|
||||
//sprintf(data_lines[i++], C_A "GPU: " C_O "(hell if I know!)");
|
||||
prog_lines[i] = "free -ut";
|
||||
@ -88,10 +94,17 @@ int main(int argc, char * argv[]) {
|
||||
rgba(0,0,0,TERM_DEFAULT_OPAC),
|
||||
premultiply(rgba(r_b, g_b, b_b, a_b)));
|
||||
|
||||
/* Print half block */
|
||||
printf("\033[38;6;%d;%d;%d;%dm\033[48;6;%d;%d;%d;%dm▄",
|
||||
_RED(back), _GRE(back), _BLU(back), _ALP(back),
|
||||
_RED(out), _GRE(out), _BLU(out), _ALP(out));
|
||||
if (term_is_toaru) {
|
||||
|
||||
/* Print half block */
|
||||
printf("\033[38;6;%d;%d;%d;%dm\033[48;6;%d;%d;%d;%dm▄",
|
||||
(int)_RED(back), (int)_GRE(back), (int)_BLU(back), (int)_ALP(back),
|
||||
(int)_RED(out), (int)_GRE(out), (int)_BLU(out), (int)_ALP(out));
|
||||
} else {
|
||||
printf("\033[38;2;%d;%d;%dm\033[48;2;%d;%d;%dm▄",
|
||||
(int)_RED(back), (int)_GRE(back), (int)_BLU(back),
|
||||
(int)_RED(out), (int)_GRE(out), (int)_BLU(out));
|
||||
}
|
||||
|
||||
}
|
||||
if (j < i) {
|
||||
@ -103,7 +116,7 @@ int main(int argc, char * argv[]) {
|
||||
}
|
||||
|
||||
while (j < i) {
|
||||
for (int x = 0; x < gimp_image.width; x++) {
|
||||
for (int x = 0; x < (int)gimp_image.width; x++) {
|
||||
printf(" ");
|
||||
}
|
||||
print_thing(j);
|
62
apps/tee.c
Normal file
62
apps/tee.c
Normal file
@ -0,0 +1,62 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* tee - copy stdin to stdout and to specified files
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int append = 0;
|
||||
int ret_val = 0;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "ai")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
append = 1;
|
||||
break;
|
||||
case 'i':
|
||||
signal(SIGINT, SIG_IGN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int file_count = argc - optind;
|
||||
FILE ** files = malloc(sizeof(FILE *) * file_count);
|
||||
|
||||
for (int i = 0, j = optind; j < argc && i < file_count; j++) {
|
||||
files[i] = fopen(argv[j], append ? "a" : "w");
|
||||
if (!files[i]) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[j], strerror(errno));
|
||||
ret_val = 1;
|
||||
file_count--;
|
||||
continue;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
while (!feof(stdin)) {
|
||||
int c = fgetc(stdin);
|
||||
if (c >= 0) {
|
||||
fputc(c, stdout);
|
||||
|
||||
for (int i = 0; i < file_count; ++i) {
|
||||
fputc(c, files[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < file_count; ++i) {
|
||||
fclose(files[i]);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
BIN
apps/terminal-font.h
Normal file
BIN
apps/terminal-font.h
Normal file
Binary file not shown.
@ -1,11 +1,19 @@
|
||||
/*
|
||||
* Terminal palette
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2012-2018 K. Lange
|
||||
*
|
||||
* terminal-palette.h - Terminal color palette
|
||||
*
|
||||
* Provides the color table for both the basic 16 colors (here,
|
||||
* chosen from the Tango design documents), as well as the other
|
||||
* colors making up the basic 256 color palette derived from xterm.
|
||||
*/
|
||||
|
||||
#define PALETTE_COLORS 256
|
||||
|
||||
uint32_t term_colors[PALETTE_COLORS] = {
|
||||
/* black */ 0x2e3436,
|
||||
/* black */ 0x000000,
|
||||
/* red */ 0xcc0000,
|
||||
/* green */ 0x3e9a06,
|
||||
/* brown */ 0xc4a000,
|
@ -1,14 +1,13 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2014 Kevin Lange
|
||||
* Copyright (C) 2014-2018 K. Lange
|
||||
*
|
||||
* Terminal Emulator - VGA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
@ -21,15 +20,18 @@
|
||||
#include <sys/wait.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <pty.h>
|
||||
#include <sys/fswait.h>
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include "lib/utf8decode.h"
|
||||
#include "lib/kbd.h"
|
||||
#include "lib/graphics.h"
|
||||
#include <toaru/decodeutf8.h>
|
||||
#include <toaru/kbd.h>
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/termemu.h>
|
||||
#include <toaru/mouse.h>
|
||||
|
||||
#include "gui/terminal/vga-palette.h"
|
||||
#include "gui/terminal/lib/termemu.h"
|
||||
#include "vga-palette.h"
|
||||
|
||||
#define USE_BELL 0
|
||||
|
||||
@ -51,6 +53,13 @@ uint8_t _hold_out = 0; /* state indicator on last cell ignore \n */
|
||||
|
||||
uint64_t mouse_ticks = 0;
|
||||
|
||||
int selection = 0;
|
||||
int selection_start_x = 0;
|
||||
int selection_start_y = 0;
|
||||
int selection_end_x = 0;
|
||||
int selection_end_y = 0;
|
||||
char * selection_text = NULL;
|
||||
|
||||
#define char_width 1
|
||||
#define char_height 1
|
||||
|
||||
@ -59,9 +68,6 @@ term_state_t * ansi_state = NULL;
|
||||
void reinit(); /* Defined way further down */
|
||||
void term_redraw_cursor();
|
||||
|
||||
/* Cursor bink timer */
|
||||
static unsigned int timer_tick = 0;
|
||||
|
||||
void term_clear();
|
||||
|
||||
void dump_buffer();
|
||||
@ -109,6 +115,7 @@ static uint32_t vga_base_colors[] = {
|
||||
0xFFFFFF,
|
||||
};
|
||||
|
||||
#if 0
|
||||
static int is_gray(uint32_t a) {
|
||||
int a_r = (a & 0xFF0000) >> 16;
|
||||
int a_g = (a & 0xFF00) >> 8;
|
||||
@ -116,12 +123,12 @@ static int is_gray(uint32_t a) {
|
||||
|
||||
return (a_r == a_g && a_g == a_b);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int best_match(uint32_t a) {
|
||||
int best_distance = INT32_MAX;
|
||||
int best_index = 0;
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
if (is_gray(a) && !is_gray(vga_base_colors[j]));
|
||||
int distance = color_distance(a, vga_base_colors[j]);
|
||||
if (distance < best_distance) {
|
||||
best_index = j;
|
||||
@ -134,10 +141,6 @@ static int best_match(uint32_t a) {
|
||||
|
||||
volatile int exit_application = 0;
|
||||
|
||||
static void set_term_font_size(float s) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/* Returns the lower of two shorts */
|
||||
uint16_t min(uint16_t a, uint16_t b) {
|
||||
return (a < b) ? a : b;
|
||||
@ -152,6 +155,234 @@ void set_title(char * c) {
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
static void cell_redraw(uint16_t x, uint16_t y);
|
||||
static void cell_redraw_inverted(uint16_t x, uint16_t y);
|
||||
|
||||
void iterate_selection(void (*func)(uint16_t x, uint16_t y)) {
|
||||
if (selection_end_y < selection_start_y) {
|
||||
for (int x = selection_end_x; x < term_width; ++x) {
|
||||
func(x, selection_end_y);
|
||||
}
|
||||
for (int y = selection_end_y + 1; y < selection_start_y; ++y) {
|
||||
for (int x = 0; x < term_width; ++x) {
|
||||
func(x, y);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x <= selection_start_x; ++x) {
|
||||
func(x, selection_start_y);
|
||||
}
|
||||
} else if (selection_start_y == selection_end_y) {
|
||||
if (selection_start_x > selection_end_x) {
|
||||
for (int x = selection_end_x; x <= selection_start_x; ++x) {
|
||||
func(x, selection_start_y);
|
||||
}
|
||||
} else {
|
||||
for (int x = selection_start_x; x <= selection_end_x; ++x) {
|
||||
func(x, selection_start_y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int x = selection_start_x; x < term_width; ++x) {
|
||||
func(x, selection_start_y);
|
||||
}
|
||||
for (int y = selection_start_y + 1; y < selection_end_y; ++y) {
|
||||
for (int x = 0; x < term_width; ++x) {
|
||||
func(x, y);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x <= selection_end_x; ++x) {
|
||||
func(x, selection_end_y);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void redraw_selection(void) {
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
}
|
||||
|
||||
static void redraw_new_selection(int old_x, int old_y) {
|
||||
if (selection_end_y == selection_start_y && old_y != selection_start_y) {
|
||||
int a, b;
|
||||
a = selection_end_x;
|
||||
b = selection_end_y;
|
||||
selection_end_x = old_x;
|
||||
selection_end_y = old_y;
|
||||
iterate_selection(cell_redraw);
|
||||
selection_end_x = a;
|
||||
selection_end_y = b;
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
} else {
|
||||
int a, b;
|
||||
a = selection_start_x;
|
||||
b = selection_start_y;
|
||||
|
||||
selection_start_x = old_x;
|
||||
selection_start_y = old_y;
|
||||
|
||||
/* Figure out direction */
|
||||
if (old_y < b) {
|
||||
/* Backwards */
|
||||
if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) {
|
||||
/* Selection extended */
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
} else {
|
||||
/* Selection got smaller */
|
||||
iterate_selection(cell_redraw);
|
||||
}
|
||||
} else if (old_y == b) {
|
||||
/* Was a single line */
|
||||
if (selection_end_y == b) {
|
||||
/* And still is */
|
||||
if (old_x < a) {
|
||||
/* Backwards */
|
||||
if (selection_end_x < old_x) {
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
} else {
|
||||
iterate_selection(cell_redraw);
|
||||
}
|
||||
} else {
|
||||
if (selection_end_x < old_x) {
|
||||
iterate_selection(cell_redraw);
|
||||
} else {
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
}
|
||||
}
|
||||
} else if (selection_end_y < b) {
|
||||
/* Moved up */
|
||||
if (old_x <= a) {
|
||||
/* Should be fine with just append */
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
} else {
|
||||
/* Need to erase first */
|
||||
iterate_selection(cell_redraw);
|
||||
selection_start_x = a;
|
||||
selection_start_y = b;
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
}
|
||||
} else if (selection_end_y > b) {
|
||||
if (old_x >= a) {
|
||||
/* Should be fine with just append */
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
} else {
|
||||
/* Need to erase first */
|
||||
iterate_selection(cell_redraw);
|
||||
selection_start_x = a;
|
||||
selection_start_y = b;
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Forward */
|
||||
if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) {
|
||||
/* Selection got smaller */
|
||||
iterate_selection(cell_redraw);
|
||||
} else {
|
||||
/* Selection extended */
|
||||
iterate_selection(cell_redraw_inverted);
|
||||
}
|
||||
}
|
||||
|
||||
cell_redraw_inverted(a,b);
|
||||
cell_redraw_inverted(selection_end_x, selection_end_y);
|
||||
|
||||
/* Restore */
|
||||
selection_start_x = a;
|
||||
selection_start_y = b;
|
||||
}
|
||||
}
|
||||
|
||||
static int _selection_count = 0;
|
||||
static int _selection_i = 0;
|
||||
|
||||
static int to_eight(uint32_t codepoint, char * out) {
|
||||
memset(out, 0x00, 7);
|
||||
|
||||
if (codepoint < 0x0080) {
|
||||
out[0] = (char)codepoint;
|
||||
} else if (codepoint < 0x0800) {
|
||||
out[0] = 0xC0 | (codepoint >> 6);
|
||||
out[1] = 0x80 | (codepoint & 0x3F);
|
||||
} else if (codepoint < 0x10000) {
|
||||
out[0] = 0xE0 | (codepoint >> 12);
|
||||
out[1] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
out[2] = 0x80 | (codepoint & 0x3F);
|
||||
} else if (codepoint < 0x200000) {
|
||||
out[0] = 0xF0 | (codepoint >> 18);
|
||||
out[1] = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
out[2] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
out[3] = 0x80 | ((codepoint) & 0x3F);
|
||||
} else if (codepoint < 0x4000000) {
|
||||
out[0] = 0xF8 | (codepoint >> 24);
|
||||
out[1] = 0x80 | (codepoint >> 18);
|
||||
out[2] = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
out[3] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
out[4] = 0x80 | ((codepoint) & 0x3F);
|
||||
} else {
|
||||
out[0] = 0xF8 | (codepoint >> 30);
|
||||
out[1] = 0x80 | ((codepoint >> 24) & 0x3F);
|
||||
out[2] = 0x80 | ((codepoint >> 18) & 0x3F);
|
||||
out[3] = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
out[4] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
out[5] = 0x80 | ((codepoint) & 0x3F);
|
||||
}
|
||||
|
||||
return strlen(out);
|
||||
}
|
||||
|
||||
void count_selection(uint16_t x, uint16_t y) {
|
||||
term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
|
||||
if (((uint32_t *)cell)[0] != 0x00000000) {
|
||||
char tmp[7];
|
||||
_selection_count += to_eight(cell->c, tmp);
|
||||
}
|
||||
if (x == term_width - 1) {
|
||||
_selection_count++;
|
||||
}
|
||||
}
|
||||
|
||||
void write_selection(uint16_t x, uint16_t y) {
|
||||
term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
|
||||
if (((uint32_t *)cell)[0] != 0x00000000) {
|
||||
char tmp[7];
|
||||
int count = to_eight(cell->c, tmp);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
selection_text[_selection_i] = tmp[i];
|
||||
_selection_i++;
|
||||
}
|
||||
}
|
||||
if (x == term_width - 1) {
|
||||
selection_text[_selection_i] = '\n';;
|
||||
_selection_i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char * copy_selection(void) {
|
||||
_selection_count = 0;
|
||||
iterate_selection(count_selection);
|
||||
|
||||
if (selection_text) {
|
||||
free(selection_text);
|
||||
}
|
||||
|
||||
if (_selection_count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
selection_text = malloc(_selection_count + 1);
|
||||
selection_text[_selection_count] = '\0';
|
||||
_selection_i = 0;
|
||||
iterate_selection(write_selection);
|
||||
|
||||
if (selection_text[_selection_count-1] == '\n') {
|
||||
/* Don't end on a line feed */
|
||||
selection_text[_selection_count-1] = '\0';
|
||||
}
|
||||
|
||||
return selection_text;
|
||||
}
|
||||
|
||||
void input_buffer_stuff(char * str) {
|
||||
size_t s = strlen(str) + 1;
|
||||
write(fd_master, str, s);
|
||||
@ -393,6 +624,7 @@ static void cell_redraw_inverted(uint16_t x, uint16_t y) {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void cell_redraw_box(uint16_t x, uint16_t y) {
|
||||
if (x >= term_width || y >= term_height) return;
|
||||
term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t));
|
||||
@ -402,14 +634,17 @@ static void cell_redraw_box(uint16_t x, uint16_t y) {
|
||||
term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags | ANSI_BORDER);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void render_cursor() {
|
||||
cell_redraw_inverted(csr_x, csr_y);
|
||||
}
|
||||
|
||||
static uint8_t cursor_flipped = 0;
|
||||
void draw_cursor() {
|
||||
if (!cursor_on) return;
|
||||
mouse_ticks = get_ticks();
|
||||
cursor_flipped = 0;
|
||||
render_cursor();
|
||||
}
|
||||
|
||||
@ -486,15 +721,6 @@ void term_write(char c) {
|
||||
draw_cursor();
|
||||
} else if (c == '\007') {
|
||||
/* bell */
|
||||
#if USE_BELL
|
||||
for (int i = 0; i < term_height; ++i) {
|
||||
for (int j = 0; j < term_width; ++j) {
|
||||
cell_redraw_inverted(j, i);
|
||||
}
|
||||
}
|
||||
syscall_nanosleep(0,10);
|
||||
term_redraw_all();
|
||||
#endif
|
||||
} else if (c == '\b') {
|
||||
if (csr_x > 0) {
|
||||
--csr_x;
|
||||
@ -547,6 +773,9 @@ int term_get_csr_y() {
|
||||
|
||||
void term_set_csr_show(int on) {
|
||||
cursor_on = on;
|
||||
if (on) {
|
||||
draw_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
void term_set_colors(uint32_t fg, uint32_t bg) {
|
||||
@ -561,7 +790,6 @@ void term_redraw_cursor() {
|
||||
}
|
||||
|
||||
void flip_cursor() {
|
||||
static uint8_t cursor_flipped = 0;
|
||||
if (cursor_flipped) {
|
||||
cell_redraw(csr_x, csr_y);
|
||||
} else {
|
||||
@ -617,7 +845,7 @@ void clear_input() {
|
||||
input_collected = 0;
|
||||
}
|
||||
|
||||
uint32_t child_pid = 0;
|
||||
pid_t child_pid = 0;
|
||||
|
||||
void handle_input(char c) {
|
||||
write(fd_master, &c, 1);
|
||||
@ -629,6 +857,25 @@ void handle_input_s(char * c) {
|
||||
|
||||
void key_event(int ret, key_event_t * event) {
|
||||
if (ret) {
|
||||
/* Special keys */
|
||||
if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) &&
|
||||
(event->modifiers & KEY_MOD_LEFT_CTRL || event->modifiers & KEY_MOD_RIGHT_CTRL) &&
|
||||
(event->keycode == 'c')) {
|
||||
if (selection) {
|
||||
/* Copy selection */
|
||||
copy_selection();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) &&
|
||||
(event->modifiers & KEY_MOD_LEFT_CTRL || event->modifiers & KEY_MOD_RIGHT_CTRL) &&
|
||||
(event->keycode == 'v')) {
|
||||
/* Paste selection */
|
||||
if (selection_text) {
|
||||
handle_input_s(selection_text);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event->modifiers & KEY_MOD_LEFT_ALT || event->modifiers & KEY_MOD_RIGHT_ALT) {
|
||||
handle_input('\033');
|
||||
}
|
||||
@ -675,21 +922,67 @@ void key_event(int ret, key_event_t * event) {
|
||||
handle_input_s("\033[23~");
|
||||
break;
|
||||
case KEY_F12:
|
||||
/* XXX This is for testing only */
|
||||
handle_input_s("テスト");
|
||||
//handle_input_s("\033[24~");
|
||||
handle_input_s("\033[24~");
|
||||
break;
|
||||
case KEY_ARROW_UP:
|
||||
handle_input_s("\033[A");
|
||||
if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[6A");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[5A");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[4A");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[3A");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT) {
|
||||
handle_input_s("\033[2A");
|
||||
} else {
|
||||
handle_input_s("\033[A");
|
||||
}
|
||||
break;
|
||||
case KEY_ARROW_DOWN:
|
||||
handle_input_s("\033[B");
|
||||
if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[6B");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[5B");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[4B");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[3B");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT) {
|
||||
handle_input_s("\033[2B");
|
||||
} else {
|
||||
handle_input_s("\033[B");
|
||||
}
|
||||
break;
|
||||
case KEY_ARROW_RIGHT:
|
||||
handle_input_s("\033[C");
|
||||
if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[6C");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[5C");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[4C");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[3C");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT) {
|
||||
handle_input_s("\033[2C");
|
||||
} else {
|
||||
handle_input_s("\033[C");
|
||||
}
|
||||
break;
|
||||
case KEY_ARROW_LEFT:
|
||||
handle_input_s("\033[D");
|
||||
if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[6D");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_CTRL) {
|
||||
handle_input_s("\033[5D");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[4D");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_ALT) {
|
||||
handle_input_s("\033[3D");
|
||||
} else if (event->modifiers & KEY_MOD_LEFT_SHIFT) {
|
||||
handle_input_s("\033[2D");
|
||||
} else {
|
||||
handle_input_s("\033[D");
|
||||
}
|
||||
break;
|
||||
case KEY_PAGE_UP:
|
||||
handle_input_s("\033[5~");
|
||||
@ -698,10 +991,10 @@ void key_event(int ret, key_event_t * event) {
|
||||
handle_input_s("\033[6~");
|
||||
break;
|
||||
case KEY_HOME:
|
||||
handle_input_s("\033OH");
|
||||
handle_input_s("\033[H");
|
||||
break;
|
||||
case KEY_END:
|
||||
handle_input_s("\033OF");
|
||||
handle_input_s("\033[F");
|
||||
break;
|
||||
case KEY_DEL:
|
||||
handle_input_s("\033[3~");
|
||||
@ -735,12 +1028,12 @@ term_callbacks_t term_callbacks = {
|
||||
term_scroll,
|
||||
term_redraw_cursor,
|
||||
input_buffer_stuff,
|
||||
set_term_font_size,
|
||||
set_title,
|
||||
unsupported,
|
||||
unsupported_int,
|
||||
unsupported_int,
|
||||
term_set_csr_show,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void reinit(int send_sig) {
|
||||
@ -768,7 +1061,7 @@ void maybe_flip_cursor(void) {
|
||||
void check_for_exit(void) {
|
||||
if (exit_application) return;
|
||||
|
||||
int pid = waitpid(-1, NULL, WNOHANG);
|
||||
pid_t pid = waitpid(-1, NULL, WNOHANG);
|
||||
|
||||
if (pid != child_pid) return;
|
||||
|
||||
@ -779,6 +1072,76 @@ void check_for_exit(void) {
|
||||
write(fd_slave, exit_message, sizeof(exit_message));
|
||||
}
|
||||
|
||||
static int mouse_x = 0;
|
||||
static int mouse_y = 0;
|
||||
static int last_mouse_buttons = 0;
|
||||
static int mouse_is_dragging = 0;
|
||||
|
||||
#define MOUSE_X_R 820
|
||||
#define MOUSE_Y_R 2621
|
||||
|
||||
static int old_x = 0;
|
||||
static int old_y = 0;
|
||||
|
||||
void handle_mouse_event(mouse_device_packet_t * packet) {
|
||||
if (mouse_is_dragging) {
|
||||
if (packet->buttons & LEFT_CLICK) {
|
||||
int old_end_x = selection_end_x;
|
||||
int old_end_y = selection_end_y;
|
||||
selection_end_x = mouse_x;
|
||||
selection_end_y = mouse_y;
|
||||
redraw_new_selection(old_end_x, old_end_y);
|
||||
} else {
|
||||
mouse_is_dragging = 0;
|
||||
}
|
||||
} else {
|
||||
if (packet->buttons & LEFT_CLICK) {
|
||||
term_redraw_all();
|
||||
selection_start_x = mouse_x;
|
||||
selection_start_y = mouse_y;
|
||||
selection_end_x = mouse_x;
|
||||
selection_end_y = mouse_y;
|
||||
selection = 1;
|
||||
redraw_selection();
|
||||
mouse_is_dragging = 1;
|
||||
} else {
|
||||
cell_redraw(old_x, old_y);
|
||||
cell_redraw_inverted(mouse_x, mouse_y);
|
||||
old_x = mouse_x;
|
||||
old_y = mouse_y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int rel_mouse_x = 0;
|
||||
static int rel_mouse_y = 0;
|
||||
|
||||
void handle_mouse(mouse_device_packet_t * packet) {
|
||||
rel_mouse_x += packet->x_difference;
|
||||
rel_mouse_y -= packet->y_difference;
|
||||
|
||||
mouse_x = rel_mouse_x / 20;
|
||||
mouse_y = rel_mouse_y / 40;
|
||||
|
||||
if (mouse_x < 0) mouse_x = 0;
|
||||
if (mouse_y < 0) mouse_y = 0;
|
||||
if (mouse_x >= term_width) mouse_x = term_width - 1;
|
||||
if (mouse_y >= term_height) mouse_y = term_height - 1;
|
||||
handle_mouse_event(packet);
|
||||
}
|
||||
|
||||
void handle_mouse_abs(mouse_device_packet_t * packet) {
|
||||
mouse_x = packet->x_difference / MOUSE_X_R;
|
||||
mouse_y = packet->y_difference / MOUSE_Y_R;
|
||||
|
||||
rel_mouse_x = mouse_x * 20;
|
||||
rel_mouse_y = mouse_y * 40;
|
||||
|
||||
handle_mouse_event(packet);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
@ -793,11 +1156,6 @@ int main(int argc, char ** argv) {
|
||||
/* Read some arguments */
|
||||
int index, c;
|
||||
while ((c = getopt_long(argc, argv, "hl", long_opts, &index)) != -1) {
|
||||
if (!c) {
|
||||
if (long_opts[index].flag == 0) {
|
||||
c = long_opts[index].val;
|
||||
}
|
||||
}
|
||||
switch (c) {
|
||||
case 'l':
|
||||
_login_shell = 1;
|
||||
@ -815,7 +1173,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
putenv("TERM=toaru");
|
||||
|
||||
syscall_openpty(&fd_master, &fd_slave, NULL, NULL, NULL);
|
||||
openpty(&fd_master, &fd_slave, NULL, NULL, NULL);
|
||||
|
||||
terminal = fdopen(fd_slave, "w");
|
||||
|
||||
@ -842,17 +1200,19 @@ int main(int argc, char ** argv) {
|
||||
|
||||
if (argv[optind] != NULL) {
|
||||
char * tokens[] = {argv[optind], NULL};
|
||||
int i = execvp(tokens[0], tokens);
|
||||
execvp(tokens[0], tokens);
|
||||
fprintf(stderr, "Failed to launch requested startup application.\n");
|
||||
} else {
|
||||
if (_login_shell) {
|
||||
char * tokens[] = {"/bin/login",NULL};
|
||||
int i = execvp(tokens[0], tokens);
|
||||
char * tokens[] = {"/bin/login-loop",NULL};
|
||||
execvp(tokens[0], tokens);
|
||||
exit(1);
|
||||
} else {
|
||||
char * shell = getenv("SHELL");
|
||||
if (!shell) shell = "/bin/sh"; /* fallback */
|
||||
char * tokens[] = {shell,NULL};
|
||||
int i = execvp(tokens[0], tokens);
|
||||
execvp(tokens[0], tokens);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -866,30 +1226,39 @@ int main(int argc, char ** argv) {
|
||||
int kfd = open("/dev/kbd", O_RDONLY);
|
||||
key_event_t event;
|
||||
char c;
|
||||
int vmmouse = 0;
|
||||
mouse_device_packet_t packet;
|
||||
|
||||
int mfd = open("/dev/mouse", O_RDONLY);
|
||||
int amfd = open("/dev/absmouse", O_RDONLY);
|
||||
if (amfd == -1) {
|
||||
amfd = open("/dev/vmmouse", O_RDONLY);
|
||||
vmmouse = 1;
|
||||
}
|
||||
|
||||
key_event_state_t kbd_state = {0};
|
||||
|
||||
/* Prune any keyboard input we got before the terminal started. */
|
||||
struct stat s;
|
||||
fstat(kfd, &s);
|
||||
for (int i = 0; i < s.st_size; i++) {
|
||||
for (unsigned int i = 0; i < s.st_size; i++) {
|
||||
char tmp[1];
|
||||
read(kfd, tmp, 1);
|
||||
}
|
||||
|
||||
int fds[2] = {fd_master, kfd};
|
||||
int fds[] = {fd_master, kfd, mfd, amfd};
|
||||
|
||||
unsigned char buf[1024];
|
||||
while (!exit_application) {
|
||||
|
||||
int index = syscall_fswait2(2,fds,200);
|
||||
int index = fswait2(amfd == -1 ? 3 : 4,fds,200);
|
||||
|
||||
check_for_exit();
|
||||
|
||||
if (index == 0) {
|
||||
maybe_flip_cursor();
|
||||
int r = read(fd_master, buf, 1024);
|
||||
for (uint32_t i = 0; i < r; ++i) {
|
||||
for (int i = 0; i < r; ++i) {
|
||||
ansi_put(ansi_state, buf[i]);
|
||||
}
|
||||
} else if (index == 1) {
|
||||
@ -900,6 +1269,25 @@ int main(int argc, char ** argv) {
|
||||
key_event(ret, &event);
|
||||
}
|
||||
} else if (index == 2) {
|
||||
/* mouse event */
|
||||
int r = read(mfd, (char *)&packet, sizeof(mouse_device_packet_t));
|
||||
if (r > 0) {
|
||||
last_mouse_buttons = packet.buttons;
|
||||
handle_mouse(&packet);
|
||||
}
|
||||
} else if (amfd != -1 && index == 3) {
|
||||
int r = read(amfd, (char *)&packet, sizeof(mouse_device_packet_t));
|
||||
if (r > 0) {
|
||||
if (!vmmouse) {
|
||||
packet.buttons = last_mouse_buttons & 0xF;
|
||||
} else {
|
||||
last_mouse_buttons = packet.buttons;
|
||||
}
|
||||
handle_mouse_abs(&packet);
|
||||
}
|
||||
continue;
|
||||
|
||||
} else {
|
||||
maybe_flip_cursor();
|
||||
}
|
||||
}
|
2412
apps/terminal.c
Normal file
2412
apps/terminal.c
Normal file
File diff suppressed because it is too large
Load Diff
25
apps/test-conf.c
Normal file
25
apps/test-conf.c
Normal file
@ -0,0 +1,25 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* test-conf - simple test app for confreader
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <toaru/confreader.h>
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
confreader_t * conf = confreader_load("/etc/demo.conf");
|
||||
|
||||
fprintf(stderr, "test 1\n");
|
||||
assert(confreader_get(conf, "", "test") != NULL);
|
||||
assert(!strcmp(confreader_get(conf, "", "test"),"hello"));
|
||||
|
||||
fprintf(stderr, "test 2\n");
|
||||
assert(!strcmp(confreader_get(conf,"sec","tion"),"test"));
|
||||
|
||||
return 0;
|
||||
}
|
5
apps/test.sh
Normal file
5
apps/test.sh
Normal file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
export-cmd UNAME uname
|
||||
export-cmd DATE date
|
||||
echo "This is a test shell script."
|
||||
echo "This is $UNAME and it is $DATE"
|
@ -1,4 +1,13 @@
|
||||
/* GIMP RGBA C-Source image dump (toaru_logo.c) */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2012 K. Lange
|
||||
*
|
||||
* toaru_logo.h - Generated by GIMP, ToaruOS logo
|
||||
*
|
||||
* Used by sysinfo. Can be used by other things as well.
|
||||
* TODO: sysinfo should probably just load a bitmap?
|
||||
*/
|
||||
|
||||
static const struct {
|
||||
unsigned int width;
|
48
apps/toggle-abs-mouse.c
Normal file
48
apps/toggle-abs-mouse.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* toggle-abs-mouse - Toggle mouse modes
|
||||
*
|
||||
* Set the mouse mode under VirtualBox, VMware, or QEMU to either
|
||||
* relative or absolute via ioctl to the relevant absolute mouse
|
||||
* device driver interface.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: argument (relative or absolute) expected\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = open("/dev/absmouse",O_WRONLY);
|
||||
if (fd < 0) {
|
||||
/* try vmmouse */
|
||||
fd = open("/dev/vmmouse",O_WRONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "%s: no valid mouse interface found.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int flag = 0;
|
||||
if (!strcmp(argv[1],"relative")) {
|
||||
flag = 1;
|
||||
}
|
||||
if (!strcmp(argv[1],"absolute")) {
|
||||
flag = 2;
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
fprintf(stderr, "%s: invalid argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ioctl(fd, flag, NULL);
|
||||
}
|
30
apps/touch.c
Normal file
30
apps/touch.c
Normal file
@ -0,0 +1,30 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013 K. Lange
|
||||
*
|
||||
* touch - Create or update file timestamps
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: argument expected\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int out = 0;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
FILE * f = fopen(argv[i], "a");
|
||||
if (!f) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
|
||||
out = 1;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
10
apps/true.c
Normal file
10
apps/true.c
Normal file
@ -0,0 +1,10 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* true - Return success code
|
||||
*/
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
112
apps/ttysize.c
Normal file
112
apps/ttysize.c
Normal file
@ -0,0 +1,112 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2018 K. Lange
|
||||
*
|
||||
* ttysize - Magically divine terminal size
|
||||
*
|
||||
* This is called by getty to determine the size of foreign
|
||||
* terminals, such as ones attached over serial.
|
||||
*
|
||||
* It works by placing the cursor in the lower right of the
|
||||
* screen and requesting its position. Note that typing things
|
||||
* while this happens can cause problems. Maybe we can flush
|
||||
* stdin before doing this to try to avoid any conflicting data?
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fswait.h>
|
||||
|
||||
static struct termios old;
|
||||
|
||||
static void set_unbuffered() {
|
||||
tcgetattr(fileno(stdin), &old);
|
||||
struct termios new = old;
|
||||
new.c_lflag &= (~ICANON & ~ECHO);
|
||||
tcsetattr(fileno(stdin), TCSAFLUSH, &new);
|
||||
}
|
||||
|
||||
static void set_buffered() {
|
||||
tcsetattr(fileno(stdin), TCSAFLUSH, &old);
|
||||
}
|
||||
|
||||
static int getc_timeout(FILE * f, int timeout) {
|
||||
int fds[1] = {fileno(f)};
|
||||
int index = fswait2(1,fds,timeout);
|
||||
if (index == 0) {
|
||||
return fgetc(f);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void divine_size(int * width, int * height) {
|
||||
set_unbuffered();
|
||||
|
||||
*width = 80;
|
||||
*height = 24;
|
||||
|
||||
fprintf(stderr, "\033[s\033[1000;1000H\033[6n\033[u");
|
||||
fflush(stderr);
|
||||
|
||||
char buf[1024] = {0};
|
||||
size_t i = 0;
|
||||
while (1) {
|
||||
char c = getc_timeout(stdin, 200);
|
||||
if (c == 'R') break;
|
||||
if (c == -1) goto _done;
|
||||
if (c == '\033') continue;
|
||||
if (c == '[') continue;
|
||||
buf[i++] = c;
|
||||
}
|
||||
|
||||
char * s = strstr(buf, ";");
|
||||
if (s) {
|
||||
*(s++) = '\0';
|
||||
|
||||
*height = atoi(buf);
|
||||
*width = atoi(s);
|
||||
}
|
||||
|
||||
_done:
|
||||
fflush(stderr);
|
||||
set_buffered();
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int width, height;
|
||||
int opt;
|
||||
int quiet = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "q")) != -1) {
|
||||
switch (opt) {
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind + 2 == argc) {
|
||||
width = atoi(argv[optind]);
|
||||
height = atoi(argv[optind+1]);
|
||||
} else {
|
||||
divine_size(&width, &height);
|
||||
}
|
||||
|
||||
struct winsize w;
|
||||
w.ws_col = width;
|
||||
w.ws_row = height;
|
||||
w.ws_xpixel = 0;
|
||||
w.ws_ypixel = 0;
|
||||
ioctl(0, TIOCSWINSZ, &w);
|
||||
|
||||
if (!quiet) {
|
||||
fprintf(stderr, "%dx%d\n", width, height);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user