Last active
October 2, 2019 12:36
-
-
Save unclechu/d2411feefd80cd8483b46175b17e93a2 to your computer and use it in GitHub Desktop.
Laptop backlight control application for using with root SUID
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Compile with this command, get rid of access to run by random users, | |
-- set SUID (to run by root), give ACL read+executing access | |
-- to your own user only ('uc' for instance, replace to your own user name): | |
-- | |
-- stack ghc --resolver=lts-14.7 \ | |
-- --package=attoparsec \ | |
-- --package=filepath \ | |
-- -- -Wall -O2 -j$(nproc --all) laptop-backlight.hs && | |
-- chmod 4550 laptop-backlight && | |
-- setfacl -m u:uc:rx laptop-backlight | |
-- | |
{-# LANGUAGE UnicodeSyntax, LambdaCase, ViewPatterns #-} | |
{-# OPTIONS_GHC -Wno-missing-signatures #-} | |
module Main (main) where | |
import Prelude hiding (fail, max) | |
import Data.Char (toLower) | |
import Data.String (fromString) | |
import qualified Data.Attoparsec.ByteString.Char8 as P | |
import Control.Monad ((>=>)) | |
import Control.Monad.Fail (fail) | |
import Control.Applicative ((<|>)) | |
import System.FilePath ((</>)) | |
import System.Environment (getArgs) | |
import System.Exit (die) | |
main ∷ IO () | |
main = do | |
max ← readSomeFile Maximum | |
getArgs >>= \case | |
["get-max"] → print max | |
["get"] → readSomeFile Current >>= print | |
["set", parseNumber → Right n] | n ≤ max → | |
writeFile (getPath Current) (show n) | |
args → die $ "Unexpected arguments: " ◇ show args | |
data File = Maximum | Current deriving Show | |
getPath ∷ File → FilePath | |
getPath = | |
("/sys/class/backlight/intel_backlight" </>) ∘ \case | |
Maximum → "max_brightness" | |
Current → "brightness" | |
readSomeFile ∷ File → IO Word | |
readSomeFile file = go $ getPath file where | |
go = readFile >=> parseNumber • either (fail ∘ failMsg) pure | |
failMsg | |
= mappend | |
$ "Failed to parse " ◇ fmap toLower (show file) ◇ " brightness value: " | |
parseNumber ∷ String → Either String Word | |
parseNumber = go where | |
go = P.parseOnly parser ∘ fromString | |
parser = P.decimal <* (() <$ P.char '\n' <|> pure ()) <* P.endOfInput | |
(∘) = (.); (•) = flip (.); (◇) = (<>); (≤) = (<=) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment