Skip to content

Instantly share code, notes, and snippets.

@unclechu
Last active October 2, 2019 12:36
Show Gist options
  • Save unclechu/d2411feefd80cd8483b46175b17e93a2 to your computer and use it in GitHub Desktop.
Save unclechu/d2411feefd80cd8483b46175b17e93a2 to your computer and use it in GitHub Desktop.
Laptop backlight control application for using with root SUID
-- 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