├── tests ├── 05-cmdline-help.expected.0 ├── 21-beep-device-dev-console.expected.1 ├── 30-beep-device-dev-tty0.expected.1 ├── 31-beep-device-dev-tty4.expected.1 ├── 33-beep-device-dev-tty63.expected.1 ├── 00-nothing.expected.0 ├── 00-nothing.sh ├── 05-cmdline-version.expected.0 ├── 10-beep-default.sh ├── 11-beep-f-880Hz.sh ├── 60-beep-from-stdin.expected.0 ├── 61-beep-from-stdin.expected.0 ├── 62-beep-from-stdin.expected.0 ├── 63-beep-from-stdin.expected.0 ├── 20-beep-default.sh ├── 50-long-len-and-signal-SIGINT.expected.0 ├── 50-long-len-and-signal-SIGTERM.expected.0 ├── 51-long-delay-and-signal-SIGINT.expected.0 ├── 03-cmdline-unhandled-option.expected.0 ├── 01-nothing.sh ├── 02-second-device-name.sh ├── 30-beep-device-dev-tty0.sh ├── 31-beep-device-dev-tty4.sh ├── 33-beep-device-dev-tty63.sh ├── 34-beep-device-dev-ttyXX.sh ├── 35-beep-device-dev-tty99.sh ├── 36-beep-device-dev-ttyX.sh ├── 37-beep-device-dev-ttyS1.sh ├── 38-beep-device-dev-tty999.sh ├── 40-beep-device-dev-vc-0.sh ├── 02-second-device-name.expected.0 ├── 21-beep-device-dev-console.sh ├── 31-beep-device-dev-tty4.expected.0 ├── 20-beep-device-dev-evdev-pcspkr.sh ├── 30-beep-device-dev-tty0.expected.0 ├── 31-beep-device-dev-tty4.expected.2 ├── 33-beep-device-dev-tty63.expected.0 ├── 37-beep-device-dev-ttyS1.expected.0 ├── 37-beep-device-dev-ttyS1.expected.1 ├── 21-beep-device-dev-console.expected.0 ├── 31-beep-device-dev-tty4.expected.3 ├── 36-beep-device-dev-ttyX.expected.0 ├── 40-beep-device-dev-vc-0.expected.0 ├── 34-beep-device-dev-ttyXX.expected.0 ├── 35-beep-device-dev-tty99.expected.0 ├── 38-beep-device-dev-tty999.expected.0 ├── 03-cmdline-unhandled-option.sh ├── 05-cmdline-help.bash ├── 05-cmdline-version.bash ├── 04-cmdline-unhandled-non-option.sh ├── 60-beep-from-stdin.sh ├── 61-beep-from-stdin.sh ├── 62-beep-from-stdin.sh ├── 63-beep-from-stdin.sh ├── 11-beep-default-logs.sh ├── 50-long-len-and-signal-SIGINT.sh ├── 50-long-len-and-signal-SIGTERM.sh ├── 51-long-delay-and-signal-SIGINT.sh ├── 11-beep-default-logs.expected.1 ├── 11-beep-default-logs.expected.0 ├── README.md └── run-tests ├── contrib ├── failure-beeps ├── success-beeps ├── status-beeps └── morse │ ├── morse2beep.sed │ └── morse2beep.pl ├── conftest-program.c ├── .github └── workflows │ ├── beep-build.yml │ └── codeql.yml ├── .gitignore ├── beep-usage.h ├── testbuild-all ├── beep-types.h ├── gen-freq-table ├── beep-usage.txt.in ├── beep-library.h ├── beep-config.h.in ├── beep-compiler.h ├── beep-driver-noop.c ├── beep-drivers.h ├── beep-drivers.c ├── beep-log.h ├── CREDITS.md ├── beep-driver.h ├── beep-library.c ├── beep-log.c ├── beep-driver-evdev.c ├── beep-driver-console.c ├── INSTALL.md ├── DEVELOPMENT.md ├── pandoc.css ├── NEWS.md ├── README.md ├── PERMISSIONS.md ├── PACKAGING.md ├── beep.1.in ├── COPYING ├── beep-main.c └── GNUmakefile /tests/05-cmdline-help.expected.0: -------------------------------------------------------------------------------- 1 | Usage: 2 | -------------------------------------------------------------------------------- /tests/21-beep-device-dev-console.expected.1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/30-beep-device-dev-tty0.expected.1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/31-beep-device-dev-tty4.expected.1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/33-beep-device-dev-tty63.expected.1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/00-nothing.expected.0: -------------------------------------------------------------------------------- 1 | BEEP=BEEP_EXECUTABLE 2 | -------------------------------------------------------------------------------- /tests/00-nothing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "BEEP=${BEEP}" 4 | -------------------------------------------------------------------------------- /tests/05-cmdline-version.expected.0: -------------------------------------------------------------------------------- 1 | beep PACKAGE_VERSION 2 | -------------------------------------------------------------------------------- /tests/10-beep-default.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | ${BEEP} 3 | -------------------------------------------------------------------------------- /tests/11-beep-f-880Hz.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | ${BEEP} -f 880 3 | -------------------------------------------------------------------------------- /tests/60-beep-from-stdin.expected.0: -------------------------------------------------------------------------------- 1 | moo 2 | foo 3 | erk 4 | bla 5 | -------------------------------------------------------------------------------- /tests/61-beep-from-stdin.expected.0: -------------------------------------------------------------------------------- 1 | moo 2 | foo 3 | erk 4 | bla 5 | -------------------------------------------------------------------------------- /tests/62-beep-from-stdin.expected.0: -------------------------------------------------------------------------------- 1 | moo 2 | foo 3 | erk 4 | bla 5 | -------------------------------------------------------------------------------- /tests/63-beep-from-stdin.expected.0: -------------------------------------------------------------------------------- 1 | moo 2 | foo 3 | erk 4 | bla 5 | -------------------------------------------------------------------------------- /tests/20-beep-default.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | ${BEEP} -f "$FREQ" 3 | -------------------------------------------------------------------------------- /tests/50-long-len-and-signal-SIGINT.expected.0: -------------------------------------------------------------------------------- 1 | Signal has aborted beep: 1 2 | -------------------------------------------------------------------------------- /tests/50-long-len-and-signal-SIGTERM.expected.0: -------------------------------------------------------------------------------- 1 | Signal has aborted beep: 1 2 | -------------------------------------------------------------------------------- /tests/51-long-delay-and-signal-SIGINT.expected.0: -------------------------------------------------------------------------------- 1 | Signal has aborted beep: 1 2 | -------------------------------------------------------------------------------- /tests/03-cmdline-unhandled-option.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: unrecognized option '--blubb' 2 | Error: Good. 3 | -------------------------------------------------------------------------------- /tests/01-nothing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # If we produce this output, this test will fail 3 | 4 | : echo "BEEP=${BEEP}" 5 | -------------------------------------------------------------------------------- /tests/02-second-device-name.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -e /dev/tty0 -e /dev/tty1; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/30-beep-device-dev-tty0.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/tty0; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/31-beep-device-dev-tty4.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/tty4; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/33-beep-device-dev-tty63.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/tty63; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/34-beep-device-dev-ttyXX.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/ttyXX; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/35-beep-device-dev-tty99.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/tty99; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/36-beep-device-dev-ttyX.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/ttyX; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/37-beep-device-dev-ttyS1.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/ttyS1; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/38-beep-device-dev-tty999.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/tty999; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/40-beep-device-dev-vc-0.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/vc/0; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/02-second-device-name.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: You cannot give the --device parameter more than once. 2 | Error 3 | -------------------------------------------------------------------------------- /tests/21-beep-device-dev-console.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} -f "$FREQ" -e /dev/console; then 2 | : 3 | else 4 | echo "Error" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/31-beep-device-dev-tty4.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: console device '/dev/tty4' does not support either API 2 | Error 3 | -------------------------------------------------------------------------------- /tests/20-beep-device-dev-evdev-pcspkr.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | ${BEEP} -f "$FREQ" -e /dev/input/by-path/platform-pcspkr-event-spkr 3 | -------------------------------------------------------------------------------- /tests/30-beep-device-dev-tty0.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/tty0 for writing: Permission denied 2 | Error 3 | -------------------------------------------------------------------------------- /tests/31-beep-device-dev-tty4.expected.2: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/tty4 for writing: Permission denied 2 | Error 3 | -------------------------------------------------------------------------------- /tests/33-beep-device-dev-tty63.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/tty63 for writing: Permission denied 2 | Error 3 | -------------------------------------------------------------------------------- /tests/37-beep-device-dev-ttyS1.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/ttyS1 for writing: Permission denied 2 | Error 3 | -------------------------------------------------------------------------------- /tests/37-beep-device-dev-ttyS1.expected.1: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/ttyS1 for writing: Input/output error 2 | Error 3 | -------------------------------------------------------------------------------- /tests/21-beep-device-dev-console.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/console for writing: Permission denied 2 | Error 3 | -------------------------------------------------------------------------------- /tests/31-beep-device-dev-tty4.expected.3: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/tty4 for writing: Operation not permitted 2 | Error 3 | -------------------------------------------------------------------------------- /tests/36-beep-device-dev-ttyX.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/ttyX for writing: No such file or directory 2 | Error 3 | -------------------------------------------------------------------------------- /tests/40-beep-device-dev-vc-0.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/vc/0 for writing: No such file or directory 2 | Error 3 | -------------------------------------------------------------------------------- /contrib/failure-beeps: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # failing sounding A minor-whatever arpeggio 3 | beep -f 880 -l 200 -n -f 659 -n -f 523 -n -f 370 -l 400 4 | -------------------------------------------------------------------------------- /tests/34-beep-device-dev-ttyXX.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/ttyXX for writing: No such file or directory 2 | Error 3 | -------------------------------------------------------------------------------- /tests/35-beep-device-dev-tty99.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/tty99 for writing: No such file or directory 2 | Error 3 | -------------------------------------------------------------------------------- /tests/38-beep-device-dev-tty999.expected.0: -------------------------------------------------------------------------------- 1 | BEEP_EXECUTABLE: Error: Could not open /dev/tty999 for writing: No such file or directory 2 | Error 3 | -------------------------------------------------------------------------------- /tests/03-cmdline-unhandled-option.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} --blubb > /dev/null; then 2 | echo "beep should not have succeeded" 3 | else 4 | echo "Error: Good." 5 | fi 6 | -------------------------------------------------------------------------------- /tests/05-cmdline-help.bash: -------------------------------------------------------------------------------- 1 | ${BEEP} --help | sed 1q 2 | if test "x${PIPESTATUS[*]}" = "x0 0"; then 3 | : 4 | else 5 | echo "Error exit, should not happen" 6 | fi 7 | -------------------------------------------------------------------------------- /tests/05-cmdline-version.bash: -------------------------------------------------------------------------------- 1 | ${BEEP} --version | sed 1q 2 | if test "x${PIPESTATUS[*]}" = "x0 0"; then 3 | : 4 | else 5 | echo "Error exit, should not happen" 6 | fi 7 | -------------------------------------------------------------------------------- /contrib/success-beeps: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # successfully sounding A major arpeggio 3 | beep -f 220 -l 100 -n -f 275 -l 100 -n -f 330 -l 100 -n -f 440 -l 100 -n -f 550 -l 100 -n -f 660 -l 100 -n -f 880 4 | -------------------------------------------------------------------------------- /tests/04-cmdline-unhandled-non-option.sh: -------------------------------------------------------------------------------- 1 | if ${BEEP} blubb > /dev/null; then 2 | echo "beep should have exited with non-0, but exited with 0" 3 | else 4 | : "The unhandled non-option argument has been detected" 5 | fi 6 | -------------------------------------------------------------------------------- /tests/60-beep-from-stdin.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | 3 | if (sleep 2; echo moo; sleep 2; echo foo; sleep 1; echo erk; sleep 1; echo bla) | ${BEEP} -s -f 880 -n -f 440 -n -f 659; then 4 | : 5 | else 6 | echo "Error" 7 | fi 8 | -------------------------------------------------------------------------------- /tests/61-beep-from-stdin.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | 3 | if (sleep 2; echo moo; sleep 2; echo foo; sleep 1; echo erk; sleep 1; echo bla) | ${BEEP} -f 880 -n -f 440 -s -n -f 659; then 4 | : 5 | else 6 | echo "Error" 7 | fi 8 | -------------------------------------------------------------------------------- /tests/62-beep-from-stdin.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | 3 | if (sleep 2; echo moo; sleep 2; echo foo; sleep 1; echo erk; sleep 1; echo bla) | ${BEEP} -f 880 -n -f 440 -n -f 659 -s ; then 4 | : 5 | else 6 | echo "Error" 7 | fi 8 | -------------------------------------------------------------------------------- /tests/63-beep-from-stdin.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | 3 | if (sleep 2; echo moo; sleep 2; echo foo; sleep 1; echo erk; sleep 1; echo bla) | ${BEEP} -s -f 880 -n -f 440 -n -f 659 -s ; then 4 | : 5 | else 6 | echo "Error" 7 | fi 8 | -------------------------------------------------------------------------------- /conftest-program.c: -------------------------------------------------------------------------------- 1 | /** \file conftest-program.c 2 | * \brief Simple program for test compilations to check for build flags 3 | */ 4 | 5 | #include 6 | 7 | int main(void) 8 | { 9 | printf("Test program\n"); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /contrib/status-beeps: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run command and depending on its exit code, produce success or failure beeps 3 | 4 | d="$(cd "$(dirname "$0")" && pwd)" 5 | 6 | if "$@"; then 7 | "$d/success-beeps" 8 | else 9 | "$d/failure-beeps" 10 | fi 11 | -------------------------------------------------------------------------------- /tests/11-beep-default-logs.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | env BEEP_LOG_LEVEL=999 ${BEEP} 2>&1 | awk '/ as fd=[1-9][0-9]*/ { fds[$7]=fd_idx++; } /beep_drivers_register/ { drivers[$5]=drv_idx++; } { for (drv in drivers) { gsub(drv, ""); }; for (fd in fds) { gsub(fd, "fd="); }; print; } BEGIN { driver="xyzxyzxyzxyz"; }' 3 | -------------------------------------------------------------------------------- /tests/50-long-len-and-signal-SIGINT.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | 3 | ts_begin="$(date +%s)" 4 | 5 | ${BEEP} -f "$FREQ" -l 10000 & 6 | pid="$!" 7 | 8 | sleep 0.2 9 | kill -s INT "$pid" 10 | 11 | wait "$pid" 12 | retcode="$?" 13 | 14 | ts_end="$(date +%s)" 15 | ts_delta="$(expr "$ts_end" - "$ts_begin")" 16 | # echo "ts_delta=$ts_delta" 17 | 18 | if test "$ts_delta" -le 2; then 19 | echo "Signal has aborted beep: ${retcode}" 20 | else 21 | echo "Signal has apparently NOT aborted beep: ${retcode}" 22 | fi 23 | -------------------------------------------------------------------------------- /tests/50-long-len-and-signal-SIGTERM.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | 3 | ts_begin="$(date +%s)" 4 | 5 | ${BEEP} -f "$FREQ" -l 10000 & 6 | pid="$!" 7 | 8 | sleep 0.2 9 | kill -s TERM "$pid" 10 | 11 | wait "$pid" 12 | retcode="$?" 13 | 14 | ts_end="$(date +%s)" 15 | ts_delta="$(expr "$ts_end" - "$ts_begin")" 16 | # echo "ts_delta=$ts_delta" 17 | 18 | if test "$ts_delta" -le 2; then 19 | echo "Signal has aborted beep: ${retcode}" 20 | else 21 | echo "Signal has apparently NOT aborted beep: ${retcode}" 22 | fi 23 | -------------------------------------------------------------------------------- /tests/51-long-delay-and-signal-SIGINT.sh: -------------------------------------------------------------------------------- 1 | : REQUIRES_HARDWARE 2 | 3 | ts_begin="$(date +%s)" 4 | 5 | ${BEEP} -f "$FREQ" -D 10000 & 6 | pid="$!" 7 | 8 | sleep 0.2 9 | kill -s INT "$pid" 10 | 11 | wait "$pid" 12 | retcode="$?" 13 | 14 | ts_end="$(date +%s)" 15 | ts_delta="$(expr "$ts_end" - "$ts_begin")" 16 | # echo "ts_delta=$ts_delta" 17 | 18 | if test "$ts_delta" -le 2; then 19 | echo "Signal has aborted beep: ${retcode}" 20 | else 21 | echo "Signal has apparently NOT aborted beep: ${retcode}" 22 | fi 23 | -------------------------------------------------------------------------------- /.github/workflows/beep-build.yml: -------------------------------------------------------------------------------- 1 | name: beep build CI 2 | 3 | on: 4 | push: 5 | branches: [ main, master ] 6 | pull_request: 7 | branches: [ main, master ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | with: 20 | fetch-depth: 0 21 | - name: create local.mk 22 | run: | 23 | echo "prefix = ${PWD}/_root" > local.mk 24 | - name: make 25 | run: make 26 | - name: 'beep --help' 27 | run: | 28 | ./beep --help > beep-usage.from--help 29 | diff -u beep-usage.txt beep-usage.from--help 30 | - name: 'make check' 31 | run: make check 32 | - name: 'make install-nobuild' 33 | run: make install-nobuild 34 | - name: 'list installed files' 35 | run: (cd "$PWD/_root" && ls -l $(find . -type f | env LC_ALL=C sort) | nl) 36 | -------------------------------------------------------------------------------- /tests/11-beep-default-logs.expected.1: -------------------------------------------------------------------------------- 1 | beep-log: Verbose: log: log_constructor 2 | beep-log: Verbose: console: beep_driver_console_constructor 3 | beep-log: Verbose: drivers: beep_drivers_register (console) 4 | beep-log: Verbose: evdev: beep_driver_evdev_constructor 5 | beep-log: Verbose: drivers: beep_drivers_register (evdev) 6 | BEEP_EXECUTABLE: Verbose: evdev: driver_detect (nil) 7 | BEEP_EXECUTABLE: Verbose: lib: opened /dev/input/by-path/platform-pcspkr-event-spkr as fd= 8 | BEEP_EXECUTABLE: Verbose: main: using evdev driver (fd=, dev=/dev/input/by-path/platform-pcspkr-event-spkr) 9 | BEEP_EXECUTABLE: Verbose: main: 1 times 200 ms beeps (100 ms delay between, 0 ms delay after) @ 440 Hz 10 | BEEP_EXECUTABLE: Verbose: evdev: driver_begin_tone 440 11 | BEEP_EXECUTABLE: Verbose: evdev: driver_end_tone 12 | BEEP_EXECUTABLE: Verbose: evdev: driver_end_tone 13 | BEEP_EXECUTABLE: Verbose: evdev: driver_fini 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files that should not be tracked by Git 2 | 3 | # The compiled executables 4 | /beep 5 | /*.clang 6 | /*.gcc 7 | /*.map 8 | /issue-6-benchmark 9 | 10 | # Built sources 11 | /beep-config.h 12 | /beep-usage.c 13 | /beep-usage.txt 14 | 15 | # Build intermediates 16 | *.dep 17 | *.tmp 18 | *.clang-o 19 | *.gcc-o 20 | *.o 21 | *.i 22 | *.s 23 | *.bc 24 | *.lst 25 | *.gcc-lst 26 | /beep.1 27 | 28 | # The compressed man page 29 | /beep.1.gz 30 | 31 | # Built stuff 32 | /dox/ 33 | /html/ 34 | /*.html 35 | /__tmp/ 36 | /tarball-dist/ 37 | /tarball-git-dist/ 38 | /beep-*.tar.gz 39 | /beep-*.tar.xz 40 | 41 | # Test results 42 | /tests/*.actual.output.new 43 | /tests/*.actual.output 44 | /tests/*.output.actual.new 45 | /tests/*.output.actual 46 | /tests/*.actual.new 47 | /tests/*.actual 48 | /tests/*.output.new 49 | /tests/*.output 50 | 51 | # Misc results 52 | *.strace 53 | /Doxyfile 54 | /doxygen.stamp 55 | 56 | # Test builds 57 | /_build-*/ 58 | /_prefix-*/ 59 | -------------------------------------------------------------------------------- /tests/11-beep-default-logs.expected.0: -------------------------------------------------------------------------------- 1 | beep-log: Verbose: log: log_constructor 2 | beep-log: Verbose: console: beep_driver_console_constructor 3 | beep-log: Verbose: drivers: beep_drivers_register (console) 4 | beep-log: Verbose: evdev: beep_driver_evdev_constructor 5 | beep-log: Verbose: drivers: beep_drivers_register (evdev) 6 | beep-log: Verbose: noop: beep_driver_noop_constructor 7 | beep-log: Verbose: drivers: beep_drivers_register (noop) 8 | BEEP_EXECUTABLE: Verbose: noop: driver_detect (nil) 9 | BEEP_EXECUTABLE: Verbose: evdev: driver_detect (nil) 10 | BEEP_EXECUTABLE: Verbose: lib: opened /dev/input/by-path/platform-pcspkr-event-spkr as fd= 11 | BEEP_EXECUTABLE: Verbose: main: using evdev driver (fd=, dev=/dev/input/by-path/platform-pcspkr-event-spkr) 12 | BEEP_EXECUTABLE: Verbose: main: 1 times 200 ms beeps (100 ms delay between, 0 ms delay after) @ 440 Hz 13 | BEEP_EXECUTABLE: Verbose: evdev: driver_begin_tone 440 14 | BEEP_EXECUTABLE: Verbose: evdev: driver_end_tone 15 | BEEP_EXECUTABLE: Verbose: evdev: driver_end_tone 16 | BEEP_EXECUTABLE: Verbose: evdev: driver_fini 17 | -------------------------------------------------------------------------------- /contrib/morse/morse2beep.sed: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sed -f 2 | # Turn Morse code into beeps. 3 | # 4 | # Copyright 2020 Hans Ulrich Niedermann 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License along 17 | # with this program; if not, write to the Free Software Foundation, Inc., 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | # 20 | # Usage: 21 | # cat text-file.txt | morse | tr '\n' '\r' | sed -f morse2beep.sed | xargs beep 22 | # 23 | # Written as a replacement for Dan Jacobson's morse2beep.pl perl script 24 | # for systems without a perl interpreter. 25 | # 26 | # Note that this does NOT strip the trailing End Of Work (...-.-) symbol. 27 | # 28 | i -l0 -D0 29 | s/ daw\r\r/-n -l300 -D700 /g 30 | s/ dit\r\r/-n -l100 -D700 /g 31 | s/ daw\r/-n -l300 -D300 /g 32 | s/ dit\r/-n -l100 -D300 /g 33 | s/ daw/-n -l300 -D100 /g 34 | s/ dit/-n -l100 -D100 /g 35 | -------------------------------------------------------------------------------- /beep-usage.h: -------------------------------------------------------------------------------- 1 | /** \file beep-usage.h 2 | * \brief interface to beep usage message string 3 | * \author Copyright (C) 2018-2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \defgroup beep_usage beep(1) usage message 21 | * 22 | * @{ 23 | * 24 | */ 25 | 26 | #ifndef BEEP_USAGE_H 27 | #define BEEP_USAGE_H 28 | 29 | 30 | /** Multi-line zero-terminated string containing the usage text for 31 | * beep(1), as is contained in the beep-usage.txt text file. 32 | */ 33 | extern char beep_usage[]; 34 | 35 | 36 | #endif /* !defined(BEEP_USAGE_H) */ 37 | 38 | 39 | /** @} */ 40 | 41 | 42 | /* 43 | * Local Variables: 44 | * c-basic-offset: 4 45 | * indent-tabs-mode: nil 46 | * End: 47 | */ 48 | -------------------------------------------------------------------------------- /testbuild-all: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd "$(dirname "$0")" 4 | 5 | export LC_ALL=C 6 | 7 | set -ex 8 | 9 | # We need to remove the built files from the $(srcdir) in order to 10 | # make the VPATH search work properly for the test builds. 11 | make clean 12 | 13 | while read id cc cflags 14 | do 15 | abs_top_srcdir="$PWD" 16 | builddir="$PWD/_build-$id" 17 | prefix="$PWD/_prefix-$id" 18 | rm -rf "$builddir" "$prefix" 19 | ( 20 | mkdir "$builddir" 21 | cd "$builddir" 22 | srcdir="${abs_top_srcdir}" 23 | cat>local.mk< after-installation.txt 41 | nl after-installation.txt 42 | if test -s after-installation.txt; then 43 | : 44 | else 45 | echo "Error: After installation, there should be files installed." 46 | exit 1 47 | fi 48 | 49 | run_make uninstall 50 | (cd "$prefix" && find . -type f | sort) > after-uninstall.txt 51 | nl after-uninstall.txt 52 | if test -s after-uninstall.txt; then 53 | echo "Error: After uninstall, there should be no files left." 54 | exit 1 55 | fi 56 | ) 57 | done < DELAY_ms] [-s] [-c] 4 | beep [OPTIONS] [-n|--new TONE_OPTS...] 5 | beep [-h|--help] 6 | beep [-v|-V|--version] 7 | 8 | Beep the PC speaker in a number of ways. 9 | 10 | Options: 11 | Information options: 12 | -h, --help 13 | print this usage information and exit 14 | -V, -v, --version 15 | print program version information and exit 16 | 17 | Global options: 18 | -e, --device=DEVICE 19 | set the device to output the beeps to (see beep(1) man page) 20 | --debug, --verbose 21 | make program output more verbose 22 | 23 | Tone options: 24 | -f FREQ_Hz frequency of the tone in Hertz (Hz) (default: @DEFAULT_FREQ@) 25 | -l LENGTH_ms length of the tone in milliseconds (ms) (default: @DEFAULT_LENGTH@) 26 | -d DELAY_ms delay between repetitions of the tone *without* delay after last 27 | repetition of the tone (default: @DEFAULT_DELAY@) 28 | -D DELAY_ms delay between repetitions of the tone *with* delay after last 29 | repetition of the tone (default: no delay after last note) 30 | -r REPS number of repetitions of the last tone 31 | (default: 1 note without repeats) 32 | 33 | -n, --new start a new tone 34 | 35 | -s read text from stdin and write it through to stdout, 36 | beeping the last defined tone for every newline in the text, 37 | until EOF in stdin 38 | -c like -s, but beep for every character in the text 39 | 40 | Exit status: 41 | 0 if OK 42 | non-0 if any problems occurred 43 | 44 | More documentation is available in the beep(1) man page via: man 1 beep 45 | -------------------------------------------------------------------------------- /beep-library.h: -------------------------------------------------------------------------------- 1 | /** \file beep-library.h 2 | * \brief library of miscellaneous macros and functions 3 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \addtogroup beep_library 21 | * 22 | * @{ 23 | * 24 | */ 25 | 26 | 27 | #ifndef BEEP_LIBRARY_H 28 | #define BEEP_LIBRARY_H 29 | 30 | 31 | /** 32 | * Open the named character device special file. 33 | * 34 | * This makes certain that the returned file descriptor is actually 35 | * for a character device special file. 36 | * 37 | * @param device_name The device name. 38 | */ 39 | int open_checked_char_device(const char *const device_name) 40 | __attribute__(( nonnull(1) )); 41 | 42 | 43 | /** 44 | * Safely exit the program with errno error message. 45 | * 46 | * The "safety" aspect refers to multithreading/signals/etc. 47 | * 48 | * @param msg The message to print before exiting. 49 | */ 50 | void safe_errno_exit(const char *const msg) 51 | __attribute__(( nonnull(1) )) 52 | __attribute__(( noreturn )); 53 | 54 | 55 | #endif /* !defined(BEEP_LIBRARY_H) */ 56 | 57 | 58 | /** @} */ 59 | 60 | 61 | /* 62 | * Local Variables: 63 | * c-basic-offset: 4 64 | * indent-tabs-mode: nil 65 | * End: 66 | */ 67 | -------------------------------------------------------------------------------- /beep-config.h.in: -------------------------------------------------------------------------------- 1 | /** \file beep-config.h 2 | * \brief The default values for beeps. 3 | * 4 | * \author Copyright (C) 2000-2010 Johnathan Nightingale 5 | * \author Copyright (C) 2010-2013 Gerfried Fuchs 6 | * \author Copyright (C) 2013-2018 Hans Ulrich Niedermann 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | */ 23 | 24 | #ifndef BEEP_CONFIG_H 25 | #define BEEP_CONFIG_H 26 | 27 | 28 | #include "beep-types.h" 29 | 30 | 31 | /* Meaningful Defaults */ 32 | 33 | /** Default value: tone pitch Middle A. */ 34 | #define DEFAULT_FREQ @DEFAULT_FREQ@ 35 | 36 | /** Default value: tone length in milliseconds. */ 37 | #define DEFAULT_LENGTH @DEFAULT_LENGTH@ 38 | 39 | /** Default value: one repetition of tone. */ 40 | #define DEFAULT_REPS 1 41 | 42 | /** Default value: delay between repeated tones in milliseconds. */ 43 | #define DEFAULT_DELAY @DEFAULT_DELAY@ 44 | 45 | /** Default value: delay after the last of the tones. */ 46 | #define DEFAULT_END_DELAY END_DELAY_NO 47 | 48 | /** Default value: whether to beep on receiving data on stdin. */ 49 | #define DEFAULT_STDIN_BEEP STDIN_BEEP_NONE 50 | 51 | 52 | #endif /* !defined(BEEP_CONFIG_H) */ 53 | 54 | 55 | /* 56 | * Local Variables: 57 | * c-basic-offset: 4 58 | * indent-tabs-mode: nil 59 | * End: 60 | */ 61 | -------------------------------------------------------------------------------- /beep-compiler.h: -------------------------------------------------------------------------------- 1 | /** \file beep-compiler.h 2 | * \brief compiler convenience definitions 3 | * \author Copyright (C) 2018-2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \defgroup beep_compiler Compiler convenience definitions 21 | * 22 | * @{ 23 | * 24 | */ 25 | 26 | #ifndef BEEP_COMPILER_H 27 | #define BEEP_COMPILER_H 28 | 29 | 30 | /** Mark an unused function parameter. 31 | * 32 | * Usage: 33 | * 34 | * void foo(int unused UNUSED_PARAM) 35 | * { 36 | * ... 37 | * } 38 | */ 39 | #define UNUSED_PARAM __attribute__(( unused )) 40 | 41 | 42 | /** Mark a constructor function to be executed once on program startup. 43 | * 44 | * Usage: 45 | * 46 | * static void foo(void) CONSTRUCTOR_FUNCTION; 47 | * static void foo(void) 48 | * { 49 | * ... 50 | * } 51 | */ 52 | #define CONSTRUCTOR_FUNCTION __attribute__(( constructor )) 53 | 54 | 55 | /** 56 | * Dummy declaration to avoid empty compilation unit when checking 57 | * headers compile by themselves. 58 | * 59 | */ 60 | extern char do_not_use_this_dummy[]; 61 | 62 | 63 | #endif /* !defined(BEEP_COMPILER_H) */ 64 | 65 | 66 | /** @} */ 67 | 68 | 69 | /* 70 | * Local Variables: 71 | * c-basic-offset: 4 72 | * indent-tabs-mode: nil 73 | * End: 74 | */ 75 | -------------------------------------------------------------------------------- /contrib/morse/morse2beep.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Turn Morse code into beeps. 3 | # 4 | # Copyright 2020 Dan Jacobson (https://www.jidanni.org/) 5 | # Copyright 2020 Hans Ulrich Niedermann 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Usage: 22 | # echo cq cq cq sos | /usr/games/morse -s | perl morse2beep [milliseconds for "."] | xargs beep 23 | # 24 | # Note that this strips the trailing End Of Work (...-.-) symbol. 25 | 26 | use strict; 27 | use warnings FATAL => q(all); 28 | ## https://en.wikipedia.org/wiki/Morse_code#Representation,_timing,_and_speeds 29 | my $short = pop || 100; 30 | my $long = $short * 3; 31 | my $word_gap = $short * 7; 32 | my @elements; 33 | sub d { die "Expected input from bsdgames package's /usr/games/morse -s." } 34 | while (<>) { 35 | chomp; 36 | s/^ // or d; 37 | if (/^\.\.\.-\.-$/) { die "Didn't get any input!" unless @elements; last; } 38 | elsif (/^$/) { $elements[-1]{delay} += $word_gap if @elements; } 39 | else { 40 | for ( split // ) { 41 | if ( $_ eq "." ) { push @elements, { lenght => $short, delay => $short }; } 42 | elsif ( $_ eq "-" ) { push @elements, { lenght => $long, delay => $short }; } 43 | else { d; } 44 | } 45 | $elements[-1]{delay} = 0; 46 | } 47 | } 48 | for (@elements) { $_->{delay} = $long unless $_->{delay} } 49 | my @strings; 50 | push @strings, sprintf "-l %d -D %d", $_->{lenght}, $_->{delay} for @elements; 51 | print join " -n ", @strings; 52 | ## Errors even generate one beep nicely, due to xargs beep! 53 | -------------------------------------------------------------------------------- /beep-driver-noop.c: -------------------------------------------------------------------------------- 1 | /** \file beep-driver-noop.c 2 | * \brief implement the beep noop driver 3 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \defgroup beep_driver_noop noop driver 21 | * \ingroup beep_driver 22 | * 23 | * @{ 24 | * 25 | */ 26 | 27 | 28 | #include 29 | 30 | 31 | #include "beep-compiler.h" 32 | #include "beep-drivers.h" 33 | #include "beep-log.h" 34 | 35 | 36 | #define LOG_MODULE "noop" 37 | 38 | 39 | static 40 | bool driver_detect(beep_driver *driver, const char *const console_device) 41 | { 42 | if (console_device) { 43 | LOG_VERBOSE("driver_detect %p %s", 44 | (void *)driver, console_device); 45 | } else { 46 | LOG_VERBOSE("driver_detect %p %p", 47 | (void *)driver, (const void *)console_device); 48 | } 49 | return false; 50 | } 51 | 52 | 53 | static 54 | void driver_init(beep_driver *driver) 55 | { 56 | LOG_VERBOSE("driver_init %p", (void *)driver); 57 | } 58 | 59 | 60 | static 61 | void driver_fini(beep_driver *driver) 62 | { 63 | LOG_VERBOSE("driver_fini %p", (void *)driver); 64 | } 65 | 66 | 67 | static 68 | void driver_begin_tone(beep_driver *driver, const uint16_t freq) 69 | { 70 | LOG_VERBOSE("driver_begin_tone %p %u", (void *)driver, freq); 71 | } 72 | 73 | 74 | static 75 | void driver_end_tone(beep_driver *driver) 76 | { 77 | LOG_VERBOSE("driver_end_tone %p", (void *)driver); 78 | } 79 | 80 | 81 | static 82 | beep_driver driver_data = 83 | { 84 | "noop", 85 | NULL, 86 | driver_detect, 87 | driver_init, 88 | driver_fini, 89 | driver_begin_tone, 90 | driver_end_tone, 91 | 0, 92 | NULL 93 | }; 94 | 95 | 96 | static 97 | void beep_driver_noop_constructor(void) 98 | CONSTRUCTOR_FUNCTION; 99 | 100 | static 101 | void beep_driver_noop_constructor(void) 102 | { 103 | LOG_VERBOSE("beep_driver_noop_constructor"); 104 | beep_drivers_register(&driver_data); 105 | } 106 | 107 | 108 | /** @} */ 109 | 110 | 111 | /* 112 | * Local Variables: 113 | * c-basic-offset: 4 114 | * indent-tabs-mode: nil 115 | * End: 116 | */ 117 | -------------------------------------------------------------------------------- /beep-drivers.h: -------------------------------------------------------------------------------- 1 | /** \file beep-drivers.h 2 | * \brief interface to the beep driver infrastructure 3 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \addtogroup beep_drivers 21 | * 22 | * @{ 23 | * 24 | */ 25 | 26 | 27 | #ifndef BEEP_DRIVERS_H 28 | #define BEEP_DRIVERS_H 29 | 30 | 31 | #include "beep-compiler.h" 32 | #include "beep-driver.h" 33 | 34 | 35 | /** 36 | * Register a beep driver with the beep driver infrastructure. 37 | * 38 | * To be called from driver's CONSTRUCTOR function which means once 39 | * per program invocation. 40 | * 41 | * @param driver The driver to register. 42 | */ 43 | void beep_drivers_register(beep_driver *driver) 44 | __attribute__(( nonnull(1) )); 45 | 46 | 47 | /** 48 | * Return the first driver whose detect() function returns true. 49 | * 50 | * @param device_name The device name. 51 | * 52 | * @return NULL if no driver has been detected. 53 | * @return Otherwise, the detected driver. 54 | */ 55 | beep_driver *beep_drivers_detect(const char *const device_name); 56 | 57 | 58 | /** 59 | * Initialize the beep driver via driver's init() function. 60 | * 61 | * @param driver The beep driver. 62 | */ 63 | void beep_drivers_init(beep_driver *driver) 64 | __attribute__(( nonnull(1) )); 65 | 66 | 67 | /** 68 | * Deinitialize the beep driver via driver's fini() function. 69 | * 70 | * @param driver The beep driver. 71 | */ 72 | void beep_drivers_fini(beep_driver *driver) 73 | __attribute__(( nonnull(1) )); 74 | 75 | 76 | /** 77 | * Call the beep driver's begin_tone() function. 78 | * 79 | * @param driver The beep driver. 80 | * @param freq The frequency to play. 81 | */ 82 | void beep_drivers_begin_tone(beep_driver *driver, const uint16_t freq) 83 | __attribute__(( nonnull(1) )); 84 | 85 | 86 | /** 87 | * Call the beep driver's end_tone() function. 88 | * 89 | * @param driver The beep driver. 90 | */ 91 | void beep_drivers_end_tone(beep_driver *driver) 92 | __attribute__(( nonnull(1) )); 93 | 94 | 95 | #endif /* !defined(BEEP_DRIVERS_H) */ 96 | 97 | 98 | /** @} */ 99 | 100 | 101 | /* 102 | * Local Variables: 103 | * c-basic-offset: 4 104 | * indent-tabs-mode: nil 105 | * End: 106 | */ 107 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '40 2 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /beep-drivers.c: -------------------------------------------------------------------------------- 1 | /** \file beep-drivers.c 2 | * \brief implement the beep driver infrastructure 3 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \defgroup beep_drivers The beep driver infrastructure 21 | * 22 | * The infrastructure for and of beep drivers. 23 | * 24 | * @{ 25 | * 26 | */ 27 | 28 | 29 | #include 30 | 31 | #include "beep-drivers.h" 32 | #include "beep-log.h" 33 | 34 | 35 | #define LOG_MODULE "drivers" 36 | 37 | 38 | /** 39 | * The beginning of the linked list of drivers. 40 | */ 41 | static 42 | beep_driver *first_driver = NULL; 43 | 44 | 45 | /* documented in header file */ 46 | void beep_drivers_register(beep_driver *driver) 47 | { 48 | LOG_VERBOSE("beep_drivers_register %p (%s)", 49 | (void *) driver, driver->name); 50 | if (first_driver) { 51 | driver->next = first_driver; 52 | first_driver = driver; 53 | } else { 54 | driver->next = NULL; 55 | first_driver = driver; 56 | } 57 | } 58 | 59 | 60 | /* documented in header file */ 61 | beep_driver *beep_drivers_detect(const char *const device_name) 62 | { 63 | if (first_driver == NULL) { 64 | LOG_ERROR("beep has been built without any driver"); 65 | exit(EXIT_FAILURE); 66 | } 67 | for (beep_driver *driver = first_driver; driver; driver=driver->next) { 68 | if (driver->detect(driver, device_name)) { 69 | return driver; 70 | } 71 | } 72 | return NULL; 73 | } 74 | 75 | 76 | /* documented in header file */ 77 | void beep_drivers_init(beep_driver *driver) 78 | { 79 | driver->init(driver); 80 | } 81 | 82 | 83 | /* documented in header file */ 84 | void beep_drivers_fini(beep_driver *driver) 85 | { 86 | driver->fini(driver); 87 | } 88 | 89 | 90 | /* documented in header file */ 91 | void beep_drivers_begin_tone(beep_driver *driver, const uint16_t freq) 92 | { 93 | driver->begin_tone(driver, freq); 94 | } 95 | 96 | 97 | /* documented in header file */ 98 | void beep_drivers_end_tone(beep_driver *driver) 99 | { 100 | driver->end_tone(driver); 101 | } 102 | 103 | 104 | /** @} */ 105 | 106 | 107 | /* 108 | * Local Variables: 109 | * c-basic-offset: 4 110 | * indent-tabs-mode: nil 111 | * End: 112 | */ 113 | -------------------------------------------------------------------------------- /beep-log.h: -------------------------------------------------------------------------------- 1 | /** \file beep-log.h 2 | * \brief interface to logging and message output 3 | * \author Copyright (C) 2018-2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \addtogroup beep_log 21 | * 22 | * @{ 23 | * 24 | */ 25 | 26 | 27 | #ifndef BEEP_LOG_H 28 | #define BEEP_LOG_H 29 | 30 | 31 | #include 32 | 33 | 34 | /** Currently active log level. 35 | * 36 | * Default is 0. Values greater than 0 are for verbose output. 37 | */ 38 | extern int log_level; 39 | 40 | 41 | /** Program name to use in log messages. 42 | * 43 | * Set this first thing in main(). Either just set it to some constant 44 | * string, or run log_init() to set this up from the non-path part of 45 | * argv[0]. 46 | */ 47 | extern const char *progname; 48 | 49 | 50 | /** Write a standard message */ 51 | void log_output(const char *const format, ...) 52 | __attribute__(( nonnull(1) )) 53 | __attribute__(( format(printf, 1, 2) )); 54 | 55 | 56 | /** Log an error message */ 57 | #define LOG_ERROR(...) log_error(__VA_ARGS__) 58 | 59 | /** Log an error message */ 60 | void log_error(const char *const format, ...) 61 | __attribute__(( nonnull(1) )) 62 | __attribute__(( format(printf, 1, 2) )); 63 | 64 | 65 | /** Log a warning message */ 66 | #define LOG_WARNING(...) log_warning(LOG_MODULE, __VA_ARGS__) 67 | 68 | /** Log a warning message */ 69 | void log_warning(const char *const module, 70 | const char *const format, ...) 71 | __attribute__(( nonnull(1, 2) )) 72 | __attribute__(( format(printf, 2, 3) )); 73 | 74 | 75 | /** Log a verbose message */ 76 | #define LOG_VERBOSE(...) log_verbose(LOG_MODULE, __VA_ARGS__) 77 | 78 | /** Log a verbose message */ 79 | void log_verbose(const char *const module, 80 | const char *const format, ...) 81 | __attribute__(( nonnull(1, 2) )) 82 | __attribute__(( format(printf, 2, 3) )); 83 | 84 | 85 | /** Initialize the log message prefix from the non-path part of argv[0]. */ 86 | void log_init(const int argc, char *const argv[]) 87 | __attribute__(( nonnull(2) )); 88 | 89 | 90 | #endif /* !defined(BEEP_LOG_H) */ 91 | 92 | 93 | /** @} */ 94 | 95 | 96 | /* 97 | * Local Variables: 98 | * c-basic-offset: 4 99 | * indent-tabs-mode: nil 100 | * End: 101 | */ 102 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | The beep testsuite 2 | ================== 3 | 4 | Deficiencies 5 | ------------ 6 | 7 | * Quick hack. 8 | 9 | * Does not test whether actual sound output happened. The different 10 | frequency might help a human detect a different melody, but that 11 | is no replacement for a properly automated test. 12 | 13 | 14 | Devices 15 | ======= 16 | 17 | ``` 18 | [root@host ~]# echo blubb > /dev/input/blubb 19 | 20 | [user@host ~]$ ls -lR /dev/tty0 /dev/vc/0 /dev/input/ 21 | ls: cannot access '/dev/vc/0': No such file or directory 22 | crw--w----+ 1 root tty 4, 0 27. Dez 17:55 /dev/tty0 23 | 24 | /dev/input/: 25 | total 4 26 | -rw-r--r--. 1 root root 6 28. Dez 01:55 blubb 27 | drwxr-xr-x. 2 root root 140 27. Dez 17:55 by-id 28 | drwxr-xr-x. 2 root root 180 27. Dez 19:19 by-path 29 | crw-rw----. 1 root input 13, 64 27. Dez 17:55 event0 30 | crw-rw----. 1 root input 13, 65 27. Dez 17:55 event1 31 | crw-rw----. 1 root input 13, 74 27. Dez 17:55 event10 32 | crw-rw----. 1 root input 13, 75 27. Dez 17:55 event11 33 | crw-rw----. 1 root input 13, 76 27. Dez 17:55 event12 34 | crw-rw----. 1 root input 13, 77 27. Dez 17:55 event13 35 | crw-rw----. 1 root input 13, 78 27. Dez 17:55 event14 36 | crw-rw----. 1 root input 13, 79 27. Dez 17:55 event15 37 | crw-rw----. 1 root input 13, 80 27. Dez 17:55 event16 38 | crw-rw----. 1 root input 13, 81 27. Dez 17:55 event17 39 | crw-rw----. 1 root input 13, 82 27. Dez 17:55 event18 40 | crw-rw----. 1 root input 13, 83 27. Dez 17:55 event19 41 | crw-rw----. 1 root input 13, 66 27. Dez 17:55 event2 42 | crw-rw----. 1 root input 13, 84 27. Dez 17:55 event20 43 | crw-rw----. 1 root input 13, 85 27. Dez 19:19 event21 44 | crw-rw----. 1 root input 13, 67 27. Dez 17:55 event3 45 | crw-rw----. 1 root input 13, 68 27. Dez 17:55 event4 46 | crw-rw----. 1 root input 13, 69 27. Dez 17:55 event5 47 | crw-rw----. 1 root input 13, 70 27. Dez 17:55 event6 48 | crw-rw----. 1 root input 13, 71 27. Dez 17:55 event7 49 | crw-rw----. 1 root input 13, 72 27. Dez 17:55 event8 50 | crw-rw----. 1 root input 13, 73 27. Dez 17:55 event9 51 | crw-rw----. 1 root input 13, 63 27. Dez 17:55 mice 52 | crw-rw----. 1 root input 13, 32 27. Dez 17:55 mouse0 53 | 54 | /dev/input/by-id: 55 | total 0 56 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 usb-B16_b_02_USB-PS_2_Optical_Mouse-event-mouse -> ../event3 57 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 usb-B16_b_02_USB-PS_2_Optical_Mouse-mouse -> ../mouse0 58 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 usb-Burr-Brown_from_TI_USB_Audio_CODEC-event-if03 -> ../event2 59 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 usb-Microsoft_Natural®_Ergonomic_Keyboard_4000-event-kbd -> ../event4 60 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 usb-Microsoft_Natural®_Ergonomic_Keyboard_4000-if01-event-kbd -> ../event5 61 | 62 | /dev/input/by-path: 63 | total 0 64 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 pci-0000:00:10.1-usb-0:1:1.3-event -> ../event2 65 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 pci-0000:00:12.2-usb-0:2.3:1.0-event-mouse -> ../event3 66 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 pci-0000:00:12.2-usb-0:2.3:1.0-mouse -> ../mouse0 67 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 pci-0000:00:12.2-usb-0:2.4:1.0-event-kbd -> ../event4 68 | lrwxrwxrwx. 1 root root 9 27. Dez 17:55 pci-0000:00:12.2-usb-0:2.4:1.1-event-kbd -> ../event5 69 | lrwxrwxrwx. 1 root root 10 27. Dez 17:55 platform-eeepc-wmi-event -> ../event20 70 | lrwxrwxrwx. 1 root root 10 27. Dez 19:19 platform-pcspkr-event-spkr -> ../event21 71 | [user@host ~]$ _ 72 | ``` 73 | -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | 3 | Credit where credit is due. 4 | 5 | > I (Johnathan Nightingale) handled the original coding, distribution, 6 | > maintenance, etc. 7 | > 8 | > Peter Tirsek (peter at tirsek dot com) filled me in on where the magical 9 | > fairy number comes from (see beep.c). He also tracked down the relevant 10 | > kernel code that causes the ioctl()s to die under certain conditions 11 | > (see the README or man page sections on ioctl). He is truly a wonderful 12 | > person. 13 | > 14 | > Andreas Hochsteger (e9625392 at student dot tuwien dot ac dot at) contributed 15 | > several useful little patches, and was my inspiration for the -d/-D 16 | > distinction. He's also thrown pointers my way about code packaging, which 17 | > are appreciated. 18 | > 19 | > Rick Franchuk (rickf at transpect dot net) came up with the idea of the -s and 20 | > -c stdin hooks. Since most people will be using beep to tell them when a new 21 | > line pops up in log, or mail, or what-have-you, this was quite clever of him 22 | > and though I really did mean to do it anyhow, he sent me the patch before I had 23 | > bothered to write it, so he gets the credit. :) 24 | > 25 | > Serge Winitzki (winitzki at erebus.phys.cwru.edu) suggested having beep take 26 | > floats for frequency, instead of int's. 27 | > 28 | > The guys at freshmeat.net really deserve a big ol whack of credit too, for 29 | > running a very cool site in general, and for running one so successfully that 30 | > my little 4k program generated literally hundreds of emails in reply. It gives 31 | > one a great sense of community to see such an overwhelming response. 32 | > 33 | > In particular, fryguy[at]freshmeat (Ryan Weaver) rocks supremely, for packaging 34 | > beep in RPM format, and maintaining said package until he decides not to. I 35 | > really did mean to make a spec for it myself, but hey, when freshmeat offers to 36 | > maintain your packages, you'd have to have a *real* good reason to say no. 37 | > 38 | > Most of all - and I write this nearly 10 years later, so I have the benefit of 39 | > history on my side here - I would like to thank Gerfried Fuchs, who has tirelessly 40 | > maintained beep in debian, along with a stack of patches, years after I stopped 41 | > hacking on it in earnest. He is amazingly dedicated, and has a new son whom we 42 | > would all be fortunate to have follow in his father's footsteps. 43 | 44 | Thanks to terom on Hacker News, Andrew Ayer, Richard Kettlewall, 45 | rain-1 on github, Jakub Wilk, and Benjamin Grange for their help with 46 | fixing 47 | [CVE-2018-0492](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-0492), 48 | [CVE-2018-1000532](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000532), 49 | and the help fixing the fixes (https://github.com/johnath/beep/issues/11). 50 | 51 | Thanks to Hanno Böck for the report on possible integer overflows 52 | (https://github.com/johnath/beep/issues/13). 53 | 54 | Thanks to Stefan Helmert for the `sig_atomic_t` idea. 55 | 56 | Thanks to Dan Jacobson (jidanni on github) and kanliot for suggesting 57 | documentation improvements especially for but not restricted to the 58 | permissions setup (https://github.com/spkr-beep/beep/issues/4). 59 | 60 | Thanks to Daniel Kamil Kozar (xavery on github) for reporting and 61 | helping with fixing the sudo check when beep runs as non-root user 62 | (https://github.com/spkr-beep/beep/issues/5). 63 | 64 | Thanks to Walter B. Vaughan for reminding me that keeping a format 65 | string in C macros using `__VA_ARGS__` is still a bad idea. 66 | 67 | Thanks to Dan Jacobson for the idea and the perl script for converting 68 | morse code to beeps via a beep command line. 69 | 70 | Thanks to a1346054 for the fixes to spelling and whitespace. 71 | -------------------------------------------------------------------------------- /beep-driver.h: -------------------------------------------------------------------------------- 1 | /** \file beep-driver.h 2 | * \brief the interface each beep driver implements 3 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 4 | * \author Copyright (C) 2022 Hans Ulrich Niedermann 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | * 21 | * \defgroup beep_driver beep driver definition 22 | * 23 | * @{ 24 | * 25 | */ 26 | 27 | 28 | #ifndef BEEP_DRIVER_H 29 | #define BEEP_DRIVER_H 30 | 31 | 32 | #include 33 | #include 34 | 35 | 36 | /** 37 | * Abstract declaration of beep_driver. 38 | */ 39 | typedef struct beep_driver beep_driver; 40 | 41 | 42 | /** 43 | * Driver function to detect whether the driver can actually work. 44 | */ 45 | typedef bool (*beep_driver_detect_func) (beep_driver *driver, 46 | const char *console_device); 47 | 48 | /** 49 | * Driver function to initialize the driver. 50 | */ 51 | typedef void (*beep_driver_init_func) (beep_driver *driver); 52 | 53 | /** 54 | * Driver function to destroy and clean up the driver. 55 | */ 56 | typedef void (*beep_driver_fini_func) (beep_driver *driver); 57 | 58 | /** 59 | * Driver function to have the driver begin a tone. 60 | */ 61 | typedef void (*beep_driver_begin_tone_func) (beep_driver *driver, 62 | const uint16_t freq); 63 | 64 | /** 65 | * Driver function to have the driver end a tone. 66 | */ 67 | typedef void (*beep_driver_end_tone_func) (beep_driver *driver); 68 | 69 | 70 | /** 71 | * Internal beep driver data structure. 72 | */ 73 | struct beep_driver { 74 | /** Unique name for the driver */ 75 | char *name; 76 | 77 | /** Link to next driver in linked list of drivers. 78 | * 79 | * To be filled out by the beep_drivers_register() function once, 80 | * and only be read from everywhere else. 81 | */ 82 | beep_driver *next; 83 | 84 | /** beep driver detect function */ 85 | beep_driver_detect_func detect; 86 | 87 | /** beep driver init function */ 88 | beep_driver_init_func init; 89 | 90 | /** beep driver fini function */ 91 | beep_driver_fini_func fini; 92 | 93 | /** beep driver begin_tone function */ 94 | beep_driver_begin_tone_func begin_tone; 95 | 96 | /** beep driver end_tone function */ 97 | beep_driver_end_tone_func end_tone; 98 | 99 | /* As long as all drivers need the following data items, we do not 100 | * need to hide them in the driver implementation. 101 | */ 102 | 103 | /** device file descriptor for this driver */ 104 | int device_fd; 105 | 106 | /** device file name for this driver */ 107 | const char *device_name; 108 | }; 109 | 110 | 111 | #endif /* !defined(BEEP_DRIVER_H) */ 112 | 113 | 114 | /** @} */ 115 | 116 | 117 | /* 118 | * Local Variables: 119 | * c-basic-offset: 4 120 | * indent-tabs-mode: nil 121 | * End: 122 | */ 123 | -------------------------------------------------------------------------------- /beep-library.c: -------------------------------------------------------------------------------- 1 | /** \file beep-library.c 2 | * \brief library of miscellaneous functions 3 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \defgroup beep_library Library of miscellaneous functions 21 | * 22 | * @{ 23 | * 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "beep-library.h" 37 | #include "beep-log.h" 38 | 39 | 40 | #define LOG_MODULE "lib" 41 | 42 | 43 | /* documented in header file */ 44 | int open_checked_char_device(const char *const device_name) 45 | { 46 | struct stat sb; 47 | 48 | if (-1 == stat(device_name, &sb)) { 49 | LOG_VERBOSE("could not stat(2) %s: %s", 50 | device_name, strerror(errno)); 51 | return -1; 52 | } 53 | 54 | if (!S_ISCHR(sb.st_mode)) { 55 | LOG_VERBOSE("%s is not a character device", 56 | device_name); 57 | return -1; 58 | } 59 | 60 | const int fd = open(device_name, O_WRONLY); 61 | if (fd == -1) { 62 | LOG_VERBOSE("could not open(2) %s: %s", 63 | device_name, strerror(errno)); 64 | return -1; 65 | } 66 | LOG_VERBOSE("opened %s as fd=%d", device_name, fd); 67 | 68 | if (-1 == fstat(fd, &sb)) { 69 | LOG_VERBOSE("could not fstat(2) %d: %s", 70 | fd, strerror(errno)); 71 | return -1; 72 | } 73 | 74 | if (!S_ISCHR(sb.st_mode)) { 75 | LOG_VERBOSE("%d is not a character device", fd); 76 | return -1; 77 | } 78 | 79 | return fd; 80 | } 81 | 82 | 83 | /* documented in header file 84 | * 85 | * We do not know for certain whether perror(3) does strange things with 86 | * global variables or malloc(3)/free(3) inside its code, so we use 87 | * strerror_r(3) and write(2) to STDERR_FILENO instead. 88 | */ 89 | void safe_errno_exit(const char *const msg) 90 | { 91 | const int saved_errno = errno; 92 | char strerr_buf[128]; 93 | const int ret = strerror_r(saved_errno, strerr_buf, sizeof(strerr_buf)); 94 | if (ret != 0) { 95 | if (write(STDERR_FILENO, "strerror_r error\n", 96 | 0+0+0+0+strlen("strerror_r error\n"))) { 97 | /* ignore all write errors */ 98 | } 99 | _exit(EXIT_FAILURE); 100 | } 101 | const size_t msglen = strlen(msg); 102 | if (write(STDERR_FILENO, msg, msglen)) { 103 | /* ignore all write errors */ 104 | } 105 | if (write(STDERR_FILENO, ": ", 2)) { 106 | /* ignore all write errors */ 107 | } 108 | const size_t errlen = strlen(strerr_buf); 109 | if (write(STDERR_FILENO, strerr_buf, errlen)) { 110 | /* ignore all write errors */ 111 | } 112 | if (write(STDERR_FILENO, "\n", 1)) { 113 | /* ignore all write errors */ 114 | } 115 | _exit(EXIT_FAILURE); 116 | } 117 | 118 | 119 | /** @} */ 120 | 121 | 122 | /* 123 | * Local Variables: 124 | * c-basic-offset: 4 125 | * indent-tabs-mode: nil 126 | * End: 127 | */ 128 | -------------------------------------------------------------------------------- /tests/run-tests: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # run-tests - run a given series of test cases for beep 4 | # Copyright (C) 2018-2019 Hans Ulrich Niedermann 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License along 17 | # with this program; if not, write to the Free Software Foundation, Inc., 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | 20 | CMP=cmp 21 | DIFF=diff 22 | SED=sed 23 | SHELL=sh 24 | 25 | # TODO: If we have more tone generating tests, find a well-known 26 | # melody without repeating notes and play that melody so that a 27 | # human can hear when the melody has holes. 28 | FREQS=(440 494 554 587 659 740 831 880 988 1109 1175 1319 1480 1661 1760) 29 | 30 | : set -e 31 | : set -x 32 | 33 | test_dir="$1" 34 | shift 35 | BEEP="$1" 36 | shift 37 | export BEEP 38 | 39 | skip=0 40 | pass=0 41 | fail=0 42 | 43 | if test -t 1; then 44 | hilite="$(tput setaf 3)" 45 | normal="$(tput sgr0)" 46 | green="$(tput setaf 2)" 47 | blue="$(tput setaf 4)" 48 | red="$(tput setaf 1)$(tput bold)" 49 | else 50 | hilite="" 51 | normal="" 52 | green="" 53 | blue="" 54 | red="" 55 | fi 56 | passmsg="${green}PASS${normal}" 57 | failmsg="${red}FAIL${normal}" 58 | skipmsg="${blue}SKIP${normal}" 59 | 60 | canonicalize_output() { 61 | ${SED} -e "s|${BEEP}|BEEP_EXECUTABLE|g" -e "s|^${BEEP##*/}:|BEEP_EXECUTABLE:|g" -e "s|$(echo "${PACKAGE_VERSION}" | ${SED} 's/\./\\./g')|PACKAGE_VERSION|g" 62 | } 63 | 64 | # taken from contrib/ 65 | failure_beeps() { 66 | if "$have_no_hardware"; then 67 | : 68 | elif test -e "beep"; then 69 | ${BEEP} -f 880 -l 200 -n -f 659 -n -f 523 -n -f 370 -l 400 70 | fi 71 | } 72 | 73 | # taken from contrib/ 74 | success_beeps() { 75 | if "$have_no_hardware"; then 76 | : 77 | elif test -e "beep"; then 78 | ${BEEP} -f 220 -l 100 -n -f 275 -l 100 -n -f 330 -l 100 -n -f 440 -l 100 -n -f 550 -l 100 -n -f 660 -l 100 -n -f 880 79 | fi 80 | } 81 | 82 | # Determine whether we can test actual hardware 83 | have_no_hardware=true 84 | if test -c /dev/input/by-path/platform-pcspkr-event-spkr; then 85 | have_no_hardware=false 86 | fi 87 | 88 | : set -x 89 | 90 | if true; then 91 | freq_idx=0 92 | for test in $(ls -1 "${test_dir}/"*.{bash,sh}); do 93 | export FREQ="${FREQS[${freq_idx}]}" 94 | base="$(basename $(basename "$test" .bash) .sh)" 95 | dir="$(dirname "$test")" 96 | actual="${dir}/${base}.actual" 97 | printf "${hilite}%-32s${normal} " "${base}" 98 | if "$have_no_hardware" && grep "^: REQUIRES_HARDWARE" "$test" > /dev/null; then 99 | skip="$(expr "${skip}" + 1)" 100 | echo "$skipmsg" 101 | elif "${test}" > "${actual}.new" 2>&1; then 102 | canonicalize_output < "${actual}.new" > "${actual}" 103 | expects_output=false 104 | for file in "${dir}/${base}.expected".[0-9]; do 105 | if test -f "$file"; then 106 | expects_output=true 107 | break 108 | fi 109 | done 110 | if "${expects_output}"; then 111 | expect_fail="true" 112 | for expected in "${dir}/${base}.expected".[0-9]; do 113 | if ${CMP} --quiet "${expected}" "${actual}"; then 114 | pass="$(expr "${pass}" + 1)" 115 | echo "${passmsg}${expected/#*expected}" 116 | expect_fail="false" 117 | break 118 | fi 119 | done 120 | if "$expect_fail"; then 121 | fail="$(expr "${fail}" + 1)" 122 | echo "${failmsg}" 123 | for expected in "${dir}/${base}.expected".[0-9]; do 124 | ${DIFF} -u "${expected}" "${actual}" 125 | done 126 | fi 127 | else 128 | if test -s "${actual}"; then 129 | fail="$(expr "${fail}" + 1)" 130 | echo "${failmsg}" 131 | cat "${actual}" 132 | else 133 | pass="$(expr "${pass}" + 1)" 134 | echo "${passmsg}" 135 | fi 136 | fi 137 | else 138 | canonicalize_output < "${actual}.new" > "${actual}" 139 | fail="$(expr "${fail}" + 1)" 140 | echo "${failmsg}" 141 | cat "${actual}" 142 | fi 143 | freq_idx="$(expr "$freq_idx" + 1)" 144 | if test "$freq_idx" -ge "${#FREQS[@]}"; then 145 | freq_idx=0 146 | fi 147 | sleep 0.35 || sleep 1 148 | done 149 | fi 150 | 151 | echo "${pass} passed, ${fail} failed, ${skip} skipped, $(expr "${pass}" + "${fail}" + "${skip}") total." 152 | 153 | if test "${fail}" -gt 0; then \ 154 | failure_beeps 155 | exit 1 156 | else 157 | success_beeps 158 | exit 0 159 | fi 160 | -------------------------------------------------------------------------------- /beep-log.c: -------------------------------------------------------------------------------- 1 | /** \file beep-log.c 2 | * \brief implement logging and message output 3 | * \author Copyright (C) 2018-2019 Hans Ulrich Niedermann 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * 20 | * \defgroup beep_log Logging and message output 21 | * 22 | * @{ 23 | * 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "beep-log.h" 32 | 33 | 34 | #define LOG_MODULE "log" 35 | 36 | 37 | /* documented in header file */ 38 | int log_level = 0; 39 | 40 | 41 | /* documented in header file */ 42 | const char *progname = "beep-log"; 43 | 44 | 45 | /** 46 | * beep-log internal function to actually do the printing of a message 47 | */ 48 | 49 | static 50 | void log_internal_vf(const char *const module, const char *levelstr, 51 | const char *const format, va_list args) 52 | __attribute__(( nonnull(2) )); 53 | 54 | 55 | static 56 | void log_internal_vf(const char *const module, const char *levelstr, 57 | const char *const format, va_list args) 58 | { 59 | va_list copied_args; 60 | va_copy(copied_args, args); 61 | 62 | if (module) { 63 | fprintf(stdout, "%s: %s: %s: ", progname, levelstr, module); 64 | } else { 65 | fprintf(stdout, "%s: %s: ", progname, levelstr); 66 | } 67 | vfprintf(stdout, format, copied_args); 68 | fputc('\n', stdout); 69 | 70 | va_end(copied_args); 71 | } 72 | 73 | 74 | /* documented in header file */ 75 | void log_output(const char *const format, ...) 76 | { 77 | va_list args; 78 | 79 | va_start(args, format); 80 | vfprintf(stdout, format, args); 81 | va_end(args); 82 | } 83 | 84 | 85 | /* documented in header file */ 86 | void log_error(const char *const format, ...) 87 | { 88 | va_list args; 89 | 90 | va_start(args, format); 91 | log_internal_vf(NULL, "Error", format, args); 92 | va_end(args); 93 | } 94 | 95 | 96 | /* documented in header file */ 97 | void log_warning(const char *const module, 98 | const char *const format, ...) 99 | { 100 | va_list args; 101 | 102 | va_start(args, format); 103 | log_internal_vf(module, "Warning", format, args); 104 | va_end(args); 105 | } 106 | 107 | 108 | /* documented in header file */ 109 | void log_verbose(const char *const module, 110 | const char *const format, ...) 111 | { 112 | va_list args; 113 | 114 | if (log_level > 0) { 115 | va_start(args, format); 116 | log_internal_vf(module, "Verbose", format, args); 117 | va_end(args); 118 | } 119 | } 120 | 121 | 122 | /* documented in header file */ 123 | void log_init(const int argc, char *const argv[]) { 124 | /* If argv[0] is "/foo/bar/beep", set progname to "beep". 125 | * Otherwise, set progname to argv[0] (if it does not contain a 126 | * slash) or keep the default progname value which points to a 127 | * constant string. 128 | */ 129 | if (argc >= 1) { 130 | if ('\0' != *argv[0]) { 131 | const char *last_slash = strrchr(argv[0], '/'); 132 | if (NULL != last_slash) { 133 | const char *post_last_slash = last_slash+1; 134 | if ('\0' != *post_last_slash) { 135 | progname = post_last_slash; 136 | } 137 | } else { 138 | progname = argv[0]; 139 | } 140 | } 141 | } 142 | } 143 | 144 | 145 | /** 146 | * beep-log internal function to initialize the log subsystem. 147 | * 148 | */ 149 | 150 | static 151 | void log_constructor(void) 152 | __attribute__(( constructor )); 153 | 154 | static 155 | void log_constructor(void) 156 | { 157 | const char *beep_log_level = secure_getenv("BEEP_LOG_LEVEL"); 158 | /* silently ignore all errors, keeping the default log_level */ 159 | if (beep_log_level) { 160 | if (*beep_log_level) { 161 | char *endptr = NULL; 162 | const long int i = strtol(beep_log_level, &endptr, 10); 163 | if (beep_log_level != endptr) { 164 | if (*endptr == '\0') { 165 | if ((-999<=i) && (i<=999)) { 166 | log_level = (int) i; 167 | } 168 | } 169 | } 170 | } 171 | } 172 | LOG_VERBOSE("log_constructor"); 173 | } 174 | 175 | 176 | /** @} */ 177 | 178 | 179 | /* 180 | * Local Variables: 181 | * c-basic-offset: 4 182 | * indent-tabs-mode: nil 183 | * End: 184 | */ 185 | -------------------------------------------------------------------------------- /beep-driver-evdev.c: -------------------------------------------------------------------------------- 1 | /** \file beep-driver-evdev.c 2 | * \brief implement the beep evdev driver 3 | * \author Copyright (C) 2000-2010 Johnathan Nightingale 4 | * \author Copyright (C) 2010-2013 Gerfried Fuchs 5 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * 22 | * \defgroup beep_driver_evdev Linux evdev API driver 23 | * \ingroup beep_driver 24 | * 25 | * @{ 26 | * 27 | */ 28 | 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | 43 | #include "beep-compiler.h" 44 | #include "beep-drivers.h" 45 | 46 | #include "beep-library.h" 47 | #include "beep-log.h" 48 | 49 | 50 | #define LOG_MODULE "evdev" 51 | 52 | 53 | static 54 | int open_checked_device(const char *const device_name) 55 | { 56 | const int fd = open_checked_char_device(device_name); 57 | if (fd == -1) { 58 | return -1; 59 | } 60 | 61 | if (-1 == ioctl(fd, EVIOCGSND(0))) { 62 | LOG_VERBOSE("%d does not implement EV_SND API", fd); 63 | return -1; 64 | } 65 | 66 | return fd; 67 | } 68 | 69 | 70 | static 71 | bool driver_detect(beep_driver *driver, const char *console_device) 72 | { 73 | if (console_device) { 74 | LOG_VERBOSE("driver_detect %p %s", 75 | (void *)driver, console_device); 76 | const int fd = open_checked_device(console_device); 77 | if (fd >= 0) { 78 | driver->device_fd = fd; 79 | driver->device_name = console_device; 80 | return true; 81 | } 82 | } else { 83 | LOG_VERBOSE("driver_detect %p %p", 84 | (void *)driver, (const void *)console_device); 85 | static 86 | const char *const well_known_device_names[] = 87 | { 88 | "/dev/input/by-path/platform-pcspkr-event-spkr", 89 | }; 90 | for (size_t i=0; i<(sizeof(well_known_device_names)/sizeof(well_known_device_names[0])); ++i) { 91 | const char *const device_name = well_known_device_names[i]; 92 | const int fd = open_checked_device(device_name); 93 | if (fd >= 0) { 94 | driver->device_fd = fd; 95 | driver->device_name = device_name; 96 | return true; 97 | } 98 | } 99 | } 100 | return false; 101 | } 102 | 103 | 104 | static 105 | void driver_init(beep_driver *driver) 106 | { 107 | LOG_VERBOSE("driver_init %p", (void *)driver); 108 | } 109 | 110 | 111 | static 112 | void driver_fini(beep_driver *driver) 113 | { 114 | LOG_VERBOSE("driver_fini %p", (void *)driver); 115 | close(driver->device_fd); 116 | driver->device_fd = -1; 117 | } 118 | 119 | 120 | static 121 | void driver_begin_tone(beep_driver *driver, const uint16_t freq) 122 | { 123 | LOG_VERBOSE("driver_begin_tone %p %u", (void *)driver, freq); 124 | 125 | struct input_event e; 126 | 127 | memset(&e, 0, sizeof(e)); 128 | e.type = EV_SND; 129 | e.code = SND_TONE; 130 | e.value = freq; 131 | 132 | if (sizeof(e) != write(driver->device_fd, &e, sizeof(e))) { 133 | /* If we cannot use the sound API, we cannot silence the sound either */ 134 | safe_errno_exit("write EV_SND"); 135 | } 136 | } 137 | 138 | 139 | static 140 | void driver_end_tone(beep_driver *driver) 141 | { 142 | LOG_VERBOSE("driver_end_tone %p", (void *)driver); 143 | 144 | struct input_event e; 145 | 146 | memset(&e, 0, sizeof(e)); 147 | e.type = EV_SND; 148 | e.code = SND_TONE; 149 | e.value = 0; 150 | 151 | if (sizeof(e) != write(driver->device_fd, &e, sizeof(e))) { 152 | safe_errno_exit("write EV_SND"); 153 | } 154 | } 155 | 156 | 157 | static 158 | beep_driver driver_data = 159 | { 160 | "evdev", 161 | NULL, 162 | driver_detect, 163 | driver_init, 164 | driver_fini, 165 | driver_begin_tone, 166 | driver_end_tone, 167 | 0, 168 | NULL 169 | }; 170 | 171 | 172 | static 173 | void beep_driver_evdev_constructor(void) 174 | CONSTRUCTOR_FUNCTION; 175 | 176 | static 177 | void beep_driver_evdev_constructor(void) 178 | { 179 | LOG_VERBOSE("beep_driver_evdev_constructor"); 180 | beep_drivers_register(&driver_data); 181 | } 182 | 183 | 184 | /** @} */ 185 | 186 | 187 | /* 188 | * Local Variables: 189 | * c-basic-offset: 4 190 | * indent-tabs-mode: nil 191 | * End: 192 | */ 193 | -------------------------------------------------------------------------------- /beep-driver-console.c: -------------------------------------------------------------------------------- 1 | /** \file beep-driver-console.c 2 | * \brief implement the beep console driver 3 | * \author Copyright (C) 2000-2010 Johnathan Nightingale 4 | * \author Copyright (C) 2010-2013 Gerfried Fuchs 5 | * \author Copyright (C) 2019 Hans Ulrich Niedermann 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * 22 | * \defgroup beep_driver_console Linux console API driver 23 | * \ingroup beep_driver 24 | * 25 | * @{ 26 | * 27 | */ 28 | 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | 37 | #include "beep-compiler.h" 38 | #include "beep-drivers.h" 39 | 40 | #include "beep-library.h" 41 | #include "beep-log.h" 42 | 43 | 44 | #define LOG_MODULE "console" 45 | 46 | 47 | #ifndef CLOCK_TICK_RATE 48 | /** The clock tick rate for calculating the PWM counter for the PIT from the frequency. 49 | * 50 | * Using the PIT_TICK_RATE value from the kernel. 51 | */ 52 | #define CLOCK_TICK_RATE 1193182UL 53 | #endif /* !defined(CLOCK_TICK_RATE) */ 54 | 55 | 56 | static 57 | int open_checked_device(const char *const device_name) 58 | { 59 | const int fd = open_checked_char_device(device_name); 60 | if (fd == -1) { 61 | return -1; 62 | } 63 | 64 | if (-1 == ioctl(fd, KIOCSOUND, 0)) { 65 | LOG_VERBOSE("%d does not implement KIOCSOUND API", fd); 66 | return -1; 67 | } 68 | 69 | return fd; 70 | } 71 | 72 | 73 | static 74 | bool driver_detect(beep_driver *driver, const char *console_device) 75 | { 76 | if (console_device) { 77 | LOG_VERBOSE("driver_detect %p %s", 78 | (void *)driver, console_device); 79 | const int fd = open_checked_device(console_device); 80 | if (fd >= 0) { 81 | driver->device_fd = fd; 82 | driver->device_name = console_device; 83 | return true; 84 | } 85 | } else { 86 | LOG_VERBOSE("driver_detect %p %p", 87 | (void *)driver, (const void *)console_device); 88 | 89 | /** \todo We could iterate over all `/dev/tty[0-9]+` and 90 | * `/dev/vc/[0-9]+` devices until one is a character 91 | * device special file which can be `open(2)`ed with 92 | * `O_WRONLY`. (We already have that code in 93 | * `issue-6-benchmark.c`.) Is that advisable from a 94 | * robustness and/or security point of view? 95 | */ 96 | static 97 | const char *const console_device_list[] = 98 | { 99 | "/dev/tty0", 100 | "/dev/vc/0", 101 | }; 102 | for (size_t i=0; i<(sizeof(console_device_list)/sizeof(console_device_list[0])); ++i) { 103 | const char *const device_name = console_device_list[i]; 104 | const int fd = open_checked_device(device_name); 105 | if (-1 != fd) { 106 | driver->device_fd = fd; 107 | driver->device_name = device_name; 108 | return true; 109 | } 110 | } 111 | } 112 | return false; 113 | } 114 | 115 | 116 | static 117 | void driver_init(beep_driver *driver) 118 | { 119 | LOG_VERBOSE("driver_init %p", (void *)driver); 120 | } 121 | 122 | 123 | static 124 | void driver_fini(beep_driver *driver) 125 | { 126 | LOG_VERBOSE("driver_fini %p", (void *)driver); 127 | close(driver->device_fd); 128 | driver->device_fd = -1; 129 | } 130 | 131 | 132 | static 133 | void driver_begin_tone(beep_driver *driver, const uint16_t freq) 134 | { 135 | LOG_VERBOSE("driver_begin_tone %p %u", (void *)driver, freq); 136 | const uintptr_t argp = ((freq != 0) ? (CLOCK_TICK_RATE/freq) : freq) & 0xffff; 137 | if (-1 == ioctl(driver->device_fd, KIOCSOUND, argp)) { 138 | /* If we cannot use the sound API, we cannot silence the sound either */ 139 | safe_errno_exit("ioctl KIOCSOUND"); 140 | } 141 | } 142 | 143 | 144 | static 145 | void driver_end_tone(beep_driver *driver) 146 | { 147 | LOG_VERBOSE("driver_end_tone %p", (void *)driver); 148 | if (-1 == ioctl(driver->device_fd, KIOCSOUND, 0)) { 149 | safe_errno_exit("ioctl KIOCSOUND"); 150 | } 151 | } 152 | 153 | 154 | static 155 | beep_driver driver_data = 156 | { 157 | "console", 158 | NULL, 159 | driver_detect, 160 | driver_init, 161 | driver_fini, 162 | driver_begin_tone, 163 | driver_end_tone, 164 | 0, 165 | NULL 166 | }; 167 | 168 | 169 | static 170 | void beep_driver_console_constructor(void) 171 | CONSTRUCTOR_FUNCTION; 172 | 173 | static 174 | void beep_driver_console_constructor(void) 175 | { 176 | LOG_VERBOSE("beep_driver_console_constructor"); 177 | beep_drivers_register(&driver_data); 178 | } 179 | 180 | 181 | /** @} */ 182 | 183 | 184 | /* 185 | * Local Variables: 186 | * c-basic-offset: 4 187 | * indent-tabs-mode: nil 188 | * End: 189 | */ 190 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | Installing beep 2 | =============== 3 | 4 | This document describes how to install `beep` from sources and how to 5 | set up the system afterwards. 6 | 7 | If you are using `beep` as shipped in a binary distribution package, 8 | that package should have done most of those steps for you. The one 9 | notable exception should be the step adding users to the `beep` group. 10 | 11 | If this file leaves open an installation question, please file an 12 | issue at https://github.com/spkr-beep/beep/issues so we can see 13 | whether we can improve the documentation or the installation procedure 14 | on the beep side. 15 | 16 | 17 | Build requirements 18 | ================== 19 | 20 | * GNU make 21 | * clang or gcc 22 | * Linux kernel headers 23 | 24 | 25 | Compile and Install 26 | =================== 27 | 28 | The basic way to build and install beep is 29 | 30 | ``` 31 | [user@host beep]$ make 32 | [user@host beep]$ make install-nobuild 33 | ``` 34 | 35 | `beep` does not have a `configure` script, so to make some 36 | configuration options last over different make invocations, do 37 | generate a `local.mk` file containing the appropriate definitions: 38 | 39 | * The buildsystem will use whatever value `CC` is as a compiler, and 40 | use a few tools like `PANDOC` for building html from markdown. You 41 | can set these to your desired values, including `PANDOC=false` to 42 | disable building and installing html files. 43 | 44 | * The installation location will be written into some files during 45 | `make`, and will then be used during `make install`. The default 46 | installation location is `prefix=/usr/local`, with `bindir`, 47 | `docdir`, `htmldir`, `mandir`, etc. being used for more 48 | specialized installation directories. For installing into a 49 | chroot environment, the `install` target(s) support 50 | `DESTDIR=/path/to/chroot`. 51 | 52 | * For changing compilation and linking, define `CPPFLAGS`, `CFLAGS`, 53 | `LDADD`, and `LDFLAGS`. 54 | 55 | You can override any of these variables from the `make` command line 56 | like e.g. 57 | 58 | ``` 59 | [user@host beep]$ make prefix=$HOME/.local 60 | [user@host beep]$ make prefix=$HOME/.local install 61 | ``` 62 | 63 | or you can put that definition (and others) into a `local.mk` file: 64 | 65 | ``` 66 | [user@host beep]$ cat>local.mk<: 5 | * 6 | * > Thanks for your interest! Gist doesn't send notifications for 7 | * > comments, if you want to get in touch with me, tweet/mail/IM me. 8 | * > 9 | * > @durka, feel free to assume its 10 | * > public domain || CC0 || MIT || Apache 2.0 :) 11 | * > I'm not sure I came up with all of it myself (like that 12 | * > _font-face trick or the usage of content with attr), but what 13 | * > I did copy should be (commonly) known patterns. 14 | * 15 | */ 16 | 17 | /* 18 | * I add this to html files generated with pandoc. 19 | */ 20 | 21 | html { 22 | font-size: 100%; 23 | overflow-y: scroll; 24 | -webkit-text-size-adjust: 100%; 25 | -ms-text-size-adjust: 100%; 26 | } 27 | 28 | body { 29 | color: #444; 30 | font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif; 31 | font-size: 12px; 32 | line-height: 1.7; 33 | padding: 1em; 34 | margin: auto; 35 | max-width: 42em; 36 | background: #fefefe; 37 | } 38 | 39 | a { 40 | color: #0645ad; 41 | text-decoration: none; 42 | } 43 | 44 | a:visited { 45 | color: #0b0080; 46 | } 47 | 48 | a:hover { 49 | color: #06e; 50 | } 51 | 52 | a:active { 53 | color: #faa700; 54 | } 55 | 56 | a:focus { 57 | outline: thin dotted; 58 | } 59 | 60 | *::-moz-selection { 61 | background: rgba(255, 255, 0, 0.3); 62 | color: #000; 63 | } 64 | 65 | *::selection { 66 | background: rgba(255, 255, 0, 0.3); 67 | color: #000; 68 | } 69 | 70 | a::-moz-selection { 71 | background: rgba(255, 255, 0, 0.3); 72 | color: #0645ad; 73 | } 74 | 75 | a::selection { 76 | background: rgba(255, 255, 0, 0.3); 77 | color: #0645ad; 78 | } 79 | 80 | p { 81 | margin: 1em 0; 82 | } 83 | 84 | img { 85 | max-width: 100%; 86 | } 87 | 88 | h1, h2, h3, h4, h5, h6 { 89 | color: #111; 90 | line-height: 125%; 91 | margin-top: 2em; 92 | font-weight: normal; 93 | } 94 | 95 | h4, h5, h6 { 96 | font-weight: bold; 97 | } 98 | 99 | h1 { 100 | font-size: 2.5em; 101 | } 102 | 103 | h2 { 104 | font-size: 2em; 105 | } 106 | 107 | h3 { 108 | font-size: 1.5em; 109 | } 110 | 111 | h4 { 112 | font-size: 1.2em; 113 | } 114 | 115 | h5 { 116 | font-size: 1em; 117 | } 118 | 119 | h6 { 120 | font-size: 0.9em; 121 | } 122 | 123 | blockquote { 124 | color: #666666; 125 | margin: 0; 126 | padding-left: 3em; 127 | border-left: 0.5em #EEE solid; 128 | } 129 | 130 | hr { 131 | display: block; 132 | height: 2px; 133 | border: 0; 134 | border-top: 1px solid #aaa; 135 | border-bottom: 1px solid #eee; 136 | margin: 1em 0; 137 | padding: 0; 138 | } 139 | 140 | pre, code, kbd, samp { 141 | color: #000; 142 | font-family: monospace, monospace; 143 | _font-family: 'courier new', monospace; 144 | font-size: 0.98em; 145 | } 146 | 147 | pre { 148 | white-space: pre; 149 | white-space: pre-wrap; 150 | word-wrap: break-word; 151 | } 152 | 153 | b, strong { 154 | font-weight: bold; 155 | } 156 | 157 | dfn { 158 | font-style: italic; 159 | } 160 | 161 | ins { 162 | background: #ff9; 163 | color: #000; 164 | text-decoration: none; 165 | } 166 | 167 | mark { 168 | background: #ff0; 169 | color: #000; 170 | font-style: italic; 171 | font-weight: bold; 172 | } 173 | 174 | sub, sup { 175 | font-size: 75%; 176 | line-height: 0; 177 | position: relative; 178 | vertical-align: baseline; 179 | } 180 | 181 | sup { 182 | top: -0.5em; 183 | } 184 | 185 | sub { 186 | bottom: -0.25em; 187 | } 188 | 189 | ul, ol { 190 | margin: 1em 0; 191 | padding: 0 0 0 2em; 192 | } 193 | 194 | li p:last-child { 195 | margin-bottom: 0; 196 | } 197 | 198 | ul ul, ol ol { 199 | margin: .3em 0; 200 | } 201 | 202 | dl { 203 | margin-bottom: 1em; 204 | } 205 | 206 | dt { 207 | font-weight: bold; 208 | margin-bottom: .8em; 209 | } 210 | 211 | dd { 212 | margin: 0 0 .8em 2em; 213 | } 214 | 215 | dd:last-child { 216 | margin-bottom: 0; 217 | } 218 | 219 | img { 220 | border: 0; 221 | -ms-interpolation-mode: bicubic; 222 | vertical-align: middle; 223 | } 224 | 225 | figure { 226 | display: block; 227 | text-align: center; 228 | margin: 1em 0; 229 | } 230 | 231 | figure img { 232 | border: none; 233 | margin: 0 auto; 234 | } 235 | 236 | figcaption { 237 | font-size: 0.8em; 238 | font-style: italic; 239 | margin: 0 0 .8em; 240 | } 241 | 242 | table { 243 | margin-bottom: 2em; 244 | border-bottom: 1px solid #ddd; 245 | border-right: 1px solid #ddd; 246 | border-spacing: 0; 247 | border-collapse: collapse; 248 | } 249 | 250 | table th { 251 | padding: .2em 1em; 252 | background-color: #eee; 253 | border-top: 1px solid #ddd; 254 | border-left: 1px solid #ddd; 255 | } 256 | 257 | table td { 258 | padding: .2em 1em; 259 | border-top: 1px solid #ddd; 260 | border-left: 1px solid #ddd; 261 | vertical-align: top; 262 | } 263 | 264 | .author { 265 | font-size: 1.2em; 266 | text-align: center; 267 | } 268 | 269 | @media only screen and (min-width: 480px) { 270 | body { 271 | font-size: 14px; 272 | } 273 | } 274 | @media only screen and (min-width: 768px) { 275 | body { 276 | font-size: 16px; 277 | } 278 | } 279 | @media print { 280 | * { 281 | background: transparent !important; 282 | color: black !important; 283 | filter: none !important; 284 | -ms-filter: none !important; 285 | } 286 | 287 | body { 288 | font-size: 12pt; 289 | max-width: 100%; 290 | } 291 | 292 | a, a:visited { 293 | text-decoration: underline; 294 | } 295 | 296 | hr { 297 | height: 1px; 298 | border: 0; 299 | border-bottom: 1px solid black; 300 | } 301 | 302 | a[href]:after { 303 | content: " (" attr(href) ")"; 304 | } 305 | 306 | abbr[title]:after { 307 | content: " (" attr(title) ")"; 308 | } 309 | 310 | .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { 311 | content: ""; 312 | } 313 | 314 | pre, blockquote { 315 | border: 1px solid #999; 316 | padding-right: 1em; 317 | page-break-inside: avoid; 318 | } 319 | 320 | tr, img { 321 | page-break-inside: avoid; 322 | } 323 | 324 | img { 325 | max-width: 100% !important; 326 | } 327 | 328 | @page :left { 329 | margin: 15mm 20mm 15mm 10mm; 330 | } 331 | 332 | @page :right { 333 | margin: 15mm 10mm 15mm 20mm; 334 | } 335 | 336 | p, h2, h3 { 337 | orphans: 3; 338 | widows: 3; 339 | } 340 | 341 | h2, h3 { 342 | page-break-after: avoid; 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | beep NEWS 2 | ========= 3 | 4 | The big and user visible changes. 5 | 6 | 1.4.xx 7 | ------ 8 | * Silence the speaker on SIGHUP (like we do on SIGINT, SIGTERM) 9 | 10 | 1.4.12 11 | ------ 12 | * Document how to override and disable packaged udev rules. 13 | * Changed the build system to be closer to the GNU makefile 14 | conventions, i.e. only one compiler/toolchain per build, default 15 | installation is prefix=/usr/local instead of prefix=/usr, use GNU 16 | style docdir= instead of RPM spec file style pkgdocdir=, etc. 17 | Still not using a `configure` script, though, as that is complex. 18 | The user writing a `local.mk` with some definitions covers 19 | everyone wanting to use the same settings across `make` 20 | invocations, though. 21 | 22 | 1.4.11 23 | ------ 24 | * Install the `contrib/morse/*` scripts just like the failure-beeps. 25 | 26 | 1.4.10 27 | ------ 28 | * Rename `CREDITS` to `CREDITS.md` and `CHANGELOG` to `NEWS.md` and 29 | reformatted them to markdown. 30 | * Fix some `__VA_ARGS__` problems with some C language compiler 31 | options. 32 | * `contrib/morse/`: Add both `perl` and `tr`+`sed` script options to 33 | have beep produce morse code by converting the output of the 34 | `morse` utility from the BSD Games package to a `beep` command 35 | line. 36 | * If built without any drivers, running `beep` will now complain and 37 | abort instead of silently (pun intended) just not beeping. 38 | * Stop using Travis CI. Use GitHub Actions workflows for CI instead. 39 | * Skip test cases using PC speaker hardware if absent (e.g. on a VM) 40 | * Improved documentation (e.g. alsamixer requirement, loading pcspkr) 41 | 42 | 1.4.9 43 | ----- 44 | * Mention default values in `beep(1)` man page and `beep --help` output. 45 | 46 | 1.4.8 47 | ----- 48 | * At build time, avoid error messages related to maybe building without 49 | git installed, or from a tarball instead of a git source tree. 50 | * Improve `issue-6-benchmark` report to help people with solving 51 | [issue #6 (evdev open/close is slooow)](https://github.com/spkr-beep/beep/issues/6). 52 | 53 | 1.4.7 54 | ----- 55 | * Install contrib scripts for both successfully and failing sounding 56 | beep note sequences. 57 | * Install man page uncompressed, so packagers can use their favoured 58 | compression format. 59 | 60 | 1.4.6 61 | ----- 62 | * Let user define `CFLAGS_*` at `make` time while internal appends 63 | still work 64 | 65 | 1.4.5 66 | ----- 67 | * Use `va_copy()` macro in function with `va_list` parameter to 68 | avoid possible bug 69 | * Use `BEEP_LOG_LEVEL` environment variable for default log level 70 | 71 | 1.4.4 72 | ----- 73 | * Remove `udev/rules.d/` and `modprobe.d/` example files to force 74 | packagers to re-read `PACKAGING.md` and `PERMISSIONS.md` 75 | * Rewritten `PERMISSIONS.md` and `INSTALL.md`, adapting `README.md` 76 | and `PACKAGING.md` and `beep.1` for consistency 77 | * Allow beep to run as non-root, even if `SUDO_*` env variables are 78 | present 79 | * Fix newline escaping when generating `beep-usage.c` 80 | * By default, use plain `-g` instead of `-gstabs` 81 | * Ensure the gcc compiler used actually supports the default flags 82 | in `CFLAGS_gcc` 83 | 84 | 1.4.3 85 | ----- 86 | * Only use `-fcf-protection` `CFLAGS_gcc` if actually supported on 87 | this platform 88 | 89 | 1.4.2 90 | ----- 91 | * Improved `beep(1)` man page and `--help` output 92 | * Cleaned signal handlers of all function calls 93 | * Use beep driver infrastructure (`console` and `evdev` drivers) 94 | * Abort on unhandled command line parameters 95 | * Use `nanosleep(2)` instead of `usleep(3)` 96 | 97 | 1.4.1 98 | ----- 99 | * Safer signal handlers (`safe_error_exit()` without global 100 | variables). 101 | * Reduce accepted range of input numbers. 5 minute beeps should 102 | still be long enough. 103 | 104 | 1.4.0 105 | ----- 106 | * Fix CVE-2018-1000532 External Control of File Name or Path 107 | vulnerability in `--device` option 108 | * Fix CVE-2018-0492 race condition that allows local privilege 109 | escalation 110 | * Make `/dev/input/by-path/platform-pcspkr-event-spkr` the default 111 | device to use as the system administrator can allow access to that 112 | without needing any privilege escalation risks via setuid or 113 | `sudo`. 114 | * Adapt `--help` output, `beep(1)` man page, `README.md`, 115 | `INSTALL.md` to reflect the new device use. 116 | * Add basic suite of tests. 117 | * Constrained a few integers to avoid integer overflows. 118 | * Only issue fallback `\a` type beeps if that `\a` actually goes to 119 | a tty device which can actually beep 120 | * Stop promoting floating point frequencies which no Kernel API can 121 | even use 122 | 123 | 1.3 124 | --- 125 | * 8 years have passed! 126 | * Integrated a bunch of Gerfried Fuchs' changes maintained for the 127 | debian version for years and years 128 | * Added him to the `CREDITS`, too. 129 | * Support for devfs, and alternate console devices. 130 | * Warnings about multiply-specified frequency 131 | * Debug mode 132 | 133 | 1.2.2 134 | ----- 135 | * Man pages now `gzip -9` for better compression 136 | * Table of frequencies added to man page 137 | * Fix for platforms with unsigned chars 138 | * On `ioctl()` errors, beep will now do a `printf("\a")` so that, at 139 | very least, you get a beep. :) 140 | 141 | 142 | 1.2.1 143 | ----- 144 | * fixed segfault when handling long options 145 | 146 | 1.2.0 147 | ----- 148 | * added `-n`/`--new` support - so beep FINALLY handles multiple 149 | beeps on a single command line. 150 | * `-f` now takes decimal frequencies, not just whole numbers. 151 | 152 | 1.0.2 153 | ----- 154 | * Added more common `-V` option, as companion to `-v` and 155 | `--version` 156 | * `README` now addresses the question of multiple beeps, and 157 | composing music with beep. 158 | 159 | 1.0.1 160 | ----- 161 | * Fixed some outdated comments in the source, and a typo in the man 162 | page. 163 | 164 | 1.0.0 165 | ----- 166 | * added a `SIGINT` handler, so Ctrl-C no longer leaves the speaker 167 | wailing forever 168 | * added `-v`/`--version` and `-h`/`--help` support 169 | * updated man page 170 | * this release is changed from 0.8 to 1.0.0, it's worthy of it. 171 | Feature complete and no outstanding bugs that I know of. 172 | 173 | 0.6.1 174 | ----- 175 | * changed man page to gzip format (instead of bzip2) 176 | * updated man page and `README` to explain ioctl problems 177 | 178 | 179 | 0.6 180 | --- 181 | * added `-D` option. Both `-d` and `-D` set inter-repetition delay, 182 | but `-D` instructs beep to delay even after the last beep, where 183 | `-d` delays only between beeps, and terminates immediately after 184 | last beep. 185 | * incorporated Rick Franchuk's idea of stdin hooks - dear god `-c` 186 | is annoying. 187 | * added a man page 188 | 189 | 190 | 0.5 191 | --- 192 | * changed over from manually parsing command line parms to `getopt()` 193 | * changed `atoi()` calls into `sscanf()` calls, to get more 194 | meaningful error handling 195 | 196 | 0.4 197 | --- 198 | * first usable 199 | * initial options supported: `-f`, `-l`, `-d`, `-r` 200 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | beep - beep the PC loudspeaker on Linux 2 | ======================================= 3 | 4 | ![Build Status](https://github.com/spkr-beep/beep/actions/workflows/beep-build.yml/badge.svg) 5 | 6 | `beep` allows you to have the PC speaker issue beeps and beep patterns 7 | with given frequencies, durations, and spacing on Linux systems. 8 | 9 | Beginning in 2019, this version of `beep` can be found at 10 | [github.com/spkr-beep/beep/](https://github.com/spkr-beep/beep/). Please 11 | report bugs and other problems at 12 | [github.com/spkr-beep/beep/issues](https://github.com/spkr-beep/beep/issues). 13 | 14 | This version of `beep` has been forked from Johnathan Nightingales' 15 | original `beep` when [CVE-2018-0492 and 16 | CVE-2018-1000532](https://github.com/johnath/beep/issues/11) required 17 | fixes in 2018, while Johnathan Nightingales' 18 | [github.com/johnath/beep/](https://github.com/johnath/beep/) and 19 | [johnath.com/beep/](http://johnath.com/beep/) was only maintained from 20 | around 2000 until around 2013. 21 | 22 | 23 | What beep does 24 | -------------- 25 | 26 | * Parse the command line arguments 27 | 28 | * Find a suitable device file and API to use on it. 29 | 30 | * Set up signal handlers to silence the beeping in case the `beep` 31 | process is interrupted or killed before it has a chance to silence 32 | the PC speaker again. 33 | 34 | * Depending on the command line arguments, either 35 | 36 | * beep in the frequencies, sequencing and timing given on the 37 | command line until the sequence has finished. 38 | 39 | * when used in a pipe, beep for every character or line passing 40 | through the pipe until said pipe is finished. 41 | 42 | 43 | What beep does not do 44 | --------------------- 45 | 46 | * `beep` does not serialize or multiplex access to the one PC 47 | speaker hardware. The sound from a `beep` process playing a very 48 | long note will be silenced as soon as another short `beep` process 49 | starts its note, and after the short `beep` finishes, the PC 50 | speaker will remain silent for the remainder of the long note's 51 | duration. 52 | 53 | * `beep` does not work on platforms and systems without a PC speaker 54 | or compatible hardware. 55 | 56 | 57 | How beep works internally 58 | ========================= 59 | 60 | The evdev API 61 | ------------- 62 | 63 | The Linux evdev API uses `write(2)` to write `EV_SND`/`SND_TONE` 64 | input_event data to the 65 | `/dev/input/by-path/platform-pcspkr-event-spkr` device file. 66 | 67 | The system administrator can set up normal file permissions on the 68 | device file to allow beeping access for certain users and groups. 69 | 70 | See [`PERMISSIONS.md`](PERMISSIONS.md) for more details on permission 71 | setup. 72 | 73 | 74 | The console API 75 | --------------- 76 | 77 | In order to be allowed to run the `KIOCSOUND` `ioctl(2)` of the 78 | classical Linux console API, the Linux kernel insists you must either 79 | be root or own the current TTY (e.g. non-root user logged in on 80 | `/dev/tty4`). 81 | 82 | `beep` only uses this API as a fallback. 83 | 84 | 85 | Documentation 86 | ============= 87 | 88 | The documentation files shipped with the `beep` source tree, sorted 89 | alphabetically: 90 | 91 | * [`COPYING`](COPYING) 92 | The licensing text. 93 | 94 | * [`CREDITS.md`](CREDITS.md) 95 | Giving credit where credit is due. 96 | 97 | * [`DEVELOPMENT.md`](DEVELOPMENT.md) 98 | Information for developers working on improving beep. 99 | 100 | * [`INSTALL.md`](INSTALL.md) 101 | How to build and install `beep` from source tree. 102 | 103 | * [`NEWS.md`](NEWS.md) 104 | Contains a list of the high level changes between `beep` releases. 105 | 106 | * [`PACKAGING.md`](PACKAGING.md) 107 | How to package `beep` for a Linux distribution. 108 | 109 | * [`PERMISSIONS.md`](PERMISSIONS.md) 110 | How to set up the permissions to allow non-root users to run 111 | `beep`. Covers installing from source tree, and distro package 112 | following and not following the beep suggested udev rule setup. 113 | 114 | * [`README.md`](README.md) 115 | This basic overview on `beep` including the history kept over from 116 | the old `README` file. 117 | 118 | 119 | Present presence of beep in the Linux distro landscape 120 | ====================================================== 121 | 122 | The following graphic from repology.org gives an overview of the prevalence 123 | of beep in the Linux distribution landscape. 124 | 125 | More detailed information on miscellaneous distributions' `beep` packages 126 | can be found at the [repology.org beep page](https://repology.org/project/beep/packages). 127 | 128 | [![Packaging status](https://repology.org/badge/vertical-allrepos/beep.svg?columns=4&minversion=1.4.2)](https://repology.org/badge/vertical-allrepos/beep.svg?columns=4&minversion=1.4.2) 129 | 130 | 131 | The history of beep 132 | =================== 133 | 134 | In late 2018, while trying to come up with a fix for CVE-2018-1000532 135 | for the Fedora package, Hans Ulrich Niedermann had to find out 136 | exactly how `beep` works, and found out that the API to use in this 137 | day and age (the evdev API) was not even in available `beep`'s default 138 | configuration, or documented with the proper device name. So a few 139 | bits in the code had to be changed, a lot of documentation had to be 140 | changed, and eventually the changes had accumulated to so much that 141 | the result could not really be called `beep-1.3` any more. 142 | 143 | However, with the last repository activity in early 2013, Johnathan's 144 | github beep repository had been basically unmaintained for almost 6 years, 145 | so Hans Ulrich created https://github.com/spkr-beep/beep/ as a new home 146 | for beep. All contributors are welcome there, old and new. 147 | 148 | This following part has been taken from the original `README` by 149 | original `beep` author Johnathan Nightingale where he tells how `beep` 150 | came about. 151 | 152 | > I just got so tired of being limited to `printf("\a");` when I wanted a terminal 153 | > beep. This program isn't supposed to be anything stupendous, it's just 154 | > supposed to get the job done. Its intended purpose in life is to live inside 155 | > shell/perl scripts, and allow a little more granularity than you get with the 156 | > default terminal bell. Maybe I'm the only one who thinks this is useful. :) 157 | > 158 | > If for any reason you decide you need to, contact me: 159 | > 160 | > `johnath@johnath.com` 161 | > http://johnath.com/ 162 | > 163 | > And beep can generally be found at: 164 | > 165 | > http://johnath.com/beep/ 166 | > 167 | > For installation instructions, see `INSTALL`. 168 | > For copying and (non-)warranty information, see `COPYING`. 169 | > For usage information, check the man page. 170 | > 171 | > There is a github repository of this code at: git://github.com/johnath/beep.git 172 | > 173 | > 174 | > Playing Songs 175 | > ------------- 176 | > 177 | > A surprising number of people have sent in requests, or even patches, to help 178 | > beep play multiple, different sounds off a single invocation. I had always 179 | > thought that if people wanted a more complex melody, they would just do 180 | > something like: 181 | > 182 | > $ cat << EOF > song.sh 183 | > #!/bin/sh 184 | > beep 185 | > beep 186 | > etc... 187 | > EOF 188 | > 189 | > Nevertheless, because of repeated and vociferous demand, version 1.2 (and 190 | > presumably all later versions) include the -n/--new switch which allows you to 191 | > use one command line to create multiple beeps. Check the man page for 192 | > details. I have also had a couple people suggest that I encourage the 193 | > development of such shell scripts/command lines, even collect the particularly 194 | > melodious ones. Certainly if anyone feels like sending some to me, I will put 195 | > them somewhere visible, or even include them as a sample. I think Dvorak's New 196 | > World Symphony, 4th Movement, for example, would make a lovely shell script. 197 | > I also wouldn't mind a rendition of BNL's If I had a million dollars. But by 198 | > all means, be creative. 199 | > 200 | > All files copyright (C) Johnathan Nightingale, 2002. 201 | > All files distributed under the GNU general public license. 202 | -------------------------------------------------------------------------------- /PERMISSIONS.md: -------------------------------------------------------------------------------- 1 | Permission setup for beep 2 | ========================= 3 | 4 | The `beep` command needs write access to the 5 | `/dev/input/by-path/platform-pcspkr-event-spkr` device special file 6 | which will be a symlink to the actual device special file called 7 | something like `/dev/input/event20`. 8 | 9 | This device special file is created when the `pcspkr.ko` PC speaker 10 | driver kernel module is loaded. The permissions given to that device 11 | special file can be changed by adding some `udev(7)` rules. 12 | 13 | The `beep` package suggests the udev rules mentioned in the sections 14 | [Users currently logged into virtual 15 | console](#users-currently-logged-into-virtual-console) and [All other 16 | users](#all-other-users) below are installed by distro package or 17 | manually by the system administrator. 18 | 19 | Then the system administrator can easily give users access to the PC 20 | speaker device as described in the [Add users to `beep` 21 | group](#add-users-to-beep-group) section at the bottom 22 | of this file. 23 | 24 | 25 | udev rules 26 | ========== 27 | 28 | 29 | udev rule basics 30 | ---------------- 31 | 32 | Whenever a new device is added to or removed from the system, the 33 | `udev(7)` system will apply its rules to the device. 34 | 35 | Every rule consists of a part to match a particular type of device 36 | (with comparison operators such as `==`), and a part which does 37 | something about that device, such as modifying or setting one or more 38 | variable (e.g. `+=' or `=`), which can change the device file's mode 39 | or ownership or file ACL. 40 | 41 | See the sections below for example rules suggested for `beep`. 42 | 43 | 44 | Where to install udev rules 45 | --------------------------- 46 | 47 | There are two locations where `udev(7)` rules can be installed: 48 | 49 | * `/usr/lib/udev/rules.d/*.rules` or `/lib/udev/rules.d/*.rules` 50 | This is the distribution dependent directory where distribution 51 | binary packages will install their static rules which are not to 52 | be modified by the system administrator. 53 | 54 | * `/etc/udev/rules.d/*.rules` 55 | This where the system administrator will install their special 56 | rules independent of any distribution packages. 57 | 58 | This location is suitable when a system administrator is 59 | installing `beep` from source tree, or when the system 60 | administrator wants to install their own rules to override the 61 | distro package provided ones. 62 | 63 | This is also where a sysadmin can override a file from 64 | `/usr/lib/udev/rules.d/` or `/lib/udev/rules.d/` by creating a 65 | file of the same name in `/etc/udev/rules.d/`. This file can 66 | contain different udev rules, or be empty (or a symlink to 67 | `/dev/null`) to just disable the rules from that file. 68 | 69 | 70 | Users currently logged into virtual console 71 | ------------------------------------------- 72 | 73 | Making use of modern GNU/Linux/freedesktop/etc. systems' session and 74 | udev magic, you can give the user logged into the currently active 75 | virtual console session access to the PC speaker by dropping the 76 | following rule into a udev rule file like 77 | `/usr/lib/udev/rules.d/70-pcspkr-beep.rules` or 78 | `/lib/udev/rules.d/70-pcspkr-beep.rules` (the exact location depends 79 | on your distribution): 80 | 81 | ``` 82 | # Give write access to the PC speaker to the user logged in on the current virtual console 83 | ACTION=="add", SUBSYSTEM=="input", ATTRS{name}=="PC Speaker", ENV{DEVNAME}!="", TAG+="uaccess" 84 | ``` 85 | 86 | This allows `beep` to run for the user currently logged in locally 87 | without any user specific setup required. 88 | 89 | However, it will _not_ allow users logged remotely (e.g. via `ssh`) or 90 | processes running in the background to beep the PC speaker, unless the 91 | same user happens to be logged in on the currently active virtual 92 | console session at the time `beep` opens the device special file. 93 | 94 | 95 | All other users 96 | ---------------- 97 | 98 | To allow `beep`ing for users logged in remotely (e.g. via ssh) or 99 | processes running as any user other than the one logged into the 100 | currently active virtual console session, the best way is to set up a 101 | system user group `beep` and give that group write access to the 102 | device special file. 103 | 104 | The exact command to add the group varies from system to 105 | system. Choose whatever works on your system: 106 | 107 | ``` 108 | [root@host ~]# addgroup --system beep # Debian, Ubuntu, etc. 109 | 110 | [root@host ~]# groupadd --system beep # Fedora, RHEL, etc. 111 | ``` 112 | 113 | Now to allow writing to the device special file for members of the 114 | `beep` user group, you have the choice between the following two udev 115 | rules for `/usr/lib/udev/rules.d/90-pcspkr-beep.rules` or 116 | `/lib/udev/rules.d/90-pcspkr-beep.rules` (the exact location depends 117 | on your distribution). 118 | 119 | * This rule uses `setfacl(1)` to add an ACL entry to grant write 120 | access for the `beep` group without changing the standard 121 | user/group access granted by the default system setup: 122 | 123 | # Add write access to the PC speaker for the "beep" group 124 | ACTION=="add", SUBSYSTEM=="input", ATTRS{name}=="PC Speaker", ENV{DEVNAME}!="", RUN+="/usr/bin/setfacl -m g:beep:w '$env{DEVNAME}'" 125 | 126 | This ACL based rule requires installing the `acl` package on those 127 | distributions which do not install it by default yet. 128 | 129 | The nice part about just adding this one ACL is that it does not 130 | need to possibly interfere with whatever else the system does to 131 | the device, e.g. to implement the effects of `TAG+="uaccess"`. 132 | 133 | * The following non-ACL rule grants access to the `beep` group by 134 | changing the owning group, removing access for the default group 135 | `input`: 136 | 137 | # Give write access to the PC speaker only to the "beep" group 138 | ACTION=="add", SUBSYSTEM=="input", ATTRS{name}=="PC Speaker", ENV{DEVNAME}!="", GROUP="beep", MODE="0620" 139 | 140 | 141 | Verifying the udev rules work 142 | ----------------------------- 143 | 144 | You will have to (re-)load the `pcspkr.ko` module to (re-)add the 145 | device so that the new rule is invoked: 146 | 147 | ``` 148 | [root@host ~]# modprobe -r pcspkr; sleep 2; modprobe pcspkr 149 | [root@host ~]# _ 150 | ``` 151 | 152 | Check that the device has the desired permissions with `ls` and/or 153 | `getfacl` (`getfacl` only if you are using ACLs). 154 | 155 | A working non-ACL setup might look something like 156 | 157 | ``` 158 | [root@host ~]# ls -lH /dev/input/by-path/platform-pcspkr-event-spkr 159 | crw-rw----. 1 jane beep 13, 84 Apr 8 07:35 /dev/input/by-path/platform-pcspkr-event-spkr 160 | [root@host ~]# _ 161 | ``` 162 | 163 | and a working ACL setup might look something like 164 | 165 | ``` 166 | [root@host ~]# ls -lH /dev/input/by-path/platform-pcspkr-event-spkr 167 | crw-rw----+ 1 root input 13, 84 Apr 8 07:35 /dev/input/by-path/platform-pcspkr-event-spkr 168 | [root@host ~]# getfacl /dev/input/by-path/platform-pcspkr-event-spkr 169 | getfacl: Removing leading '/' from absolute path names 170 | # file: dev/input/by-path/platform-pcspkr-event-spkr 171 | # owner: root 172 | # group: input 173 | user::rw- 174 | user:jane:rw- 175 | group::rw- 176 | group:beep:-w- 177 | mask::rw- 178 | other::--- 179 | 180 | [root@host ~]# _ 181 | ``` 182 | 183 | 184 | General rules for permissions setup 185 | ----------------------------------- 186 | 187 | To keep your system secure, try to keep your permissions as 188 | restrictive as possible, while allowing for what you want. Give access 189 | to a single user. Give access to a special group of users. 190 | 191 | Here are a few __bad ideas__ you should __avoid__ when you change the 192 | permissions setup: 193 | 194 | * DO NOT add users to the `input` group 195 | This would allow the users from the `input` group access to 196 | __all__ input devices. This includes keyboards and mice which are 197 | none of their business (think keyloggers or reprogramming 198 | programmable keyboards). 199 | 200 | * DO NOT run `beep` setuid root or via sudo-root 201 | There have been a few serious security issues for `beep` in 2018 202 | (CVE-2018-0492 and CVE-2018-1000532). Both had their impact when 203 | `beep` was run setuid root or via sudo-root. 204 | 205 | Therefore, `beep` now checks whether it is being run setuid root 206 | or via sudo-root, and if so, `beep` aborts without doing anything 207 | else, because that something else might turn out to be harmful. 208 | Also, this reminds people still using setuid-root or sudo-root 209 | setups to switch to the new more granular permission setup. 210 | 211 | 212 | Add users to `beep` group 213 | ========================= 214 | 215 | The suggested way to regulate permissions to the speaker device is to 216 | have the system administrator add all users who should be able to run 217 | beep to the `beep` group. 218 | 219 | To add user `jane` to the `beep` group, the system administrator has 220 | to run a command like 221 | 222 | ``` 223 | [root@host ~]# usermod jane -a -G beep 224 | ``` 225 | 226 | After having user `jane` log out (and after killing user `jane`'s 227 | running `tmux` instances, killing `system --user` sessions for user 228 | `jane`, or just plain rebooting), user `jane` can log back in and 229 | check whether she now is a `beep` group member: 230 | 231 | ``` 232 | [jane@host ~]$ id 233 | uid=1000(jane) gid=1000(jane) groups=1000(jane),10(wheel),942(beep) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 234 | [jane@host ~]$ ./beep -f 220 -n -f 275 -n -f 330 -n -f 440 -n -f 550 -n -f 660 -n -f 880 235 | [jane@host ~]$ _ 236 | ``` 237 | -------------------------------------------------------------------------------- /PACKAGING.md: -------------------------------------------------------------------------------- 1 | Packaging beep for Linux distributions 2 | ====================================== 3 | 4 | This file contains a number of ideas and suggestions and references to 5 | other documentation which might come in helpful in case you are 6 | packaging `beep` for a Linux distribution. 7 | 8 | In addition, to a packager of `beep`, [`INSTALL.md`](INSTALL.md) might 9 | also be interesting. 10 | 11 | If this file leaves open a packaging question, please file an issue at 12 | https://github.com/spkr-beep/beep/issues so we can see whether we can 13 | improve the documentation or the packaging procedure on the beep side. 14 | 15 | 16 | Building and installing 17 | ----------------------- 18 | 19 | The building and installing during a package build can be achieved with 20 | 21 | ```sh 22 | make 23 | make install-nobuild DESTDIR=/path/to/package-root 24 | ``` 25 | 26 | While not strictly necessary, using `make install-nobuild` makes sure 27 | that no compilation happens during the installation phase. 28 | 29 | You can also add to the default compiler flags by setting or adding to 30 | `CFLAGS`, `CPPFLAGS`, `LDFLAGS`, and `LDADD`, by running `make` like 31 | e.g. 32 | 33 | ```sh 34 | make CFLAGS="-O -g -flto=auto -ffat-lto-objects" CPPFLAGS="-I/opt/include" LDFLAGS="-f" LDADD="-L/opt/lib -lmoo" 35 | ``` 36 | 37 | or putting those definitions into the `local.mk` file. 38 | 39 | The buildsystem will use whatever compiler `CC` is set to. `clang` and 40 | `gcc` are known to work, other toolchains might. 41 | 42 | ```sh 43 | make CC=clang 44 | ``` 45 | 46 | If your package build has `pandoc` available and working, HTML files 47 | will be built from the markdown files and installed later. If you do 48 | not want HTML files built and installed, you can set `PANDOC=false`. 49 | 50 | If you need to set any of the `*dir` variables like `prefix` or 51 | `docdir` on the `make` command line, you need to set them for both the 52 | build step (`make`) and for the install step (`make install`). You 53 | might either give the very same command line for every invocation of 54 | `make`, or you can write those definitions into a make include file 55 | called `local.mk` once. For example, you might want to achieve the 56 | effect of 57 | 58 | ```sh 59 | make prefix='/usr' docdir='$(docdir)/$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)' 60 | make prefix='/usr' docdir='$(docdir)/$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)' DESTDIR=/path/to/package-root install 61 | ``` 62 | 63 | by creating a `local.mk` which might look as follows in e.g. an RPM 64 | spec file: 65 | 66 | ```sh 67 | cat>local.mk< local.mk 81 | echo 'prefix = /usr' >> local.mk 82 | echo 'CFLAGS = $(shell dpkg-buildflags --get CFLAGS)' >> local.mk 83 | ``` 84 | 85 | Files to install for beep 86 | ------------------------- 87 | 88 | ### User facing files 89 | 90 | * `/usr/bin/beep` 91 | The `beep` executable. 92 | 93 | * `/usr/share/man/man1/beep.1` 94 | 95 | Man page for the `beep` executable. 96 | 97 | If your distribution package ships a special `README.Distro` file 98 | (such as `README.Debian` or `README.fedora`), you might want to 99 | add a reference to that file in the man page's __SEE ALSO__ 100 | section instead of the commented out placeholder reference to 101 | `README.Distro`. 102 | 103 | ### Documentation files 104 | 105 | * `/usr/share/doc/beep/README.md` 106 | General description of `beep`. 107 | 108 | * `/usr/share/doc/beep/PERMISSIONS.md` 109 | Gives package users and system administrators the information they 110 | need to successfully set up device permissions for non-root users. 111 | 112 | Covers installing from source tree, and distro package following 113 | and not following the beep suggested udev rule setup. 114 | 115 | * `/usr/share/doc/beep/NEWS.md` 116 | 117 | * `/usr/share/doc/beep/COPYING` 118 | 119 | * `/usr/share/doc/beep/CREDITS.md` 120 | 121 | The files [`INSTALL.md`](INSTALL.md), 122 | [`DEVELOPMENT.md`](DEVELOPMENT.md), [`PACKAGING.md`](PACKAGING.md) are 123 | not useful for binary packages. They only make sense for source 124 | trees. 125 | 126 | 127 | ### System setup including permissions 128 | 129 | * `/etc/modprobe.d/pcspkr-beep.conf` 130 | When the system administrator uncomments the `alias` line, this 131 | tells the system to load the `pcspkr.ko` kernel module: 132 | 133 | alias platform:pcspkr pcspkr 134 | 135 | Without `pcspkr.ko` loaded, there will be no sound from the PC 136 | speaker at all. 137 | 138 | Use, change, replace as is fitting for your distribution. 139 | 140 | * `/usr/lib/udev/rules.d/70-pcspkr-beep.rules` or `/lib/udev/rules.d/70-pcspkr-beep.rules` (location depends on distribution) 141 | 142 | If you want to use the suggested permission setup, ship this 143 | file. For the contents, cf. [`PERMISSIONS.md`](PERMISSIONS.md). 144 | 145 | Use, change, replace as is fitting for your distribution. 146 | 147 | * `/usr/lib/udev/rules.d/90-pcspkr-beep.rules` or `/lib/udev/rules.d/90-pcspkr-beep.rules` (location depends on distribution) 148 | 149 | If you want to use the suggested permission setup, ship this 150 | file. For the contents, cf. [`PERMISSIONS.md`](PERMISSIONS.md). 151 | 152 | Use, change, replace as is fitting for your distribution. 153 | 154 | * Shipping the two permission approaches (`TAG+="uaccess"` and the 155 | group based one) in separate udev rule files allows the sysadmin 156 | to override or completely disable either one of those rules by 157 | placing a file of the same name into `/etc/udev/rules.d/`, which 158 | does not require changing things in `/usr` which might be a 159 | readonly filesystem or be overwritten by the next update of the 160 | beep packge. 161 | 162 | * Add a `beep` system user group 163 | 164 | If you want to use the suggested permission setup 165 | (cf. [`PERMISSIONS.md`](PERMISSIONS.md)), have the package run 166 | something like e.g. 167 | 168 | # Fedora, RHEL, etc. 169 | getent group beep >/dev/null || groupadd --system beep 170 | 171 | # Debian, Ubuntu, etc. 172 | getent group beep >/dev/null || addgroup --system beep 173 | 174 | inside the package installation scripts. 175 | 176 | * `/usr/share/doc/beep/PERMISSIONS.md` 177 | 178 | The [`PERMISSIONS.md`](PERMISSIONS.md) file describes to system 179 | administrators how to give users permissions to actually beep the 180 | PC speaker, both with the suggested udev rules, and generally. 181 | 182 | If your distribution ships a different set of udev rules, you 183 | should describe those in some distribution specific README file 184 | (like e.g. `README.Debian` or `README.fedora`). 185 | 186 | All files installed into `/etc` are config files which the system 187 | administrator may change and expect to not be overwritten with 188 | package updates. 189 | 190 | The sysadmin may add their own udev rules to `/etc/udev/rules.d/` 191 | which should not be touched by the `beep` package. 192 | 193 | 194 | Architectures 195 | ============= 196 | 197 | PC platforms 198 | ------------ 199 | 200 | `beep` was written for the x86 platform, and works on both 32bit 201 | and 64bit x86 platforms. 202 | 203 | 204 | Non-PC platforms implementing the `EV_SND`/`SND_TONE` interface 205 | --------------------------------------------------------------- 206 | 207 | From a cursory glance through the Linux kernel source code, there 208 | appear to be a number of devices implementing the same 209 | `EV_SND`/`SND_TONE` evdev interface `pcspkr.ko` implements, like 210 | e.g. `m68kspkr` or `sparcspkr`. 211 | 212 | It would be interesting to know on which non-PC platforms `beep` 213 | actually makes sense. The S/390 e.g. probably does not belong to 214 | the systems where beeper hardware is to be expected. 215 | 216 | 217 | Platforms without `pcspkr.ko` or other `EV_SND`/`SND_TONE` devices 218 | ------------------------------------------------------------------ 219 | 220 | For platforms *without* a PC speaker, packaging beep only makes sense 221 | if there is both hardware support for beeping, and software support 222 | for that hardware. 223 | 224 | At this time, `beep` provides no software support for any of those 225 | platforms. 226 | 227 | 228 | Packages 229 | ======== 230 | 231 | The following is a list of links to some distributions' packages of 232 | `beep`: 233 | 234 | * [archlinux](https://www.archlinux.org/) 235 | [overview](https://www.archlinux.org/packages/extra/x86_64/beep/) 236 | [sources](https://git.archlinux.org/svntogit/packages.git/tree/trunk?h=packages/beep) 237 | [bugs](https://bugs.archlinux.org/?project=1&string=beep) 238 | 239 | * [Debian](https://www.debian.org/) 240 | [overview](https://packages.debian.org/search?keywords=beep) 241 | [tracker](https://tracker.debian.org/pkg/beep) 242 | [sources](https://sources.debian.org/src/beep/) 243 | [bugs](https://bugs.debian.org/cgi-bin/pkgreport.cgi?package=beep) 244 | [unstable bugs](https://bugs.debian.org/cgi-bin/pkgreport.cgi?dist=unstable;package=beep) 245 | 246 | * [Fedora](https://getfedora.org/) 247 | [overview](https://apps.fedoraproject.org/packages/beep) 248 | [bugs](https://apps.fedoraproject.org/packages/beep/bugs/) 249 | [sources](https://src.fedoraproject.org/rpms/beep) 250 | 251 | * [Gentoo](https://www.gentoo.org/) 252 | [overview](https://packages.gentoo.org/packages/app-misc/beep) 253 | [sources](https://gitweb.gentoo.org/repo/gentoo.git/tree/app-misc/beep) 254 | [bugs](https://bugs.gentoo.org/buglist.cgi?quicksearch=app-misc%2Fbeep) 255 | 256 | * [OpenWRT](https://openwrt.org/) 257 | [overview](https://openwrt.org/packages/pkgdata/beep) 258 | [bugs](https://github.com/openwrt/packages/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+beep) 259 | [sources](https://github.com/openwrt/packages/tree/master/utils/beep) 260 | [sources openwrt-18.06](https://github.com/openwrt/packages/tree/openwrt-18.06/utils/beep) 261 | 262 | * [openSUSE](https://www.opensuse.org/) 263 | [overview](https://software.opensuse.org/package/beep) 264 | [overview](https://build.opensuse.org/package/show/home%3AChristianMauderer%3Aopensuse-installations/beep) 265 | 266 | * [Raspbian](https://www.raspbian.org/) 267 | Sources: See Debian. 268 | 269 | * [Ubuntu](https://www.ubuntu.com/) 270 | http://packages.ubuntu.com/src:beep 271 | Sources: See Debian. 272 | 273 | More information on miscellaneous distributions' `beep` packages can be found 274 | at the [repology.org beep page](https://repology.org/project/beep/packages). 275 | 276 | [![Packaging status](https://repology.org/badge/vertical-allrepos/beep.svg?columns=4&minversion=1.4.2)](https://repology.org/badge/vertical-allrepos/beep.svg?columns=4&minversion=1.4.2) 277 | -------------------------------------------------------------------------------- /beep.1.in: -------------------------------------------------------------------------------- 1 | .\" The beep(1) man page 2 | .\" 3 | .\" This man page has been rewritten adhering to the following 4 | .\" documentation: man(7), man-pages(7), tbl(1) 5 | .\" 6 | .TH BEEP 1 "2020\-01\-01" "Linux" "User commands" 7 | .\" 8 | .\" ==================================================================== 9 | .\" 10 | .SH NAME 11 | beep \- beep the pc speaker any number of ways 12 | .\" 13 | .\" ==================================================================== 14 | .\" 15 | .SH SYNOPSIS 16 | .B beep 17 | .RB [\| GLOBALS \|] 18 | .RB [\| \-f 19 | .IR FREQ \|] 20 | .RB [\| \-l 21 | .IR LEN \|] 22 | .RB [\| \-r 23 | .IR REPEATS \|] 24 | .RB [\|< \-d|\-D > 25 | .IR DELAY \|] 26 | .RB [\| \-s \|] 27 | .RB [\| \-c \|] 28 | .br 29 | .B beep 30 | .RB [\| GLOBALS \|] 31 | .RI <\| TONE_OPTIONS \|> 32 | .RB [\| \-n|\-\-new \|] 33 | .RI <\| TONE_OPTIONS \|> 34 | .br 35 | .B beep 36 | .RI <\| \-h | \-\-help \|> 37 | .br 38 | .B beep 39 | .RI <\| \-v | \-V | \-\-version \|> 40 | .\" 41 | .\" ==================================================================== 42 | .\" 43 | .SH DESCRIPTION 44 | .PP 45 | \fBbeep\fR allows the user to control the PC speaker with precision, allowing different sounds to indicate different events. While \fBbeep\fR can be run quite happily on the command line, \fBbeep\fR's intended use is within shell/perl scripts, notifying the user when something interesting occurs. Of course, it has no notion of what \fIIS\fR interesting, but it is good at the notifying part. 46 | .PP 47 | All options have default values, meaning that just typing '\fBbeep\fR' will work. If an option is specified more than once on the command line, subsequent options override their predecessors. So '\fBbeep\fR \-f 200 \-f 300' will beep at 300Hz. 48 | .PP 49 | All durations are given in a unit of milliseconds, frequencies as Hertz, and the number of repeats is a dimensionless number. 50 | .\" 51 | .\" ==================================================================== 52 | .\" 53 | .SH OPTIONS 54 | .SS "Global options" 55 | .TP 56 | .BI \-e\ DEVICE \fR, \ \fB\-\-device= DEVICE 57 | Explicitly set the device \fBbeep\fR shall use to generate beep tones. When not given a device explicitly, \fBbeep\fR runs through an internal list of devices until one appears to work. 58 | .TP 59 | .BR \-\-debug ,\ \-\-verbose 60 | Make the \fBbeep\fR program more verbose. 61 | .SS "Tone options" 62 | .TP 63 | .BI \-f\ FREQ 64 | Beep with a tone frequency of \fIFREQ\fR Hz, where 0 < \fIFREQ\fR < 20000. As a general ballpark, the regular terminal beep is around 750Hz. For backwards compatibility, you can give \fIFREQ\fR as a floating point number, but \fBbeep\fR will round that to integer values as the kernel APIs expect them. Default value: @DEFAULT_FREQ@ Hz. 65 | .TP 66 | .BI \-l\ LEN 67 | Beep for a tone length of \fILEN\fR milliseconds. Default value: @DEFAULT_LENGTH@ ms. 68 | .TP 69 | .BI \-r\ REPEATS 70 | Repeat the tone including delays \fIREPEATS\fR times. Default value: 1 tone, not repeated. 71 | .TP 72 | .BI \-d\ DELAY\fR\ |\ \-D\ DELAY 73 | Specify a delay of \fIDELAY\fR milliseconds between repetitions. Small letter \fB\-d\fR specifies that this delay should only occur \fIbetween\fR beeps, that is, it should \fInot\fR occur after the last repetition. Capital letter \fB\-D\fR specifies that the delay should occur after every repetition, \fIincluding\fR after the last one. Normally, \fB\-d\fR is what you want, but if, for example, you are stringing several \fBbeep\fR commands together to play the star wars anthem, you may want control over every delay. Default value: @DEFAULT_DELAY@ ms delay between beeps with no delay after the last beep. 74 | .TP 75 | .BR \-n ,\ \-\-new 76 | The \fB\-\-new\fR option allows you to chain multiple beeps together on a single command line. Each time the \fB\-\-new\FR is used, \fBbeep\fR starts treating all further arguments as though they were for a new beep. So for example: 77 | 78 | \fBbeep\fR \-f 1000 \-n \-f 2000 \-n \-f 1500 79 | 80 | would produce a sequence of three beeps, the first with a frequency of 1000Hz (and otherwise default values), then a second beep with a frequency of 2000Hz (again, with things like delay and reps being set to their defaults), then a third beep, at 1500Hz. This is different from specifying a \fB\-r\fR value, since \fB\-r\fR repeats the same beep multiple times, whereas \fB\-\-new\fR allows you to specify different beeps. After a \fB\-\-new\fR, the new beep is created with all the default values, and any of these can be specified without altering values for preceding (or later) beeps. See the \fBEXAMPLES\fR section if this managed to confuse you. 81 | .TP 82 | .BR \-s ,\ \-c 83 | Both the \fB\-s\fR and the \fB\-c\fR option put \fBbeep\fR into input processing mode, reading from \fIstdin\fR and copying all received data to \fIstdout\fR. This makes it easy to slip \fBbeep\fR into a text processing pipeline to acoustically monitor the data flow within that pipeline. See the \fBEXAMPLES\fR section. 84 | .RS 85 | .TP 86 | .BR \-c 87 | Beep after every character received. 88 | .TP 89 | .BR \-s 90 | Beep after every set of data received. Usually, this means after newlines occur in text processing pipes. 91 | .PP 92 | In a sequence of notes specified with one or more occurrences of \fB\-n\fR or \fB\-\-new\fR, it only makes sense to have one single note marked with either \fB\-s\fR or \fB\-c\fR attached to it. Then \fBbeep\fR will beep all notes until it reaches that marked note, then repeat the marked note according to the input it receives, and once the input has reached EOF, \fBbeep\fR will continue with the remainder of the note sequence. 93 | .PP 94 | The behaviour of \fBbeep\fR with more than one note marked with \fB\-s\fR or \fB\-c\fR is undefined. 95 | .RE 96 | .SS "Other Actions" 97 | .BR \-h ,\ \-\-help 98 | Display \fBbeep\fR usage info and exit. 99 | .TP 100 | .BR \-v ,\ \-V ,\ \-\-version 101 | Display \fBbeep\fR version information and exit. 102 | .\" 103 | .\" ==================================================================== 104 | .\" 105 | .SH EXIT STATUS 106 | .PP 107 | When successful, 108 | .B beep 109 | returns with exit code 0. 110 | .PP 111 | Any non\-0 exit code means 112 | .B beep 113 | has encountered an error and has bailed out. 114 | .\" 115 | .\" ==================================================================== 116 | .\" 117 | .SH ENVIRONMENT 118 | .TP 119 | .BR BEEP_LOG_LEVEL 120 | When set to a number between -999 and 999, 121 | .B BEEP_LOG_LEVEL 122 | will be used as the default loglevel until overridden by a command line parameter. 123 | .\" 124 | .\" ==================================================================== 125 | .\" 126 | .SH FILES 127 | The device files 128 | .B beep 129 | uses by default are the following: 130 | .\" 131 | /dev/input/by\-path/platform\-pcspkr\-event\-spkr 132 | /dev/tty0 133 | /dev/vc/0 134 | .\" 135 | .\" ==================================================================== 136 | .\" 137 | .SH NOTES 138 | .SS "Devices and Permissions" 139 | .PP 140 | When you run \fBbeep\fR without explicitly giving a device to use, \fBbeep\fR tries opening the following devices in sequence until one succeeds: 141 | .IP "\fB/dev/input/by\-path/platform\-pcspkr\-event\-spkr\fR" 4 142 | Uses the evdev API, and system administrator can allow access to any set of users and groups using the normal file permissions. 143 | .IP "\fB/dev/tty0\fR" 4 144 | Uses the console API, and the kernel insists you are root or own the TTY. 145 | .IP "\fB/dev/vc/0\fR" 4 146 | Uses the console API, and the kernel insists you are root or own the TTY. 147 | .PP 148 | .B beep 149 | does not support running as setuid root or via 150 | .BR "sudo" "(1)" . 151 | .PP 152 | For non\-root uses, the system administrator can set up a 153 | .BR udev "(7)" 154 | rule to allow write access to 155 | .B /dev/input/by\-path/platform\-pcspkr\-event\-spkr 156 | for certain users and/or user groups. For details, see the 157 | .B beep 158 | .B @docdir@/PERMISSIONS.md 159 | file. 160 | .\" 161 | .SS "APIs" 162 | .IP "evdev" 4 163 | Uses the input event device driver, which means running 164 | .BR "write" "(2)" 165 | on 166 | .BR /dev/input/by\-path/platform\-pcspkr\-event\-spkr . 167 | .IP 168 | The permissions to this device file can be set up such that beep can be run by any non-root user the system administrator wants to. 169 | .IP 170 | Opening this device takes on the order of magnitude of 20ms in the Linux kernel for every time you start the 171 | .B beep 172 | command. Therefore, if you need to play multiple notes in a rhythmical sequence for a melody, use one 173 | .B beep 174 | command invocation with multiple notes, not several 175 | .B beep 176 | invocations playing one note each. 177 | .IP "console" 4 178 | Uses the ancient console API, which means running the 179 | .B "KIOCSOUND" 180 | .BR "ioctl" "(2)" 181 | on a tty device like 182 | .BR /dev/tty0\ or\ /dev/vc/0. 183 | .IP 184 | This requires being root, unless the non-root user happens be logged into the virtual console and be using that specific virtual console device like e.g. \fB/dev/tty4\fR. This makes the console driver useless for non-root users logged in via ssh, and often X11 or Wayland. 185 | .IP 186 | Use the evdev API instead. 187 | .\" 188 | .SS "Concurrent Invocations" 189 | Concurrent invocations of \fBbeep\fR are not supported. There is only one tone generator in the PC hardware, and we do not manage access to that shared resource in any way. So if a first 190 | .B "beep \-f 1000 \-l 10000" 191 | process starts a long 10 second beep with 1000Hz, and 2 seconds later a second quick 192 | .B "beep \-f 2050 \-l 100" 193 | with 2050Hz comes in, you will hear that 2050Hz beep for 100ms, and then silence as the quick beep silences the tone generator. Now you will not hear that the first \fBbeep\fR process is still running after having waited for the first 2100ms of its 10000ms. You will also not hear that the first \fBbeep\fR process will silence the already silent speaker 7900ms later, i.e. 10000ms after the first \fBbeep\fR started. 194 | .\" 195 | .SS "Sound Volume" 196 | .PP 197 | The PC speaker hardware has no way to explicitly set the volume of a beep. 198 | .PP 199 | If you have a 200 | .IR "standalone PC" , 201 | however, chances are you have a piezo beeper connected to the mainboard. If you prioritize a loud beep over a certain frequency beep, you can choose to beep at a frequency close to the resonance frequency of the piezo beeper. Typical piezo beepers have a resonance frequency around 2000Hz, so you can test frequencies around that range. The author's piezo beeper is the loudest at about 2050Hz. 202 | .PP 203 | If you have a 204 | .IR "PC laptop" , 205 | chances are that your laptop will not have a piezo beeper hardware inside and that it will route the output of the pcspkr circuit to the laptop's internal speakers via the sound card mixer. In that case, you can and/or must change the mixer level for the beeper using a sound card mixer application. 206 | .\" 207 | .SS "Frequency Table" 208 | .PP 209 | This frequency table might come in handy for translating musical notes to frequencies. The frequencies are rounded to integer numbers as the kernel driver only works with integers. The column for 210 | .B "octave 4" 211 | is the octave of middle C. 212 | .\" This table was generated by the gen-freq-table script and 213 | .\" inserted into this man page manually. 214 | .TS 215 | center box; 216 | Cb | Cb s s s 217 | Cb | Cb Cb Cb Cb 218 | - | - - - - 219 | C | N N N N. 220 | note octave 221 | name 3 4 5 6 222 | C 131 262 523 1047 223 | C# 139 277 554 1109 224 | D 147 294 587 1175 225 | D# 156 311 622 1245 226 | E 165 330 659 1319 227 | F 175 349 698 1397 228 | F# 185 370 740 1480 229 | G 196 392 784 1568 230 | G# 208 415 831 1661 231 | A 220 440 880 1760 232 | A# 233 466 932 1865 233 | B 247 494 988 1976 234 | C 262 523 1047 2093 235 | .TE 236 | .\" 237 | .\" ==================================================================== 238 | .\" 239 | .SH BUGS 240 | Report bugs to 241 | .UR https://github.com/spkr\-beep/beep/issues 242 | .UE . 243 | .\" 244 | .\" ==================================================================== 245 | .\" 246 | .SH EXAMPLES 247 | .PP 248 | At its simplest (yet still effective) 249 | 250 | \fBbeep\fR 251 | .\" 252 | .PP 253 | A more interesting standalone setup 254 | 255 | \fBbeep\fR \-f 300.7 \-r 2 \-d 100 \-l 400 256 | .\" 257 | .PP 258 | As part of a log watching pipeline 259 | 260 | tail \-f /var/log/xferlog | grep 'passwd' | \fBbeep\fR \-f 1000 \-r 5 \-s 261 | .\" 262 | .PP 263 | When using \-c mode, I recommend using a short \-D, and a shorter \-l, so that the beeps do not blur together. Something like this will get you a cheesy 1970's style beep\-as\-you\-type\-each\-letter effect 264 | 265 | cat file | \fBbeep\fR \-c \-f 400 \-D 50 \-l 10 266 | .\" 267 | .PP 268 | A highly contrived example of \-n/\-\-new usage 269 | 270 | \fBbeep\fR \-f 1000 \-r 2 \-n \-r 5 \-l 10 \-\-new 271 | 272 | will produce first two 1000Hz beeps, then 5 beeps at the default tone, but only 10ms long each, followed by a third beep using all the default settings (since none are specified). 273 | .\" 274 | .PP See also the \fBFREQUENCY TABLE\fR below. 275 | .\" 276 | .\" ==================================================================== 277 | .\" 278 | .SH SEE ALSO 279 | .\" Distro packages might want to replace the next line with their README 280 | .\" .BR @docdir@/README.Distro , 281 | .BR @docdir@/README.md , 282 | .BR @docdir@/PERMISSIONS.md , 283 | .UR "https://github.com/spkr\-beep/beep" 284 | .UE 285 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /beep-main.c: -------------------------------------------------------------------------------- 1 | /** \file beep-main.c 2 | * \brief main program to beep the pc speaker any number of ways 3 | * \author Copyright (C) 2000-2010 Johnathan Nightingale 4 | * \author Copyright (C) 2010-2013 Gerfried Fuchs 5 | * \author Copyright (C) 2013-2022 Hans Ulrich Niedermann 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * 22 | * \defgroup beep_main The main program 23 | * 24 | * For more documentation on using `beep`, see the `beep-usage.txt` and 25 | * `beep.1.in` files. 26 | * 27 | * More general information can be found in the `README.md`, 28 | * `PERMISSIONS.md`, `INSTALL.md`, and if you want to create a binary 29 | * distribution package, `PACKAGING.md` file. 30 | * 31 | * In case you want to start developing `beep` itself, 32 | * `DEVELOPMENT.md` may be of interest to you. 33 | * 34 | * @{ 35 | * 36 | */ 37 | 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | 56 | #include "beep-config.h" 57 | #include "beep-compiler.h" 58 | #include "beep-drivers.h" 59 | #include "beep-library.h" 60 | #include "beep-log.h" 61 | #include "beep-types.h" 62 | #include "beep-usage.h" 63 | 64 | 65 | #define LOG_MODULE "main" 66 | 67 | 68 | /** 69 | * Version message to be printed for "beep --version". 70 | */ 71 | static 72 | const char version_message[] = 73 | PACKAGE_TARNAME " " PACKAGE_VERSION "\n" 74 | "Copyright (C) 2002-2016 Johnathan Nightingale\n" 75 | "Copyright (C) 2013-2022 Hans Ulrich Niedermann\n" 76 | "Use and Distribution subject to GPL.\n" 77 | "For information: http://www.gnu.org/copyleft/.\n"; 78 | 79 | 80 | /** 81 | * Per note parameter set. 82 | */ 83 | typedef struct beep_parms_T beep_parms_T; 84 | 85 | 86 | /* The default values are defined in beep-config.h */ 87 | 88 | 89 | /** 90 | * Per note parameter set (including heritage information and linked list pointer). 91 | */ 92 | struct beep_parms_T 93 | { 94 | unsigned int freq; /**< tone frequency (Hz) */ 95 | unsigned int length; /**< tone length (ms) */ 96 | unsigned int reps; /**< number of repetitions */ 97 | unsigned int delay; /**< delay between reps (ms) */ 98 | end_delay_E end_delay; /**< do we delay after last rep? */ 99 | 100 | /** Are we using stdin triggers? 101 | * 102 | * We have three options: 103 | * - just beep and terminate (default) 104 | * - beep after a line of input 105 | * - beep after a character of input 106 | * In the latter two cases, pass the text back out again, 107 | * so that beep can be tucked appropriately into a text- 108 | * processing pipe. 109 | */ 110 | stdin_beep_E stdin_beep; 111 | 112 | beep_parms_T *next; /**< in case -n/--new is used. */ 113 | }; 114 | 115 | 116 | /** 117 | * Global flag for signalling program abort due to signal handlers. 118 | * 119 | * Initialized as false. Written only by the signal handlers (set to 120 | * true), read only by the main thread. 121 | */ 122 | static 123 | volatile sig_atomic_t global_abort = false; 124 | 125 | 126 | /** 127 | * Signal handler for signals like SIGHUP, SIGINT and SIGTERM. 128 | * 129 | * If we get terminated in any way, it would be nice to not leave the 130 | * speaker beeping in perpetuity. 131 | * 132 | * Everything called from this signal handler must be thread-safe, 133 | * signal-safe, reentrant including all API functions. Otherwise, we 134 | * get another CVE-2018-0492. 135 | * 136 | * So we make certain we keep to using the following API calls: 137 | * 138 | * * close(2): safe 139 | * * _exit(2): safe (which exit(3) is NOT) 140 | * * bzero(3): MT-safe 141 | * * memset(3): MT-safe 142 | * * write(2): safe 143 | * * strerror_r(3): MT-safe 144 | * * strlen(3): MT-safe 145 | * 146 | * Just setting a global flag of type sig_atomic_t is MT-safe. 147 | * 148 | * @param unused_signum The signal number being handled. Unused. 149 | */ 150 | 151 | void handle_signal_global_abort(int unused_signum UNUSED_PARAM); 152 | 153 | void handle_signal_global_abort(int unused_signum UNUSED_PARAM) 154 | { 155 | global_abort = true; 156 | } 157 | 158 | 159 | /** 160 | * Print usage message, but leave exit code up to the caller. 161 | */ 162 | static 163 | void print_usage(void) 164 | { 165 | fputs(beep_usage, stdout); 166 | } 167 | 168 | 169 | /** 170 | * Print usage message and exit. 171 | */ 172 | 173 | static 174 | void usage_bail(void) 175 | __attribute__(( noreturn )); 176 | 177 | static 178 | void usage_bail(void) 179 | { 180 | print_usage(); 181 | exit(EXIT_FAILURE); 182 | } 183 | 184 | 185 | /** 186 | * Global device name parameter. 187 | * 188 | * Written by parse_command_line(), read by main() initialization. 189 | */ 190 | static 191 | char *param_device_name = NULL; 192 | 193 | 194 | /** 195 | * Parse the command line. 196 | * 197 | * argv should be untampered, as passed to main(). Beep parameters 198 | * are returned in result, subsequent parameters in `argv` will over- 199 | * ride previous ones. 200 | * 201 | * Currently valid parameters: 202 | * "-f " 203 | * "-l " 204 | * "-r " 205 | * "-d " 206 | * "-D " (similar to -d, but delay after last repetition as well) 207 | * "-s" (beep after each line of input from stdin, echo line to stdout) 208 | * "-c" (beep after each char of input from stdin, echo char to stdout) 209 | * "--verbose/--debug" 210 | * "-h/--help" 211 | * "-v/-V/--version" 212 | * "-n/--new" 213 | * 214 | * March 29, 2002 - Daniel Eisenbud points out that `ch` should be 215 | * `int`, not `char`, for correctness on platforms with unsigned 216 | * chars. 217 | * 218 | * @param argc Argument counter passed from main(). 219 | * @param argv Argument string array passed from main(). 220 | * @param result Linked list to be built by parse_command_line(). 221 | */ 222 | static 223 | void parse_command_line(const int argc, char *const argv[], beep_parms_T *result) 224 | __attribute__(( nonnull(3) )); 225 | 226 | static 227 | void parse_command_line(const int argc, char *const argv[], beep_parms_T *result) 228 | { 229 | int ch; 230 | 231 | static 232 | const struct option opt_list[] = 233 | { {"help", no_argument, NULL, 'h'}, 234 | {"version", no_argument, NULL, 'V'}, 235 | {"new", no_argument, NULL, 'n'}, 236 | {"verbose", no_argument, NULL, 'X'}, 237 | {"debug", no_argument, NULL, 'X'}, 238 | {"device", required_argument, NULL, 'e'}, 239 | {NULL, 0, NULL, 0 } 240 | }; 241 | 242 | while ((ch = getopt_long(argc, argv, "f:l:r:d:D:schvVne:", opt_list, NULL)) 243 | != EOF) { 244 | /* Temporary storage for parsing numbers for various arguments */ 245 | int argval_i = -1; 246 | unsigned int argval_u = ~0U; 247 | float argval_f = -1.0f; 248 | 249 | switch (ch) { 250 | case 'f': /* freq */ 251 | if (sscanf(optarg, "%f", &argval_f) != 1) { 252 | usage_bail(); 253 | } 254 | if ((0.0f > argval_f) || (argval_f > 20000.0f)) { 255 | usage_bail(); 256 | } 257 | argval_i = (int) (argval_f + 0.5f); 258 | argval_u = (unsigned int) argval_i; 259 | if (result->freq != 0) { 260 | LOG_WARNING("multiple -f values given, only last one is used."); 261 | } 262 | result->freq = argval_u; 263 | break; 264 | case 'l' : /* length */ 265 | if (sscanf(optarg, "%u", &argval_u) != 1) { 266 | usage_bail(); 267 | } 268 | if (argval_u > 300000U) { 269 | usage_bail(); 270 | } 271 | result->length = argval_u; 272 | break; 273 | case 'r' : /* repetitions */ 274 | if (sscanf(optarg, "%u", &argval_u) != 1) { 275 | usage_bail(); 276 | } 277 | if (argval_u > 300000U) { 278 | usage_bail(); 279 | } 280 | result->reps = argval_u; 281 | break; 282 | case 'd' : /* delay between reps - WITHOUT delay after last beep*/ 283 | if (sscanf(optarg, "%u", &argval_u) != 1) { 284 | usage_bail(); 285 | } 286 | if (argval_u > 300000U) { 287 | usage_bail(); 288 | } 289 | result->delay = argval_u; 290 | result->end_delay = END_DELAY_NO; 291 | break; 292 | case 'D' : /* delay between reps - WITH delay after last beep */ 293 | if (sscanf(optarg, "%u", &argval_u) != 1) { 294 | usage_bail(); 295 | } 296 | if (argval_u > 300000U) { 297 | usage_bail(); 298 | } 299 | result->delay = argval_u; 300 | result->end_delay = END_DELAY_YES; 301 | break; 302 | case 's' : 303 | result->stdin_beep = STDIN_BEEP_LINE; 304 | break; 305 | case 'c' : 306 | result->stdin_beep = STDIN_BEEP_CHAR; 307 | break; 308 | case 'v' : 309 | case 'V' : /* also --version */ 310 | fputs(version_message, stdout); 311 | exit(EXIT_SUCCESS); 312 | /* break; unreachable */ 313 | case 'n' : /* also --new - create another beep */ 314 | if (result->freq == 0) { 315 | result->freq = DEFAULT_FREQ; 316 | } 317 | result->next = (beep_parms_T *)malloc(sizeof(beep_parms_T)); 318 | result->next->freq = 0; 319 | result->next->length = DEFAULT_LENGTH; 320 | result->next->reps = DEFAULT_REPS; 321 | result->next->delay = DEFAULT_DELAY; 322 | result->next->end_delay = DEFAULT_END_DELAY; 323 | result->next->stdin_beep = DEFAULT_STDIN_BEEP; 324 | result->next->next = NULL; 325 | result = result->next; /* yes, I meant to do that. */ 326 | break; 327 | case 'X' : /* --debug / --verbose */ 328 | if (log_level < 999) { 329 | /* just limit to some finite value */ 330 | log_level++; 331 | } 332 | break; 333 | case 'e' : /* also --device */ 334 | if (param_device_name) { 335 | LOG_ERROR("You cannot give the --device parameter more than once."); 336 | exit(EXIT_FAILURE); 337 | } 338 | param_device_name = optarg; 339 | break; 340 | case 'h': /* also --help */ 341 | print_usage(); 342 | exit(EXIT_SUCCESS); 343 | /* break; unreachable */ 344 | default: 345 | usage_bail(); 346 | /* break; unreachable */ 347 | } 348 | } 349 | if (optind < argc) { 350 | LOG_ERROR("non-option arguments left on command line"); 351 | usage_bail(); 352 | } 353 | if (result->freq == 0) { 354 | result->freq = DEFAULT_FREQ; 355 | } 356 | } 357 | 358 | 359 | /** 360 | * Sleep for a number of milliseconds. 361 | * 362 | * @param driver The driver to close in case of #global_abort. 363 | * @param milliseconds The number of milliseconds to sleep. 364 | * 365 | * @return The nanosleep(2) result (0 if successful, -1 on signal handler or error) 366 | */ 367 | 368 | static 369 | int sleep_ms(beep_driver *driver, unsigned int milliseconds) 370 | __attribute__(( nonnull(1) )); 371 | 372 | static 373 | int sleep_ms(beep_driver *driver, unsigned int milliseconds) 374 | { 375 | const time_t seconds = milliseconds / 1000U; 376 | const long nanoseconds = (milliseconds % 1000UL) * 1000UL * 1000UL; 377 | const struct timespec request = 378 | { seconds, 379 | nanoseconds }; 380 | const int retcode = nanosleep(&request, NULL); 381 | if (global_abort) { 382 | beep_drivers_end_tone(driver); 383 | beep_drivers_fini(driver); 384 | exit(EXIT_FAILURE); 385 | } 386 | return retcode; 387 | } 388 | 389 | 390 | /** 391 | * Play one (possibly repeated) note. 392 | * 393 | * @param driver The driver to run the note on. 394 | * @param parms The note parameters. 395 | */ 396 | 397 | static 398 | void play_beep(beep_driver *driver, beep_parms_T parms) 399 | __attribute__(( nonnull(1) )); 400 | 401 | static 402 | void play_beep(beep_driver *driver, beep_parms_T parms) 403 | { 404 | LOG_VERBOSE("%d times %d ms beeps (%d ms delay between, " 405 | "%d ms delay after) @ %d Hz", 406 | parms.reps, parms.length, parms.delay, parms.end_delay, 407 | parms.freq); 408 | 409 | /* repeat the beep */ 410 | for (unsigned int i = 0; (!global_abort) && (i < parms.reps); i++) { 411 | beep_drivers_begin_tone(driver, parms.freq & 0xffff); 412 | sleep_ms(driver, parms.length); 413 | beep_drivers_end_tone(driver); 414 | if ((parms.end_delay == END_DELAY_YES) || ((i+1) < parms.reps)) { 415 | sleep_ms(driver, parms.delay); 416 | } 417 | } 418 | } 419 | 420 | 421 | /** 422 | * If stdout is a TTY, print a bell character to stdout as a fallback. 423 | */ 424 | static 425 | void fallback_beep(void) 426 | { 427 | /* Printing '\a' can only beep if we print it to a tty */ 428 | if (isatty(STDOUT_FILENO)) { 429 | fputc('\a', stdout); 430 | } 431 | } 432 | 433 | 434 | /** 435 | * Main program for `beep(1)`. 436 | * 437 | * @param argc Length of the `argv` string array. 438 | * @param argv Command line argument string array. 439 | * 440 | * @return EXIT_FAILURE in case of any error 441 | * @return EXIT_SUCCESS otherwise 442 | */ 443 | int main(const int argc, char *const argv[]) 444 | { 445 | log_init(argc, argv); 446 | 447 | /* Check for setuid and/or sudo 448 | * 449 | * Old beep (pre-1.4) mostly needed to run as root in order to use 450 | * the console API to the PC speaker. Two popular ways to achieve 451 | * that were to make the beep executable setuid-root and using 452 | * sudo and a shell alias to run beep as root. 453 | * 454 | * New beep (1.4 and later) uses the evdev API to the PC speaker 455 | * which does not require being root at all. 456 | * 457 | * As it is near impossible to make beep safe for running with 458 | * elevated privileges (beep opens files for writing, and usually 459 | * even writes to them, and checking the device file with realpath 460 | * leaks information), we now check for these two popular old 461 | * permission setups being carried over to a new beep installation 462 | * by mistake. 463 | * 464 | * These checks are not security measures for future attack 465 | * scenarios. These are checks are for detecting remainders of 466 | * old setups which have no place in a contemporary system. 467 | */ 468 | 469 | /* Bail out if running setuid or setgid. 470 | */ 471 | if ((getuid() != geteuid()) || (getgid() != getegid())) { 472 | LOG_ERROR("Running setuid or setgid, " 473 | "which is not supported for security reasons."); 474 | LOG_ERROR("Set up permissions for the pcspkr evdev device file instead."); 475 | exit(EXIT_FAILURE); 476 | } 477 | 478 | /* Bail out if running as root under sudo. 479 | */ 480 | if ((getuid() == 0) || (geteuid() == 0) || 481 | (getgid() == 0) || (getegid() == 0)) { 482 | LOG_VERBOSE("Running with root permissions. " 483 | "Checking for SUDO_* in environment."); 484 | if (getenv("SUDO_COMMAND") || getenv("SUDO_USER") || 485 | getenv("SUDO_UID") || getenv("SUDO_GID")) { 486 | LOG_ERROR("Running as root under sudo, " 487 | "which is not supported for security reasons."); 488 | LOG_ERROR("Set up permissions for the pcspkr evdev device " 489 | "file and run as non-root user instead."); 490 | exit(EXIT_FAILURE); 491 | } 492 | } 493 | 494 | /* Parse command line */ 495 | beep_parms_T *parms = (beep_parms_T *)malloc(sizeof(beep_parms_T)); 496 | if (NULL == parms) { 497 | perror("malloc"); 498 | exit(EXIT_FAILURE); 499 | } 500 | parms->freq = 0; 501 | parms->length = DEFAULT_LENGTH; 502 | parms->reps = DEFAULT_REPS; 503 | parms->delay = DEFAULT_DELAY; 504 | parms->end_delay = DEFAULT_END_DELAY; 505 | parms->stdin_beep = DEFAULT_STDIN_BEEP; 506 | parms->next = NULL; 507 | 508 | parse_command_line(argc, argv, parms); 509 | 510 | beep_driver *driver = NULL; 511 | 512 | if (param_device_name) { 513 | driver = beep_drivers_detect(param_device_name); 514 | if (!driver) { 515 | const int saved_errno = errno; 516 | LOG_ERROR("Could not open %s for writing: %s", 517 | param_device_name, strerror(saved_errno)); 518 | exit(EXIT_FAILURE); 519 | } 520 | } else { 521 | driver = beep_drivers_detect(NULL); 522 | if (!driver) { 523 | LOG_ERROR("Could not open any device"); 524 | /* Output the only beep we can, in an effort to fall back on usefulness */ 525 | fallback_beep(); 526 | exit(EXIT_FAILURE); 527 | } 528 | } 529 | 530 | LOG_VERBOSE("using %s driver (fd=%d, dev=%s)", 531 | driver->name, 532 | driver->device_fd, driver->device_name); 533 | 534 | /* At this time, we know what API to use on which device, and we do 535 | * not have to fall back onto printing '\a' any more. 536 | */ 537 | 538 | /* Memory barrier. All globals have been set up, so we make sure the 539 | * values are actually written to memory. Only then do we install 540 | * the signal handlers. 541 | * 542 | * TBD: Use C11 atomic_signal_fence() instead of "__asm__ volatile"? 543 | */ 544 | __asm__ volatile ("" : : : "memory"); 545 | 546 | /* After all the initialization has happened and the global 547 | * variables used to communicate with the signal handlers have 548 | * actually been set up properly, we can finally install the 549 | * signal handlers. As we do not start making any noises until 550 | * later, there is no need to install the signal handlers any 551 | * earlier. 552 | */ 553 | signal(SIGHUP, handle_signal_global_abort); 554 | signal(SIGINT, handle_signal_global_abort); 555 | signal(SIGTERM, handle_signal_global_abort); 556 | 557 | /* This outermost while loop handles the possibility that -n/--new 558 | * has been used, i.e. that we have a sequence of multiple beeps 559 | * specified. Each loop iteration will play, then free() one parms 560 | * instance. 561 | */ 562 | while ((!global_abort) && parms) { 563 | beep_parms_T *next = parms->next; 564 | 565 | if (parms->stdin_beep != STDIN_BEEP_NONE) { 566 | /* In this case, beep is probably part of a pipe, in which 567 | case POSIX says stdin and out should be fully buffered. 568 | This however means very laggy performance with beep 569 | just twiddling it's thumbs until a buffer fills. Thus, 570 | kill the buffering. In some situations, this too won't 571 | be enough, namely if we're in the middle of a long 572 | pipe, and the processes feeding us stdin are buffered, 573 | we'll have to wait for them, not much to be done about 574 | that. */ 575 | setvbuf(stdin, NULL, _IONBF, 0); 576 | setvbuf(stdout, NULL, _IONBF, 0); 577 | 578 | char sin[4096]; 579 | while ((!global_abort) && (fgets(sin, 4096, stdin))) { 580 | if (parms->stdin_beep == STDIN_BEEP_CHAR) { 581 | for (char *ptr=sin; (!global_abort) && (*ptr); ptr++) { 582 | putchar(*ptr); 583 | fflush(stdout); 584 | play_beep(driver, *parms); 585 | } 586 | } else { /* STDIN_BEEP_LINE */ 587 | fputs(sin, stdout); 588 | play_beep(driver, *parms); 589 | } 590 | } 591 | } else { 592 | play_beep(driver, *parms); 593 | } 594 | 595 | /* Junk each parms struct after playing it */ 596 | free(parms); 597 | parms = next; 598 | } 599 | 600 | beep_drivers_end_tone(driver); 601 | beep_drivers_fini(driver); 602 | 603 | if (global_abort) { 604 | return EXIT_FAILURE; 605 | } else { 606 | return EXIT_SUCCESS; 607 | } 608 | } 609 | 610 | 611 | /** @} */ 612 | 613 | 614 | /* 615 | * Local Variables: 616 | * c-basic-offset: 4 617 | * indent-tabs-mode: nil 618 | * End: 619 | */ 620 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | ######################################################################## 2 | # GNUmakefile for beep 3 | # 4 | # This GNUmakefile has been written to mostly follow the GNU Makefile 5 | # conventions[1], even if there is no "configure" script to accompany 6 | # the GNUmakefile. If you want to keep some definitions across "make" 7 | # invocations instead of providing them on each "make" command line, 8 | # write the definitions into a file "local.mk" make include file, e.g. 9 | # 10 | # CC = clang 11 | # prefix = $(HOME)/foo-prefix 12 | # 13 | # The GNUmakefile also internally follows some conventions known from 14 | # Automake (e.g. bin_PROGRAMS variables), but uses features specific 15 | # to GNU make to implement those Automake like features. 16 | # 17 | # This GNUmakefile makes extensive use of GNU make features and some 18 | # tricks for using GNU make, such as 19 | # * Advanced Auto Dependency Generation[2] 20 | # * Deferred Simple Variable Expansion[3] 21 | # 22 | # [1]: https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html 23 | # [2]: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ 24 | # [3]: http://make.mad-scientist.net/deferred-simple-variable-expansion/ 25 | # 26 | ######################################################################## 27 | 28 | 29 | ######################################################################## 30 | # Package metadata 31 | ######################################################################## 32 | 33 | PACKAGE_TARNAME = beep 34 | PACKAGE_VERSION = 1.4.13 35 | 36 | 37 | ######################################################################## 38 | # Installation directories 39 | ######################################################################## 40 | 41 | # We use GNU makefile conventions for directory names. 42 | 43 | prefix = /usr/local 44 | exec_prefix = $(prefix) 45 | bindir = $(exec_prefix)/bin 46 | sbindir = $(exec_prefix)/sbin 47 | datarootdir = $(prefix)/share 48 | mandir = $(datarootdir)/man 49 | man1dir = $(mandir)/man1 50 | docdir = $(datarootdir)/doc/$(PACKAGE_TARNAME) 51 | contribdir = $(docdir)/contrib 52 | htmldir = $(docdir) 53 | 54 | 55 | # TODO: We might want to autodetect which kind of $(docdir) is used on 56 | # this system. Until then, people will just need to set 57 | # docdir='$(datarootdir)/doc/$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)' 58 | # if they want to use that. Note that what the GNU makefile 59 | # conventions call $(docdir) is called other names by other 60 | # software components, e.g. %{_pkgdocdir} in RPM spec files. 61 | 62 | 63 | ######################################################################## 64 | # Tools 65 | ######################################################################## 66 | 67 | # This makes it easy to replace any of those tools with specific 68 | # versions, or to disable specific parts of the build. For example, to 69 | # test the portability of the SED commands, you can run with 70 | # SED="busybox sed", or to disable building HTML files from the 71 | # markdown files you can run with PANDOC="false". 72 | 73 | CMP = cmp 74 | DIFF = diff 75 | DOT = dot 76 | DOXYGEN = doxygen 77 | EGREP = $(GREP) -E 78 | FIND = find 79 | GIT = git 80 | GREP = grep 81 | INSTALL = install 82 | MKDIR_P = mkdir -p 83 | PANDOC = pandoc 84 | PYTHON3 = python3 85 | SED = sed 86 | TAR = tar 87 | TPUT = tput 88 | WC = wc 89 | 90 | DIFF_U = $(DIFF) -u 91 | 92 | # The _DATA and _PROGRAM variants are GNU makefile convention. 93 | # The _DIR variant is our idea. 94 | INSTALL_DIR = $(INSTALL) -m 0755 -d 95 | INSTALL_DATA = $(INSTALL) -m 0644 -p 96 | INSTALL_PROGRAM = $(INSTALL) -m 0755 -p 97 | 98 | 99 | ######################################################################## 100 | # This needs to be the first rule 101 | ######################################################################## 102 | 103 | .PHONY: all 104 | all: all-local 105 | 106 | 107 | ######################################################################## 108 | # Initialize some things for the build system 109 | ######################################################################## 110 | 111 | 112 | # Prevent make from using its built-in rules 113 | .SUFFIXES: 114 | COMPILE.c = false COMPILE.c 115 | LINK.c = false LINK.c 116 | 117 | 118 | ######################################################################## 119 | # Variables to add to later 120 | ######################################################################## 121 | 122 | dist-files = 123 | dist-files += GNUmakefile 124 | 125 | # targets to build for the "all" target 126 | all_TARGETS = 127 | 128 | # targets to build for the "check" target 129 | check_TARGETS = 130 | 131 | bin_PROGRAMS = 132 | check_PROGRAMS = 133 | contrib_DATA = 134 | contrib_SCRIPTS = 135 | sbin_PROGRAMS = 136 | CLEANFILES = 137 | html_DATA = 138 | noinst_html_DATA = 139 | man1_DATA = 140 | doc_DATA = 141 | 142 | 143 | ######################################################################## 144 | # Define compiler and linker flags 145 | ######################################################################## 146 | 147 | CLEANFILES += conftest-program.o 148 | EXTRA_DIST += conftest-program.c 149 | 150 | comma := , 151 | 152 | # If supported by $(CC), add given flags to CFLAGS type variable. 153 | # Example usage: 154 | # $(eval $(call check-cflags,common-CFLAGS,-fasynchronous-unwind-tables)) 155 | define check-cflags 156 | $(1) += $$(if $$(shell if $$(CC) $$(patsubst -Wno-%,-W%,$(2)) -x c -o compile-check.o -c - < /dev/null > /dev/null 2>&1; then echo yes; else :; fi; rm -f compile-check.o > /dev/null 2>&1),$(2)) 157 | endef 158 | 159 | # This might be useful or not. 160 | CFLAGS = 161 | CPPFLAGS = 162 | LDFLAGS = 163 | LDADD = 164 | 165 | # Flags common to all executable targets 166 | common_CFLAGS = 167 | common_CPPFLAGS = 168 | common_LDFLAGS = 169 | common_LDADD = 170 | 171 | common_CPPFLAGS += -DPACKAGE_TARNAME='"$(PACKAGE_TARNAME)"' 172 | common_CPPFLAGS += -DPACKAGE_VERSION='"$(PACKAGE_VERSION)"' 173 | common_CFLAGS += -std=gnu99 174 | ifeq (yes,$(shell if $(CC) -Wall -Wextra -Werror -Wa$(comma)-adhlns=conftest-program.lst -o conftest-program.o -c conftest-program.c 2>/dev/null; then echo yes; else echo no; fi)) 175 | common_CFLAGS += $(if $(filter %.o,$@),-Wa$(comma)-adhlns=$(@:.o=.lst)) 176 | endif 177 | common_CFLAGS += -pedantic 178 | $(eval $(call check-cflags,common_CFLAGS,-Werror=unknown-warning-option)) 179 | $(eval $(call check-cflags,common_CFLAGS,-Wno-gnu-line-marker)) 180 | $(eval $(call check-cflags,common_CFLAGS,-Wall)) 181 | $(eval $(call check-cflags,common_CFLAGS,-Wextra)) 182 | $(eval $(call check-cflags,common_CFLAGS,-Wmost)) 183 | $(eval $(call check-cflags,common_CFLAGS,-Werror)) 184 | $(eval $(call check-cflags,common_CFLAGS,-Wno-padded)) 185 | $(eval $(call check-cflags,common_CFLAGS,-Werror=format-security)) 186 | $(eval $(call check-cflags,common_CFLAGS,-Wno-disabled-macro-expansion)) 187 | $(eval $(call check-cflags,common_CFLAGS,-Wno-format-nonliteral)) 188 | $(eval $(call check-cflags,CPPFLAGS,-D_FORTIFY_SOURCE=2 -O)) 189 | $(eval $(call check-cflags,CPPFLAGS,-D_GLIBCXX_ASSERTIONS)) 190 | # $(eval $(call check-cflags,CFLAGS,-Wp$$(comma)-D_FORTIFY_SOURCE=2)) 191 | # $(eval $(call check-cflags,CFLAGS,-Wp$$(comma)-D_GLIBCXX_ASSERTIONS)) 192 | $(eval $(call check-cflags,CFLAGS,-fasynchronous-unwind-tables)) 193 | $(eval $(call check-cflags,CFLAGS,-fanalyzer)) 194 | $(eval $(call check-cflags,CFLAGS,-fstack-protector-strong)) 195 | $(eval $(call check-cflags,CFLAGS,-fstack-clash-protection)) 196 | $(eval $(call check-cflags,CFLAGS,-fcf-protection)) 197 | $(eval $(call check-cflags,CFLAGS,-fsanitize=undefined)) 198 | 199 | 200 | CFLAGS += -O2 -g 201 | CFLAGS += -save-temps=obj 202 | 203 | 204 | # Create this file to override any of the make variables defined 205 | # above. 206 | -include local.mk 207 | 208 | 209 | ifneq (,$(V)) 210 | $(info #=======================================================================) 211 | else 212 | $(info In case of build problems, try running `make' with V=1 to help find the cause.) 213 | endif 214 | 215 | 216 | ifneq (,$(V)) 217 | $(info # common_CFLAGS=$(common_CFLAGS)) 218 | $(info # common_CPPFLAGS=$(common_CPPFLAGS)) 219 | $(info # common_LDADD=$(common_LDADD)) 220 | $(info # common_LDFLAGS=$(common_LDFLAGS)) 221 | $(info # CFLAGS=$(CFLAGS)) 222 | $(info # CPPFLAGS=$(CPPFLAGS)) 223 | $(info # LDADD=$(LDADD)) 224 | $(info # LDFLAGS=$(LDFLAGS)) 225 | endif 226 | 227 | 228 | ######################################################################## 229 | # Detect libraries 230 | ######################################################################## 231 | 232 | 233 | ######################################################################## 234 | # Define executables and their flags 235 | ######################################################################## 236 | 237 | check_PROGRAMS += issue-6-benchmark 238 | issue_6_benchmark_SOURCES = issue-6-benchmark.c 239 | issue_6_benchmark_LDADD = -lm 240 | 241 | bin_PROGRAMS += beep 242 | beep_SOURCES = 243 | beep_SOURCES += beep-compiler.h 244 | beep_SOURCES += beep-types.h 245 | beep_SOURCES += beep-log.c 246 | beep_SOURCES += beep-log.h 247 | beep_SOURCES += beep-main.c 248 | beep_SOURCES += beep-library.c 249 | beep_SOURCES += beep-library.h 250 | beep_SOURCES += beep-usage.c 251 | beep_SOURCES += beep-usage.h 252 | beep_SOURCES += beep-drivers.c 253 | beep_SOURCES += beep-drivers.h 254 | 255 | # The drivers here use `__attribute__((constructor))` functions to 256 | # register themselves with `beep_drivers_register()`, so the last one 257 | # listed here will be linked last and have its constructor called at 258 | # the latest time, and thus will have its `driver_detect()` function 259 | # called first. 260 | 261 | beep_SOURCES += beep-driver.h 262 | beep_SOURCES += beep-driver-console.c 263 | beep_SOURCES += beep-driver-evdev.c 264 | 265 | EXTRA_DIST += beep-driver-noop.c 266 | ifneq ($(BEEP_DEBUG_BUILD),) 267 | beep_SOURCES += beep-driver-noop.c 268 | endif 269 | 270 | beep_LDADD = 271 | 272 | beep-log.o : override common_CPPFLAGS += -D_GNU_SOURCE 273 | # beep-log.clang-o : override CFLAGS_clang += -Wno-format-nonliteral 274 | 275 | # sbin_PROGRAMS += beep-foo 276 | # beep_foo_SOURCES = 277 | # beep_foo_SOURCES += beep-log.c 278 | # beep_foo_SOURCES += beep.c 279 | # beep_foo_LDADD = 280 | # beep_foo_LDADD += -lm 281 | 282 | 283 | ######################################################################## 284 | # Built sources 285 | ######################################################################## 286 | 287 | EXTRA_DIST += beep-usage.txt.in 288 | CLEANFILES += beep-usage.txt 289 | 290 | BUILT_SOURCES += beep-usage.c 291 | CLEANFILES += beep-usage.c 292 | beep-usage.c: beep-usage.txt 293 | $(inhibit-build-command) 294 | @$(call print-rule-description,CONVERT,$@,$<) 295 | printf '%s\n' '/* Auto-generated from `$<`. Modify that file instead. */' > $@ 296 | printf '%s\n' '#include "beep-usage.h"' >> $@ 297 | printf '%s\n' 'char beep_usage[] =' >> $@ 298 | set -e; IFS=""; while read line; do \ 299 | printf ' "%s\\n"\n' "$${line}" >> $@; \ 300 | done < $< 301 | printf '%s\n' ' ;' >> $@ 302 | 303 | 304 | ######################################################################## 305 | # Compile and Link rules including automatic dependency generation 306 | # 307 | # For details on the automatic dependency generation, see 308 | # http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ 309 | ######################################################################## 310 | 311 | 312 | # CALL: define-link-rule 313 | # Defines the per-executable rules. 314 | define define-link-rule 315 | CLEANFILES += $(1).map 316 | dist-files += $$($(2)_SOURCES) 317 | $(2)_OBJS := $$(foreach src,$$($(2)_SOURCES),$$(if $$(filter %.c,$$(src)),$$(src:%.c=%.o),$$(if $$(filter %.h,$$(src)),,$$(error Unhandled source type in $(2)_SOURCES: $$(src))))) 318 | 319 | $(1): $$($(2)_OBJS) 320 | $$(inhibit-build-command) 321 | @$$(call print-rule-description,LINK,$$@) 322 | $$(CC) -Wl,-Map=$(1).map $$(common_CFLAGS) $$(CFLAGS) $$(common_LDFLAGS) $$($(2)_LDFLAGS) $$(LDFLAGS) -o $$@ $$^ $$(common_LDADD) $$($(2)_LDADD) $$(LDADD) 323 | 324 | $$(patsubst %.o,.deps/%.o.dep,$$($(2)_OBJS))): 325 | 326 | -include $$(wildcard $$(patsubst %.o,.deps/%.o.dep,$$($(2)_OBJS))) 327 | endef 328 | 329 | 330 | $(foreach exec,$(bin_PROGRAMS), $(eval $(call define-link-rule,$(exec),$(subst -,_,$(exec)),bin))) 331 | $(foreach exec,$(check_PROGRAMS),$(eval $(call define-link-rule,$(exec),$(subst -,_,$(exec)),check))) 332 | $(foreach exec,$(sbin_PROGRAMS), $(eval $(call define-link-rule,$(exec),$(subst -,_,$(exec)),sbin))) 333 | 334 | %.o: %.c | .deps 335 | $(inhibit-build-command) 336 | @$(call print-rule-description,COMPILE,$@,$<) 337 | $(CC) -MT $@ -MMD -MP -MF .deps/$*.o.dep $(common_CPPFLAGS) $(CPPFLAGS) $(common_CFLAGS) $(CFLAGS) -o $@ -c $< 338 | 339 | .deps: 340 | $(inhibit-build-command) 341 | @$(MKDIR_P) $@ 342 | 343 | 344 | ######################################################################## 345 | # Generate doc and similar files 346 | ######################################################################## 347 | 348 | EXTRA_DIST += gen-freq-table 349 | 350 | EXTRA_DIST += beep.1.in 351 | man1_DATA += beep.1 352 | CLEANFILES += beep.1 353 | 354 | CLEANFILES += CREDITS.html 355 | CLEANFILES += NEWS.html 356 | CLEANFILES += PERMISSIONS.html 357 | CLEANFILES += README.html 358 | 359 | CLEANFILES += DEVELOPMENT.html 360 | CLEANFILES += INSTALL.html 361 | CLEANFILES += PACKAGING.html 362 | 363 | EXTRA_DIST += pandoc.css 364 | 365 | ifeq (yes,$(shell if $(PANDOC) --version > /dev/null 2>&1; then echo yes; else echo no; fi)) 366 | 367 | html_DATA += pandoc.css 368 | 369 | html_DATA += CREDITS.html 370 | html_DATA += NEWS.html 371 | html_DATA += PERMISSIONS.html 372 | html_DATA += README.html 373 | 374 | noinst_html_DATA += DEVELOPMENT.html 375 | noinst_html_DATA += INSTALL.html 376 | noinst_html_DATA += PACKAGING.html 377 | 378 | %.html: %.md 379 | $(inhibit-build-command) 380 | @$(call print-rule-description,PANDOC,$@,$<) 381 | $(PANDOC) --from gfm --to html --standalone -M pagetitle="$$($(SED) -n 1p $<)" -M title="" -c pandoc.css $< -o $@ 382 | endif 383 | 384 | .PHONY: html 385 | html: $(html_DATA) $(noinst_html_DATA) 386 | all-local: $(html_DATA) $(noinst_html_DATA) 387 | 388 | DEFAULT_FREQ = 440 389 | DEFAULT_LENGTH = 200 390 | DEFAULT_DELAY = 100 391 | 392 | REPLACEMENTS = 393 | REPLACEMENTS += -e 's|@PACKAGE_TARNAME@|$(PACKAGE_TARNAME)|g' 394 | REPLACEMENTS += -e 's|@PACKAGE_VERSION@|$(PACKAGE_VERSION)|g' 395 | 396 | REPLACEMENTS += -e 's|@DEFAULT_FREQ@|$(DEFAULT_FREQ)|g' 397 | REPLACEMENTS += -e 's|@DEFAULT_LENGTH@|$(DEFAULT_LENGTH)|g' 398 | REPLACEMENTS += -e 's|@DEFAULT_DELAY@|$(DEFAULT_DELAY)|g' 399 | 400 | REPLACEMENTS += -e 's|[@]docdir@|$(docdir)|g' 401 | 402 | EXTRA_DIST += beep-config.h.in 403 | CLEANFILES += beep-config.h 404 | BUILT_SOURCES += beep-config.h 405 | beep-main.o : beep-config.h 406 | 407 | EXTRA_DIST += Doxyfile.in 408 | CLEANFILES += Doxyfile 409 | CLEANFILES += Doxyfile.new 410 | 411 | %: %.in GNUmakefile 412 | $(inhibit-build-command) 413 | @$(call print-rule-description,SUBSTITUTE,$@,$<) 414 | $(SED) $(REPLACEMENTS) < $< > $@.new 415 | @if $(EGREP) '@([A-Za-z][A-Za-z0-9_]*)@' $@.new; then \ 416 | echo "Error: GNUmakefile fails to substitute some of the variables in \`$<'."; \ 417 | exit 1; \ 418 | fi 419 | mv -f $@.new $@ 420 | 421 | CLEANFILES += doxygen.stamp 422 | .PHONY: doxygen.stamp 423 | doxygen.stamp: Doxyfile $(wildcard *.c) $(wildcard *.h) 424 | $(inhibit-build-command) 425 | @$(call print-rule-description,DOXYGEN,html dox) 426 | cat $< $(if $(V),,| $(SED) -e 's!^QUIET *=.*!QUIET = YES!') | $(DOXYGEN) - 427 | echo > $@ 428 | 429 | dox: doxygen.stamp 430 | 431 | .PHONY: serve-dox 432 | serve-dox: dox 433 | @$(call print-rule-description,SERVING,doxygen html files,dox/html) 434 | $(PYTHON3) -m http.server --directory dox/html 435 | 436 | EXTRA_DIST += COPYING 437 | doc_DATA += COPYING 438 | 439 | EXTRA_DIST += CREDITS.md 440 | doc_DATA += CREDITS.md 441 | 442 | EXTRA_DIST += NEWS.md 443 | doc_DATA += NEWS.md 444 | 445 | EXTRA_DIST += README.md 446 | doc_DATA += README.md 447 | 448 | EXTRA_DIST += PERMISSIONS.md 449 | doc_DATA += PERMISSIONS.md 450 | 451 | EXTRA_DIST += DEVELOPMENT.md 452 | EXTRA_DIST += INSTALL.md 453 | EXTRA_DIST += PACKAGING.md 454 | 455 | EXTRA_DIST += contrib/failure-beeps 456 | contrib_SCRIPTS += contrib/failure-beeps 457 | EXTRA_DIST += contrib/status-beeps 458 | contrib_SCRIPTS += contrib/status-beeps 459 | EXTRA_DIST += contrib/success-beeps 460 | contrib_SCRIPTS += contrib/success-beeps 461 | EXTRA_DIST += contrib/morse/morse2beep.pl 462 | contrib_SCRIPTS += contrib/morse/morse2beep.pl 463 | EXTRA_DIST += contrib/morse/morse2beep.sed 464 | contrib_SCRIPTS += contrib/morse/morse2beep.sed 465 | 466 | 467 | ######################################################################## 468 | # Generic targets 469 | ######################################################################## 470 | 471 | all_TARGETS += $(bin_PROGRAMS) 472 | all_TARGETS += $(sbin_PROGRAMS) 473 | all_TARGETS += $(man1_DATA) 474 | 475 | .PHONY: all-local 476 | all-local: $(all_TARGETS) 477 | 478 | check_TARGETS += $(all_TARGETS) 479 | check_TARGETS += $(check_PROGRAMS) 480 | 481 | .PHONY: check-targets 482 | check-targets: $(check_TARGETS) 483 | 484 | .PHONY: check 485 | check: tests/run-tests beep $(check_TARGETS) 486 | $(inhibit-build-command) 487 | @$(call print-rule-description,CHECK,$(PWD)/beep) 488 | env PACKAGE_VERSION="${PACKAGE_VERSION}" \ 489 | /bin/bash $< $( __tmp/$(distdir)/local.mk 634 | (cd __tmp/$(distdir) && $(FIND) . -type f) | env LC_ALL=C sort > __tmp/before-build.filelist 635 | $(MAKE) -C __tmp/$(distdir) 636 | $(MAKE) -C __tmp/$(distdir) check 637 | $(MAKE) -C __tmp/$(distdir) install-nobuild 638 | (cd __tmp/_prefix && $(FIND) . -type f) | env LC_ALL=C sort > __tmp/after-install.filelist 639 | @n="$$($(WC) -l < __tmp/after-install.filelist)"; \ 640 | if test "$$n" -eq 0; then \ 641 | echo "Error: Found no installed files"; \ 642 | exit 1; \ 643 | elif test "$$n" -gt 10; then \ 644 | echo "Found $${n} installed files: good."; \ 645 | else \ 646 | echo "Error: Found only $${n} installed files"; \ 647 | exit 1; \ 648 | fi 649 | $(MAKE) -C __tmp/$(distdir) uninstall 650 | (cd __tmp/_prefix && $(FIND) . -type f) | env LC_ALL=C sort > __tmp/after-uninstall.filelist 651 | @n="$$($(WC) -l < __tmp/after-uninstall.filelist)"; \ 652 | if test "$$n" -gt 0; then \ 653 | echo "Error: Found $${n} left over installed files after uninstall"; \ 654 | exit 1; \ 655 | else \ 656 | echo "Found no installed files after uninstall"; \ 657 | fi 658 | $(MAKE) -C __tmp/$(distdir) clean 659 | (cd __tmp/$(distdir) && $(FIND) . -type f) | env LC_ALL=C sort > __tmp/after-clean.filelist 660 | cd __tmp && $(DIFF_U) before-build.filelist after-clean.filelist 661 | 662 | 663 | ######################################################################## 664 | # Development helpers 665 | ######################################################################## 666 | 667 | # Only have make deal with those variables and rules if this is a git 668 | # repo, and if the git executable has been found. 669 | GIT_INFO_EXCLUDE = $(firstword $(wildcard .git/info/exclude)) 670 | ifneq ($(strip $(GIT_INFO_EXCLUDE)),) 671 | ifdef GIT 672 | 673 | # List all references to documentation in the git repo 674 | .PHONY: refs 675 | refs: 676 | $(GIT) grep -n -E '((http|https)://[a-zA-Z0-9\._/-]+|([A-Z]+\.md)|([a-zA-Z][a-zA-Z0-9_-]+\([0-9]+\)))' 677 | 678 | # List all TODOs and FIXMEs in the git repo 679 | .PHONY: todo fixme 680 | todo fixme: 681 | $(GIT) grep -n -E '(TODO:|FIXME:|\\todo\s|@todo\s)' 682 | 683 | # Generate a kind of dist tarball to help with preparing for release 684 | PACKAGE_TARBASE = $(eval PACKAGE_TARBASE := $$(PACKAGE_TARNAME)-$$(shell $$(GIT) describe --tags | $$(SED) 's/^v\([0-9]\)/\1/'))$(PACKAGE_TARBASE) 685 | .PHONY: git-dist 686 | git-dist: 687 | @$(call print-rule-description,GIT ARCHIVE,$(PACKAGE_TARBASE).tar.gz) 688 | $(GIT) archive --format=tar.gz --prefix=$(PACKAGE_TARBASE)/ --output=$(PACKAGE_TARBASE).tar.gz HEAD 689 | 690 | # Check that the lists of files inside the "git archive" and the "tar" 691 | # dist tarballs are the same. 692 | .PHONY: compare-tarballs 693 | distcheck: compare-tarballs 694 | compare-tarballs: dist git-dist 695 | @$(call print-rule-description,COMPARE,contents of git archive and dist tarball) 696 | rm -rf tarball-dist tarball-git-dist 697 | mkdir tarball-dist && cd tarball-dist && $(TAR) xf ../$(distdir).tar.gz 698 | mkdir tarball-git-dist && cd tarball-git-dist && $(TAR) xf ../$(PACKAGE_TARBASE).tar.gz 699 | diff -ruN tarball-git-dist/$(PACKAGE_TARBASE) tarball-dist/$(distdir) 700 | rm -rf tarball-dist tarball-git-dist 701 | 702 | endif 703 | endif 704 | 705 | 706 | ######################################################################## 707 | # Print rule descriptions and silent rules 708 | # 709 | # This is a bit more complex than mad scientist's simple silent 710 | # rules[1]: 711 | # 712 | # * In silent mode, we print aligned descriptions for each target 713 | # being built. 714 | # 715 | # * In non-silent mode, we print a description of the recipe before 716 | # each recipe is actually run, but highlighted a bit to stand out 717 | # from the endless sequence of recipe command text: The description 718 | # line always starts with a "#", and on a TTY, it will be printed 719 | # in bold. 720 | # 721 | # [1]: http://make.mad-scientist.net/managing-recipe-echoing/ 722 | ######################################################################## 723 | 724 | # Set V to empty to disable silent rules, non-empty to enable them. 725 | V=1 726 | V= 727 | 728 | # Note that we cannot use "test -t 1" inside a $(shell ) command, as 729 | # the $(shell) will capture stdout into a variable, so the "test -t 1" 730 | # will always test negative. 731 | 732 | ifeq (,$(V)) 733 | .SILENT: 734 | print-rule-description = $(or\ 735 | $(if $(3),printf "%12s %-22s FROM %s\n" "$(1)" "$(2)" "$(3)"),\ 736 | $(if $(2),printf "%12s %s\n" "$(1)" "$(2)"),\ 737 | $(error $(0) requires at least two parameters)) 738 | else 739 | set-color-vars = if test -t 1; then cb="$$($(TPUT) bold)"; cn="$$($(TPUT) sgr0)"; fi 740 | print-rule-description = $(set-color-vars); $(or\ 741 | $(if $(3),printf "%s# %s %s FROM %s%s\n" "$$cb" "$(1)" "$(2)" "$(3)" "$$cn"),\ 742 | $(if $(2),printf "%s# %s %s%s\n" "$$cb" "$(1)" "$(2)" "$$cn"),\ 743 | $(error $(0) requires at least two parameters)) 744 | endif 745 | 746 | 747 | ######################################################################## 748 | # End of GNUmakefile 749 | ######################################################################## 750 | 751 | ifneq (,$(V)) 752 | $(info #=======================================================================) 753 | endif 754 | --------------------------------------------------------------------------------