Compare commits
1 Commits
master
...
d0bfb069bc
| Author | SHA1 | Date | |
|---|---|---|---|
|
d0bfb069bc
|
24
.clang-tidy
@@ -16,13 +16,15 @@ Checks: >
|
||||
readability-*,
|
||||
-readability-braces-around-statements,
|
||||
|
||||
WarningsAsErrors: ""
|
||||
HeaderFilterRegex: ".*"
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: '.*'
|
||||
FormatStyle: file
|
||||
|
||||
CheckOptions:
|
||||
- key: readability-magic-numbers.IgnoredIntegerValues
|
||||
value: "0;1;2;3;10;255"
|
||||
value: '0;1;2;3;10;255'
|
||||
# - key: readability-magic-numbers.IgnoredValues
|
||||
# value: '0;1;2;3;10;255'
|
||||
- key: readability-identifier-naming.VariableCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ConstantParameterCase
|
||||
@@ -30,20 +32,16 @@ CheckOptions:
|
||||
|
||||
- key: readability-identifier-naming.ConstantCase
|
||||
value: "UPPER_CASE"
|
||||
- key: readability-identifier-naming.EnumCase
|
||||
value: "CamelCase"
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: "lower_case"
|
||||
|
||||
- key: readability-identifier-length.VariableThreshold
|
||||
value: "2"
|
||||
value: '2'
|
||||
- key: readability-identifier-length.ParameterThreshold
|
||||
value: "2"
|
||||
value: '2'
|
||||
- key: readability-identifier-length.LocalConstantThreshold
|
||||
value: "2"
|
||||
value: '2'
|
||||
- key: readability-identifier-length.MemberThreshold
|
||||
value: "2"
|
||||
value: '2'
|
||||
- key: readability-identifier-length.MinimumParameterNameLength
|
||||
value: "2"
|
||||
value: '2'
|
||||
- key: readability-identifier-length.MinimumVariableNameLength
|
||||
value: "2"
|
||||
value: '2'
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[codespell]
|
||||
skip = ./assets/pkg/aur/*/src,./assets/pkg/aur/*/*/objects,./assets/pkg/aur/*/*.tar.*
|
||||
skip = ./assets/pkg/aur/*/src,./assets/pkg/aur/*/*/objects
|
||||
|
||||
2
.gitattributes
vendored
@@ -1,2 +0,0 @@
|
||||
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
38
.github/workflows/build.yml
vendored
@@ -67,8 +67,7 @@ jobs:
|
||||
apt-get update && \
|
||||
apt-get install -y make gcc libpam0g-dev
|
||||
run: ARCH=aarch64 GITHUB_STEP_SUMMARY=gss.out GITHUB_OUTPUT=go.out assets/github_scripts/build.sh
|
||||
- if: always()
|
||||
run: set +e; cat gss.out >>"$GITHUB_STEP_SUMMARY"; cat go.out >>"$GITHUB_OUTPUT"
|
||||
- run: set +e; cat gss.out >>"$GITHUB_STEP_SUMMARY"; cat go.out >>"$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -95,8 +94,7 @@ jobs:
|
||||
apt-get update && \
|
||||
apt-get install -y make gcc libpam0g-dev
|
||||
run: ARCH=armv7 GITHUB_STEP_SUMMARY=gss.out GITHUB_OUTPUT=go.out assets/github_scripts/build.sh
|
||||
- if: always()
|
||||
run: set +e; cat gss.out >>"$GITHUB_STEP_SUMMARY"; cat go.out >>"$GITHUB_OUTPUT"
|
||||
- run: set +e; cat gss.out >>"$GITHUB_STEP_SUMMARY"; cat go.out >>"$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -123,40 +121,10 @@ jobs:
|
||||
apt-get update && \
|
||||
apt-get install -y make gcc libpam0g-dev
|
||||
run: ARCH=riscv64 GITHUB_STEP_SUMMARY=gss.out GITHUB_OUTPUT=go.out assets/github_scripts/build.sh
|
||||
- if: always()
|
||||
run: set +e; cat gss.out >>"$GITHUB_STEP_SUMMARY"; cat go.out >>"$GITHUB_OUTPUT"
|
||||
- run: set +e; cat gss.out >>"$GITHUB_STEP_SUMMARY"; cat go.out >>"$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-riscv64
|
||||
path: lidm-riscv64
|
||||
retention-days: 1
|
||||
|
||||
# This build job is only symbolic, the behavior of the packaged Void Linux version may differ.
|
||||
build-linux-amd64-musl:
|
||||
name: amd64-musl
|
||||
runs-on: ubuntu-24.04
|
||||
permissions: write-all
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run in Musl Container
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
image: ghcr.io/void-linux/void-musl-full
|
||||
options: -v ${{ github.workspace }}:/workspace
|
||||
run: |
|
||||
cd /workspace
|
||||
|
||||
xbps-install -Syu xbps && xbps-install -yu
|
||||
xbps-install -y git pam-devel make gcc bash git
|
||||
|
||||
ARCH=amd64-musl GITHUB_STEP_SUMMARY=gss.out GITHUB_OUTPUT=go.out assets/github_scripts/build.sh
|
||||
- if: always()
|
||||
run: set +e; cat gss.out >>"$GITHUB_STEP_SUMMARY"; cat go.out >>"$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-amd64-musl
|
||||
path: lidm-amd64-musl
|
||||
retention-days: 1
|
||||
|
||||
24
.github/workflows/check.yml
vendored
@@ -26,26 +26,18 @@ jobs:
|
||||
with:
|
||||
packages: "shellcheck"
|
||||
version: 1.0
|
||||
- run: git ls-files "*.sh" "*/PKGBUILD" | xargs shellcheck --shell=bash
|
||||
- run: find . -type f -name '*.sh' -not -path './assets/pkg/aur/*/src/*' | xargs shellcheck
|
||||
|
||||
clangcheck:
|
||||
name: Clang
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ubuntu:25.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: apt -y update && apt install -y clang-format clang-tidy make gcc git bear libpam0g-dev
|
||||
|
||||
- uses: awalsh128/cache-apt-pkgs-action@latest
|
||||
with:
|
||||
packages: "clang-format clang-tidy bear libpam0g-dev"
|
||||
version: 1.0
|
||||
- run: bear -- make
|
||||
- run: clang-format -version && clang-format -dump-config
|
||||
- run: |
|
||||
set -euo pipefail
|
||||
clang-format -ni src/*.c include/*.h -Werror 2>&1 | \
|
||||
sed -E 's/^([^ ]+\.[ch]):([0-9]+):([0-9]+): ([a-z]+): (.*)$/::\4 file=\1,line=\2,col=\3::\5/'
|
||||
- run: clang-tidy -version && clang-tidy -dump-config
|
||||
- run: |
|
||||
set -euo pipefail
|
||||
clang-tidy -p . src/*.c include/*.h -warnings-as-errors=\* 2>&1 1>/dev/null |
|
||||
sed -E 's/^([^ ]+\.[ch]):([0-9]+):([0-9]+): ([a-z]+): (.*)$/::\4 file=\1,line=\2,col=\3::\5/'
|
||||
- run: clang-format -ni src/*.c include/*.h
|
||||
- run: clang-tidy -p . src/*.c include/*.h
|
||||
|
||||
32
.github/workflows/make-release.yml
vendored
@@ -16,8 +16,6 @@ jobs:
|
||||
packages: "git"
|
||||
version: 1.0
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
|
||||
- name: Check Version Changed
|
||||
id: check-ver-changed
|
||||
@@ -29,7 +27,6 @@ jobs:
|
||||
echo "ERR: Git tag matches makefile, did you bump Makefile up?" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "VERSION=$MAKE_TAG" >> "$GITHUB_OUTPUT"
|
||||
|
||||
|
||||
@@ -65,36 +62,37 @@ jobs:
|
||||
artifactErrorsFailBuild: true
|
||||
body: Release notes not generated yet.
|
||||
|
||||
nix-update:
|
||||
name: Update NixOS module
|
||||
aur-update:
|
||||
name: Update AUR pkgs
|
||||
runs-on: ubuntu-24.04
|
||||
container: archlinux:latest
|
||||
permissions: write-all
|
||||
needs: [ release-checks, release ]
|
||||
steps:
|
||||
- uses: cachix/install-nix-action@v31
|
||||
- run: pacman -Sy --noconfirm git github-cli base-devel pacman-contrib
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
|
||||
- run: |
|
||||
tmpdir=$(mktemp -d)
|
||||
git archive v${{ needs.release-checks.outputs.VERSION }} | tar -xC "$tmpdir"
|
||||
sha256sum=$(nix hash path "$tmpdir")
|
||||
chage -E -1 nobody
|
||||
passwd -u nobody
|
||||
|
||||
sed -i -E 's/(.*version\s*=\s*")[0-9.]*(".*)/\1'${{ needs.release-checks.outputs.VERSION }}'\2/' assets/pkg/nix/module.nix
|
||||
sed -i -E 's|(.*sha256\s*=\s*")[^"]*(".*)|\1'"$sha256sum"'\2|' assets/pkg/nix/module.nix
|
||||
# would be cool to be able to check the new module.nix builds
|
||||
cd "assets/pkg/aur"
|
||||
chown nobody:nobody . -R
|
||||
su - -s /bin/bash nobody -c "$PWD/update-pkgs.sh ${{ needs.release-checks.outputs.VERSION }}"
|
||||
su - -s /bin/bash nobody -c "$PWD/test-makepkg.sh" # This will also update -git pkgver
|
||||
chown $UID:$(id -g) . -R
|
||||
|
||||
- run: |
|
||||
BRANCH=actions/update-nix-${{ needs.release-checks.outputs.VERSION }}
|
||||
BRANCH=actions/update-aur-${{ needs.release-checks.outputs.VERSION }}
|
||||
git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
git config user.name "GitHub Actions"
|
||||
git config user.email "actions@github.com"
|
||||
git checkout -b $BRANCH
|
||||
git commit -am "Update NixOS module to v${{ needs.release-checks.outputs.VERSION }}"
|
||||
git commit -am "Update AUR pkgs to v${{ needs.release-checks.outputs.VERSION }}"
|
||||
git push -u origin $BRANCH
|
||||
gh pr create --head $BRANCH \
|
||||
--title "[Nix update]: Bump to ${{ needs.release-checks.outputs.VERSION }}" \
|
||||
--title "[AUR update]: Bump to ${{ needs.release-checks.outputs.VERSION }}" \
|
||||
--body "*This PR was created automatically*"
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
17
.github/workflows/push.yml
vendored
@@ -12,24 +12,7 @@ jobs:
|
||||
name: Check
|
||||
uses: ./.github/workflows/check.yml
|
||||
permissions: write-all
|
||||
check_paths:
|
||||
name: Paths Filter
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
code_changed: ${{ steps.filter.outputs.code }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- id: filter
|
||||
uses: dorny/paths-filter@v3
|
||||
with:
|
||||
filters: |
|
||||
code:
|
||||
- Makefile
|
||||
- 'src/**'
|
||||
- 'include/**'
|
||||
build:
|
||||
name: Build
|
||||
needs: check_paths
|
||||
if: github.event_name != 'push' || needs.check_paths.outputs.code_changed == 'true'
|
||||
uses: ./.github/workflows/build.yml
|
||||
permissions: write-all
|
||||
|
||||
2
.gitignore
vendored
@@ -8,3 +8,5 @@ valgrind-out.txt
|
||||
|
||||
# nix build result
|
||||
result
|
||||
|
||||
include/version.h
|
||||
|
||||
23
CHANGELOG.md
@@ -1,23 +0,0 @@
|
||||
<!-- Unspecified dates shall be in CET/CEST -->
|
||||
|
||||
<!-- Add only very relevant changes, bottom to top -->
|
||||
<!-- By "very relevant" I mean big features or something manual packagers should know, like leftover files -->
|
||||
<!-- Once a release would be opened, group the last bunch of dangling changes, add release version as header and its date -->
|
||||
|
||||
# 2.0.2
|
||||
|
||||
- fix off-by-one error with launch state save
|
||||
|
||||
# 2.0.1
|
||||
|
||||
- source and header files can be nested in `src/` and `include/`
|
||||
- lidm now calls bash for logging in and sourcing profile files, other shells can be configured
|
||||
- a good PATH default is fetched from `confstr`
|
||||
- debug logs are now unbuffered
|
||||
|
||||
# 2.0.0
|
||||
|
||||
- Most stuff (most of `/etc` being a notable exception) now installs to `/usr/local` by default, check [`docs/PACKAGERS.md`](./docs/PACKAGERS.md).
|
||||
- Added a changelog.
|
||||
- Finally add proper (experimental) xorg support.
|
||||
- Systemd service install path changed to `/usr/local/lib/systemd`, there could be a leftover file at `/etc/systemd/system/lidm.service`.
|
||||
75
INSTALL.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Index
|
||||
|
||||
- [Index](#index)
|
||||
- [Installing from Source](#installing-from-source)
|
||||
- [AUR](#aur)
|
||||
- [Nix Flake](#nix-flake)
|
||||
|
||||
> [!CAUTION]
|
||||
> I encourage you to read the manual installation steps to understand what will get installed in your computer by this package.
|
||||
|
||||
# Installing from Source
|
||||
|
||||
Firstly, you'll need to build the package, this also includes man pages, default config, themes and other files you might need.
|
||||
|
||||
To build it you only need to have some basic packages (should come pre-installed in almost all distros): `make`, `gcc` or another `gcc`ish compiler, and libpam headers. If it builds, it surely works anyways.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/javalsai/lidm.git
|
||||
cd lidm
|
||||
make # 👍
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> There's pre-built binaries on the [releases tab](https://github.com/javalsai/lidm/releases) too.
|
||||
|
||||
Then you can install the files onto your filesystem with:
|
||||
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
|
||||
And additionally, to install service files (start-up behavior). <sup>[more docs](./assets/services/README.md)</sup>
|
||||
|
||||
```sh
|
||||
# automatically detects your init system
|
||||
# and install service file (for tty7)
|
||||
make install-service
|
||||
|
||||
# or if you don't like autodetection
|
||||
make install-service-systemd # systemd
|
||||
make install-service-dinit # dinit
|
||||
make install-service-runit # runit (/etc/sv)
|
||||
make install-service-runit-etc # runit (/etc/runit/sv)
|
||||
make install-service-openrc # openrc
|
||||
make install-service-s6 # s6 (/etc/sv)
|
||||
make install-service-s6-etc # s6 (/etc/s6/sv)
|
||||
|
||||
# For runit and s6, some distros (e.g. Artix) like to put it in /etc/<init>/sv
|
||||
# to better isolate their packages while other distros (e.g. Void) just put it
|
||||
# in /etc/sv
|
||||
```
|
||||
|
||||
# AUR
|
||||
|
||||
[AUR packages](https://aur.archlinux.org/packages?K=lidm\&SeB=n) will automatically install most files.
|
||||
|
||||
> [!CAUTION]
|
||||
> [service files](./assets/pkg/aur#services) have to be manually installed by now.
|
||||
|
||||
# Nix Flake
|
||||
|
||||
You can install by doing
|
||||
|
||||
```sh
|
||||
nix profile install github:javalsai/lidm
|
||||
```
|
||||
|
||||
or try it out without installing by:
|
||||
|
||||
```sh
|
||||
nix run github:javalsai/lidm
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> This doesn't include [service files](./assets/pkg/aur#services) neither
|
||||
151
Makefile
@@ -1,45 +1,49 @@
|
||||
VERSION := 2.0.2
|
||||
VERSION = 1.2.1
|
||||
.DEFAULT_GOAL := lidm
|
||||
|
||||
CDIR = src
|
||||
LDIR = lib
|
||||
IDIR = include
|
||||
ODIR = dist
|
||||
CDIR=src
|
||||
LDIR=lib
|
||||
IDIR=include
|
||||
ODIR=dist
|
||||
|
||||
PREFIX = /usr/local
|
||||
PREFIX=/usr
|
||||
|
||||
INFO_GIT_REV ?= $(shell git describe --long --tags --always || echo '?')
|
||||
INFO_GIT_REV := $(INFO_GIT_REV)
|
||||
INFO_BUILD_TS ?= $(shell date +%s)
|
||||
INFO_BUILD_TS := $(INFO_BUILD_TS)
|
||||
CC?=gcc
|
||||
CFLAGS?=-O3 -Wall
|
||||
ALLFLAGS=$(CFLAGS) -I$(IDIR)
|
||||
|
||||
CFLAGS ?= -O3 -Wall -Wextra -fdata-sections -ffunction-sections
|
||||
# C PreProcessor flags, not C Plus Plus
|
||||
CPPFLAGS ?=
|
||||
_DFLAGS?= \
|
||||
-DLIDM_VERSION=\"$(VERSION)\" \
|
||||
-DLIDM_GIT_REV=\"$(INFO_GIT_REV)\" \
|
||||
-DLIDM_BUILD_TS=$(INFO_BUILD_TS)
|
||||
ALLFLAGS = $(_DFLAGS) $(CFLAGS) $(CPPFLAGS) -I$(IDIR)
|
||||
LDFLAGS ?= -Wl,--gc-sections
|
||||
LIBS=-lpam
|
||||
|
||||
LIBS = -lpam
|
||||
_DEPS = version.h log.h util.h ui.h ui_state.h config.h desktop.h auth.h ofield.h efield.h keys.h users.h sessions.h chvt.h macros.h launch_state.h
|
||||
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
|
||||
|
||||
# includes all headers in `$(IDIR)` and compiles everything in `$(CDIR)`
|
||||
DEPS = $(wildcard $(IDIR)/*.h $(IDIR)/**/*.h)
|
||||
_SOURCES = $(wildcard $(CDIR)/*.c) $(wildcard $(CDIR)/**/*.c)
|
||||
OBJ = $(patsubst $(CDIR)/%.c,$(ODIR)/%.o,$(_SOURCES))
|
||||
_OBJ = main.o log.o util.o ui.o ui_state.o config.o desktop.o auth.o ofield.o efield.o users.o sessions.o chvt.o launch_state.o
|
||||
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
|
||||
|
||||
.git/HEAD:
|
||||
|
||||
$(IDIR)/version.h: Makefile .git/HEAD
|
||||
@tmp=$$(mktemp); \
|
||||
printf '' > $$tmp; \
|
||||
echo '#define LIDM_VERSION "'$(VERSION)'"' >> $$tmp; \
|
||||
echo '#define LIDM_GIT_REV "'$$(git describe --long --tags --always || echo '?')'"' >> $$tmp; \
|
||||
echo '#define LIDM_BUILD_TS '$$(date +%s) >> $$tmp; \
|
||||
if ! cmp -s $$tmp $@; then \
|
||||
mv $$tmp $@; \
|
||||
fi; \
|
||||
rm -f $$tmp;
|
||||
|
||||
$(ODIR)/%.o: $(CDIR)/%.c $(DEPS)
|
||||
@mkdir -p $(dir $@)
|
||||
@mkdir -p $(ODIR)
|
||||
$(CC) -c -o $@ $< $(ALLFLAGS)
|
||||
|
||||
lidm: $(OBJ)
|
||||
$(CC) -o $@ $^ $(ALLFLAGS) $(LIBS) $(LDFLAGS)
|
||||
$(CC) -o $@ $^ $(ALLFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -rf $(ODIR) lidm
|
||||
rm -f $(ODIR)/*.o lidm
|
||||
|
||||
# Copy lidm to ${DESTDIR}${PREFIX}/bin (/usr/bin)
|
||||
install: lidm
|
||||
mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${PREFIX}/share/man/man{1,5}
|
||||
install -Dm755 ./lidm ${DESTDIR}${PREFIX}/bin/
|
||||
@@ -47,25 +51,102 @@ install: lidm
|
||||
install -Dm644 ./assets/man/lidm.1 ${DESTDIR}${PREFIX}/share/man/man1/
|
||||
install -Dm644 ./assets/man/lidm-config.5 ${DESTDIR}${PREFIX}/share/man/man5/
|
||||
|
||||
uninstall: uninstall-service
|
||||
uninstall:
|
||||
rm -rf ${DESTDIR}${PREFIX}/bin/lidm ${DESTDIR}/etc/lidm.ini
|
||||
rm -rf ${DESTDIR}${PREFIX}/share/man/man{1/lidm.1,5/lidm-config.5}.gz
|
||||
rm -rf ${DESTDIR}/usr/share/man/man{1/lidm.1,5/lidm-config.5}.gz
|
||||
rm -rf ${DESTDIR}/etc/systemd/system/lidm.service ${DESTDIR}/etc/dinit.d/lidm ${DESTDIR}/etc/runit/sv/lidm
|
||||
|
||||
include services.mk
|
||||
install-service:
|
||||
@if command -v systemctl &> /dev/null; then \
|
||||
make install-service-systemd; \
|
||||
elif command -v dinitctl &> /dev/null; then \
|
||||
make install-service-dinit; \
|
||||
elif command -v sv &> /dev/null; then \
|
||||
if [ -d /etc/sv ]; then \
|
||||
make install-service-runit; \
|
||||
elif [ -d /etc/runit/sv ]; then \
|
||||
make install-service-runit-etc; \
|
||||
else \
|
||||
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
|
||||
fi \
|
||||
elif command -v rc-update &> /dev/null; then \
|
||||
make install-service-openrc; \
|
||||
elif command -v s6-service &> /dev/null; then \
|
||||
if [ -d /etc/sv ]; then\
|
||||
make install-service-s6; \
|
||||
elif [ -d /etc/r6nit/sv ]; then \
|
||||
make install-service-s6-etc; \
|
||||
else \
|
||||
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
|
||||
fi \
|
||||
else \
|
||||
printf '\033[1;31m%s\033[0m\n' "Unknown init system, skipping service install..." >&"; \
|
||||
fi
|
||||
|
||||
install-service-systemd:
|
||||
install -m644 ./assets/services/systemd.service ${DESTDIR}/etc/systemd/system/lidm.service
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'systemctl enable lidm'"
|
||||
install-service-dinit:
|
||||
install -m644 ./assets/services/dinit ${DESTDIR}/etc/dinit.d/lidm
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'dinitctl enable lidm'"
|
||||
install-service-runit:
|
||||
@if [ ! -e /etc/sv ] && [ -d /etc/runit/sv ] && [ -z "$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/runit/sv does" >&2 \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit-etc'" >&2 \
|
||||
exit 1 \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/sv/lidm
|
||||
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/sv/lidm /var/service' or your distro equivalent"
|
||||
install-service-runit-etc:
|
||||
@if [ ! -e /etc/runit/sv ] && [ -d /etc/sv ] && [ -z "$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/runit/sv doesn't exist but /etc/sv does" >&2 \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit'" >&2 \
|
||||
exit 1 \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/runit/sv/lidm
|
||||
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/runit/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/runit/sv/lidm /run/runit/service' or your distro equivalent"
|
||||
install-service-openrc:
|
||||
install -m755 ./assets/services/openrc ${DESTDIR}/etc/init.d/lidm
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'rc-update add lidm'"
|
||||
install-service-s6:
|
||||
@if [ ! -e /etc/sv ] && [ -d /etc/s6/sv ] && [ -z "$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/s6/sv does" >&2 \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6-etc'" >&2 \
|
||||
exit 1 \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/sv/lidm
|
||||
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
|
||||
install-service-s6-etc:
|
||||
@if [ ! -e /etc/s6/sv ] && [ -d /etc/sv ] && [ -z "$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/s6/sv doesn't exist but /etc/sv does" >&2 \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6'" >&2 \
|
||||
exit 1 \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/s6/sv/lidm
|
||||
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/s6/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
|
||||
|
||||
pre-commit:
|
||||
codespell
|
||||
prettier -c "**/*.md"
|
||||
git ls-files "*.sh" "*/PKGBUILD" | xargs shellcheck --shell=bash
|
||||
find . -type f -name '*.sh' -not -path './assets/pkg/aur/*/src/*' | xargs shellcheck
|
||||
clang-format -i $$(git ls-files "*.c" "*.h")
|
||||
git ls-files -z "*.c" "*.h" | \
|
||||
parallel -j$$(nproc) -q0 --no-notice --will-cite --tty clang-tidy -warnings-as-errors=\* --quiet |& \
|
||||
grep -v "warnings generated." || true
|
||||
clang-tidy -p . $$(git ls-files "*.c" "*.h")
|
||||
|
||||
print-version:
|
||||
@echo $(VERSION)
|
||||
|
||||
.PHONY: clean \
|
||||
install uninstall \
|
||||
install-service \
|
||||
install-service-s6 \
|
||||
install-service-s6-etc \
|
||||
install-service-dinit \
|
||||
install-service-runit \
|
||||
install-service-runit-etc \
|
||||
install-service-openrc \
|
||||
install-service-systemd \
|
||||
pre-commit \
|
||||
print-version
|
||||
|
||||
110
README.md
@@ -10,47 +10,33 @@ LiDM is like any [Display Manager](https://en.wikipedia.org/wiki/X_display_manag
|
||||
|
||||

|
||||
|
||||
<blockquote><details>
|
||||
<summary><i>
|
||||
shown as in a featured terminal emulator, actual linux console doesn't support as much color and decorations
|
||||
</i></summary>
|
||||
> *shown as in a featured terminal emulator, actual linux console doesn't support as much color and decorations*
|
||||
|
||||
If you want to add fancy color and font support to your TTYs you can try wrapping lidm in [`kmscon`](https://wiki.archlinux.org/title/KMSCON). (edit appropriate service files). e.g:
|
||||
|
||||
```sh
|
||||
kmscon -l --vt /dev/tty7 --font-name "Cascadia Code" -- /usr/bin/lidm
|
||||
```
|
||||
|
||||
Kmscon is NOT officially supported so you are on your own when trying this, [according to the arch wiki](https://wiki.archlinux.org/title/KMSCON#Window_managers_cannot_be_started_from_KMS_console) it's not possible to start window managers if you do this.
|
||||
|
||||
But [according to farouk](https://github.com/javalsai/lidm/issues/91#issuecomment-3708503568) you can make it work if you tell kmscon to work in `no-drm` mode. There's still input grabbing issues which cause <kbd><kbd>Ctrl</kbd> + <kbd>C</kbd></kbd> to kill lidm, they are likely fixable though.
|
||||
|
||||
</details></blockquote>
|
||||
|
||||
> _however, all colors and strings are fully customizable_
|
||||
> *however, all colors and strings are fully customizable*
|
||||
|
||||
## Features
|
||||
|
||||
- Simple as C, meant to depend only on standard libc and basic unix system headers.
|
||||
- Fully customizable: ALL strings, colors (with its ANSI keys) and most behavior.
|
||||
- Experimental Xorg support[\*](https://github.com/javalsai/lidm/pull/80?#issuecomment-3764073217) and wayland sessions, while supporting the default user shell (if enabled in config)
|
||||
- Init agnostinc (systemd, dinit, runit, openrc and s6).
|
||||
- Supports [fido yubikeys](./docs/yubikey.md) (via pam_u2f).
|
||||
* Simple as C, you only need a C compiler and standard unix libraries to build this.
|
||||
* Fully customizable, from strings, including action keys, to colors (I hope you know ansi escape codes)
|
||||
* Automatically detects xorg and wayland sessions, plus allowing to launch the default user shell (if enabled in config)
|
||||
* Starts with many init systems (systemd, dinit, runit, openrc and s6).
|
||||
|
||||
# Table of Contents
|
||||
# Index
|
||||
|
||||
- [Ideology](#ideology)
|
||||
- [Usage](#usage)
|
||||
- [Arguments](#arguments)
|
||||
- [Program](#program)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation)
|
||||
- [Configuring](#configuring)
|
||||
- [PAM](#pam)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
- [Inspiration](#inspiration)
|
||||
- [Contributors](#contributors)
|
||||
* [LiDM](#lidm)
|
||||
* [Features](#features)
|
||||
* [WIP](#wip)
|
||||
* [Index](#index)
|
||||
* [Ideology](#ideology)
|
||||
* [Usage](#usage)
|
||||
* [Arguments](#arguments)
|
||||
* [Program](#program)
|
||||
* [Requirements](#requirements)
|
||||
* [Installation](#installation)
|
||||
* [Configuring](#configuring)
|
||||
* [Contributing](#contributing)
|
||||
* [Inspiration](#inspiration)
|
||||
* [Contributors](#contributors)
|
||||
|
||||
# Ideology
|
||||
|
||||
@@ -58,7 +44,7 @@ We all know that the most important thing in a project is the ideology of the au
|
||||
|
||||
[  ](https://stopchatcontrol.eu)
|
||||
|
||||
> _there's also a [change.org post](https://www.change.org/p/stoppt-die-chatkontrolle-grundrechte-gelten-auch-im-netz)._
|
||||
> *there's also a [change.org post](https://www.change.org/p/stoppt-die-chatkontrolle-grundrechte-gelten-auch-im-netz).*
|
||||
|
||||
# Usage
|
||||
|
||||
@@ -70,33 +56,25 @@ If a single argument is provided (don't even do `--` or standard unix parsing...
|
||||
|
||||
Base (mostly intuitive):
|
||||
|
||||
- Use arrow keys to navigate the inputs and type over any of them to override the default value.
|
||||
- Enter will just attempt to login.
|
||||
- If you are focused on an edited input, horizontal arrow keys will attempt to move across the text just as expected.
|
||||
* Use arrow keys to navigate the inputs and type over any of them to override the default value.
|
||||
* Enter will just attempt to login.
|
||||
* If you are focused on an edited input, horizontal arrow keys will attempt to move across the text just as expected.
|
||||
|
||||
On top of that:
|
||||
|
||||
- Using the horizontal arrow keys if the focused input is not in text mode or the movement would overflow the input. It will try to change in such direction the option of session or the user.
|
||||
- Pressing <kbd>ESC</kbd> and then horizontal arrows will force to change the option of the focused input even if it's in edit mode.
|
||||
- Editing an option on a user or a shell session will put you in edit mode appending after the original value.
|
||||
* Using the horizontal arrow keys if the focused input is not in text mode or the movement would overflow the input. It will try to change in such direction the option of session or the user.
|
||||
* Pressing <kbd>ESC</kbd> and then horizontal arrows will force to change the option of the focused input even if it's in edit mode.
|
||||
* Editing an option on a user or a shell session will put you in edit mode appending after the original value.
|
||||
|
||||
# Requirements
|
||||
|
||||
- Make (Also optional, but does things automatically, make sure `gcc` and `mkdir -p` work as expected).
|
||||
- A compiler like `cc`, `gcc` or `clang`. Make sure to use the desired `CC=<compiler>` on the `make` command.
|
||||
- PAM library, used for user authentication, just what `login` or `su` use internally. Don't worry, it's surely pre-installed.
|
||||
* Make (Also optional, but does things automatically, make sure `gcc` and `mkdir -p` work as expected).
|
||||
* A compiler like `cc`, `gcc` or `clang`. Make sure to use the desired `CC=<compiler>` on the `make` command.
|
||||
* PAM library, used for user authentication, just what `login` or `su` use internally. Don't worry, it's surely pre-installed.
|
||||
|
||||
# Installation
|
||||
|
||||
Check the [installation guide](./docs/INSTALL.md) to use your preferred installation source.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Packagers read here!!</summary>
|
||||
|
||||
If you are a package maintainer or are willing to become one, please read [the packagers guide](./docs/PACKAGERS.md).
|
||||
|
||||
</details>
|
||||
Check the [installation guide](INSTALL.md) to use your preferred installation source.
|
||||
|
||||
# Configuring
|
||||
|
||||
@@ -112,20 +90,10 @@ Colors are gonna be put inside `\x1b[...m`, if you don't know what this is check
|
||||
> [!TIP]
|
||||
> If you don't like seeing an element, you can change the fg color of it to be the same as the bg, making it invisible.
|
||||
|
||||
# PAM
|
||||
|
||||
If your distribution does not use the standard PAM service name `login` (`/etc/pam.d/login`) for its PAM services or if you want to use another PAM file, simply set the `LIDM_PAM_SERVICE` env variable to your PAM service name.
|
||||
|
||||
When the env variable is empty it defaults to the `login` PAM service or whatever fallback your distribution packager has defined during compilation.
|
||||
|
||||
# Contributing
|
||||
|
||||
If you want to contribute check the [contribution guide](docs/CONTRIBUTING.md).
|
||||
|
||||
# License
|
||||
|
||||
This project is licensed under the GNU General Public License v3.0 **only**.
|
||||
|
||||
# Inspiration
|
||||
|
||||
This project was started after facing some issues building [ly](https://github.com/fairyglade/ly) on an ancient laptop, the UI is heavily inspired by it.
|
||||
@@ -134,21 +102,21 @@ For this reason the project's philosophy is to be simple and minimal, such that
|
||||
|
||||
I forgot what exactly the name came from, but it surely was a mix of a few things so:
|
||||
|
||||
- Obviously it's inspired by `ly`. `ly-dm` leads to "lydm".
|
||||
- Wow make "lydm" simple with a "y" → "i" transformation.
|
||||
- Associate it with the "i" in s**i**mple and other display managers like **Li**ghtDM.
|
||||
- And the **la**ptop this project started in has a **lid**.
|
||||
* Obviously it's inspired by `ly`. `ly-dm` leads to "lydm".
|
||||
* Wow make "lydm" simple with a "y" → "i" transformation.
|
||||
* Associate it with the "i" in s**i**mple and other display managers like **Li**ghtDM.
|
||||
* And the **la**ptop this project started in has a **lid**.
|
||||
|
||||
# Contributors
|
||||
|
||||
[](https://github.com/javalsai/lidm/graphs/contributors)
|
||||
[](https://github.com/javalsai/lidm/graphs/contributors)
|
||||
|
||||
[killertofus](https://github.com/killertofus), [deadvey](https://github.com/deadvey), [grialion](https://github.com/grialion/), cerealexperiments\_, [antiz96](https://github.com/Antiz96), [rmntgx](https://github.com/rmntgx) and [more...](https://github.com/javalsai/lidm/graphs/contributors)
|
||||
|
||||
With their big or small contributions, every commit has helped in its own way and encouraged me to keep putting my soul into this.
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
🌟 Finally, consider starring this repo [or...](https://www.reddit.com/r/github/comments/1l2mchg/is_this_allowed) 🔪
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -13,9 +13,8 @@ make -j"$(nproc)" "$@" 2> /tmp/stderr || ERR=$?
|
||||
BSIZE=$(stat --printf="%s" lidm)
|
||||
HSIZE=$(numfmt --to=iec-i<<<"$BSIZE")B
|
||||
WARNS=$(
|
||||
sed -nE \
|
||||
's/^([^ ]+\.[ch]):([0-9]+):([0-9]+): ([a-z]+): (.*)$/::\4 file=\1,line=\2,col=\3::\5/p' \
|
||||
/tmp/stderr
|
||||
{ grep -E '^[^ ]+\.[ch]:[0-9]+:[0-9]+: [a-z]+:' /tmp/stderr || :; } \
|
||||
| sed -E 's/^([^ ]+\.[ch]):([0-9]+):([0-9]+): ([a-z]+): (.*)$/::\4 file=\1,line=\2,col=\3::\5/'
|
||||
)
|
||||
WARNS_NUM=$({ [[ "$WARNS" == "" ]] && echo 0; } || wc -l <<<"$WARNS")
|
||||
|
||||
|
||||
@@ -69,13 +69,13 @@ Characters for the corners of the box (ctl = corner top left, cbr = corner botto
|
||||
.SS functions
|
||||
All these are of type \fBKEY\fP.
|
||||
.TP
|
||||
\fBpoweroff, reboot, fido, refresh\fP
|
||||
\fBpoweroff, reboot, refresh\fP
|
||||
Function key to use for such action.
|
||||
|
||||
.SS strings
|
||||
Display strings to use for some elements.
|
||||
.TP
|
||||
\fBf_poweroff, f_reboot, f_fido, f_refresh\fP
|
||||
\fBf_poweroff, f_reboot, f_refresh\fP
|
||||
Text displayed to name such functions at the bottom of the screen.
|
||||
.TP
|
||||
\fBe_user, e_passwd\fP
|
||||
@@ -104,9 +104,6 @@ Specify the time format string to be displayed. Check \fBstrftime (3)\fP to know
|
||||
.TP
|
||||
\fBrefresh_rate\fP
|
||||
Rate (in milliseconds) at which the UI should refresh, affects clock and resize behavior.
|
||||
.TP
|
||||
\fBbypass_shell_login\fP
|
||||
Type \fBBOOL\fP, lidm logins through a login shell (e.g. `bash`) in login mode (e.g. `arg0` being `-bash`) to load `/etc/profile/, `/etc/profile.d/` and more. If this option is enabled that's bypassed entirely.
|
||||
|
||||
|
||||
.SH "SEE ALSO"
|
||||
|
||||
|
Before Width: | Height: | Size: 131 B After Width: | Height: | Size: 205 KiB |
4
assets/pkg/aur/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*/*
|
||||
!*/.gitignore
|
||||
!*/PKGBUILD
|
||||
!*/.SRCINFO
|
||||
12
assets/pkg/aur/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# AUR Packages
|
||||
|
||||
These files are just for reference, I'll manually edit and publish them, at least until I automate it with github actions (like updating version automatically on a release).
|
||||
|
||||
There are three packages that follow standard conventions:
|
||||
|
||||
* [`lidm`](https://aur.archlinux.org/packages/lidm): Builds latest release (manually updated per release basis)
|
||||
* [`lidm-bin`](https://aur.archlinux.org/packages/lidm-bin): Fetches latest release binary (compiled by GitHub Actions, also updated per release)
|
||||
* [`lidm-git`](https://aur.archlinux.org/packages/lidm-git): Fetches latest commit and builds it (should be updated automatically)
|
||||
|
||||
> \[!IMPORTANT]
|
||||
> None of those packages include the service files. [You have to do this yourself](../../services/README.md).
|
||||
20
assets/pkg/aur/lidm-bin/.SRCINFO
Normal file
@@ -0,0 +1,20 @@
|
||||
pkgbase = lidm-bin
|
||||
pkgdesc = A fully colorful customizable TUI display manager made in C. (release binary)
|
||||
pkgver = 1.2.0
|
||||
pkgrel = 1
|
||||
url = https://github.com/javalsai/lidm
|
||||
arch = x86_64
|
||||
license = GPL
|
||||
depends = pam
|
||||
provides = lidm
|
||||
conflicts = lidm
|
||||
source = lidm::https://github.com/javalsai/lidm/releases/download/v1.2.0/lidm-amd64
|
||||
source = default-theme.ini::https://raw.githubusercontent.com/javalsai/lidm/v1.2.0/themes/default.ini
|
||||
source = lidm.1::https://raw.githubusercontent.com/javalsai/lidm/v1.2.0/assets/man/lidm.1
|
||||
source = lidm-config.5::https://raw.githubusercontent.com/javalsai/lidm/v1.2.0/assets/man/lidm-config.5
|
||||
sha256sums = 6bf4403c21bd26607302d99d7bd1a129822e7d2506e949fb483ea445e022eb6d
|
||||
sha256sums = ffaa5fe2cf5011bf53c90f81bfec8585158d35f72c0666db0bd4d3866ae041ca
|
||||
sha256sums = 7f2fb91f55088be1a9b1c93ecf5d6c1e437f369b56df2eacc9d10b00c93c39f8
|
||||
sha256sums = 0aa5755bdcc60ea80cd9ee0f89233ffaf22c6cee9db9da277274a62c6ed477d9
|
||||
|
||||
pkgname = lidm-bin
|
||||
3
assets/pkg/aur/lidm-bin/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!PKGBUILD
|
||||
!.SRCINFO
|
||||
29
assets/pkg/aur/lidm-bin/PKGBUILD
Normal file
@@ -0,0 +1,29 @@
|
||||
# shellcheck disable=SC2034,SC2148,SC2128,SC2154,SC2164
|
||||
# Maintainer: javalsai <javalsai@proton.me>
|
||||
pkgname=lidm-bin
|
||||
pkgver=1.2.0
|
||||
pkgrel=1
|
||||
depends=('pam')
|
||||
pkgdesc="A fully colorful customizable TUI display manager made in C. (release binary)"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/javalsai/lidm"
|
||||
license=('GPL')
|
||||
provides=('lidm')
|
||||
conflicts=('lidm')
|
||||
source=(
|
||||
"lidm::$url/releases/download/v$pkgver/lidm-amd64"
|
||||
"default-theme.ini::https://raw.githubusercontent.com/javalsai/lidm/v$pkgver/themes/default.ini"
|
||||
"lidm.1::https://raw.githubusercontent.com/javalsai/lidm/v$pkgver/assets/man/lidm.1"
|
||||
"lidm-config.5::https://raw.githubusercontent.com/javalsai/lidm/v$pkgver/assets/man/lidm-config.5"
|
||||
)
|
||||
sha256sums=('6bf4403c21bd26607302d99d7bd1a129822e7d2506e949fb483ea445e022eb6d'
|
||||
'ffaa5fe2cf5011bf53c90f81bfec8585158d35f72c0666db0bd4d3866ae041ca'
|
||||
'7f2fb91f55088be1a9b1c93ecf5d6c1e437f369b56df2eacc9d10b00c93c39f8'
|
||||
'0aa5755bdcc60ea80cd9ee0f89233ffaf22c6cee9db9da277274a62c6ed477d9')
|
||||
|
||||
package() {
|
||||
install -Dm755 lidm "${pkgdir}/usr/bin/lidm"
|
||||
install -Dm644 default-theme.ini "${pkgdir}/etc/lidm.ini"
|
||||
install -Dm644 lidm.1 "${pkgdir}/usr/share/man/man1/lidm.1"
|
||||
install -Dm644 lidm-config.5 "${pkgdir}/usr/share/man/man5/lidm-config.5"
|
||||
}
|
||||
17
assets/pkg/aur/lidm-git/.SRCINFO
Normal file
@@ -0,0 +1,17 @@
|
||||
pkgbase = lidm-git
|
||||
pkgdesc = A fully colorful customizable TUI display manager made in C. (last git commit)
|
||||
pkgver = 0.1.0.r0.g8071694
|
||||
pkgrel = 1
|
||||
url = https://github.com/javalsai/lidm
|
||||
arch = any
|
||||
license = GPL
|
||||
makedepends = git
|
||||
makedepends = make
|
||||
makedepends = gcc
|
||||
depends = pam
|
||||
provides = lidm
|
||||
conflicts = lidm
|
||||
source = lidm::git+https://github.com/javalsai/lidm
|
||||
sha256sums = SKIP
|
||||
|
||||
pkgname = lidm-git
|
||||
3
assets/pkg/aur/lidm-git/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!PKGBUILD
|
||||
!.SRCINFO
|
||||
31
assets/pkg/aur/lidm-git/PKGBUILD
Normal file
@@ -0,0 +1,31 @@
|
||||
# shellcheck disable=SC2034,SC2148,SC2128,SC2154,SC2164
|
||||
# Maintainer: javalsai <javalsai@proton.me>
|
||||
pkgname=lidm-git
|
||||
pkgver=1.2.0.r0.g7f75b8e
|
||||
pkgrel=1
|
||||
depends=('pam')
|
||||
makedepends=('git' 'make' 'gcc')
|
||||
pkgdesc="A fully colorful customizable TUI display manager made in C. (last git commit)"
|
||||
arch=('any')
|
||||
url="https://github.com/javalsai/lidm"
|
||||
license=('GPL')
|
||||
provides=('lidm')
|
||||
conflicts=('lidm')
|
||||
source=("lidm::git+https://github.com/javalsai/lidm")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "lidm"
|
||||
git describe --long --abbrev=7 --tags | \
|
||||
sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "lidm"
|
||||
make CFLAGS="-O3"
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "lidm"
|
||||
make install DESTDIR="${pkgdir}"
|
||||
}
|
||||
14
assets/pkg/aur/lidm/.SRCINFO
Normal file
@@ -0,0 +1,14 @@
|
||||
pkgbase = lidm
|
||||
pkgdesc = A fully colorful customizable TUI display manager made in C. (build latest tag)
|
||||
pkgver = 1.2.0
|
||||
pkgrel = 1
|
||||
url = https://github.com/javalsai/lidm
|
||||
arch = any
|
||||
license = GPL
|
||||
makedepends = git
|
||||
makedepends = gcc
|
||||
depends = pam
|
||||
source = tarball.tar.gz::https://github.com/javalsai/lidm/archive/refs/tags/v1.2.0.tar.gz
|
||||
sha256sums = 0dffded5fcef45cb45fe88358b0cba8de04f614e323a9c6e4162f84b6e3a50b6
|
||||
|
||||
pkgname = lidm
|
||||
3
assets/pkg/aur/lidm/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!PKGBUILD
|
||||
!.SRCINFO
|
||||
25
assets/pkg/aur/lidm/PKGBUILD
Normal file
@@ -0,0 +1,25 @@
|
||||
# shellcheck disable=SC2034,SC2148,SC2128,SC2154,SC2164
|
||||
# Maintainer: javalsai <javalsai@proton.me>
|
||||
pkgname=lidm
|
||||
pkgver=1.2.0
|
||||
pkgrel=1
|
||||
depends=('pam')
|
||||
makedepends=('git' 'gcc')
|
||||
pkgdesc="A fully colorful customizable TUI display manager made in C. (build latest tag)"
|
||||
arch=('any')
|
||||
url="https://github.com/javalsai/lidm"
|
||||
license=('GPL')
|
||||
source=("tarball.tar.gz::https://github.com/javalsai/lidm/archive/refs/tags/v$pkgver.tar.gz")
|
||||
sha256sums=('0dffded5fcef45cb45fe88358b0cba8de04f614e323a9c6e4162f84b6e3a50b6')
|
||||
|
||||
build() {
|
||||
tar -xzf "tarball.tar.gz"
|
||||
cd "lidm-$pkgver"
|
||||
|
||||
make CFLAGS="-O3"
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "lidm-$pkgver"
|
||||
make install DESTDIR="${pkgdir}"
|
||||
}
|
||||
12
assets/pkg/aur/make-srcinfo.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
MYSELF=$(realpath "$0")
|
||||
MYDIR=$(dirname "$MYSELF")
|
||||
|
||||
for pkg in "$MYDIR"/*/; do
|
||||
cd "$pkg"
|
||||
printf "\x1b[1mEntering '%s'\x1b[0m\n" "$pkg"
|
||||
makepkg --printsrcinfo | tee .SRCINFO
|
||||
echo
|
||||
done
|
||||
21
assets/pkg/aur/test-makepkg.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
MYSELF=$(realpath "$0")
|
||||
MYDIR=$(dirname "$MYSELF")
|
||||
|
||||
for pkg in "$MYDIR"/*/; do
|
||||
printf "\x1b[1mEntering '%s'\x1b[0m\n" "$pkg"
|
||||
cd "$pkg"
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source "PKGBUILD"
|
||||
for source in "${source[@]}"; do
|
||||
awk -F'::' '{print $1}' <<<"$source" | xargs rm -rf
|
||||
done
|
||||
|
||||
rm -rf ./*.{gz,zst} src pkg
|
||||
makepkg -f .
|
||||
|
||||
echo
|
||||
done
|
||||
29
assets/pkg/aur/update-pkgs.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
MYSELF=$(realpath "$0")
|
||||
MYDIR=$(dirname "$MYSELF")
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
printf "\x1b[1;31mERR: No version to update provided\x1b[0m\n" >&2
|
||||
exit 1;
|
||||
fi
|
||||
version="$1"
|
||||
printf "\x1b[34mINF: Using '%s' version\x1b[0m\n" "$version"
|
||||
|
||||
for pkg in "$MYDIR"/lidm{,-bin}/; do
|
||||
cd "$pkg"
|
||||
printf "\x1b[1mEntering '%s'\x1b[0m\n" "$pkg"
|
||||
sed -i "s/pkgver=.*/pkgver=$1/" PKGBUILD
|
||||
sed -i "s/pkgrel=.*/pkgrel=1/" PKGBUILD
|
||||
|
||||
grep 'source = ' <.SRCINFO | awk -F'= |::' '{print $2}' | \
|
||||
while read -r srcfile; do
|
||||
printf "\x1b[31mDeleting '%s'\x1b[0m\n" "$srcfile"
|
||||
rm -f "$srcfile"
|
||||
done
|
||||
|
||||
updpkgsums
|
||||
makepkg --printsrcinfo | tee .SRCINFO
|
||||
echo
|
||||
done
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
cfg,
|
||||
src,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
maker = import ./make-cfg.nix {
|
||||
inherit lib;
|
||||
keys-h-file = builtins.readFile "${src}/include/keys.h";
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit maker;
|
||||
file = builtins.toFile "lidm.conf" (
|
||||
if builtins.isString cfg then
|
||||
builtins.readFile "${src}/themes/${cfg}.ini"
|
||||
else if builtins.isAttrs cfg then
|
||||
maker.make cfg
|
||||
else
|
||||
builtins.throw "invalid cfg type, expected str or attrs"
|
||||
);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
get-cfg =
|
||||
if config.cfg != null then
|
||||
import ./get-cfg-file.nix {
|
||||
inherit lib;
|
||||
inherit (config) cfg src;
|
||||
}
|
||||
else
|
||||
null;
|
||||
cfg-file = get-cfg.file;
|
||||
maker = get-cfg.maker;
|
||||
in
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
pname = "lidm";
|
||||
version = config.version;
|
||||
src = config.src;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
gcc
|
||||
gnumake
|
||||
linux-pam
|
||||
];
|
||||
|
||||
makeFlags =
|
||||
[
|
||||
"DESTDIR=$(out)"
|
||||
"PREFIX="
|
||||
]
|
||||
++ lib.optional (
|
||||
config.xsessions != null
|
||||
) "CPPFLAGS+=-DSESSIONS_XSESSIONS=\\\"${config.xsessions}\\\""
|
||||
++ lib.optional (
|
||||
config.wayland-sessions != null
|
||||
) "CPPFLAGS+=-DSESSIONS_WAYLAND=\\\"${config.wayland-sessions}\\\""
|
||||
++ lib.optional (cfg-file != null) "CPPFLAGS+=-DLIDM_CONF_PATH=\\\"${cfg-file}\\\"";
|
||||
|
||||
fixupPhase = ''
|
||||
rm -rf $out/etc
|
||||
'';
|
||||
|
||||
passthru = {
|
||||
keysEnum = maker.keys-enum;
|
||||
};
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
{ lib, keys-h-file }:
|
||||
|
||||
let
|
||||
double-match-to-nameval = dmatch: {
|
||||
name = builtins.elemAt dmatch 0;
|
||||
value = builtins.elemAt dmatch 1;
|
||||
};
|
||||
|
||||
keys-enum =
|
||||
let
|
||||
key-names = builtins.replaceStrings [ "\n" " " ] [ "" "" ] (
|
||||
builtins.elemAt (builtins.match ".*KEY_NAMES\\[][[:blank:]]*=[[:blank:]]*\\{([^}]*)}.*" keys-h-file) 0
|
||||
);
|
||||
|
||||
keys-2d-list = builtins.map (builtins.match "\\[(.*)]=\"(.*)\"") (
|
||||
builtins.filter (s: builtins.isString s && s != "") (builtins.split "," key-names)
|
||||
);
|
||||
|
||||
in
|
||||
builtins.listToAttrs (
|
||||
builtins.map (
|
||||
k:
|
||||
k
|
||||
// {
|
||||
value = {
|
||||
__enum_key = k.value;
|
||||
};
|
||||
}
|
||||
) (builtins.map double-match-to-nameval keys-2d-list)
|
||||
);
|
||||
in
|
||||
{
|
||||
inherit keys-enum;
|
||||
make =
|
||||
let
|
||||
name-val-to-attrs = (name: value: { inherit name value; });
|
||||
map-attrs = attrset: fn: lib.map fn (lib.attrsets.mapAttrsToList name-val-to-attrs attrset);
|
||||
|
||||
try-foldl' =
|
||||
op: nul: list:
|
||||
if (builtins.length list) == 0 then "" else builtins.foldl' op nul list;
|
||||
concat-with = sepr: list: try-foldl' (x: y: if x == null then y else x + sepr + y) null list;
|
||||
|
||||
ser-bool = bool: if bool then "true" else "false";
|
||||
ser-str = str: "\"${builtins.replaceStrings [ "\n" "\"" ] [ "\\n" "\\\"" ] str}\"";
|
||||
ser-kvs =
|
||||
{ name, value }:
|
||||
if builtins.isList value then
|
||||
concat-with "\n" (builtins.map (value: ser-kvs { inherit name value; }) value)
|
||||
else
|
||||
"${name} = ${
|
||||
if builtins.isString value then
|
||||
ser-str value
|
||||
else if builtins.isInt value then
|
||||
builtins.toString value
|
||||
else if builtins.isBool value then
|
||||
ser-bool value
|
||||
else if builtins.isAttrs value then
|
||||
value.__enum_key
|
||||
else
|
||||
builtins.throw "type not supported"
|
||||
}";
|
||||
|
||||
ser-table =
|
||||
table':
|
||||
let
|
||||
tname = table'.name;
|
||||
table = table'.value;
|
||||
in
|
||||
"[${tname}]\n" + (concat-with "\n" (map-attrs table ser-kvs));
|
||||
in
|
||||
cfg: concat-with "\n\n" (map-attrs cfg ser-table);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.lidm;
|
||||
|
||||
dmcfg = config.services.displayManager;
|
||||
desktops = dmcfg.sessionData.desktops;
|
||||
|
||||
version = "2.0.1";
|
||||
lidmPkg = pkgs.callPackage ./lidm.nix {
|
||||
inherit pkgs;
|
||||
config = {
|
||||
inherit version lib;
|
||||
cfg = cfg.config;
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "javalsai";
|
||||
repo = "lidm";
|
||||
rev = "v${version}";
|
||||
sha256 = "sha256-bpUqhD1JSiYRf7w7ylEMXHMvEpnSri1zZSxRQPdZWB4=";
|
||||
};
|
||||
|
||||
xsessions = "${desktops}/share/xsessions";
|
||||
wayland-sessions = "${desktops}/share/wayland-sessions";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
lidm.keysEnum = lib.mkOption {
|
||||
type = with lib.types; attrs;
|
||||
default = lidm.passthru.keysEnum;
|
||||
readOnly = true;
|
||||
description = "Keys enum constants";
|
||||
};
|
||||
services.lidm.config = lib.mkOption {
|
||||
type =
|
||||
with lib.types;
|
||||
oneOf [
|
||||
str
|
||||
attrs
|
||||
];
|
||||
default = { };
|
||||
description = "Config options for lidm | Either attr tree or name of bundled themes";
|
||||
};
|
||||
};
|
||||
config = {
|
||||
services.displayManager.defaultSession = "lidm";
|
||||
|
||||
systemd.services.lidm = {
|
||||
description = "TUI display manager";
|
||||
aliases = [ "display-manager.service" ];
|
||||
after = [
|
||||
"systemd-user-sessions.service"
|
||||
"plymouth-quit-wait.service"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "idle";
|
||||
ExecStart = "${lidmPkg}/bin/lidm 7";
|
||||
StandardInput = "tty";
|
||||
StandardOutput = "tty";
|
||||
StandardError = "tty";
|
||||
TTYPath = "/dev/tty7";
|
||||
TTYReset = "yes";
|
||||
TTYVHangup = "yes";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,44 +2,41 @@
|
||||
|
||||
This folder contains the files necessary to set up lidm on start up for the supported init systems, all of them are configured for tty7.
|
||||
|
||||
If you're using lidm from a packaged source, this should be included with the package. Only read this for manual installations, if you are packaging or if your package exceptionally doesn't include them.
|
||||
|
||||
If you don't know what a init system is, you're certainly using `systemd`.
|
||||
|
||||
There's make scripts to automatically copy the service files to the proper locations, you just have to run `make install-service-$INIT` (or `make install-service-$INIT-etc`). `make install-service` will attempt to detect the init system in use and install for it.
|
||||
|
||||
The manual steps for installation are:
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you think this should be packaged too, there's [a discussion](https://github.com/javalsai/lidm/discussions/39) to talk about this.
|
||||
|
||||
## Systemd
|
||||
|
||||
- Copy `systemd.service` to `/usr/local/lib/systemd/system/lidm.service` (if the directory doesn't exist, create it first) or `/usr/lib/systemd/system/lidm.service` (if you wish to install along your system files).
|
||||
- To enable it you can run `systemctl enable lidm`
|
||||
* Copy `systemd.service` to `/etc/systemd/system/lidm.service`
|
||||
* To enable it you can run `systemctl enable lidm`
|
||||
|
||||
## Dinit
|
||||
|
||||
- Copy `dinit` to `/etc/dinit.d/lidm`
|
||||
- To enable it, run `dinitctl enable lidm`
|
||||
* Copy `dinit` to `/etc/dinit.d/lidm`
|
||||
* To enable it, run `dinitctl enable lidm`
|
||||
|
||||
## Runit
|
||||
|
||||
Your runit service path can be either `/etc/runit/sv` or `/etc/sv`.
|
||||
|
||||
- Copy `runit/` to `runit-path/lidm/`
|
||||
- Add the service with `ln -s runit-path/lidm /run/runit/service`
|
||||
- And to enable it `sv enable lidm`
|
||||
* Copy `runit/` to `/etc/runit/sv/lidm/`
|
||||
* Add the service with `ln -s /etc/runit/sv/lidm /run/runit/service`
|
||||
* And to enable it `sv enable lidm`
|
||||
|
||||
## OpenRC
|
||||
|
||||
- Copy `openrc` to `/etc/init.d/lidm`
|
||||
- Enable the service with `rc-update add lidm`
|
||||
* Copy `openrc` to `/etc/init.d/lidm`
|
||||
* Enable the service with `rc-update add lidm`
|
||||
|
||||
## S6
|
||||
|
||||
Your S6 service path can be either `/etc/s6/sv` or `/etc/sv`.
|
||||
|
||||
- Copy `s6/` to `s6-path/lidm/`
|
||||
- Add the service with `s6-service add default lidm`
|
||||
- Reload the database with `s6-db-reload` (you might have to run this every time the service file changes)
|
||||
* Copy `s6/` to `/etc/s6/sv/lidm/`
|
||||
* Add the service with `s6-service add default lidm`
|
||||
* Reload the database with `s6-db-reload` (you might have to run this every time the service file changes)
|
||||
|
||||
> [!WARNING]
|
||||
> Make sure to disable any other service that might run on tty7, such us lightdm or most display managers out there.
|
||||
|
||||
@@ -5,13 +5,12 @@ After=systemd-user-sessions.service plymouth-quit-wait.service
|
||||
[Service]
|
||||
Type=idle
|
||||
ExecStart=/usr/bin/lidm 7
|
||||
StandardError=journal
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
StandardError=tty
|
||||
TTYPath=/dev/tty7
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
Alias=display-manager.service
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
type = process
|
||||
command = /bin/sh -c "LIDM_LOG=/tmp/lidm.debug /sbin/agetty tty8 linux-c -n -l /usr/local/bin/lidm -o 8"
|
||||
restart = true
|
||||
depends-on = login.target
|
||||
termsignal = HUP
|
||||
smooth-recovery = true
|
||||
inittab-id = 8
|
||||
inittab-line = tty8
|
||||
log-type = buffer
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
Contributions are welcome! Here's how you can help:
|
||||
|
||||
- [Contributing](#contributing)
|
||||
- [Code](#code)
|
||||
- [Issues](#issues)
|
||||
- [Other](#other)
|
||||
* [Contributing code](#code)
|
||||
* [Reporting issues](#issues)
|
||||
* [Other](#other)
|
||||
|
||||
## Code
|
||||
|
||||
@@ -13,33 +12,33 @@ For small fixes or incremental improvements simply fork the repo and follow the
|
||||
|
||||
1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository and [clone](https://help.github.com/articles/cloning-a-repository/) your fork.
|
||||
|
||||
2. Start coding! (it might be helpful to read a [quide on the project structure and conventions](./structure.md) before this)
|
||||
- Configure clangd LSP by generating `compile_commands.json` (e.g. `bear -- make` or `compiledb make`)
|
||||
- Implement your feature.
|
||||
- Check your code works as expected.
|
||||
- Run the code formatter: `clang-format -i $(git ls-files "*.c" "*.h")`.
|
||||
- Run the code linter: `clang-tidy -p . $(git ls-files "*.c" "*.h")`. Some checks are pretty pedantic, feel free to ignore or debate some of the rules.
|
||||
- If you prefer, you can run `make pre-commit` to run several code style checks like the above along a few extra stuff (shellcheck, spellcheck, prettier, etc).
|
||||
2. Start coding! (it might be helpful to read a [quide on the project structure and conventions](structure.md) before this)
|
||||
* Configure clangd LSP by generating `compile_commands.json` (e.g. `bear -- make` or `compiledb make`)
|
||||
* Implement your feature.
|
||||
* Check your code works as expected.
|
||||
* Run the code formatter: `clang-format -i $(git ls-files "*.c" "*.h")`
|
||||
* Run the code linter: `clang-tidy -p . $(git ls-files "*.c" "*.h")`. Some checks are pretty pedantic, feel free to ignore or debate some of the rules.
|
||||
* If you prefer, you can run `make pre-commit` to run several code style checks like the avobe along a few extra stuff.
|
||||
|
||||
3. Commit your changes to a new branch (not `master`, one change per branch) and push it:
|
||||
- Commit messages should:
|
||||
- Header line: explain the commit in one line (use the imperative) ("feat" for features, "fix", "style", "chore", "docs", etc)
|
||||
- Be descriptive.
|
||||
- Don't make the title too long and add commit descriptions if you think the changes need it.
|
||||
- e.g. "feat: add support for X", "fix(config): config parser segfaulting", "docs(typo): fix a typo in README.md"
|
||||
* Commit messages should:
|
||||
* Header line: explain the commit in one line (use the imperative) ("feat" for features, "fix", "style", "chore", "docs", etc)
|
||||
* Be descriptive.
|
||||
* Don't make the title too long and add commit descriptions if you think the changes need it.
|
||||
* e.g. "feat: add support for X", "fix(config): config parser segfaulting", "docs(typo): fix a typo in README.md"
|
||||
|
||||
4. Once you are happy with your changes, submit a pull request.
|
||||
- Open the pull request.
|
||||
- Add a short description explaining what you've done (or if it's a work-in-progress - what you need to do)
|
||||
* Open the pull request.
|
||||
* Add a short description explaining what you've done (or if it's a work-in-progress - what you need to do)
|
||||
|
||||
## Issues
|
||||
|
||||
1. Do a quick search on GitHub to check if the issue has already been reported.
|
||||
2. [Open an issue](https://github.com//javalsai/lidm/issues/new) and describe the issue you are having - you could include:
|
||||
- Screenshots.
|
||||
- Ways to reproduce the issue.
|
||||
- Your lidm version.
|
||||
- Your platform (e.g. arch linux or Ubuntu 15.04 x64) and init system if you know.
|
||||
* Screenshots.
|
||||
* Ways to reproduce the issue.
|
||||
* Your lidm version.
|
||||
* Your platform (e.g. arch linux or Ubuntu 15.04 x64) and init system if you know.
|
||||
|
||||
After reporting you should aim to answer questions or clarifications as this helps pinpoint the cause of the issue.
|
||||
|
||||
|
||||
175
docs/INSTALL.md
@@ -1,175 +0,0 @@
|
||||
# Table of Contents
|
||||
|
||||
- [Packages](#packages)
|
||||
- [Void Linux](#void-linux)
|
||||
- [Fedora](#fedora)
|
||||
- [AUR](#aur)
|
||||
- [Nix Flake](#nix-flake)
|
||||
- [Nix Module](#nix-module)
|
||||
- [Installing from Source](#installing-from-source)
|
||||
|
||||
# Packages
|
||||
|
||||
Lidm relies on its community to package lidm for distributions and make the installation easier for everyone. Please raise any issues on the packages themselves and not the source repository.
|
||||
|
||||
If you packaged lidm for any distribution not listed here or keep your own version of an inactive package, feel free to contact me to be added here. (could be a GitHub discussion or an email if you don't use GitHub)
|
||||
|
||||
These packages just install lidm, once installed you have to enable it. It depends on your init system, but if you're using systemd (most likely), first find your currently active display manager (if any, examples are `sddm`, `gdm`, `ly`) and disable it:
|
||||
|
||||
```sh
|
||||
systemctl disable <display manager name here>
|
||||
```
|
||||
|
||||
And then enable lidm:
|
||||
|
||||
```sh
|
||||
systemctl enable lidm
|
||||
```
|
||||
|
||||
Lidm now should show on the next boot!
|
||||
|
||||
If you are on a TTY and don't wish to reboot, you should be able to use `--now` with both commands. It's likely to kill your current desktop environment if it was launched from it.
|
||||
|
||||
## Void Linux
|
||||
|
||||
Lidm can be installed from the official Void Linux packages:
|
||||
|
||||
```sh
|
||||
xbps-install lidm
|
||||
```
|
||||
|
||||
To enable the service that starts on boot:
|
||||
|
||||
```sh
|
||||
ln -s /etc/sv/lidm /var/service/
|
||||
```
|
||||
|
||||
It is recommended to disable any other display managers that are still enabled:
|
||||
|
||||
```sh
|
||||
touch /etc/sv/lightdm/down # replace lightdm with your previous display manager (e.g., sddm, gdm)
|
||||
```
|
||||
|
||||
## Fedora
|
||||
|
||||
Thanks to @KernelFreeze there's a COPR repo available at <https://copr.fedorainfracloud.org/coprs/celestelove/lidm/> to install lidm. (<https://github.com/javalsai/lidm/discussions/92>)
|
||||
|
||||
## AUR
|
||||
|
||||
There are several [AUR packages](https://aur.archlinux.org/packages?K=lidm&SeB=n) for most things. You only need to install one of the following:
|
||||
|
||||
- `lidm`
|
||||
- `lidm-bin`
|
||||
- `lidm-git`
|
||||
|
||||
Each of those depend on `lidm-service` which is provided by `lidm-systemd` and `lidm-dinit` (you'll have to pick one). I maintain both but I'm open to anyone that actually uses systemd to take the first one.
|
||||
|
||||
There's packagers needed for openrc, s6 and runit. If you know how to make AUR packages, feel free to take any of those if you use each init system.
|
||||
|
||||
## Nix Flake
|
||||
|
||||
You can install by doing
|
||||
|
||||
```sh
|
||||
nix profile install github:javalsai/lidm
|
||||
```
|
||||
|
||||
or try it out without installing by:
|
||||
|
||||
```sh
|
||||
nix run github:javalsai/lidm
|
||||
```
|
||||
|
||||
## Nix Module
|
||||
|
||||
<details>
|
||||
<summary>Sidenote</summary>
|
||||
|
||||
The nix module lacks on several aspects, if you know much about nix and know
|
||||
how to improve this package, feel free to open an issue or a PR to help. The
|
||||
nix package maintainer position is open too.
|
||||
|
||||
</details>
|
||||
|
||||
Lidm includes a nix module in `assets/pkg/nix/module.nix` that you can add
|
||||
(along the included nix files) and import in your `configuration.nix`.
|
||||
|
||||
Once imported you'll need to add:
|
||||
|
||||
```nix
|
||||
services.displayManager.enable = true;
|
||||
systemd.services.lidm.enable = true;
|
||||
```
|
||||
|
||||
Optionally, you can configure it setting `services.lidm.config`. You can either
|
||||
pass:
|
||||
|
||||
- A string to copy the config from a theme in `themes/` with said name
|
||||
(**name**, e.g `"cherry"`).
|
||||
- An attribute tree with the same names as the config file, e.g:
|
||||
|
||||
```nix
|
||||
with config.lidm.keysEnum; {
|
||||
strings = {
|
||||
f_poweroff = "custom_poweroff";
|
||||
};
|
||||
|
||||
behavior = {
|
||||
include_defshell = true;
|
||||
source = [
|
||||
"path1"
|
||||
"path2"
|
||||
];
|
||||
};
|
||||
|
||||
functions = { poweroff = F1; };
|
||||
|
||||
# etc...
|
||||
};
|
||||
```
|
||||
|
||||
> _it's not necessary to cover all keys and anything can be put there, even if it's not valid config_
|
||||
|
||||
# Installing from Source
|
||||
|
||||
Firstly, you'll need to build the package, this also includes man pages, default config, themes and other files you might need.
|
||||
|
||||
To build it you only need to have some basic packages (should come pre-installed in almost all distros): `make`, `gcc` or another `gcc`ish compiler, and libpam headers. If it builds, it surely works anyways.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/javalsai/lidm.git
|
||||
cd lidm
|
||||
make # 👍
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> There are pre-built binaries on the [releases tab](https://github.com/javalsai/lidm/releases) too.
|
||||
|
||||
Then you can install the files onto your filesystem with:
|
||||
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
|
||||
This will install mostly into `/usr/local` by default, this path is mostly unused nowadays (systemd can load services from it but man usually doesn't find manual pages in there) and could feel like lidm didn't install at all. You can add `PREFIX=/usr` to install along the rest of your system packages if you wish.
|
||||
|
||||
And additionally, to install service files (start-up behavior). <sup>[more docs](../assets/services/README.md)</sup>
|
||||
|
||||
```sh
|
||||
# automatically detects your init system
|
||||
# and install service file (for tty7)
|
||||
make install-service
|
||||
|
||||
# or if you don't like autodetection
|
||||
make install-service-systemd # systemd
|
||||
make install-service-dinit # dinit
|
||||
make install-service-runit # runit (/etc/sv)
|
||||
make install-service-runit-etc # runit (/etc/runit/sv)
|
||||
make install-service-openrc # openrc
|
||||
make install-service-s6 # s6 (/etc/sv)
|
||||
make install-service-s6-etc # s6 (/etc/s6/sv)
|
||||
|
||||
# For runit and s6, some distros (e.g. Artix) like to put it in /etc/<init>/sv
|
||||
# to better isolate their packages while other distros (e.g. Void) just put it
|
||||
# in /etc/sv
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
This is a guide listing all possible options packagers have to tweak behavior of lidm and the extra stuff to package.
|
||||
|
||||
# Components
|
||||
|
||||
If you want to package lidm for a distribution you have to package the binary and:
|
||||
|
||||
- Man pages ([`../assets/man/`](../assets/man/))
|
||||
- Service files ([`../assets/services/`](../assets/services/))
|
||||
- PAM (see [#preprocessor-defines](#preprocessor-defines))
|
||||
- And optionally you can include some default themes in `/usr` ([`../themes/`](../themes/))
|
||||
|
||||
# Preprocessor Defines
|
||||
|
||||
Most of the behavior that can be tweaked using preprocessor `#define`s, to include some simply add `CPPFLAGS+='-D{{name}}={{value}}'` to your `make` command. e.g:
|
||||
|
||||
```sh
|
||||
make \
|
||||
CPPFLAGS+='-DSESSIONS_XSESSIONS=\"/var/empty\"' \
|
||||
CPPFLAGS+='-DSESSIONS_WAYLAND=\"/var/empty\"'
|
||||
```
|
||||
|
||||
The list of possible `#define`s is:
|
||||
|
||||
| Name | Default | Description | Env Override? |
|
||||
| -------------------------- | ------------------------------------- | -------------------------------------------------------------------------- | ------------------------ |
|
||||
| `PAM_SERVICE_FALLBACK` | `"login"` | Name of the default PAM module to use. Defaults to the distro's `"login"`. | Yes (`LIDM_PAM_SERVICE`) |
|
||||
| `SESSIONS_XSESSIONS` | `"/usr/share/xsessions"` | | No |
|
||||
| `SESSIONS_XSESSIONS_LOCAL` | `"/usr/local/share/xsessions"` | | No |
|
||||
| `SESSIONS_WAYLAND` | `"/usr/share/wayland-sessions"` | | No |
|
||||
| `SESSIONS_WAYLAND_LOCAL` | `"/usr/local/share/wayland-sessions"` | | No |
|
||||
| `LIDM_CONF_PATH` | `"/etc/lidm.ini"` | Path of the default configuration. | Yes (`LIDM_CONF`) |
|
||||
| `LOGIN_SHELL` | `"bash"` | Login shell name. | No |
|
||||
|
||||
# Other Build Settings
|
||||
|
||||
## Compiler
|
||||
|
||||
Lidm attempts to support being built by `gcc` and `clang` with preference over the first. However, if you wish to take advantage of LLVM's optimizations over GNU's you can change the compiler with `make CC=clang` or try any other compiler.
|
||||
|
||||
## Compiler Flags
|
||||
|
||||
Compiler flags should be passed with `CFLAGS`, its `-O3 -Wall` by default so adding anything will overwrite this.
|
||||
|
||||
## Build Metadata
|
||||
|
||||
`lidm -v` outputs some information about the build version, this can be weaked with `INFO_GIT_REV` and `INFO_BUILD_TS`, by default they are:
|
||||
|
||||
```make
|
||||
INFO_GIT_REV?=$$(git describe --long --tags --always || echo '?')
|
||||
INFO_BUILD_TS?=$$(date +%s)
|
||||
```
|
||||
|
||||
But this can be changed by just passing those env variables, for example, in the case git is not applicable in the build environment of the package.
|
||||
|
||||
## Target Directory
|
||||
|
||||
`DESTDIR` can be used to for installation recipes to install on alternative root directories. Along with `PREFIX` (defaults to `/usr/local`, packaging this you'll probably want to make it `/usr`) for systems which don't use the common `/usr` structure. e.g. `make install DESTDIR=$out PREFIX=`
|
||||
|
||||
`/etc` is sometimes in that `PREFIX` and sometimes not, be careful.
|
||||
|
||||
```txt
|
||||
$ fd -t f . --base-directory $out
|
||||
bin/lidm
|
||||
etc/lidm.ini
|
||||
share/man/man1/lidm.1
|
||||
share/man/man5/lidm-config.5
|
||||
```
|
||||
|
||||
# Build Recipes for Packaging
|
||||
|
||||
To ease most of the installation process there's several `make` recipes to install man pages and service files, I encpurage you to check their source yourself, but:
|
||||
|
||||
- `make` / `make lidm`: Builds the app binary.
|
||||
- `make install`: Attempts to install the binary, place a default config file in `/etc/lidm.ini` and install the man pages.
|
||||
- `make install-service-(systemd|dinit|runit|openrc|s6)(|-etc)`: Just check the source, service files for different init systems and `-etc` variants for alternative paths. You might need `FORCE=1` in the environment if you are packaging for other init system or scripting.
|
||||
- `make print-version`: Outputs the current version in the `Makefile` for scripts that might want to extract that info.
|
||||
|
||||
You can choose to use these packages or create your own service files / etc. There's are merely suggestions on what to use.
|
||||
@@ -1,30 +0,0 @@
|
||||
# Yubikeys
|
||||
|
||||
Quick reference explaining how yubikeys work for now.
|
||||
|
||||
# Enable
|
||||
|
||||
Yubikeys are disabled by default, to enable them activate a keybinding for it (`[functions] fido`) in the config file.
|
||||
|
||||
Note that pressing this configured keybinding has no difference from trying to log in with an empty password, there's virtually no difference.
|
||||
|
||||
`pam_u2f` must be configured with a registered key (`pamu2fcfg`).
|
||||
|
||||
# Extra
|
||||
|
||||
All my yubikey knowledge comes from the [pr that implemented this](https://github.com/javalsai/lidm/pull/89), please refer to it for extra details. Contributions to this documentation are welcome (explaining more in detail, potential issues... really anything that improves this).
|
||||
|
||||
Allegedly this pam module configuration should work:
|
||||
|
||||
```pam
|
||||
#%PAM-1.0
|
||||
|
||||
auth sufficient pam_u2f.so cue
|
||||
auth requisite pam_nologin.so
|
||||
auth include system-local-login
|
||||
account include system-local-login
|
||||
session include system-local-login
|
||||
password include system-local-login
|
||||
```
|
||||
|
||||
Also, I recommend giving the [arch wiki](https://wiki.archlinux.org/title/YubiKey) a read anyways.
|
||||
12
flake.lock
generated
@@ -5,11 +5,11 @@
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -20,11 +20,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1751637120,
|
||||
"narHash": "sha256-xVNy/XopSfIG9c46nRmPaKfH1Gn/56vQ8++xWA8itO4=",
|
||||
"lastModified": 1724224976,
|
||||
"narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5c724ed1388e53cc231ed98330a60eb2f7be4be3",
|
||||
"rev": "c374d94f1536013ca8e92341b540eba4c22f9c62",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
50
flake.nix
@@ -1,46 +1,46 @@
|
||||
{
|
||||
description = "A ✨fully✨ colorful customizable TUI display manager made in C for simplicity.";
|
||||
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
flake-utils,
|
||||
nixpkgs,
|
||||
self,
|
||||
}:
|
||||
{ flake-utils, nixpkgs, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
|
||||
name = "lidm";
|
||||
version = builtins.elemAt (builtins.match "VERSION[[:blank:]]*=[[:space:]]*([^\n]*)\n.*" (builtins.readFile ./Makefile)) 0;
|
||||
version = "0.0.2";
|
||||
|
||||
lidm = (
|
||||
pkgs.stdenv.mkDerivation {
|
||||
pname = name;
|
||||
version = version;
|
||||
|
||||
lidm = pkgs.callPackage assets/pkg/nix/lidm.nix {
|
||||
inherit pkgs;
|
||||
lib = pkgs.lib;
|
||||
config = {
|
||||
inherit version;
|
||||
src = ./.;
|
||||
xsessions = null;
|
||||
wayland-sessions = null;
|
||||
cfg = null;
|
||||
# cfg = "cherry";
|
||||
};
|
||||
};
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
gcc
|
||||
gnumake
|
||||
linux-pam
|
||||
];
|
||||
|
||||
makeFlags = [
|
||||
"DESTDIR=$(out)"
|
||||
"PREFIX="
|
||||
];
|
||||
|
||||
fixupPhase = ''
|
||||
rm -rf $out/etc
|
||||
'';
|
||||
}
|
||||
);
|
||||
in
|
||||
rec {
|
||||
defaultApp = flake-utils.lib.mkApp { drv = defaultPackage; };
|
||||
defaultPackage = lidm;
|
||||
devShell = pkgs.mkShell { buildInputs = lidm.nativeBuildInputs ++ [ pkgs.clang-tools ]; };
|
||||
formatter = nixpkgs.legacyPackages.${system}.nixfmt-tree;
|
||||
}
|
||||
)
|
||||
// {
|
||||
nixosModules.lidm = assets/pkg/nix/module.nix;
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#include "config.h"
|
||||
#include "sessions.h"
|
||||
|
||||
bool launch(char* NNULLABLE user, char* NNULLABLE passwd,
|
||||
struct session session, void (*NULLABLE cb)(void),
|
||||
struct config* NNULLABLE config);
|
||||
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
||||
struct config* config);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
#include "keys.h"
|
||||
#include "macros.h"
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
|
||||
enum IntrospectionType {
|
||||
enum introspection_type {
|
||||
STRING,
|
||||
BOOL,
|
||||
NUMBER,
|
||||
@@ -26,7 +26,7 @@ static const char* NNULLABLE const INTROS_TYS_NAMES[] = {
|
||||
struct introspection_item {
|
||||
char* NNULLABLE name;
|
||||
size_t offset;
|
||||
enum IntrospectionType typ;
|
||||
enum introspection_type typ;
|
||||
};
|
||||
|
||||
#define INTROS_ITEM(key, table, ty) \
|
||||
@@ -90,17 +90,15 @@ BUILD(colors, COLORS, TABLE_COLORS);
|
||||
BUILD(chars, CHARS, TABLE_CHARS);
|
||||
|
||||
#define TABLE_FUNCTIONS(F, name) \
|
||||
F(enum Keys, poweroff, KEY, F1, name) \
|
||||
F(enum Keys, reboot, KEY, F2, name) \
|
||||
F(enum Keys, fido, KEY, NONE, name) \
|
||||
F(enum Keys, refresh, KEY, F5, name)
|
||||
F(enum keys, poweroff, KEY, F1, name) \
|
||||
F(enum keys, reboot, KEY, F2, name) \
|
||||
F(enum keys, refresh, KEY, F5, name)
|
||||
|
||||
BUILD(functions, FUNCTIONS, TABLE_FUNCTIONS);
|
||||
|
||||
#define TABLE_STRINGS(F, name) \
|
||||
F(char* NNULLABLE, f_poweroff, STRING, "poweroff", name) \
|
||||
F(char* NNULLABLE, f_reboot, STRING, "reboot", name) \
|
||||
F(char* NNULLABLE, f_fido, STRING, "fido", name) \
|
||||
F(char* NNULLABLE, f_refresh, STRING, "refresh", name) \
|
||||
F(char* NNULLABLE, e_user, STRING, "user", name) \
|
||||
F(char* NNULLABLE, e_passwd, STRING, "password", name) \
|
||||
@@ -122,8 +120,7 @@ BUILD(strings, STRINGS, TABLE_STRINGS);
|
||||
F(struct Vector, source, STRING_ARRAY, NULL_VEC, name) \
|
||||
F(struct Vector, user_source, STRING_ARRAY, NULL_VEC, name) \
|
||||
F(char* NNULLABLE, timefmt, STRING, "%X %x", name) \
|
||||
F(long long, refresh_rate, NUMBER, 100, name) \
|
||||
F(bool, bypass_shell_login, BOOL, false, name)
|
||||
F(long long, refresh_rate, NUMBER, 100, name)
|
||||
|
||||
BUILD(behavior, BEHAVIOR, TABLE_BEHAVIOR);
|
||||
|
||||
@@ -153,15 +150,15 @@ struct introspection_table {
|
||||
|
||||
static const struct introspection_table CONFIG_INSTROSPECTION[] = {
|
||||
{"colors", offsetof(struct config, colors), INTROS_TABLE_COLORS,
|
||||
LEN(INTROS_TABLE_COLORS)},
|
||||
sizeof(INTROS_TABLE_COLORS) / sizeof(INTROS_TABLE_COLORS[0])},
|
||||
{"chars", offsetof(struct config, chars), INTROS_TABLE_CHARS,
|
||||
LEN(INTROS_TABLE_CHARS)},
|
||||
sizeof(INTROS_TABLE_CHARS) / sizeof(INTROS_TABLE_CHARS[0])},
|
||||
{"functions", offsetof(struct config, functions), INTROS_TABLE_FUNCTIONS,
|
||||
LEN(INTROS_TABLE_FUNCTIONS)},
|
||||
sizeof(INTROS_TABLE_FUNCTIONS) / sizeof(INTROS_TABLE_FUNCTIONS[0])},
|
||||
{"strings", offsetof(struct config, strings), INTROS_TABLE_STRINGS,
|
||||
LEN(INTROS_TABLE_STRINGS)},
|
||||
sizeof(INTROS_TABLE_STRINGS) / sizeof(INTROS_TABLE_STRINGS[0])},
|
||||
{"behavior", offsetof(struct config, behavior), INTROS_TABLE_BEHAVIOR,
|
||||
LEN(INTROS_TABLE_BEHAVIOR)},
|
||||
sizeof(INTROS_TABLE_BEHAVIOR) / sizeof(INTROS_TABLE_BEHAVIOR[0])},
|
||||
};
|
||||
|
||||
//// FUNCTIONS
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// TODO: rewrite properly
|
||||
// NOLINTBEGIN(clang-diagnostic-nullability-completeness)
|
||||
|
||||
#ifndef DESKTOP_EXEC_H_
|
||||
#define DESKTOP_EXEC_H_
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
char* NULLABLE desktop_as_cmdline(char** args);
|
||||
int parse_exec_string(const char* exec_s, int* arg_count, char*** args);
|
||||
void free_parsed_args(int arg_count, char** args);
|
||||
|
||||
#endif
|
||||
// NOLINTEND(clang-diagnostic-nullability-completeness)
|
||||
@@ -2,17 +2,16 @@
|
||||
#define EFIELDH_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// holds also the max string buffer in itself, not dynamic
|
||||
struct editable_field {
|
||||
uint8_t pos;
|
||||
u_char pos;
|
||||
char content[255];
|
||||
};
|
||||
|
||||
struct editable_field efield_new(char* content);
|
||||
void efield_trim(struct editable_field* self, uint8_t pos);
|
||||
void efield_trim(struct editable_field* self, u_char pos);
|
||||
void efield_update(struct editable_field* self, char* update);
|
||||
bool efield_seek(struct editable_field* self, char seek);
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
#ifndef KEYSH_
|
||||
#define KEYSH_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
enum Keys {
|
||||
enum keys {
|
||||
ESC,
|
||||
F1,
|
||||
F2,
|
||||
@@ -35,11 +32,9 @@ enum Keys {
|
||||
END,
|
||||
PAGE_UP,
|
||||
PAGE_DOWN,
|
||||
NONE,
|
||||
};
|
||||
|
||||
static const char* const KEY_NAMES[] = {
|
||||
[NONE] = "NONE",
|
||||
[ESC] = "ESC",
|
||||
[F1] = "F1",
|
||||
[F2] = "F2",
|
||||
@@ -71,7 +66,7 @@ static const char* const KEY_NAMES[] = {
|
||||
};
|
||||
|
||||
struct key_mapping {
|
||||
enum Keys key;
|
||||
enum keys key;
|
||||
const char* sequences[3];
|
||||
};
|
||||
|
||||
@@ -106,15 +101,4 @@ static const struct key_mapping KEY_MAPPINGS[] = {
|
||||
{PAGE_DOWN, {"\x1b[6~", NULL}},
|
||||
};
|
||||
|
||||
struct option_keys {
|
||||
bool is_some;
|
||||
enum Keys key;
|
||||
};
|
||||
|
||||
int find_keyname(enum Keys* at, const char* name);
|
||||
struct option_keys find_ansi(const char* seq);
|
||||
void read_press(uint8_t* length, char* out);
|
||||
// non blocking, waits up to tv or interrupt, returns true if actually read
|
||||
bool read_press_nb(uint8_t* length, char* out, struct timeval* tv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
void log_init(FILE* NNULLABLE fd);
|
||||
void log_puts(const char* NNULLABLE msg);
|
||||
void log_printf(const char* NNULLABLE fmt, ...);
|
||||
void log_init(FILE* fd);
|
||||
void log_puts(const char* msg);
|
||||
void log_printf(const char* fmt, ...);
|
||||
// NOLINTNEXTLINE(readability-identifier-length)
|
||||
void log_perror(const char* NNULLABLE s);
|
||||
void log_perror(const char* s);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,31 +1,26 @@
|
||||
#ifndef MACROSH_
|
||||
#define MACROSH_
|
||||
|
||||
// More like constants but I'm not making yet another header file just for this
|
||||
#ifndef LIDM_CONF_PATH
|
||||
#define LIDM_CONF_PATH "/etc/lidm.ini"
|
||||
#endif
|
||||
|
||||
// Do we just replace the compiler with clang??
|
||||
#ifdef __clang__
|
||||
#if defined(__clang__)
|
||||
#define NULLABLE _Nullable
|
||||
#else
|
||||
#define NULLABLE
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if defined(__clang__)
|
||||
#define NNULLABLE _Nonnull
|
||||
#else
|
||||
#define NNULLABLE
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if defined(__clang__)
|
||||
#define UNULLABLE _Null_unspecified
|
||||
#else
|
||||
#define UNULLABLE
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if defined(__clang__)
|
||||
#define COMPILER_VERSION __VERSION__
|
||||
#elif defined(__GNUC__)
|
||||
#define xstr(s) str(s)
|
||||
@@ -36,6 +31,5 @@
|
||||
#endif
|
||||
|
||||
#define LEN(X) (sizeof(X) / sizeof((X)[0]))
|
||||
#define UNUSED(x) ((void)(x))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,6 @@ void ofield_kbd_type(struct opts_field* self, char* typed, char* empty_default);
|
||||
bool ofield_opts_seek(struct opts_field* self, char seek);
|
||||
bool ofield_seek(struct opts_field* self, char seek);
|
||||
|
||||
uint8_t ofield_display_cursor_col(struct opts_field* self, uint8_t maxlen);
|
||||
u_char ofield_display_cursor_col(struct opts_field* self, u_char maxlen);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef PAM_H
|
||||
#define PAM_H
|
||||
|
||||
#include <pwd.h>
|
||||
#include <security/_pam_types.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "sessions.h"
|
||||
|
||||
#define PAMH_ERR_NOERR 0
|
||||
#define PAMH_ERR_ALLOC 1
|
||||
#define PAMH_ERR_ERRNO 2
|
||||
#define PAMH_ERR_NOERRNO 3
|
||||
|
||||
struct pamh_getenv_status {
|
||||
char error_flag;
|
||||
union {
|
||||
char* NULLABLE* NNULLABLE envlist;
|
||||
const char* NNULLABLE errfn;
|
||||
};
|
||||
};
|
||||
|
||||
// Doesn't include `source`s
|
||||
struct pamh_getenv_status pamh_get_complete_env(pam_handle_t* NNULLABLE handle,
|
||||
struct passwd* NNULLABLE pw,
|
||||
enum SessionType session_typ);
|
||||
|
||||
void free_envlist(char* NULLABLE* NNULLABLE envlist);
|
||||
pam_handle_t* NULLABLE get_pamh(char* NNULLABLE user, char* NNULLABLE passwd);
|
||||
|
||||
#endif /* PAM_H */
|
||||
@@ -2,64 +2,23 @@
|
||||
#define SESSIONSH_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
|
||||
enum SessionType {
|
||||
enum session_type {
|
||||
XORG,
|
||||
WAYLAND,
|
||||
SHELL,
|
||||
};
|
||||
|
||||
enum ExecType {
|
||||
EXEC_SHELL,
|
||||
EXEC_DESKTOP,
|
||||
};
|
||||
|
||||
struct desktop_exec {
|
||||
char* NULLABLE* NNULLABLE args;
|
||||
int arg_count;
|
||||
};
|
||||
|
||||
struct session_exec {
|
||||
enum ExecType typ;
|
||||
union {
|
||||
char* NNULLABLE shell;
|
||||
struct desktop_exec desktop;
|
||||
};
|
||||
};
|
||||
|
||||
static inline struct session_exec session_exec_shell(char* NNULLABLE shell) {
|
||||
return (struct session_exec){
|
||||
.typ = EXEC_SHELL,
|
||||
.shell = shell,
|
||||
};
|
||||
}
|
||||
|
||||
static inline struct session_exec session_exec_desktop(
|
||||
int arg_count, char* NULLABLE* NNULLABLE args) {
|
||||
return (struct session_exec){
|
||||
.typ = EXEC_DESKTOP,
|
||||
.desktop =
|
||||
{
|
||||
.args = args,
|
||||
.arg_count = arg_count,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
struct session {
|
||||
char* NNULLABLE name;
|
||||
struct session_exec exec;
|
||||
enum SessionType type;
|
||||
char* NNULLABLE exec;
|
||||
char* NULLABLE tryexec;
|
||||
enum session_type type;
|
||||
};
|
||||
|
||||
struct Vector get_avaliable_sessions();
|
||||
int session_exec_exec(struct session_exec* NNULLABLE exec,
|
||||
char* NULLABLE* NNULLABLE envp);
|
||||
int session_exec_login_through_shell(struct session_exec* NNULLABLE exec,
|
||||
char* NULLABLE* NNULLABLE envp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef SIGNALHANDLERH_
|
||||
#define SIGNALHANDLERH_
|
||||
|
||||
// handle SIGTERM by sending SIGTERM to all children, resulting
|
||||
// in a graceful graphical shutdown
|
||||
void setup_sigterm();
|
||||
|
||||
#endif /* SIGNALHANDLERH_ */
|
||||
10
include/ui.h
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "ofield.h"
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
|
||||
// [box_start]
|
||||
// ↓
|
||||
@@ -39,17 +39,15 @@
|
||||
#define VALUES_SEPR 3
|
||||
#define VALUE_MAXLEN (BOX_WIDTH - VALUES_COL + 1 - BOX_HMARGIN - 2)
|
||||
|
||||
enum Input { SESSION, USER, PASSWD };
|
||||
extern const uint8_t INPUTS_N;
|
||||
enum input { SESSION, USER, PASSWD };
|
||||
extern const u_char INPUTS_N;
|
||||
|
||||
void setup(struct config* config);
|
||||
int load(struct Vector* users, struct Vector* sessions);
|
||||
void print_err(const char* /*msg*/);
|
||||
void print_errno(const char* /*descr*/);
|
||||
void print_pam_msg(const char* msg, int msg_style);
|
||||
void clear_pam_msg(void);
|
||||
|
||||
void ui_update_field(enum Input focused_input);
|
||||
void ui_update_field(enum input focused_input);
|
||||
void ui_update_ffield();
|
||||
void ui_update_ofield(struct opts_field* self);
|
||||
void ui_update_cursor_focus();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "macros.h"
|
||||
#include "ui.h"
|
||||
|
||||
extern enum Input focused_input;
|
||||
extern enum input focused_input;
|
||||
|
||||
extern struct opts_field of_session;
|
||||
extern struct opts_field of_user;
|
||||
@@ -15,7 +15,7 @@ extern struct opts_field of_passwd;
|
||||
extern struct Vector* UNULLABLE gusers;
|
||||
extern struct Vector* UNULLABLE gsessions;
|
||||
|
||||
struct opts_field* NNULLABLE get_opts_field(enum Input from);
|
||||
struct opts_field* NNULLABLE get_opts_field(enum input from);
|
||||
struct opts_field* NNULLABLE get_opts_ffield();
|
||||
|
||||
struct user st_user();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
|
||||
struct user {
|
||||
char* shell;
|
||||
|
||||
43
include/util.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef UTILH_
|
||||
#define UTILH_
|
||||
|
||||
#include <bits/types/struct_timeval.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "keys.h"
|
||||
|
||||
int find_keyname(enum keys* at, const char* name);
|
||||
enum keys find_ansi(const char* seq);
|
||||
void read_press(u_char* length, char* out);
|
||||
// non blocking, waits up to tv or interrupt, returns true if actually read
|
||||
bool read_press_nb(u_char* length, char* out, struct timeval* tv);
|
||||
|
||||
bool utf8_iscont(char byte);
|
||||
size_t utf8len(const char* str);
|
||||
size_t utf8len_until(const char* str, const char* until);
|
||||
const char* utf8back(const char* str);
|
||||
const char* utf8seek(const char* str);
|
||||
const char* utf8seekn(const char* str, size_t n);
|
||||
|
||||
struct Vector {
|
||||
uint32_t length;
|
||||
uint32_t capacity;
|
||||
void** pages;
|
||||
};
|
||||
|
||||
extern const struct Vector VEC_NEW;
|
||||
int vec_resize(struct Vector* self, size_t size);
|
||||
int vec_reserve(struct Vector* self, size_t size);
|
||||
int vec_reserve_exact(struct Vector* self, size_t size);
|
||||
int vec_push(struct Vector* self, void* item);
|
||||
void vec_free(struct Vector* self);
|
||||
void vec_clear(struct Vector* self);
|
||||
void vec_reset(struct Vector* self);
|
||||
void* vec_pop(struct Vector* self); // won't free it, nor shrink vec list space
|
||||
void* vec_get(struct Vector* self, size_t index);
|
||||
|
||||
#endif
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef UTIL_PATH_H
|
||||
#define UTIL_PATH_H
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
char* NULLABLE search_path(const char* NNULLABLE for_binary);
|
||||
int execvpe(const char* NNULLABLE file, char* NULLABLE const argv[NNULLABLE],
|
||||
char* NULLABLE const envp[NNULLABLE]);
|
||||
|
||||
#endif /* UTIL_PATH_H */
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef UTIL_UTF8_H
|
||||
#define UTIL_UTF8_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
bool utf8_iscont(char byte);
|
||||
size_t utf8len(const char* str);
|
||||
size_t utf8len_until(const char* str, const char* until);
|
||||
size_t utf8trunc(char* str, size_t n);
|
||||
const char* utf8back(const char* str);
|
||||
const char* utf8seek(const char* str);
|
||||
const char* utf8seekn(const char* str, size_t n);
|
||||
|
||||
#endif /* UTIL_UTF8_H */
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef UTIL_VEC_H
|
||||
#define UTIL_VEC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct Vector {
|
||||
uint32_t length;
|
||||
uint32_t capacity;
|
||||
void** pages;
|
||||
};
|
||||
|
||||
struct Vector vec_from_raw(void** raw);
|
||||
void** vec_as_raw(struct Vector self);
|
||||
extern const struct Vector VEC_NEW;
|
||||
int vec_resize(struct Vector* self, size_t size);
|
||||
int vec_reserve(struct Vector* self, size_t size);
|
||||
int vec_reserve_exact(struct Vector* self, size_t size);
|
||||
int vec_push(struct Vector* self, void* item);
|
||||
void vec_free(struct Vector* self);
|
||||
void vec_clear(struct Vector* self);
|
||||
void vec_reset(struct Vector* self);
|
||||
void* vec_pop(struct Vector* self); // won't free it, nor shrink vec list space
|
||||
void* vec_get(struct Vector* self, size_t index);
|
||||
|
||||
#endif /* UTIL_VEC_H */
|
||||
91
services.mk
@@ -1,91 +0,0 @@
|
||||
install-service:
|
||||
@if command -v systemctl &> /dev/null; then \
|
||||
make install-service-systemd; \
|
||||
elif command -v dinitctl &> /dev/null; then \
|
||||
make install-service-dinit; \
|
||||
elif command -v sv &> /dev/null; then \
|
||||
if [ -d /etc/sv ]; then \
|
||||
make install-service-runit; \
|
||||
elif [ -d /etc/runit/sv ]; then \
|
||||
make install-service-runit-etc; \
|
||||
else \
|
||||
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
|
||||
fi \
|
||||
elif command -v rc-update &> /dev/null; then \
|
||||
make install-service-openrc; \
|
||||
elif command -v s6-service &> /dev/null; then \
|
||||
if [ -d /etc/sv ]; then \
|
||||
make install-service-s6; \
|
||||
elif [ -d /etc/r6nit/sv ]; then \
|
||||
make install-service-s6-etc; \
|
||||
else \
|
||||
printf '\033[31m%s\033[0m\n' "Unknown init system structure, skipping service install..." >&2; \
|
||||
fi \
|
||||
else \
|
||||
printf '\033[1;31m%s\033[0m\n' "Unknown init system, skipping service install..." >&2; \
|
||||
fi
|
||||
|
||||
install-service-systemd:
|
||||
@sed -e 's|ExecStart=/usr/bin/lidm|ExecStart=${DESTDIR}${PREFIX}/bin/lidm|' ./assets/services/systemd.service > ./dist/lidm.service
|
||||
install -Dm644 ./dist/lidm.service ${DESTDIR}${PREFIX}/lib/systemd/system/lidm.service
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'systemctl enable lidm'"
|
||||
install-service-dinit:
|
||||
install -m644 ./assets/services/dinit ${DESTDIR}/etc/dinit.d/lidm
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'dinitctl enable lidm'"
|
||||
install-service-runit:
|
||||
@if [ ! -e /etc/sv ] && [ -d /etc/runit/sv ] && [ -z "$$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/runit/sv does" >&2; \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit-etc'" >&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/sv/lidm
|
||||
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/sv/lidm /var/service' or your distro equivalent"
|
||||
install-service-runit-etc:
|
||||
@if [ ! -e /etc/runit/sv ] && [ -d /etc/sv ] && [ -z "$$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/runit/sv doesn't exist but /etc/sv does" >&2; \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-runit'" >&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/runit/sv/lidm
|
||||
cp -r --update=all ./assets/services/runit/* ${DESTDIR}/etc/runit/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'ln -s ${DESTDIR}/etc/runit/sv/lidm /run/runit/service' or your distro equivalent"
|
||||
install-service-openrc:
|
||||
install -m755 ./assets/services/openrc ${DESTDIR}/etc/init.d/lidm
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 'rc-update add lidm'"
|
||||
install-service-s6:
|
||||
@if [ ! -e /etc/sv ] && [ -d /etc/s6/sv ] && [ -z "$$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/sv doesn't exist but /etc/s6/sv does" >&2; \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6-etc'" >&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/sv/lidm
|
||||
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
|
||||
install-service-s6-etc:
|
||||
@if [ ! -e /etc/s6/sv ] && [ -d /etc/sv ] && [ -z "$$FORCE" ]; then \
|
||||
printf '\033[31m%s\033[0m\n' "/etc/s6/sv doesn't exist but /etc/sv does" >&2; \
|
||||
printf '\033[31m%s\033[0m\n' "you probably meant to 'make install-service-s6'" >&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
mkdir -p ${DESTDIR}/etc/s6/sv/lidm
|
||||
cp -r --update=all ./assets/services/s6/* ${DESTDIR}/etc/s6/sv/lidm/
|
||||
@printf '\033[1m%s\033[0m\n\n' " don't forget to run 's6-service add default lidm' and 's6-db-reload'"
|
||||
|
||||
uninstall-service:
|
||||
rm -rf \
|
||||
${DESTDIR}${PREFIX}/lib/systemd/system/lidm.service \
|
||||
${DESTDIR}/etc/dinit.d/lidm \
|
||||
${DESTDIR}/etc/sv/lidm \
|
||||
${DESTDIR}/etc/runit/sv/lidm \
|
||||
${DESTDIR}/etc/init.d/lidm \
|
||||
${DESTDIR}/etc/s6/sv/lidm
|
||||
|
||||
.PHONY: install-service uninstall-service \
|
||||
install-service-s6 \
|
||||
install-service-s6-etc \
|
||||
install-service-dinit \
|
||||
install-service-runit \
|
||||
install-service-runit-etc \
|
||||
install-service-openrc \
|
||||
install-service-systemd
|
||||
479
src/auth.c
@@ -1,40 +1,75 @@
|
||||
// TODO: handle `fork() == -1`
|
||||
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <security/pam_misc.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "auth.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
#include "pam.h"
|
||||
#include "sessions.h"
|
||||
#include "ui.h"
|
||||
#include "util/path.h"
|
||||
#include "util/vec.h"
|
||||
#include "unistd.h"
|
||||
#include "util.h"
|
||||
|
||||
#define XORG_MESSAGE_LENGTH 16
|
||||
|
||||
static void try_source_file(struct Vector* NNULLABLE vec_envlist,
|
||||
char* NNULLABLE filepath) {
|
||||
log_printf("sourcing %s\n", filepath);
|
||||
FILE* file2source = fopen(filepath, "r");
|
||||
if (file2source == NULL) {
|
||||
log_printf("error sourcing %s\n", filepath);
|
||||
return;
|
||||
int pam_conversation(int num_msg, const struct pam_message** msg,
|
||||
struct pam_response** resp, void* appdata_ptr) {
|
||||
struct pam_response* reply =
|
||||
(struct pam_response*)malloc(sizeof(struct pam_response) * num_msg);
|
||||
if (!reply) {
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
for (size_t i = 0; i < num_msg; i++) {
|
||||
reply[i].resp = NULL;
|
||||
reply[i].resp_retcode = 0;
|
||||
if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF ||
|
||||
msg[i]->msg_style == PAM_PROMPT_ECHO_ON) {
|
||||
char* input = (char*)appdata_ptr;
|
||||
reply[i].resp = strdup(input);
|
||||
}
|
||||
}
|
||||
*resp = reply;
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
#define CHECK_PAM_RET(call) \
|
||||
ret = (call); \
|
||||
if (ret != PAM_SUCCESS) { \
|
||||
pam_end(pamh, ret); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
void clear_screen() {
|
||||
printf("\x1b[H\x1b[J");
|
||||
}
|
||||
|
||||
pam_handle_t* get_pamh(char* user, char* passwd) {
|
||||
pam_handle_t* pamh = NULL;
|
||||
struct pam_conv pamc = {pam_conversation, (void*)passwd};
|
||||
int ret;
|
||||
|
||||
CHECK_PAM_RET(pam_start("login", user, &pamc, &pamh))
|
||||
CHECK_PAM_RET(pam_authenticate(pamh, 0))
|
||||
CHECK_PAM_RET(pam_acct_mgmt(pamh, 0))
|
||||
CHECK_PAM_RET(pam_setcred(pamh, PAM_ESTABLISH_CRED))
|
||||
CHECK_PAM_RET(pam_open_session(pamh, 0))
|
||||
CHECK_PAM_RET(pam_setcred(pamh, PAM_REINITIALIZE_CRED))
|
||||
|
||||
return pamh;
|
||||
}
|
||||
#undef CHECK_PAM_RET
|
||||
|
||||
void* shmalloc(size_t size) {
|
||||
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
}
|
||||
|
||||
void sourceFileTry(char* file) {
|
||||
FILE* file2source = fopen(file, "r");
|
||||
if (file2source == NULL) return;
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
@@ -44,10 +79,13 @@ static void try_source_file(struct Vector* NNULLABLE vec_envlist,
|
||||
if (read == 0 || (read > 0 && *line == '#')) continue;
|
||||
if (line[read - 1] == '\n') line[read - 1] = '\0';
|
||||
|
||||
for (ssize_t i = 1; i < read; i++) {
|
||||
/* printf("Retrieved line of length %zu:\n", read); */
|
||||
/* printf("%s\n", line); */
|
||||
for (size_t i = 1; i < read; i++) {
|
||||
if (line[i] == '=') {
|
||||
vec_push(vec_envlist, (void*)line);
|
||||
line = NULL;
|
||||
/* printf("FOUND '='!\n"); */
|
||||
line[i] = '\0';
|
||||
setenv(line, &line[i + 1], 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -57,239 +95,66 @@ static void try_source_file(struct Vector* NNULLABLE vec_envlist,
|
||||
(void)fclose(file2source);
|
||||
}
|
||||
|
||||
static void source_paths(struct Vector* NNULLABLE vec_envlist,
|
||||
struct Vector* NNULLABLE abs_source,
|
||||
const char* NULLABLE user_home,
|
||||
struct Vector* NNULLABLE user_source) {
|
||||
for (size_t i = 0; i < abs_source->length; i++) {
|
||||
char* path = vec_get(abs_source, i);
|
||||
try_source_file(vec_envlist, path);
|
||||
}
|
||||
void moarEnv(char* user, struct session session, struct passwd* pw,
|
||||
struct config* config) {
|
||||
if (chdir(pw->pw_dir) == -1) print_errno("can't chdir to user home");
|
||||
|
||||
if (user_home)
|
||||
for (size_t i = 0; i < user_source->length; i++) {
|
||||
char* path = NULL;
|
||||
asprintf(&path, "%s/%s", user_home, (char*)vec_get(user_source, i));
|
||||
if (!path) {
|
||||
log_puts("alloc failure on user source\n");
|
||||
continue;
|
||||
setenv("HOME", pw->pw_dir, true);
|
||||
setenv("USER", pw->pw_name, true);
|
||||
setenv("SHELL", pw->pw_shell, true);
|
||||
// TERM
|
||||
setenv("LOGNAME", pw->pw_name, true);
|
||||
// MAIL?
|
||||
|
||||
// PATH?
|
||||
|
||||
char* xdg_session_type = "unknown";
|
||||
if (session.type == SHELL) xdg_session_type = "tty";
|
||||
if (session.type == XORG) xdg_session_type = "x11";
|
||||
if (session.type == WAYLAND) xdg_session_type = "wayland";
|
||||
setenv("XDG_SESSION_TYPE", xdg_session_type, true);
|
||||
|
||||
printf("\n\n\n\n\x1b[1m");
|
||||
for (size_t i = 0; i < config->behavior.source.length; i++) {
|
||||
/* printf("DEBUG(source)!!!! %d %s\n", i, (char*)vec_get(&behavior->source,
|
||||
* i)); */
|
||||
sourceFileTry((char*)vec_get(&config->behavior.source, i));
|
||||
}
|
||||
try_source_file(vec_envlist, path);
|
||||
/* printf("\n"); */
|
||||
|
||||
if (pw->pw_dir) {
|
||||
const char* home = pw->pw_dir;
|
||||
size_t home_len = strlen(home);
|
||||
|
||||
for (size_t i = 0; i < config->behavior.user_source.length; i++) {
|
||||
const char* filename = (char*)vec_get(&config->behavior.user_source, i);
|
||||
size_t filename_len = strlen(filename);
|
||||
|
||||
size_t path_len = home_len + 1 + filename_len + 1; // nullbyte and slash
|
||||
char* path = malloc(path_len);
|
||||
if (!path) continue; // can't bother
|
||||
|
||||
memcpy(path, home, home_len);
|
||||
path[home_len] = '/'; // assume pw_dir doesn't start with '/' :P
|
||||
memcpy(&path[home_len + 1], filename, filename_len);
|
||||
path[path_len - 1] = '\0';
|
||||
|
||||
sourceFileTry(path);
|
||||
free(path);
|
||||
}
|
||||
else {
|
||||
log_puts("user has no home\n");
|
||||
}
|
||||
|
||||
/*char *buf;*/
|
||||
/*size_t bsize = snprintf(NULL, 0, "/run/user/%d", pw->pw_uid) + 1;*/
|
||||
/*buf = malloc(bsize);*/
|
||||
/*snprintf(buf, bsize, "/run/user/%d", pw->pw_uid);*/
|
||||
/*setenv("XDG_RUNTIME_DIR", buf, true);*/
|
||||
/*setenv("XDG_SESSION_CLASS", "user", true);*/
|
||||
/*setenv("XDG_SESSION_ID", "1", true);*/
|
||||
/*setenv("XDG_SESSION_DESKTOP", , true);*/
|
||||
/*setenv("XDG_SEAT", "seat0", true);*/
|
||||
}
|
||||
|
||||
struct child_msg {
|
||||
char* msg;
|
||||
int _errno;
|
||||
bool err;
|
||||
};
|
||||
|
||||
/// block until X returns the display number or an error occurs
|
||||
static bool x_get_display(const int xorg_pipefd[2], int* display) {
|
||||
char buffer[XORG_MESSAGE_LENGTH];
|
||||
bool status;
|
||||
|
||||
close(xorg_pipefd[1]);
|
||||
ssize_t bytes_read = read(xorg_pipefd[0], buffer, sizeof(buffer) - 1);
|
||||
buffer[bytes_read] = '\0';
|
||||
|
||||
if (bytes_read > 0) {
|
||||
char* endptr;
|
||||
int val = (int)strtol(buffer, &endptr, 10);
|
||||
if (endptr == buffer) {
|
||||
(void)fputs("failed to parse Xorg display response\n", stderr);
|
||||
status = false;
|
||||
} else {
|
||||
*display = val;
|
||||
status = true;
|
||||
}
|
||||
} else if (bytes_read == 0) {
|
||||
(void)fputs("Xorg pipe closed\n", stderr);
|
||||
status = false;
|
||||
} else {
|
||||
perror("read");
|
||||
status = false;
|
||||
}
|
||||
|
||||
close(xorg_pipefd[0]);
|
||||
return status;
|
||||
}
|
||||
|
||||
/// small helper to push dyn arr
|
||||
static void push_dyn_arr(void*** arr, void* item) {
|
||||
struct Vector vec = vec_from_raw(*arr);
|
||||
vec_push(&vec, item);
|
||||
*arr = vec_as_raw(vec);
|
||||
}
|
||||
|
||||
// TODO: properly pass this down
|
||||
extern int vt;
|
||||
|
||||
static void start_xorg_server(struct passwd* pw, char** NNULLABLE envlist,
|
||||
int xorg_pipefd[2]) {
|
||||
close(xorg_pipefd[0]);
|
||||
if (!pw->pw_dir) _exit(EXIT_FAILURE);
|
||||
// !!!!!!!!!! ATTENTION: this fails silently, of course add failure msgs but
|
||||
// for now I can't so be careful
|
||||
if (vt == -1) _exit(EXIT_FAILURE);
|
||||
|
||||
// pass the pipe so Xorg can write the DISPLAY value in there
|
||||
char* fd_str;
|
||||
asprintf(&fd_str, "%d", xorg_pipefd[1]);
|
||||
if (!fd_str) _exit(EXIT_FAILURE);
|
||||
|
||||
char* vt_path;
|
||||
asprintf(&vt_path, "vt%d", vt);
|
||||
if (!vt_path) {
|
||||
free(fd_str);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char* xorg_path = search_path("Xorg");
|
||||
if (!xorg_path) {
|
||||
(void)fputs("couldn't find Xorg binary in PATH, sure it's installed?\n",
|
||||
stderr);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int exit = execle(xorg_path, xorg_path, "-displayfd", fd_str, vt_path, NULL,
|
||||
envlist);
|
||||
perror("exec");
|
||||
|
||||
free(vt_path);
|
||||
free(fd_str);
|
||||
free(xorg_path);
|
||||
_exit(exit);
|
||||
}
|
||||
|
||||
// TODO: add error msgs
|
||||
/// returns on completion
|
||||
static void launch_with_xorg_server(struct config* config,
|
||||
struct session_exec* NNULLABLE exec,
|
||||
struct passwd* pw,
|
||||
char** NNULLABLE envlist) {
|
||||
int xorg_pipefd[2];
|
||||
if (pipe(xorg_pipefd) == -1) _exit(EXIT_FAILURE);
|
||||
|
||||
(void)fflush(NULL);
|
||||
pid_t xorg_pid = fork();
|
||||
if (xorg_pid == 0) {
|
||||
start_xorg_server(pw, envlist, xorg_pipefd);
|
||||
}
|
||||
|
||||
int display = 0;
|
||||
if (!x_get_display(xorg_pipefd, &display)) {
|
||||
(void)fputs("failed to get X display, aborting\n", stderr);
|
||||
int status;
|
||||
waitpid(xorg_pid, &status, 0);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char* display_env;
|
||||
asprintf(&display_env, "DISPLAY=:%d", display);
|
||||
if (!display_env) {
|
||||
(void)fputs("failure allocating memory for DISPLAY string\n", stderr);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
// convert back for convenient push-ing
|
||||
push_dyn_arr((void***)&envlist, display_env);
|
||||
if (!envlist) {
|
||||
(void)fputs("failure allocating memory for DISPLAY env\n", stderr);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
(void)fflush(NULL);
|
||||
pid_t xorg_session_pid = fork();
|
||||
if (xorg_session_pid == 0) {
|
||||
if (config->behavior.bypass_shell_login)
|
||||
session_exec_exec(exec, envlist);
|
||||
else
|
||||
session_exec_login_through_shell(exec, envlist);
|
||||
|
||||
perror("session exec error");
|
||||
(void)fputs("failure calling session\n", stderr);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// looks weird, waiting on -1 should wait on any child and then just check if
|
||||
// its xorg server or the session and kill the other waiting on it
|
||||
pid_t pid;
|
||||
int status; // not even read for now
|
||||
while ((pid = waitpid(-1, &status, 0)) > 0) {
|
||||
if (pid == xorg_pid || pid == xorg_session_pid) {
|
||||
pid_t pid_to_kill = pid ^ xorg_pid ^ xorg_session_pid;
|
||||
if (pid == xorg_pid) printf("Xorg server died\n");
|
||||
if (pid == xorg_session_pid) printf("Xorg session died\n");
|
||||
|
||||
kill(pid_to_kill, SIGTERM);
|
||||
waitpid(pid_to_kill, &status, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SEND_MSG(MSG) \
|
||||
{ \
|
||||
write(pipefd[1], &(MSG), sizeof(struct child_msg)); \
|
||||
close(pipefd[1]); \
|
||||
}
|
||||
#define SEND_ERR(MSG) \
|
||||
{ \
|
||||
write(pipefd[1], \
|
||||
&(struct child_msg){.msg = (MSG), ._errno = errno, .err = true}, \
|
||||
sizeof(struct child_msg)); \
|
||||
close(pipefd[1]); \
|
||||
_exit(EXIT_FAILURE); \
|
||||
}
|
||||
#define DUMMY_READ() \
|
||||
{ \
|
||||
char _dummy; \
|
||||
read(pipefd[0], &_dummy, sizeof(_dummy)); \
|
||||
}
|
||||
inline static void forked(struct config* config, int pipefd[2],
|
||||
struct passwd* pw, char* NNULLABLE user,
|
||||
struct session* NNULLABLE session,
|
||||
char** NNULLABLE envlist) {
|
||||
if (chdir(pw->pw_dir) == -1) SEND_ERR("chdir");
|
||||
if (setgid(pw->pw_gid) == -1) SEND_ERR("setgid");
|
||||
if (initgroups(user, pw->pw_gid) == -1) SEND_ERR("initgroups");
|
||||
if (setuid(pw->pw_uid) == -1) SEND_ERR("setuid");
|
||||
|
||||
SEND_MSG((struct child_msg){.err = false});
|
||||
DUMMY_READ();
|
||||
close(pipefd[0]);
|
||||
|
||||
if (!getenv("PATH")) {
|
||||
size_t path_size = confstr(_CS_PATH, NULL, 0);
|
||||
char* path_env = malloc(path_size);
|
||||
confstr(_CS_PATH, path_env, path_size);
|
||||
setenv("PATH", path_env, 1);
|
||||
free(path_env);
|
||||
}
|
||||
|
||||
log_printf(" [I] using shell login?: %s",
|
||||
config->behavior.bypass_shell_login ? "true" : "false");
|
||||
if (session->type == XORG) {
|
||||
launch_with_xorg_server(config, &session->exec, pw, envlist);
|
||||
_exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
if (config->behavior.bypass_shell_login)
|
||||
session_exec_exec(&session->exec, envlist);
|
||||
else
|
||||
session_exec_login_through_shell(&session->exec, envlist);
|
||||
perror("session exec error");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#undef SEND_MSG
|
||||
#undef SEND_ERR
|
||||
#undef DUMMY_READ
|
||||
|
||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
||||
struct config* config) {
|
||||
@@ -301,63 +166,93 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
||||
|
||||
pam_handle_t* pamh = get_pamh(user, passwd);
|
||||
if (pamh == NULL) {
|
||||
print_pam_msg("authentication failed", PAM_ERROR_MSG);
|
||||
return false;
|
||||
}
|
||||
clear_pam_msg();
|
||||
|
||||
struct pamh_getenv_status env_ret =
|
||||
pamh_get_complete_env(pamh, pw, session.type);
|
||||
if (env_ret.error_flag != PAMH_ERR_NOERR) {
|
||||
if (env_ret.error_flag == PAMH_ERR_ALLOC) {
|
||||
print_err("allocator error");
|
||||
} else if (env_ret.error_flag == PAMH_ERR_ERRNO) {
|
||||
print_errno(env_ret.errfn);
|
||||
} else if (env_ret.error_flag == PAMH_ERR_NOERRNO) {
|
||||
print_err(env_ret.errfn);
|
||||
}
|
||||
print_err("error on pam authentication");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Vector envlist_vec = vec_from_raw((void**)env_ret.envlist);
|
||||
|
||||
source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir,
|
||||
&config->behavior.user_source);
|
||||
char** envlist = (char**)vec_as_raw(envlist_vec);
|
||||
if (!envlist) {
|
||||
print_err("vec alloc error");
|
||||
bool* reach_session = shmalloc(sizeof(bool));
|
||||
if (reach_session == NULL) {
|
||||
perror("error allocating shared memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
int pipefd[2];
|
||||
pipe(pipefd);
|
||||
*reach_session = false;
|
||||
|
||||
uint pid = fork();
|
||||
if (pid == 0)
|
||||
forked(config, pipefd, pw, user, &session, envlist);
|
||||
else {
|
||||
struct child_msg msg;
|
||||
read(pipefd[0], &msg, sizeof(struct child_msg));
|
||||
close(pipefd[0]);
|
||||
if (msg.err) {
|
||||
errno = msg._errno;
|
||||
print_errno(msg.msg);
|
||||
return false;
|
||||
if (pid == 0) { // child
|
||||
char* term = NULL;
|
||||
char* getterm = getenv("TERM");
|
||||
// TODO: handle malloc error
|
||||
if (getterm != NULL) term = strdup(getterm);
|
||||
if (clearenv() != 0) {
|
||||
print_errno("clearenv");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (cb) cb();
|
||||
printf("\x1b[0m\x1b[H\x1b[J");
|
||||
(void)fflush(stdout);
|
||||
close(pipefd[1]);
|
||||
char** envlist = pam_getenvlist(pamh);
|
||||
if (envlist == NULL) {
|
||||
print_errno("pam_getenvlist");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
for (size_t i = 0; envlist[i] != NULL; i++) {
|
||||
putenv(envlist[i]);
|
||||
}
|
||||
// FIXME: path hotfix
|
||||
putenv("PATH=/bin:/usr/bin");
|
||||
if (term != NULL) {
|
||||
setenv("TERM", term, true);
|
||||
free(term);
|
||||
}
|
||||
|
||||
int exit_code;
|
||||
waitpid((pid_t)pid, &exit_code, 0);
|
||||
free((void*)envlist);
|
||||
moarEnv(user, session, pw, config);
|
||||
|
||||
// TODO: chown stdin to user
|
||||
// does it inherit stdin from parent and
|
||||
// does parent need to reclaim it after
|
||||
// this dies?
|
||||
|
||||
if (setgid(pw->pw_gid) == -1) {
|
||||
print_errno("setgid");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
if (initgroups(user, pw->pw_gid) == -1) {
|
||||
print_errno("initgroups");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setuid(pw->pw_uid) == -1) {
|
||||
perror("setuid");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (cb != NULL) cb();
|
||||
|
||||
*reach_session = true;
|
||||
|
||||
// TODO: these will be different due to TryExec
|
||||
// and, Exec/TryExec might contain spaces as args
|
||||
printf("\x1b[0m");
|
||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||
if (session.type == SHELL) {
|
||||
clear_screen();
|
||||
(void)fflush(stdout);
|
||||
execlp(session.exec, session.exec, NULL);
|
||||
} else if (session.type == XORG || session.type == WAYLAND) {
|
||||
clear_screen();
|
||||
(void)fflush(stdout);
|
||||
execlp(session.exec, session.exec, NULL);
|
||||
}
|
||||
perror("execl error");
|
||||
(void)fputs("failure calling session\n", stderr);
|
||||
} else {
|
||||
__pid_t child_pid = (__pid_t)pid;
|
||||
waitpid(child_pid, NULL, 0);
|
||||
|
||||
pam_setcred(pamh, PAM_DELETE_CRED);
|
||||
pam_close_session(pamh, 0);
|
||||
pam_end(pamh, PAM_SUCCESS);
|
||||
|
||||
if (exit_code != 0) return false;
|
||||
if (*reach_session == false) return false;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "chvt.h"
|
||||
#include "macros.h"
|
||||
|
||||
static char* vterms[] = {"/dev/tty", "/dev/tty0", "/dev/vc/0", "/dev/systty",
|
||||
"/dev/console"};
|
||||
@@ -24,16 +23,16 @@ int chvt_str(char* str) {
|
||||
return chvt((int)i);
|
||||
}
|
||||
|
||||
int vt = -1;
|
||||
int chvt(int n) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
||||
(void)fprintf(stderr, "activating vt %d\n", n);
|
||||
vt = n;
|
||||
// NOLINTNEXTLINE(readability-identifier-length)
|
||||
char c = 0;
|
||||
for (size_t i = 0; i < LEN(vterms); i++) {
|
||||
for (size_t i = 0; i < sizeof(vterms) / sizeof(vterms[0]); i++) {
|
||||
int fd = open(vterms[i], O_RDWR);
|
||||
if (fd >= 0 && isatty(fd) && ioctl(fd, KDGKBTYPE, &c) == 0 && c < 3) {
|
||||
if (ioctl(fd, VT_ACTIVATE, n) < 0 || ioctl(fd, VT_WAITACTIVE, n) < 0) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
||||
(void)fprintf(stderr, "Couldn't activate vt %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
24
src/config.c
@@ -11,15 +11,13 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "desktop.h"
|
||||
#include "keys.h"
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
|
||||
#define UPPER_HALF_BYTE 4
|
||||
int parse_hex(char* _at, char x1, char x2) {
|
||||
// make linter happy
|
||||
uint8_t* at = (uint8_t*)_at;
|
||||
u_char* at = (u_char*)_at;
|
||||
|
||||
*at = 0;
|
||||
|
||||
@@ -118,12 +116,12 @@ union typ_ptr {
|
||||
char** string;
|
||||
long long* number;
|
||||
bool* boolean;
|
||||
enum Keys* key;
|
||||
enum keys* key;
|
||||
struct Vector* vec;
|
||||
uintptr_t ptr;
|
||||
};
|
||||
struct parser_error parse_key(enum IntrospectionType typ, union typ_ptr at,
|
||||
char* key) {
|
||||
struct parser_error parse_key(enum introspection_type typ, union typ_ptr at,
|
||||
char* key, size_t offset) {
|
||||
char* aux_str = NULL;
|
||||
struct parser_error aux_err;
|
||||
|
||||
@@ -220,7 +218,7 @@ struct status config_line_handler(void* _config, char* table, char* k,
|
||||
|
||||
log_printf("[I] parsing [%s.%s] as %s\n", table, k,
|
||||
INTROS_TYS_NAMES[this_intros_key->typ]);
|
||||
struct parser_error err = parse_key(this_intros_key->typ, k_addr, v);
|
||||
struct parser_error err = parse_key(this_intros_key->typ, k_addr, v, offset);
|
||||
if (err.msg != NULL) {
|
||||
log_printf("[E] cfg parser, failed to parse [%s.%s] (%s): %s\n", table, k,
|
||||
INTROS_TYS_NAMES[this_intros_key->typ], err.msg);
|
||||
@@ -242,10 +240,12 @@ struct status config_line_handler(void* _config, char* table, char* k,
|
||||
int parse_config(struct config* NNULLABLE config, char* NNULLABLE path) {
|
||||
FILE* fd = fopen(path, "r");
|
||||
if (fd == NULL) {
|
||||
log_perror("fopen");
|
||||
log_printf(" [I] No config, place one at " LIDM_CONF_PATH
|
||||
" or set the LIDM_CONF env variable\n");
|
||||
return 0; // Its fine now anyways
|
||||
perror("fopen");
|
||||
(void)fputs(
|
||||
"Please place a config file at /etc/lidm.ini or set the LIDM_CONF "
|
||||
"env variable",
|
||||
stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ret = read_desktop(fd, config, config_line_handler);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// NOLINTBEGIN(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,readability-function-cognitive-complexity)
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -19,7 +20,6 @@ char* trim_str(char* str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
int read_desktop(FILE* fd, void* ctx,
|
||||
struct status (*cb)(void* ctx, char* table, char* key,
|
||||
char* value)) {
|
||||
@@ -66,7 +66,7 @@ int read_desktop(FILE* fd, void* ctx,
|
||||
buf_start[eq_idx] = '\0'; // the equal
|
||||
key = trim_str(key);
|
||||
char* value = &buf_start[eq_idx + 1];
|
||||
if (buf_start[read_size - 1] == '\n') buf_start[read_size - 1] = '\0';
|
||||
buf_start[read_size - 1] = '\0'; // the newline
|
||||
value = trim_str(value);
|
||||
|
||||
// Callback
|
||||
@@ -82,3 +82,4 @@ int read_desktop(FILE* fd, void* ctx,
|
||||
if (buf != NULL) free(buf);
|
||||
return ret;
|
||||
}
|
||||
// NOLINTEND(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,readability-function-cognitive-complexity)
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
// TODO: rewrite properly
|
||||
// NOLINTBEGIN(clang-diagnostic-nullability-completeness)
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "desktop_exec.h"
|
||||
#include "macros.h"
|
||||
#include "util/path.h"
|
||||
|
||||
// constants for exec string parsing
|
||||
#define MAX_ARGS 100
|
||||
// ARG_LENGTH is the initial length of a parsed argument
|
||||
#define ARG_LENGTH 64
|
||||
|
||||
char* NULLABLE desktop_as_cmdline(char** args) {
|
||||
if (args[0] == NULL) return NULL;
|
||||
size_t fmtd_len = 0;
|
||||
|
||||
char** ptr = args;
|
||||
while (*ptr) {
|
||||
fmtd_len += strlen(*ptr) + 1;
|
||||
ptr++;
|
||||
}
|
||||
fmtd_len -= 1;
|
||||
|
||||
char* fmt_cmdline = malloc(fmtd_len + 1);
|
||||
if (!fmt_cmdline) return NULL;
|
||||
|
||||
size_t fmting_len = 0;
|
||||
ptr = args;
|
||||
while (*ptr) {
|
||||
char* nbyte = stpcpy(&fmt_cmdline[fmting_len], *ptr);
|
||||
*nbyte = ' ';
|
||||
|
||||
fmting_len += nbyte - &fmt_cmdline[fmting_len] + 1;
|
||||
ptr++;
|
||||
}
|
||||
fmt_cmdline[fmting_len - 1] = '\0';
|
||||
|
||||
return fmt_cmdline;
|
||||
}
|
||||
|
||||
// parse Exec=/bin/prog arg1 arg2\ with\ spaces
|
||||
void free_parsed_args(int arg_count, char** args) {
|
||||
if (!args) return;
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
free(args[i]);
|
||||
}
|
||||
free((void*)args);
|
||||
}
|
||||
|
||||
/* small closure-like struct to pass state to helper functions */
|
||||
struct ctx {
|
||||
char** pcur;
|
||||
size_t* pcur_len;
|
||||
size_t* pcur_cap;
|
||||
char*** pargv;
|
||||
int* pargc;
|
||||
};
|
||||
/* append_char(state, ch) -> 0 on error, 1 on success */
|
||||
int append_char(struct ctx* st, char ch) {
|
||||
char** pcur = st->pcur;
|
||||
size_t* plen = st->pcur_len;
|
||||
size_t* pcap = st->pcur_cap;
|
||||
if (*plen + 1 >= *pcap) {
|
||||
size_t newcap = *pcap ? (*pcap) * 2 : ARG_LENGTH;
|
||||
char* cur = (char*)realloc(*pcur, newcap);
|
||||
if (!cur) return 0;
|
||||
*pcur = cur;
|
||||
*pcap = newcap;
|
||||
}
|
||||
(*pcur)[(*plen)++] = ch;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* push_arg(state) -> 0 on error, 1 on success */
|
||||
int push_arg(struct ctx* st) {
|
||||
char** pcur = st->pcur;
|
||||
size_t* plen = st->pcur_len;
|
||||
size_t* pcap = st->pcur_cap;
|
||||
char*** pargv = st->pargv;
|
||||
int* pargc = st->pargc;
|
||||
|
||||
if (*pargc > MAX_ARGS) {
|
||||
return 1;
|
||||
}
|
||||
if (!*pcur) {
|
||||
char* empty = strdup("");
|
||||
if (!empty) return 0;
|
||||
char** na = (char**)realloc((void*)*pargv, sizeof(char*) * ((*pargc) + 1));
|
||||
if (!na) {
|
||||
free(empty);
|
||||
return 0;
|
||||
}
|
||||
*pargv = na;
|
||||
(*pargv)[(*pargc)++] = empty;
|
||||
return 1;
|
||||
}
|
||||
if (!append_char(st, '\0')) return 0;
|
||||
char* final = (char*)realloc(*pcur, *plen);
|
||||
if (!final) final = *pcur;
|
||||
*pcur = NULL;
|
||||
*plen = 0;
|
||||
*pcap = 0;
|
||||
char** na = (char**)realloc((void*)*pargv, sizeof(char*) * ((*pargc) + 1));
|
||||
if (!na) {
|
||||
free(final);
|
||||
return 0;
|
||||
}
|
||||
*pargv = na;
|
||||
(*pargv)[(*pargc)++] = final;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return codes:
|
||||
0 = success
|
||||
1 = bad args
|
||||
2 = memory
|
||||
3 = syntax
|
||||
Important: call free_parsed_args afterwards to free the passed ***args
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||
int parse_exec_string(const char* exec_s, int* arg_count, char*** args) {
|
||||
if (!exec_s || !args || !arg_count) return 1;
|
||||
*args = NULL;
|
||||
*arg_count = 0;
|
||||
|
||||
size_t len = strlen(exec_s);
|
||||
size_t idx = 0;
|
||||
char* cur = NULL;
|
||||
size_t cur_len = 0;
|
||||
size_t cur_cap = 0;
|
||||
char** argv = NULL;
|
||||
int argc = 0;
|
||||
int in_quote = 0;
|
||||
|
||||
struct ctx ctx;
|
||||
ctx.pcur = &cur;
|
||||
ctx.pcur_len = &cur_len;
|
||||
ctx.pcur_cap = &cur_cap;
|
||||
ctx.pargv = &argv;
|
||||
ctx.pargc = &argc;
|
||||
|
||||
while (idx < len) {
|
||||
char cur_c = exec_s[idx];
|
||||
if (!in_quote && (cur_c == ' ' || cur_c == '\t' || cur_c == '\n')) {
|
||||
if (cur_cap) {
|
||||
if (!push_arg(&ctx)) goto nomem;
|
||||
}
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
if (!in_quote && cur_c == '"') {
|
||||
in_quote = 1;
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
if (in_quote && cur_c == '"') {
|
||||
in_quote = 0;
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur_c == '\\') {
|
||||
if (idx + 1 >= len) goto syntax_err;
|
||||
if (!append_char(&ctx, exec_s[idx + 1])) goto nomem;
|
||||
idx += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur_c == '%') {
|
||||
if (idx + 1 >= len) goto syntax_err;
|
||||
if (exec_s[idx + 1] == '%') {
|
||||
if (!append_char(&ctx, '%')) goto nomem;
|
||||
idx += 2;
|
||||
continue;
|
||||
}
|
||||
/* drop any %X */
|
||||
idx += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!append_char(&ctx, cur_c)) goto nomem;
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (in_quote) goto syntax_err;
|
||||
if (cur_cap) {
|
||||
if (!push_arg(&ctx)) goto nomem;
|
||||
}
|
||||
char** na = (char**)realloc((void*)argv, sizeof(char*) * (argc + 1));
|
||||
if (!na) goto nomem;
|
||||
argv = na;
|
||||
argv[argc] = NULL;
|
||||
|
||||
*args = argv;
|
||||
*arg_count = argc;
|
||||
return 0;
|
||||
|
||||
nomem:
|
||||
if (cur) free(cur);
|
||||
free_parsed_args(argc, argv);
|
||||
*args = NULL;
|
||||
*arg_count = 0;
|
||||
return 2;
|
||||
|
||||
syntax_err:
|
||||
if (cur) free(cur);
|
||||
free_parsed_args(argc, argv);
|
||||
*args = NULL;
|
||||
*arg_count = 0;
|
||||
return 3;
|
||||
}
|
||||
// NOLINTEND(readability-function-cognitive-complexity)
|
||||
// NOLINTEND(clang-diagnostic-nullability-completeness)
|
||||
14
src/efield.c
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "efield.h"
|
||||
#include "ui.h"
|
||||
#include "util/utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
// NOLINTBEGIN(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
||||
|
||||
struct editable_field efield_new(char* content) {
|
||||
struct editable_field efield;
|
||||
@@ -16,14 +18,14 @@ struct editable_field efield_new(char* content) {
|
||||
return efield;
|
||||
}
|
||||
|
||||
void efield_trim(struct editable_field* self, uint8_t pos) {
|
||||
void efield_trim(struct editable_field* self, u_char pos) {
|
||||
self->pos = pos;
|
||||
self->content[pos + 1] = '\0';
|
||||
}
|
||||
|
||||
#define BACKSPACE_CODE 127
|
||||
void efield_update(struct editable_field* self, char* update) {
|
||||
uint8_t insert_len = strlen(update);
|
||||
u_char insert_len = strlen(update);
|
||||
if (insert_len == 0) return;
|
||||
|
||||
if (self->pos > strlen(self->content))
|
||||
@@ -61,7 +63,7 @@ bool efield_seek(struct editable_field* self, char seek) {
|
||||
if (*self->content == '\0') return false;
|
||||
if (seek == 0) return false;
|
||||
|
||||
uint8_t count = seek < 0 ? -seek : seek;
|
||||
u_char count = seek < 0 ? -seek : seek;
|
||||
char* ptr = &self->content[self->pos];
|
||||
char* start = ptr;
|
||||
|
||||
@@ -75,6 +77,8 @@ bool efield_seek(struct editable_field* self, char seek) {
|
||||
}
|
||||
}
|
||||
|
||||
self->pos = (uint8_t)(ptr - self->content);
|
||||
self->pos = (u_char)(ptr - self->content);
|
||||
return ptr != start;
|
||||
}
|
||||
|
||||
// NOLINTEND(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
||||
|
||||
77
src/keys.c
@@ -1,77 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "keys.h"
|
||||
#include "macros.h"
|
||||
#include "ui.h"
|
||||
|
||||
static int selret_magic();
|
||||
|
||||
int find_keyname(enum Keys* at, const char* name) {
|
||||
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
|
||||
if (strcmp(KEY_NAMES[i], name) == 0) {
|
||||
*at = (enum Keys)i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct option_keys find_ansi(const char* seq) {
|
||||
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
|
||||
struct key_mapping mapping = KEY_MAPPINGS[i];
|
||||
for (size_t j = 0; mapping.sequences[j] != NULL; j++) {
|
||||
if (strcmp(mapping.sequences[j], seq) == 0) {
|
||||
return (struct option_keys){
|
||||
.is_some = true,
|
||||
.key = (enum Keys)i,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return (struct option_keys){.is_some = false};
|
||||
}
|
||||
|
||||
void read_press(uint8_t* length, char* out) {
|
||||
*length = 0;
|
||||
|
||||
while (true) {
|
||||
if (read(STDIN_FILENO, &out[(*length)++], 1) != 1) {
|
||||
print_errno("read error");
|
||||
sleep(3);
|
||||
exit(1);
|
||||
}
|
||||
int selret = selret_magic();
|
||||
if (selret == -1) {
|
||||
print_errno("selret error");
|
||||
} else if (selret != 1) {
|
||||
out[*length] = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool read_press_nb(uint8_t* length, char* out, struct timeval* tv) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
errno = 0;
|
||||
int ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, tv);
|
||||
if (errno || ret <= 0) return false;
|
||||
|
||||
read_press(length, out);
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/48040042
|
||||
static int selret_magic() {
|
||||
fd_set set;
|
||||
struct timeval timeout;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(STDIN_FILENO, &set);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
return select(1, &set, NULL, NULL, &timeout);
|
||||
}
|
||||
@@ -21,17 +21,15 @@ int read_launch_state(struct LaunchState* NNULLABLE state) {
|
||||
};
|
||||
|
||||
size_t num = 0;
|
||||
ssize_t chars = getline(&state->username, &num, state_fd);
|
||||
if (chars <= 0) goto fail;
|
||||
if (state->username[chars - 1] == '\n') state->username[chars - 1] = 0;
|
||||
if (getline(&state->username, &num, state_fd) < 0) goto fail;
|
||||
state->username[strcspn(state->username, "\n")] = 0;
|
||||
|
||||
num = 0;
|
||||
chars = getline(&state->session_opt, &num, state_fd);
|
||||
if (chars <= 0) {
|
||||
if (getline(&state->session_opt, &num, state_fd) < 0) {
|
||||
free(state->session_opt);
|
||||
goto fail;
|
||||
}
|
||||
if (state->session_opt[chars - 1] == '\n') state->session_opt[chars - 1] = 0;
|
||||
state->session_opt[strcspn(state->session_opt, "\n")] = 0;
|
||||
|
||||
(void)fclose(state_fd);
|
||||
return 0;
|
||||
|
||||
@@ -8,7 +8,6 @@ static FILE* logger_out = NULL;
|
||||
|
||||
void log_init(FILE* fd) {
|
||||
if (logger_out) (void)fclose(logger_out);
|
||||
(void)setvbuf(fd, NULL, _IONBF, 0);
|
||||
logger_out = fd;
|
||||
}
|
||||
|
||||
@@ -33,7 +32,7 @@ void log_perror(const char* s) {
|
||||
if (!logger_out) return;
|
||||
|
||||
if (s)
|
||||
(void)fprintf(logger_out, "%s: %s\n", s, strerror(errno));
|
||||
(void)fprintf(logger_out, "%s: %s", s, strerror(errno));
|
||||
else
|
||||
(void)fprintf(logger_out, "%s\n", strerror(errno));
|
||||
(void)fprintf(logger_out, "%s", strerror(errno));
|
||||
}
|
||||
|
||||
11
src/main.c
@@ -12,13 +12,12 @@
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
#include "sessions.h"
|
||||
#include "signal_handler.h"
|
||||
#include "ui.h"
|
||||
#include "users.h"
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
#include "version.h"
|
||||
|
||||
#define DATESTR_MAXBUFSIZE 0x20
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Logger
|
||||
char* log_output = getenv("LIDM_LOG");
|
||||
@@ -31,7 +30,6 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
log_init(log_fd);
|
||||
log_puts("Starting log:");
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
@@ -74,10 +72,9 @@ int main(int argc, char* argv[]) {
|
||||
chvt_str(argv[1]);
|
||||
}
|
||||
|
||||
// Copy
|
||||
struct config config = DEFAULT_CONFIG;
|
||||
char* conf_override = getenv("LIDM_CONF");
|
||||
char* conf_path = conf_override ? conf_override : LIDM_CONF_PATH;
|
||||
char* conf_path = conf_override ? conf_override : "/etc/lidm.ini";
|
||||
if (parse_config(&config, conf_path) != 0) {
|
||||
(void)fputs("error parsing config\n", stderr);
|
||||
return 1;
|
||||
@@ -87,8 +84,6 @@ int main(int argc, char* argv[]) {
|
||||
struct Vector users = get_human_users();
|
||||
struct Vector sessions = get_avaliable_sessions();
|
||||
|
||||
setup_sigterm();
|
||||
|
||||
int ret = load(&users, &sessions);
|
||||
if (ret == 0) execl(argv[0], argv[0], NULL);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "efield.h"
|
||||
#include "ofield.h"
|
||||
#include "ui.h"
|
||||
#include "util/utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
struct opts_field ofield_new(size_t opts) {
|
||||
if (opts == 0) {
|
||||
@@ -54,10 +55,10 @@ bool ofield_seek(struct opts_field* self, char seek) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ofield_display_cursor_col(struct opts_field* self, uint8_t maxlen) {
|
||||
u_char ofield_display_cursor_col(struct opts_field* self, u_char maxlen) {
|
||||
if (self->current_opt == 0) {
|
||||
uint8_t display_len = utf8len(self->efield.content);
|
||||
uint8_t pos = utf8len_until(self->efield.content,
|
||||
u_char display_len = utf8len(self->efield.content);
|
||||
u_char pos = utf8len_until(self->efield.content,
|
||||
&self->efield.content[self->efield.pos]);
|
||||
|
||||
if (display_len > maxlen) {
|
||||
|
||||
197
src/pam.c
@@ -1,197 +0,0 @@
|
||||
#include <pwd.h>
|
||||
#include <security/_pam_types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
#include "pam.h"
|
||||
#include "sessions.h"
|
||||
#include "ui.h"
|
||||
|
||||
struct envpair {
|
||||
const char* NNULLABLE name;
|
||||
char* NULLABLE value;
|
||||
};
|
||||
|
||||
char* NULLABLE make_env_kv(const char* NNULLABLE key, char* NNULLABLE value) {
|
||||
char* buf = NULL;
|
||||
asprintf(&buf, "%s=%s", key, value);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void free_envlist(char** NNULLABLE envlist) {
|
||||
for (char** ptr = envlist; *ptr; ptr++)
|
||||
free(*ptr);
|
||||
free((void*)envlist);
|
||||
}
|
||||
|
||||
// NULL when allocation failure
|
||||
// in any case, envlist would be freed after this function
|
||||
char** NULLABLE merge_envlist(char** NNULLABLE envlist, struct envpair extra[],
|
||||
size_t extra_len) {
|
||||
size_t envlist_len = 0;
|
||||
while (envlist[envlist_len])
|
||||
envlist_len++;
|
||||
|
||||
size_t nonnullelems = 0;
|
||||
for (size_t i = 0; i < extra_len; i++) {
|
||||
if (extra[i].value) nonnullelems++;
|
||||
}
|
||||
|
||||
size_t new_envlist_len = envlist_len + nonnullelems + 1;
|
||||
char** new_envlist =
|
||||
(char**)realloc((void*)envlist, sizeof(char*) * new_envlist_len);
|
||||
if (!new_envlist) {
|
||||
free_envlist(envlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-length)
|
||||
size_t k = 0;
|
||||
for (size_t i = 0; i < extra_len; i++) {
|
||||
if (!extra[i].value) continue;
|
||||
char* env_kv = make_env_kv(extra[i].name, extra[i].value);
|
||||
if (!env_kv) goto free_new_envlist_extra;
|
||||
new_envlist[envlist_len + k++] = env_kv;
|
||||
}
|
||||
|
||||
new_envlist[envlist_len + nonnullelems] = NULL;
|
||||
return new_envlist;
|
||||
|
||||
free_new_envlist_extra:
|
||||
for (size_t j = 0; j < envlist_len + k; j++) {
|
||||
free(new_envlist[envlist_len + j]);
|
||||
}
|
||||
free((void*)new_envlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* NULLABLE xdg_ssession_type_str(enum SessionType typ) {
|
||||
char* xdg_session_type = NULL;
|
||||
if (typ == SHELL) xdg_session_type = "tty";
|
||||
if (typ == XORG) xdg_session_type = "x11";
|
||||
if (typ == WAYLAND) xdg_session_type = "wayland";
|
||||
return xdg_session_type;
|
||||
}
|
||||
|
||||
#define FAIL_ALLOC() \
|
||||
{ \
|
||||
return (struct pamh_getenv_status){.error_flag = PAMH_ERR_ALLOC}; \
|
||||
}
|
||||
#define FAIL(ERR, ERRFN) \
|
||||
{ \
|
||||
return (struct pamh_getenv_status){.error_flag = (ERR), .errfn = (ERRFN)}; \
|
||||
}
|
||||
|
||||
struct pamh_getenv_status pamh_get_complete_env(pam_handle_t* handle,
|
||||
struct passwd* NNULLABLE pw,
|
||||
enum SessionType session_typ) {
|
||||
char** raw_envlist = pam_getenvlist(handle);
|
||||
if (!raw_envlist) FAIL(PAMH_ERR_ERRNO, "pam_getenvlist");
|
||||
|
||||
char** ptr = raw_envlist;
|
||||
while (*ptr)
|
||||
log_printf("[I] got pam env %s\n", *(ptr++));
|
||||
|
||||
struct envpair extra_env[] = {
|
||||
{"TERM", getenv("TERM")},
|
||||
{"PATH", getenv("PATH")},
|
||||
{"HOME", pw->pw_dir},
|
||||
{"USER", pw->pw_name},
|
||||
{"SHELL", pw->pw_shell},
|
||||
{"LOGNAME", pw->pw_name},
|
||||
{"XDG_SESSION_TYPE", xdg_ssession_type_str(session_typ)}};
|
||||
|
||||
char** envlist = merge_envlist(raw_envlist, extra_env, LEN(extra_env));
|
||||
if (!envlist) FAIL_ALLOC();
|
||||
return (struct pamh_getenv_status){
|
||||
.error_flag = PAMH_ERR_NOERR,
|
||||
.envlist = envlist,
|
||||
};
|
||||
}
|
||||
|
||||
#undef FAIL
|
||||
#undef FAIL_ALLOC
|
||||
|
||||
///////////////
|
||||
|
||||
struct pam_conv_data {
|
||||
char* password;
|
||||
void (*display_pam_msg)(const char* msg, int msg_style);
|
||||
};
|
||||
|
||||
int pam_conversation(int num_msg, const struct pam_message** msg,
|
||||
struct pam_response** resp, void* appdata_ptr) {
|
||||
struct pam_response* reply = malloc(sizeof(struct pam_response) * num_msg);
|
||||
if (!reply) {
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
struct pam_conv_data* conv_data = (struct pam_conv_data*)appdata_ptr;
|
||||
|
||||
for (int i = 0; i < num_msg; i++) {
|
||||
reply[i].resp = NULL;
|
||||
reply[i].resp_retcode = 0;
|
||||
|
||||
switch (msg[i]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
reply[i].resp = strdup(conv_data->password);
|
||||
if (!reply[i].resp) {
|
||||
for (int j = 0; j < i; j++)
|
||||
free(reply[j].resp);
|
||||
free(reply);
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
break;
|
||||
|
||||
case PAM_TEXT_INFO:
|
||||
case PAM_ERROR_MSG:
|
||||
if (conv_data->display_pam_msg && msg[i]->msg) {
|
||||
conv_data->display_pam_msg(msg[i]->msg, msg[i]->msg_style);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*resp = reply;
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef PAM_SERVICE_FALLBACK
|
||||
#define PAM_SERVICE_FALLBACK "login"
|
||||
#endif
|
||||
|
||||
#define CHECK_PAM_RET(call) \
|
||||
ret = (call); \
|
||||
if (ret != PAM_SUCCESS) { \
|
||||
pam_end(pamh, ret); \
|
||||
return NULL; \
|
||||
}
|
||||
pam_handle_t* get_pamh(char* user, char* passwd) {
|
||||
pam_handle_t* pamh = NULL;
|
||||
struct pam_conv_data conv_data = {.password = passwd,
|
||||
.display_pam_msg = print_pam_msg};
|
||||
struct pam_conv pamc = {pam_conversation, (void*)&conv_data};
|
||||
int ret;
|
||||
|
||||
char* pam_service_override = getenv("LIDM_PAM_SERVICE");
|
||||
char* pam_service_name =
|
||||
pam_service_override ? pam_service_override : PAM_SERVICE_FALLBACK;
|
||||
|
||||
CHECK_PAM_RET(pam_start(pam_service_name, user, &pamc, &pamh))
|
||||
CHECK_PAM_RET(pam_authenticate(pamh, 0))
|
||||
CHECK_PAM_RET(pam_acct_mgmt(pamh, 0))
|
||||
CHECK_PAM_RET(pam_setcred(pamh, PAM_ESTABLISH_CRED))
|
||||
CHECK_PAM_RET(pam_open_session(pamh, 0))
|
||||
CHECK_PAM_RET(pam_setcred(pamh, PAM_REINITIALIZE_CRED))
|
||||
|
||||
return pamh;
|
||||
}
|
||||
#undef CHECK_PAM_RET
|
||||
117
src/sessions.c
@@ -1,4 +1,3 @@
|
||||
#include <errno.h>
|
||||
#include <ftw.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
@@ -7,38 +6,20 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "desktop.h"
|
||||
#include "desktop_exec.h"
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
#include "sessions.h"
|
||||
#include "util/path.h"
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
|
||||
struct source_dir {
|
||||
enum SessionType type;
|
||||
enum session_type type;
|
||||
char* dir;
|
||||
};
|
||||
|
||||
#ifndef SESSIONS_XSESSIONS
|
||||
#define SESSIONS_XSESSIONS "/usr/share/xsessions"
|
||||
#endif
|
||||
#ifndef SESSIONS_XSESSIONS_LOCAL
|
||||
#define SESSIONS_XSESSIONS_LOCAL "/usr/local/share/xsessions"
|
||||
#endif
|
||||
#ifndef SESSIONS_WAYLAND
|
||||
#define SESSIONS_WAYLAND "/usr/share/wayland-sessions"
|
||||
#endif
|
||||
#ifndef SESSIONS_WAYLAND_LOCAL
|
||||
#define SESSIONS_WAYLAND_LOCAL "/usr/local/share/wayland-sessions"
|
||||
#endif
|
||||
static const struct source_dir SOURCES[] = {{XORG, SESSIONS_XSESSIONS},
|
||||
{XORG, SESSIONS_XSESSIONS_LOCAL},
|
||||
{WAYLAND, SESSIONS_WAYLAND},
|
||||
{WAYLAND, SESSIONS_WAYLAND_LOCAL}};
|
||||
static const struct source_dir SOURCES[] = {
|
||||
{XORG, "/usr/share/xsessions"},
|
||||
{WAYLAND, "/usr/share/wayland-sessions"},
|
||||
};
|
||||
|
||||
static struct Vector* cb_sessions = NULL;
|
||||
|
||||
@@ -84,11 +65,9 @@ struct status cb(void* _ctx, char* NULLABLE table, char* key, char* value) {
|
||||
|
||||
// also, always return 0 or we will break parsing and we don't want a bad
|
||||
// desktop file to break all possible sessions
|
||||
static enum SessionType session_type;
|
||||
static enum session_type session_type;
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
static int fn(const char* fpath, const struct stat* sb, int typeflag) {
|
||||
UNUSED(sb);
|
||||
|
||||
// guessing symlink behavior
|
||||
// - FTW_PHYS if set doesn't follow symlinks, so ftw() has no flags and it
|
||||
// follows symlinks, we should never get to handle that
|
||||
@@ -109,33 +88,22 @@ static int fn(const char* fpath, const struct stat* sb, int typeflag) {
|
||||
}
|
||||
|
||||
int ret = read_desktop(fd, &ctx, &cb);
|
||||
// any error
|
||||
if (ret < 0) goto err_close;
|
||||
if (ret < 0) { // any error
|
||||
log_printf("[E] format error parsing %s", fpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)fclose(fd);
|
||||
|
||||
// TODO: filter based on tryexec
|
||||
// https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html
|
||||
free(ctx.tryexec);
|
||||
|
||||
// just add this to the list
|
||||
if (ctx.name != NULL && ctx.exec != NULL) {
|
||||
struct session* this_session = malloc(sizeof(struct session));
|
||||
if (this_session == NULL) return 0;
|
||||
|
||||
int arg_count;
|
||||
char** args;
|
||||
int parse_status = parse_exec_string(ctx.exec, &arg_count, &args);
|
||||
if (parse_status != 0 || arg_count == 0 || !args[0]) {
|
||||
log_printf("[E] parsing exec string '%s': %d\n", ctx.exec, parse_status);
|
||||
free(this_session);
|
||||
goto err_parsing;
|
||||
}
|
||||
free(ctx.exec);
|
||||
|
||||
*this_session = (struct session){
|
||||
.name = ctx.name,
|
||||
.exec = session_exec_desktop(arg_count, args),
|
||||
.exec = ctx.exec,
|
||||
.tryexec = ctx.tryexec,
|
||||
.type = session_type,
|
||||
};
|
||||
|
||||
@@ -143,12 +111,6 @@ static int fn(const char* fpath, const struct stat* sb, int typeflag) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_close:
|
||||
(void)fclose(fd);
|
||||
err_parsing:
|
||||
log_printf("[E] format error parsing %s", fpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This code is designed to be run purely single threaded
|
||||
@@ -158,7 +120,7 @@ struct Vector get_avaliable_sessions() {
|
||||
vec_reserve(&sessions, LIKELY_BOUND_SESSIONS);
|
||||
|
||||
cb_sessions = &sessions;
|
||||
for (size_t i = 0; i < LEN(SOURCES); i++) {
|
||||
for (size_t i = 0; i < (sizeof(SOURCES) / sizeof(SOURCES[0])); i++) {
|
||||
log_printf("[I] parsing into %s\n", SOURCES[i].dir);
|
||||
session_type = SOURCES[i].type;
|
||||
ftw(SOURCES[i].dir, &fn, 1);
|
||||
@@ -167,54 +129,3 @@ struct Vector get_avaliable_sessions() {
|
||||
|
||||
return sessions;
|
||||
}
|
||||
|
||||
int session_exec_exec(struct session_exec* NNULLABLE exec,
|
||||
char* NULLABLE* NNULLABLE envp) {
|
||||
switch (exec->typ) {
|
||||
case EXEC_SHELL: {
|
||||
char* argv[] = {exec->shell, NULL};
|
||||
return execvpe(exec->shell, argv, envp);
|
||||
}
|
||||
case EXEC_DESKTOP:
|
||||
return execvpe(exec->desktop.args[0], exec->desktop.args, envp);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
/// So the reason this doesn't use the user shell is because that can really be
|
||||
/// anything, also assuming it were fish for example, it can't execute posix
|
||||
/// shell files and that leaves it out of most `/etc/profile.d/` scripts.
|
||||
///
|
||||
/// I'll just default to bash for now as it's able to source almost everything
|
||||
/// and takes most flags. Maybe will try to make this more sophisticated in the
|
||||
/// future.
|
||||
///
|
||||
/// This respects errno. Even also works as any exec family function.
|
||||
#ifndef LOGIN_SHELL
|
||||
#define LOGIN_SHELL "bash"
|
||||
#endif
|
||||
// This triggers login behavior
|
||||
#define LOGIN_SHELL_ARG0 "-" LOGIN_SHELL
|
||||
int session_exec_login_through_shell(struct session_exec* NNULLABLE exec,
|
||||
char* NULLABLE* NNULLABLE envp) {
|
||||
switch (exec->typ) {
|
||||
case EXEC_SHELL: {
|
||||
char* argv[] = {LOGIN_SHELL_ARG0, "-c", exec->shell, NULL};
|
||||
return execvpe(LOGIN_SHELL, argv, envp);
|
||||
}
|
||||
case EXEC_DESKTOP: {
|
||||
char* name = desktop_as_cmdline(exec->desktop.args);
|
||||
if (!name) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
char* argv[] = {LOGIN_SHELL_ARG0, "-c", name, NULL};
|
||||
int ret = execvpe(LOGIN_SHELL, argv, envp);
|
||||
free(name);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "signal_handler.h"
|
||||
|
||||
static void handle_sigterm(int sig) {
|
||||
(void)sig;
|
||||
|
||||
(void)signal(SIGTERM, SIG_IGN);
|
||||
kill(-getpgrp(), SIGTERM);
|
||||
|
||||
int status;
|
||||
while (waitpid(-1, &status, 0) > 0 || errno == EINTR) {
|
||||
}
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
void setup_sigterm() {
|
||||
setpgid(0, 0);
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = handle_sigterm;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
}
|
||||
211
src/ui.c
@@ -3,9 +3,7 @@
|
||||
|
||||
#include <asm-generic/errno.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
@@ -26,15 +24,14 @@
|
||||
#include "keys.h"
|
||||
#include "launch_state.h"
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
#include "ofield.h"
|
||||
#include "sessions.h"
|
||||
#include "ui.h"
|
||||
#include "ui_state.h"
|
||||
#include "users.h"
|
||||
#include "util/utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
const uint8_t INPUTS_N = 3;
|
||||
const u_char INPUTS_N = 3;
|
||||
|
||||
struct uint_point {
|
||||
uint x;
|
||||
@@ -63,15 +60,9 @@ struct config* g_config = NULL;
|
||||
static volatile sig_atomic_t need_resize = 0;
|
||||
|
||||
static void process_sigwinch(int signal) {
|
||||
UNUSED(signal);
|
||||
need_resize = 1;
|
||||
}
|
||||
|
||||
static inline void draw_bg() {
|
||||
// apply bg color to all screen
|
||||
printf("\x1b[%sm\x1b[2J", g_config->colors.bg);
|
||||
}
|
||||
|
||||
void setup(struct config* config) {
|
||||
g_config = config;
|
||||
|
||||
@@ -81,9 +72,10 @@ void setup(struct config* config) {
|
||||
term.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDOUT_FILENO, TCSANOW, &term);
|
||||
|
||||
// save cursor pos, save screen
|
||||
printf("\x1b[s\x1b[?47h");
|
||||
draw_bg();
|
||||
// save cursor pos, save screen, set color and reset screen
|
||||
// (applying color to all screen)
|
||||
printf("\x1b[s\x1b[?47h\x1b[%s;%sm\x1b[2J", g_config->colors.bg,
|
||||
g_config->colors.fg);
|
||||
|
||||
(void)atexit(restore_all);
|
||||
(void)signal(SIGINT, signal_handler);
|
||||
@@ -116,30 +108,38 @@ static char* fmt_time(const char* fmt) {
|
||||
}
|
||||
}
|
||||
|
||||
char* trunc_gethostname(size_t maxlen, const char* const ELLIPSIS) {
|
||||
if (utf8len(ELLIPSIS) > maxlen) return NULL;
|
||||
size_t alloc_size = HOST_NAME_MAX + strlen(ELLIPSIS) + 1;
|
||||
char* trunc_gethostname(const size_t MAXSIZE, const char* const ELLIPSIS) {
|
||||
if (utf8len(ELLIPSIS) > MAXSIZE) return NULL;
|
||||
size_t alloc_size = MAXSIZE + 1;
|
||||
char* buf = malloc(alloc_size);
|
||||
if (!buf) return NULL;
|
||||
while (true) {
|
||||
if (gethostname(buf, alloc_size) == 0) return buf;
|
||||
if (errno == ENAMETOOLONG) {
|
||||
buf[alloc_size] = '\0';
|
||||
if (utf8len(buf) > MAXSIZE - utf8len(ELLIPSIS)) {
|
||||
strcpy(&buf[MAXSIZE - utf8len(ELLIPSIS)], ELLIPSIS);
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (gethostname(buf, alloc_size) != 0) {
|
||||
alloc_size *= 2;
|
||||
char* nbuf = realloc(buf, alloc_size);
|
||||
if (!nbuf) goto fail;
|
||||
buf = nbuf;
|
||||
} else
|
||||
goto fail;
|
||||
}
|
||||
fail:
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (utf8len(buf) > maxlen) {
|
||||
size_t end = utf8trunc(buf, maxlen - utf8len(ELLIPSIS));
|
||||
strcpy(&buf[end], ELLIPSIS);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void ui_update_cursor_focus() {
|
||||
uint8_t line = box_start.y;
|
||||
uint8_t col = box_start.x + VALUES_COL;
|
||||
u_char line = box_start.y;
|
||||
u_char col = box_start.x + VALUES_COL;
|
||||
|
||||
struct opts_field* ofield = get_opts_ffield();
|
||||
uint8_t maxlen = VALUE_MAXLEN;
|
||||
u_char maxlen = VALUE_MAXLEN;
|
||||
if (ofield->opts > 1) {
|
||||
maxlen -= utf8len(g_config->strings.opts_pre) +
|
||||
utf8len(g_config->strings.opts_post);
|
||||
@@ -158,7 +158,7 @@ void ui_update_cursor_focus() {
|
||||
(void)printf("\x1b[%d;%dH", line, col);
|
||||
}
|
||||
|
||||
void ui_update_field(enum Input focused_input) {
|
||||
void ui_update_field(enum input focused_input) {
|
||||
if (focused_input == PASSWD) {
|
||||
print_passwd(utf8len(of_passwd.efield.content), false);
|
||||
} else if (focused_input == SESSION) {
|
||||
@@ -177,7 +177,7 @@ void ui_update_ffield() {
|
||||
}
|
||||
|
||||
void ui_update_ofield(struct opts_field* NNULLABLE self) {
|
||||
enum Input input;
|
||||
enum input input;
|
||||
if (self == &of_session)
|
||||
input = SESSION;
|
||||
else if (self == &of_user)
|
||||
@@ -190,7 +190,6 @@ void ui_update_ofield(struct opts_field* NNULLABLE self) {
|
||||
ui_update_field(input);
|
||||
}
|
||||
|
||||
/// draw everything
|
||||
void scratch_print_ui() {
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &window);
|
||||
box_start = (struct uint_point){
|
||||
@@ -198,16 +197,15 @@ void scratch_print_ui() {
|
||||
.y = ((window.ws_row - BOX_HEIGHT) / 2), // leave more space under
|
||||
};
|
||||
|
||||
if (window.ws_row < BOX_HEIGHT + (INNER_BOX_OUT_MARGIN * 2) ||
|
||||
window.ws_col < BOX_WIDTH + (INNER_BOX_OUT_MARGIN * 2)) {
|
||||
if (window.ws_row < BOX_HEIGHT + INNER_BOX_OUT_MARGIN * 2 ||
|
||||
window.ws_col < BOX_WIDTH + INNER_BOX_OUT_MARGIN * 2) {
|
||||
printf("\033[2J\033[H"); // Clear screen
|
||||
printf("\x1b[1;31mScreen too small\x1b[0m\n");
|
||||
printf("\x1b[%s;%sm\x1b[2J", g_config->colors.bg, g_config->colors.fg);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\033[2J\033[H\033c"); // Clear screen
|
||||
draw_bg();
|
||||
printf("\033[2J\033[H"); // Clear screen
|
||||
|
||||
/// PRINTING
|
||||
// printf box
|
||||
@@ -269,7 +267,7 @@ int load(struct Vector* users, struct Vector* sessions) {
|
||||
scratch_print_ui();
|
||||
|
||||
/// INTERACTIVE
|
||||
uint8_t len;
|
||||
u_char len;
|
||||
char seq[0xff];
|
||||
uint esc = 0;
|
||||
while (true) {
|
||||
@@ -289,46 +287,28 @@ int load(struct Vector* users, struct Vector* sessions) {
|
||||
(void)fflush(stdout);
|
||||
if (!read_press_nb(&len, seq, &tv)) continue;
|
||||
if (*seq == '\x1b') {
|
||||
struct option_keys ansi_code = find_ansi(seq);
|
||||
if (ansi_code.is_some) {
|
||||
enum Keys ansi_key = ansi_code.key;
|
||||
if (ansi_key == ESC) {
|
||||
enum keys ansi_code = find_ansi(seq);
|
||||
if (ansi_code != -1) {
|
||||
if (ansi_code == ESC) {
|
||||
esc = 2;
|
||||
} else if (ansi_key == g_config->functions.refresh) {
|
||||
} else if (ansi_code == g_config->functions.refresh) {
|
||||
restore_all();
|
||||
return 0;
|
||||
} else if (ansi_key == g_config->functions.reboot) {
|
||||
} else if (ansi_code == g_config->functions.reboot) {
|
||||
restore_all();
|
||||
reboot(RB_AUTOBOOT);
|
||||
exit(0);
|
||||
} else if (ansi_key == g_config->functions.poweroff) {
|
||||
} else if (ansi_code == g_config->functions.poweroff) {
|
||||
restore_all();
|
||||
reboot(RB_POWER_OFF);
|
||||
exit(0);
|
||||
} else if (g_config->functions.fido != NONE &&
|
||||
ansi_key == g_config->functions.fido) {
|
||||
bool successful_write = write_launch_state((struct LaunchState){
|
||||
.username = st_user().username,
|
||||
.session_opt =
|
||||
st_session(g_config->behavior.include_defshell).name,
|
||||
});
|
||||
if (!successful_write) log_puts("[E] failed to write launch state");
|
||||
|
||||
if (!launch(st_user().username, "",
|
||||
st_session(g_config->behavior.include_defshell),
|
||||
&restore_all, g_config)) {
|
||||
print_passwd(utf8len(of_passwd.efield.content), true);
|
||||
ui_update_cursor_focus();
|
||||
} else {
|
||||
scratch_print_ui();
|
||||
}
|
||||
} else if (ansi_key == A_UP || ansi_key == A_DOWN) {
|
||||
st_ch_focus(ansi_key == A_DOWN ? 1 : -1);
|
||||
} else if (ansi_key == A_RIGHT || ansi_key == A_LEFT) {
|
||||
} else if (ansi_code == A_UP || ansi_code == A_DOWN) {
|
||||
st_ch_focus(ansi_code == A_DOWN ? 1 : -1);
|
||||
} else if (ansi_code == A_RIGHT || ansi_code == A_LEFT) {
|
||||
if (esc)
|
||||
st_ch_of_opts(ansi_key == A_RIGHT ? 1 : -1);
|
||||
st_ch_of_opts(ansi_code == A_RIGHT ? 1 : -1);
|
||||
else
|
||||
st_ch_ef_col(ansi_key == A_RIGHT ? 1 : -1);
|
||||
st_ch_ef_col(ansi_code == A_RIGHT ? 1 : -1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -344,8 +324,6 @@ int load(struct Vector* users, struct Vector* sessions) {
|
||||
&restore_all, g_config)) {
|
||||
print_passwd(utf8len(of_passwd.efield.content), true);
|
||||
ui_update_cursor_focus();
|
||||
} else {
|
||||
scratch_print_ui();
|
||||
}
|
||||
} else
|
||||
st_kbd_type(seq, g_config->behavior.include_defshell);
|
||||
@@ -362,48 +340,33 @@ void clean_line(struct uint_point origin, uint line) {
|
||||
printf("\x1b[%d;%dH%s", origin.y + line, origin.x + 1, line_cleaner);
|
||||
}
|
||||
|
||||
uint8_t get_render_pos_offset(struct opts_field* self, uint8_t maxlen) {
|
||||
u_char get_render_pos_offset(struct opts_field* self, u_char maxlen) {
|
||||
if (self->current_opt != 0) return 0;
|
||||
|
||||
uint8_t pos = utf8len_until(self->efield.content,
|
||||
u_char pos = utf8len_until(self->efield.content,
|
||||
&self->efield.content[self->efield.pos]);
|
||||
return pos - ofield_display_cursor_col(self, maxlen);
|
||||
}
|
||||
|
||||
#define HOSTNAME_SIZE (VALUES_COL - VALUES_SEPR - BOX_HMARGIN - 1)
|
||||
void print_head() {
|
||||
char* fmtd_time = fmt_time(g_config->behavior.timefmt);
|
||||
size_t len_tm = utf8len(fmtd_time);
|
||||
|
||||
// calculate the space available for the host name
|
||||
ssize_t hostname_size = BOX_WIDTH - (BOX_HMARGIN * 2) - len_tm - VALUES_SEPR;
|
||||
if (hostname_size < 0) hostname_size = 0;
|
||||
|
||||
// hostname doesn't just change on runtime,
|
||||
// but the length of the time string might
|
||||
static char* NULLABLE hostname = NULL;
|
||||
static ssize_t hostname_calcd_size;
|
||||
|
||||
// save the truncated hostname and the length it truncated to,
|
||||
// if said length changes recalculate this (and free previous str)
|
||||
if (!hostname || hostname_calcd_size != hostname_size) {
|
||||
if (hostname) free(hostname);
|
||||
hostname = trunc_gethostname(hostname_size, g_config->strings.ellipsis);
|
||||
hostname_calcd_size = hostname_size;
|
||||
}
|
||||
// hostname doesn't just change on runtime
|
||||
static char* hostname = NULL;
|
||||
if (!hostname)
|
||||
hostname = trunc_gethostname(HOSTNAME_SIZE, g_config->strings.ellipsis);
|
||||
if (!hostname) hostname = "unknown";
|
||||
|
||||
clean_line(box_start, HEAD_ROW);
|
||||
|
||||
// put hostname
|
||||
if (hostname_size)
|
||||
printf("\x1b[%dG\x1b[%sm%s\x1b[%sm", box_start.x + 1 + BOX_HMARGIN,
|
||||
g_config->colors.e_hostname, hostname ? hostname : "unknown",
|
||||
g_config->colors.fg);
|
||||
printf("\x1b[%dG\x1b[%sm%s\x1b[%sm",
|
||||
box_start.x + VALUES_COL - VALUES_SEPR - (uint)utf8len(hostname),
|
||||
g_config->colors.e_hostname, hostname, g_config->colors.fg);
|
||||
|
||||
// put date
|
||||
char* fmtd_time = fmt_time(g_config->behavior.timefmt);
|
||||
printf("\x1b[%dG\x1b[%sm%s\x1b[%sm",
|
||||
box_start.x + BOX_WIDTH - 1 - BOX_HMARGIN - (uint)len_tm,
|
||||
box_start.x + BOX_WIDTH - 1 - BOX_HMARGIN - (uint)utf8len(fmtd_time),
|
||||
g_config->colors.e_date, fmtd_time, g_config->colors.fg);
|
||||
|
||||
free(fmtd_time);
|
||||
}
|
||||
|
||||
@@ -439,7 +402,7 @@ void print_session(struct session session, bool multiple) {
|
||||
|
||||
char* toprint = session.name;
|
||||
if (multiple) {
|
||||
uint8_t maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) -
|
||||
u_char maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) -
|
||||
utf8len(g_config->strings.opts_post);
|
||||
toprint += get_render_pos_offset(&of_session, maxlen);
|
||||
size_t printlen = utf8seekn(toprint, maxlen) - toprint;
|
||||
@@ -467,14 +430,13 @@ void print_user(struct user user, bool multiple) {
|
||||
|
||||
char* toprint = user.display_name;
|
||||
if (multiple) {
|
||||
uint8_t maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) -
|
||||
u_char maxlen = VALUE_MAXLEN - utf8len(g_config->strings.opts_pre) -
|
||||
utf8len(g_config->strings.opts_post);
|
||||
toprint += get_render_pos_offset(&of_session, maxlen);
|
||||
size_t printlen = utf8seekn(toprint, maxlen) - toprint;
|
||||
|
||||
printf("\r\x1b[%dC%s\x1b[%sm%.*s\x1b[%sm%s", box_start.x + VALUES_COL - 1,
|
||||
g_config->strings.opts_pre, user_color, (int)printlen, toprint,
|
||||
g_config->colors.fg, g_config->strings.opts_post);
|
||||
printf("\r\x1b[%dC< \x1b[%sm%.*s\x1b[%sm >", box_start.x + VALUES_COL - 1,
|
||||
user_color, (int)printlen, toprint, g_config->colors.fg);
|
||||
} else {
|
||||
toprint += get_render_pos_offset(&of_user, VALUE_MAXLEN);
|
||||
size_t printlen = utf8seekn(toprint, VALUE_MAXLEN) - toprint;
|
||||
@@ -539,8 +501,6 @@ static void print_box() {
|
||||
}
|
||||
|
||||
static void print_footer() {
|
||||
bool fido_enabled = g_config->functions.fido != NONE;
|
||||
|
||||
size_t bsize = utf8len(g_config->strings.f_poweroff) +
|
||||
utf8len(KEY_NAMES[g_config->functions.poweroff]) +
|
||||
utf8len(g_config->strings.f_reboot) +
|
||||
@@ -548,31 +508,19 @@ static void print_footer() {
|
||||
utf8len(g_config->strings.f_refresh) +
|
||||
utf8len(KEY_NAMES[g_config->functions.refresh]);
|
||||
|
||||
bsize += (2 * 2) + (3 * 1);
|
||||
|
||||
if (fido_enabled) {
|
||||
bsize += utf8len(g_config->strings.f_fido) +
|
||||
utf8len(KEY_NAMES[g_config->functions.fido]) + 2 + 1;
|
||||
}
|
||||
bsize += 2 * 2 + // 2 wide separators between 3 items
|
||||
3 * 1; // 3 thin separators inside every item
|
||||
|
||||
uint row = window.ws_row - 1;
|
||||
uint col = window.ws_col - 2 - bsize;
|
||||
|
||||
printf("\x1b[%d;%dH%s \x1b[%sm%s\x1b[%sm %s \x1b[%sm%s\x1b[%sm ", row, col,
|
||||
g_config->strings.f_poweroff, g_config->colors.e_key,
|
||||
KEY_NAMES[g_config->functions.poweroff], g_config->colors.fg,
|
||||
g_config->strings.f_reboot, g_config->colors.e_key,
|
||||
KEY_NAMES[g_config->functions.reboot], g_config->colors.fg);
|
||||
|
||||
if (fido_enabled) {
|
||||
printf("%s \x1b[%sm%s\x1b[%sm ", g_config->strings.f_fido,
|
||||
g_config->colors.e_key, KEY_NAMES[g_config->functions.fido],
|
||||
g_config->colors.fg);
|
||||
}
|
||||
|
||||
printf("%s \x1b[%sm%s\x1b[%sm", g_config->strings.f_refresh,
|
||||
g_config->colors.e_key, KEY_NAMES[g_config->functions.refresh],
|
||||
g_config->colors.fg);
|
||||
printf(
|
||||
"\x1b[%3$d;%4$dH%8$s \x1b[%1$sm%5$s\x1b[%2$sm %9$s "
|
||||
"\x1b[%1$sm%6$s\x1b[%2$sm %10$s \x1b[%1$sm%7$s\x1b[%2$sm",
|
||||
g_config->colors.e_key, g_config->colors.fg, row, col,
|
||||
KEY_NAMES[g_config->functions.poweroff],
|
||||
KEY_NAMES[g_config->functions.reboot],
|
||||
KEY_NAMES[g_config->functions.refresh], g_config->strings.f_poweroff,
|
||||
g_config->strings.f_reboot, g_config->strings.f_refresh);
|
||||
}
|
||||
|
||||
void print_err(const char* msg) {
|
||||
@@ -580,21 +528,6 @@ void print_err(const char* msg) {
|
||||
msg, errno, strerror(errno));
|
||||
}
|
||||
|
||||
void print_pam_msg(const char* msg, int msg_style) {
|
||||
uint row = box_start.y + BOX_HEIGHT + 1;
|
||||
const char* color =
|
||||
(msg_style == PAM_ERROR_MSG) ? g_config->colors.err : g_config->colors.fg;
|
||||
printf("\x1b[%d;%dH\x1b[K\x1b[%sm%.*s\x1b[%sm", row, box_start.x, color,
|
||||
BOX_WIDTH, msg, g_config->colors.fg);
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
|
||||
void clear_pam_msg(void) {
|
||||
uint row = box_start.y + BOX_HEIGHT + 1;
|
||||
printf("\x1b[%d;%dH\x1b[K", row, box_start.x);
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
|
||||
void print_errno(const char* descr) {
|
||||
if (descr == NULL)
|
||||
(void)fprintf(stderr, "\x1b[%d;%dH\x1b[%smunknown error(%d): %s",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "ui.h"
|
||||
#include "users.h"
|
||||
|
||||
enum Input focused_input = PASSWD;
|
||||
enum input focused_input = PASSWD;
|
||||
|
||||
struct Vector* gusers;
|
||||
struct Vector* gsessions;
|
||||
@@ -13,7 +13,7 @@ struct opts_field of_session;
|
||||
struct opts_field of_user;
|
||||
struct opts_field of_passwd;
|
||||
|
||||
struct opts_field* NNULLABLE get_opts_field(enum Input from) {
|
||||
struct opts_field* NNULLABLE get_opts_field(enum input from) {
|
||||
if (from == SESSION) return &of_session;
|
||||
if (from == USER) return &of_user;
|
||||
if (from == PASSWD) return &of_passwd;
|
||||
@@ -40,8 +40,7 @@ struct session st_session(bool include_defshell) {
|
||||
if (include_defshell && of_session.current_opt == gsessions->length + 1) {
|
||||
struct session shell_session;
|
||||
shell_session.type = SHELL;
|
||||
shell_session.exec =
|
||||
session_exec_shell(shell_session.name = st_user().shell);
|
||||
shell_session.exec = shell_session.name = st_user().shell;
|
||||
return shell_session;
|
||||
}
|
||||
|
||||
@@ -50,8 +49,7 @@ struct session st_session(bool include_defshell) {
|
||||
|
||||
struct session custom_session;
|
||||
custom_session.type = SHELL;
|
||||
custom_session.exec =
|
||||
session_exec_shell(custom_session.name = of_session.efield.content);
|
||||
custom_session.name = custom_session.exec = of_session.efield.content;
|
||||
return custom_session;
|
||||
}
|
||||
|
||||
@@ -88,7 +86,7 @@ void st_kbd_type(char* text, bool cfg_include_defshell) {
|
||||
start = st_user().username;
|
||||
if (focused_input == SESSION && of_session.current_opt != 0 &&
|
||||
st_session(cfg_include_defshell).type == SHELL)
|
||||
start = st_session(cfg_include_defshell).exec.shell;
|
||||
start = st_session(cfg_include_defshell).exec;
|
||||
|
||||
ofield_kbd_type(field, text, start);
|
||||
ui_update_ffield();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
#include "users.h"
|
||||
#include "util/vec.h"
|
||||
#include "util.h"
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-length)
|
||||
int build_user(struct user* NNULLABLE user, struct passwd* p) {
|
||||
|
||||
200
src/util.c
Normal file
@@ -0,0 +1,200 @@
|
||||
#include <asm-generic/errno-base.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "keys.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
|
||||
static int selret_magic();
|
||||
|
||||
int find_keyname(enum keys* at, const char* name) {
|
||||
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
|
||||
if (strcmp(KEY_NAMES[i], name) == 0) {
|
||||
*at = (enum keys)i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum keys find_ansi(const char* seq) {
|
||||
for (size_t i = 0; i < LEN(KEY_MAPPINGS); i++) {
|
||||
struct key_mapping mapping = KEY_MAPPINGS[i];
|
||||
for (size_t j = 0; mapping.sequences[j] != NULL; j++) {
|
||||
if (strcmp(mapping.sequences[j], seq) == 0) {
|
||||
return (enum keys)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void read_press(u_char* length, char* out) {
|
||||
*length = 0;
|
||||
|
||||
while (true) {
|
||||
if (read(STDIN_FILENO, &out[(*length)++], 1) != 1) {
|
||||
print_errno("read error");
|
||||
sleep(3);
|
||||
exit(1);
|
||||
}
|
||||
int selret = selret_magic();
|
||||
if (selret == -1) {
|
||||
print_errno("selret error");
|
||||
} else if (selret != 1) {
|
||||
out[*length] = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool read_press_nb(u_char* length, char* out, struct timeval* tv) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
errno = 0;
|
||||
int ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, tv);
|
||||
if (errno || ret <= 0) return false;
|
||||
|
||||
read_press(length, out);
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/48040042
|
||||
static int selret_magic() {
|
||||
fd_set set;
|
||||
struct timeval timeout;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(STDIN_FILENO, &set);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
return select(1, &set, NULL, NULL, &timeout);
|
||||
}
|
||||
|
||||
// UTF-8 shii
|
||||
#define UTF8_CONT_MSK 0b11000000
|
||||
#define UTF8_CONT_VAL 0b10000000
|
||||
bool utf8_iscont(char byte) {
|
||||
return (byte & UTF8_CONT_MSK) == UTF8_CONT_VAL;
|
||||
}
|
||||
|
||||
size_t utf8len(const char* str) {
|
||||
size_t len = 0;
|
||||
while (*str != '\0') {
|
||||
if (!utf8_iscont(*(str++))) len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t utf8len_until(const char* str, const char* until) {
|
||||
size_t len = 0;
|
||||
while (str < until) {
|
||||
if (!utf8_iscont(*(str++))) len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
const char* utf8back(const char* str) {
|
||||
while (utf8_iscont(*(--str))) {
|
||||
}
|
||||
return str;
|
||||
}
|
||||
const char* utf8seek(const char* str) {
|
||||
while (utf8_iscont(*(++str))) {
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
const char* utf8seekn(const char* str, size_t n) {
|
||||
while (n > 0 && *str != '\0') {
|
||||
str = utf8seek(str);
|
||||
n--;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Vector shii
|
||||
const struct Vector VEC_NEW = {
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
.pages = NULL,
|
||||
};
|
||||
|
||||
int vec_resize(struct Vector* self, size_t size) {
|
||||
void** new_location =
|
||||
(void**)realloc((void*)self->pages, size * sizeof(void*));
|
||||
if (new_location != NULL) {
|
||||
if (self->length > size) self->length = size;
|
||||
self->capacity = size;
|
||||
self->pages = new_location;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vec_reserve(struct Vector* self, size_t size) {
|
||||
uint32_t new_capacity = self->capacity;
|
||||
while (self->length + size > new_capacity) {
|
||||
new_capacity = new_capacity + (new_capacity >> 1) +
|
||||
1; // cap * 1.5 + 1; 0 1 2 4 7 11...
|
||||
}
|
||||
return vec_resize(self, new_capacity);
|
||||
}
|
||||
|
||||
int vec_reserve_exact(struct Vector* self, size_t size) {
|
||||
uint32_t needed_capacity = self->length + size;
|
||||
if (self->capacity < needed_capacity) {
|
||||
return vec_resize(self, needed_capacity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vec_push(struct Vector* self, void* item) {
|
||||
int res_ret = vec_reserve(self, 1);
|
||||
if (res_ret != 0) return res_ret;
|
||||
|
||||
self->pages[self->length++] = item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vec_free(struct Vector* self) {
|
||||
while (self->length > 0)
|
||||
free(self->pages[--self->length]);
|
||||
|
||||
vec_clear(self);
|
||||
}
|
||||
|
||||
void vec_clear(struct Vector* self) {
|
||||
free((void*)self->pages);
|
||||
vec_reset(self);
|
||||
}
|
||||
|
||||
void vec_reset(struct Vector* self) {
|
||||
*self = (struct Vector){
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
.pages = NULL,
|
||||
};
|
||||
}
|
||||
|
||||
void* vec_pop(struct Vector* self) {
|
||||
if (self->length == 0) return NULL;
|
||||
|
||||
return self->pages[--self->length];
|
||||
}
|
||||
|
||||
void* vec_get(struct Vector* self, size_t index) {
|
||||
if (index >= self->length) return NULL;
|
||||
|
||||
return self->pages[index];
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util/path.h"
|
||||
|
||||
// returns NULL on any error
|
||||
// otherwise it returns the absolute path of the program that MUST BE FREED
|
||||
//
|
||||
// Should be almost completely posix compliant, except it won't resolve empty
|
||||
// PATH entries relative to the cwd
|
||||
char* NULLABLE search_path(const char* NNULLABLE for_binary) {
|
||||
if (strchr(for_binary, '/') != NULL) {
|
||||
// skip absolute paths
|
||||
return strdup(for_binary);
|
||||
}
|
||||
char* path_env = getenv("PATH");
|
||||
if (!path_env) return NULL;
|
||||
char* path = strdup(path_env);
|
||||
if (!path) return NULL;
|
||||
|
||||
char* tok = strtok(path, ":");
|
||||
while (tok) {
|
||||
char* bin_path;
|
||||
asprintf(&bin_path, "%s/%s", tok, for_binary);
|
||||
if (!bin_path) {
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct stat stat_buf;
|
||||
if (stat(bin_path, &stat_buf) == 0 && access(bin_path, X_OK) == 0) {
|
||||
free(path);
|
||||
return bin_path;
|
||||
}
|
||||
|
||||
free(bin_path);
|
||||
tok = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This is present in glibc ONLY with GNU extensions, this aims to provide a
|
||||
// musl compatible variant.
|
||||
//
|
||||
// Respects errno of exec functions family.
|
||||
int execvpe(const char* NNULLABLE file, char* NULLABLE const argv[NNULLABLE],
|
||||
char* NULLABLE const envp[NNULLABLE]) {
|
||||
char* path = search_path(file);
|
||||
if (!path) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
int ret = execve(path, argv, envp);
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#include "util/utf8.h"
|
||||
|
||||
#define UTF8_CONT_MSK 0b11000000
|
||||
#define UTF8_CONT_VAL 0b10000000
|
||||
bool utf8_iscont(char byte) {
|
||||
return (byte & UTF8_CONT_MSK) == UTF8_CONT_VAL;
|
||||
}
|
||||
|
||||
size_t utf8len(const char* str) {
|
||||
size_t len = 0;
|
||||
while (*str != '\0') {
|
||||
if (!utf8_iscont(*(str++))) len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t utf8len_until(const char* str, const char* until) {
|
||||
size_t len = 0;
|
||||
while (str < until) {
|
||||
if (!utf8_iscont(*(str++))) len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t utf8trunc(char* str, size_t n) {
|
||||
size_t bytes = 0;
|
||||
while (true) {
|
||||
if (str[bytes] == '\0') break;
|
||||
if (utf8_iscont(str[bytes])) {
|
||||
bytes++;
|
||||
continue;
|
||||
}
|
||||
if (n == 0) {
|
||||
str[bytes] = '\0';
|
||||
break;
|
||||
}
|
||||
bytes++;
|
||||
n--;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const char* utf8back(const char* str) {
|
||||
while (utf8_iscont(*(--str))) {
|
||||
}
|
||||
return str;
|
||||
}
|
||||
const char* utf8seek(const char* str) {
|
||||
while (utf8_iscont(*(++str))) {
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
const char* utf8seekn(const char* str, size_t n) {
|
||||
while (n > 0 && *str != '\0') {
|
||||
str = utf8seek(str);
|
||||
n--;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util/vec.h"
|
||||
|
||||
const struct Vector VEC_NEW = {
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
.pages = NULL,
|
||||
};
|
||||
|
||||
struct Vector vec_from_raw(void** raw) {
|
||||
size_t len = 0;
|
||||
while (raw[len])
|
||||
len++;
|
||||
|
||||
return (struct Vector){
|
||||
.length = len,
|
||||
.capacity = len,
|
||||
.pages = raw,
|
||||
};
|
||||
}
|
||||
|
||||
void** vec_as_raw(struct Vector self) {
|
||||
if (vec_push(&self, NULL) != 0) return NULL;
|
||||
return self.pages;
|
||||
}
|
||||
|
||||
int vec_resize(struct Vector* self, size_t size) {
|
||||
void** new_location =
|
||||
(void**)realloc((void*)self->pages, size * sizeof(void*));
|
||||
if (new_location != NULL) {
|
||||
if (self->length > size) self->length = size;
|
||||
self->capacity = size;
|
||||
self->pages = new_location;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vec_reserve(struct Vector* self, size_t size) {
|
||||
uint32_t new_capacity = self->capacity;
|
||||
while (self->length + size > new_capacity) {
|
||||
new_capacity = new_capacity + (new_capacity >> 1) +
|
||||
1; // cap * 1.5 + 1; 0 1 2 4 7 11...
|
||||
}
|
||||
return vec_resize(self, new_capacity);
|
||||
}
|
||||
|
||||
int vec_reserve_exact(struct Vector* self, size_t size) {
|
||||
uint32_t needed_capacity = self->length + size;
|
||||
if (self->capacity < needed_capacity) {
|
||||
return vec_resize(self, needed_capacity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vec_push(struct Vector* self, void* item) {
|
||||
int res_ret = vec_reserve(self, 1);
|
||||
if (res_ret != 0) return res_ret;
|
||||
|
||||
self->pages[self->length++] = item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vec_free(struct Vector* self) {
|
||||
while (self->length > 0)
|
||||
free(self->pages[--self->length]);
|
||||
|
||||
vec_clear(self);
|
||||
}
|
||||
|
||||
void vec_clear(struct Vector* self) {
|
||||
free((void*)self->pages);
|
||||
vec_reset(self);
|
||||
}
|
||||
|
||||
void vec_reset(struct Vector* self) {
|
||||
*self = (struct Vector){
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
.pages = NULL,
|
||||
};
|
||||
}
|
||||
|
||||
void* vec_pop(struct Vector* self) {
|
||||
if (self->length == 0) return NULL;
|
||||
|
||||
return self->pages[--self->length];
|
||||
}
|
||||
|
||||
void* vec_get(struct Vector* self, size_t index) {
|
||||
if (index >= self->length) return NULL;
|
||||
|
||||
return self->pages[index];
|
||||
}
|
||||
@@ -1,21 +1,5 @@
|
||||
# Themes
|
||||
|
||||
## catppuccin-frappe.ini
|
||||
|
||||

|
||||
|
||||
## catppuccin-latte.ini
|
||||
|
||||

|
||||
|
||||
## catppuccin-macchiato.ini
|
||||
|
||||

|
||||
|
||||
## catppuccin-mocha.ini
|
||||
|
||||

|
||||
|
||||
## cherry.ini
|
||||
|
||||

|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
##############################################
|
||||
# #
|
||||
# Catppuccin Theme #
|
||||
# #
|
||||
##############################################
|
||||
|
||||
# Catppuccin Frappé
|
||||
# This theme was created by: Catppuccin Org! <3
|
||||
|
||||
[colors]
|
||||
bg = "23;24;25;48;2;48;52;70"
|
||||
fg = "22;23;24;25;29;38;2;198;208;245"
|
||||
err = "1;4;23;24;25;38;2;231;130;132"
|
||||
s_wayland = "3;22;24;25;38;2;202;158;230"
|
||||
s_xorg = "3;22;24;25;38;2;202;158;230"
|
||||
s_shell = "3;22;24;25;38;2;244;184;228"
|
||||
e_hostname = "1;3;24;25;29;38;2;242;213;207"
|
||||
e_date = "3;22;24;25;29;38;2;165;173;206"
|
||||
e_box = "1;23;24;25;29;38;2;115;121;148"
|
||||
e_header = "1;3;24;25;29;38;2;239;159;118"
|
||||
e_user = "3;22;24;25;29;38;2;140;170;238"
|
||||
e_passwd = "1;23;24;25;29;38;2;166;209;137"
|
||||
e_badpasswd = "1;9;23;24;25;38;2;231;130;132"
|
||||
e_key = "22;23;24;25;38;2;129;200;190"
|
||||
@@ -1,24 +0,0 @@
|
||||
##############################################
|
||||
# #
|
||||
# Catppuccin Theme #
|
||||
# #
|
||||
##############################################
|
||||
|
||||
# Catppuccin Latte
|
||||
# This theme was created by: Catppuccin Org! <3
|
||||
|
||||
[colors]
|
||||
bg = "23;24;25;48;2;239;241;245"
|
||||
fg = "22;23;24;25;29;38;2;76;79;105"
|
||||
err = "1;4;23;24;25;38;2;210;15;57"
|
||||
s_wayland = "3;22;24;25;38;2;136;57;239"
|
||||
s_xorg = "3;22;24;25;38;2;136;57;239"
|
||||
s_shell = "3;22;24;25;38;2;234;118;203"
|
||||
e_hostname = "1;3;24;25;29;38;2;220;138;120"
|
||||
e_date = "3;22;24;25;29;38;2;108;111;133"
|
||||
e_box = "1;23;24;25;29;38;2;156;160;176"
|
||||
e_header = "1;3;24;25;29;38;2;254;100;11"
|
||||
e_user = "3;22;24;25;29;38;2;30;102;245"
|
||||
e_passwd = "1;23;24;25;29;38;2;64;160;43"
|
||||
e_badpasswd = "1;9;23;24;25;38;2;210;15;57"
|
||||
e_key = "22;23;24;25;38;2;23;146;153"
|
||||
@@ -1,24 +0,0 @@
|
||||
##############################################
|
||||
# #
|
||||
# Catppuccin Theme #
|
||||
# #
|
||||
##############################################
|
||||
|
||||
# Catppuccin Macchiato
|
||||
# This theme was created by: Catppuccin Org! <3
|
||||
|
||||
[colors]
|
||||
bg = "23;24;25;48;2;36;39;58"
|
||||
fg = "22;23;24;25;29;38;2;202;211;245"
|
||||
err = "1;4;23;24;25;38;2;237;135;150"
|
||||
s_wayland = "3;22;24;25;38;2;198;160;246"
|
||||
s_xorg = "3;22;24;25;38;2;198;160;246"
|
||||
s_shell = "3;22;24;25;38;2;245;189;230"
|
||||
e_hostname = "1;3;24;25;29;38;2;244;219;214"
|
||||
e_date = "3;22;24;25;29;38;2;165;173;203"
|
||||
e_box = "1;23;24;25;29;38;2;110;115;141"
|
||||
e_header = "1;3;24;25;29;38;2;245;169;127"
|
||||
e_user = "3;22;24;25;29;38;2;138;173;244"
|
||||
e_passwd = "1;23;24;25;29;38;2;166;218;149"
|
||||
e_badpasswd = "1;9;23;24;25;38;2;237;135;150"
|
||||
e_key = "22;23;24;25;38;2;139;213;202"
|
||||
@@ -1,24 +0,0 @@
|
||||
##############################################
|
||||
# #
|
||||
# Catppuccin Theme #
|
||||
# #
|
||||
##############################################
|
||||
|
||||
# Catppuccin Mocha
|
||||
# This theme was created by: Catppuccin Org! <3
|
||||
|
||||
[colors]
|
||||
bg = "23;24;25;48;2;30;30;46"
|
||||
fg = "22;23;24;25;29;38;2;205;214;244"
|
||||
err = "1;4;23;24;25;38;2;243;139;168"
|
||||
s_wayland = "3;22;24;25;38;2;203;166;247"
|
||||
s_xorg = "3;22;24;25;38;2;203;166;247"
|
||||
s_shell = "3;22;24;25;38;2;245;194;231"
|
||||
e_hostname = "1;3;24;25;29;38;2;245;224;220"
|
||||
e_date = "3;22;24;25;29;38;2;166;173;200"
|
||||
e_box = "1;23;24;25;29;38;2;108;112;134"
|
||||
e_header = "1;3;24;25;29;38;2;250;179;135"
|
||||
e_user = "3;22;24;25;29;38;2;137;180;250"
|
||||
e_passwd = "1;23;24;25;29;38;2;166;227;161"
|
||||
e_badpasswd = "1;9;23;24;25;38;2;243;139;168"
|
||||
e_key = "22;23;24;25;38;2;148;226;213"
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
whiskers:
|
||||
version: ^2.5.1
|
||||
matrix:
|
||||
- flavor
|
||||
filename: catppuccin-{{ flavor.identifier }}.ini
|
||||
---
|
||||
{%- macro rgb(col) -%}
|
||||
2;{{ col.rgb.r }};{{ col.rgb.g }};{{ col.rgb.b }}
|
||||
{%- endmacro rgb -%}
|
||||
|
||||
##############################################
|
||||
# #
|
||||
# Catppuccin Theme #
|
||||
# #
|
||||
##############################################
|
||||
|
||||
# Catppuccin {{flavor.name}}
|
||||
# This theme was created by: Catppuccin Org! <3
|
||||
|
||||
[colors]
|
||||
bg = "23;24;25;48;{{ self::rgb(col=base) }}"
|
||||
fg = "22;23;24;25;29;38;{{ self::rgb(col=text) }}"
|
||||
err = "1;4;23;24;25;38;{{ self::rgb(col=red) }}"
|
||||
s_wayland = "3;22;24;25;38;{{ self::rgb(col=mauve) }}"
|
||||
s_xorg = "3;22;24;25;38;{{ self::rgb(col=mauve) }}"
|
||||
s_shell = "3;22;24;25;38;{{ self::rgb(col=pink) }}"
|
||||
e_hostname = "1;3;24;25;29;38;{{ self::rgb(col=rosewater) }}"
|
||||
e_date = "3;22;24;25;29;38;{{ self::rgb(col=subtext0) }}"
|
||||
e_box = "1;23;24;25;29;38;{{ self::rgb(col=overlay0) }}"
|
||||
e_header = "1;3;24;25;29;38;{{ self::rgb(col=peach) }}"
|
||||
e_user = "3;22;24;25;29;38;{{ self::rgb(col=blue) }}"
|
||||
e_passwd = "1;23;24;25;29;38;{{ self::rgb(col=green) }}"
|
||||
e_badpasswd = "1;9;23;24;25;38;{{ self::rgb(col=red) }}"
|
||||
e_key = "22;23;24;25;38;{{ self::rgb(col=teal) }}"
|
||||
@@ -25,13 +25,11 @@
|
||||
[functions]
|
||||
# poweroff = F1
|
||||
# reboot = F2
|
||||
# fido = NONE
|
||||
# refresh = F5
|
||||
|
||||
[strings]
|
||||
# f_poweroff = "poweroff"
|
||||
# f_reboot = "reboot"
|
||||
# f_fido = "fido"
|
||||
# f_refresh = "refresh"
|
||||
# e_user = "user"
|
||||
# e_passwd = "password"
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0704a1aadffee71bc0753c861d8ac8b8588aae76ad8cdcb4f2c2700b98ec095c
|
||||
size 23814
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:58d56d6e16e14f0eddaa8a11e8bf238f2056e784b9c7c46d88aa8ff2d948355e
|
||||
size 23110
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:225dba8cf87de1ae7118bfd98a1966fdb92cc826418dd9ef7dda5ee77ae8d0f3
|
||||
size 23886
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0c8269cc55fdc26bfff240b3dccd94ffab6400b33c049af23912b74a62247943
|
||||
size 23826
|
||||
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 15 KiB |