Score:0

How do I maintain permission across reboots for a script to write to `/sys/class/backlight/acpi_video0/brightness`?

ru flag

I wrote a script that lets me toggle my laptop screen's brightness (I run if from a hotkey bound by xbindkeys),
but it involves writing to /sys/class/backlight/acpi_video0/brightness.

For now, I've just been making it able to write to that file by doing
sudo chown $USER: /sys/class/backlight/acpi_video0/brightness
but that resets after every time I reboot the laptop,
so I need to rerun it before I can use my hotkey.

What's the proper and persistent way to do this?



EDIT_3 (ie, added after the below 2 edits) (technically "the answer"):

I got fed up trying to make the udev stuff work,
and (after much confusion (an unknown amount of which was caused by me simply typoing and missing the "t" in "brightness"))
finally got it to work like so:

(To be explicit, my echo $USER is o1.)

So


  • (1)

I created a file:
/home/o1/.icanhasbrightness.sh
containing:

#!/usr/bin/bash  
chown o1: /sys/class/backlight/acpi_video0/brightness  

  • (2)

I did:
> sudo chown root:root /home/o1/.icanhasbrightness.sh
and
> sudo chmod 0711 /home/o1/.icanhasbrightness.sh
(
such that
> stat /home/o1/.icanhasbrightness.sh|head -n 4|tail -n 1
#=>
Access: (0711/-rwx--x--x) Uid: ( 0/ root) Gid: ( 0/ root)
)


  • (3)

I did:
> sudo visudo
and added the line:
o1 ALL=(ALL) NOPASSWD: /home/o1/.icanhasbrightness.sh


  • (4)

I modified my fishshell function to check if I'm not the owner of the brightness file, and if not, run that script.
(

function brightness_set_current  
    #todo this is prolly the "wrong" way of handling this but whatever it works  
        if test $USER != (stat -c %U /sys/class/backlight/acpi_video0/brightness)  
            sudo /home/o1/.icanhasbrightness.sh  
        end  
    echo $argv > /sys/class/backlight/acpi_video0/brightness  
end  

)


... So I guess that technically answers my own question, but...

  • (1) I feel this is probably the "wrong" way of doing it(?)
  • (2) I'm so tired of messing around with this by now that I don't feel like posting it an an "answer" right now anyway

(((
And for the benefit of any hypothetical future equivalents of my past self
(
ie, admittedly unrelated to the actual question I was trying to get an answer to here,
but I'll leave it here for now and figure out some better place to put it later, where it's actually likely to be seen by someone who would find it useful
),
who just want a hotkey to toggle brightness and screen colour temperatures,
then, assuming you're already using fishshell (and know to save these as autoloading functions and all that), the code was:

function brightness_get_current
    cat /sys/class/backlight/acpi_video0/brightness
end

function brightness_set_current
    #td FIX(?)
        if test $USER != (stat -c %U /sys/class/backlight/acpi_video0/brightness)
            sudo /home/o1/.icanhasbrightness.sh
        end
    echo $argv > /sys/class/backlight/acpi_video0/brightness
end

function brightness_get_max --description 'max brightness, mb'
    cat /sys/class/backlight/acpi_video0/max_brightness
end

function brightness_set_max --description 'max brightness, mb'
    brightness_set_current (brightness_get_max)
end

function brightness_toggle
    #
        #
            set -l verbose $argv
            set -l current_brightness (brightness_get_current)
            set -l current_ct (xsct|g --nocolor -o '\d+$')
                #bk
                    # echo current_ct $current_ct
        #
            set -l brightness
                if test $current_brightness -eq 0
                    set brightness 'min'
                else if test $current_brightness -eq (brightness_get_max)
                    set brightness 'max'
                else
                    set brightness 'mid'
                end
            set -l redness
                if test $current_ct -eq 1000
                    set redness 'red'
                else if test $current_ct -lt 1000
                    set redness 'red_super'
                else if test $current_ct -lt 700
                    set redness 'red_impossible'
                else if test $current_ct -lt 6500
                    set redness 'mid'
                else if test $current_ct -eq 6500
                    set redness 'white'
                else
                    set redness 'blue'
                end
        #
            function brightness_set_to_max_white
                brightness_set_max
                D0 xsct 0   #ie 6500
            end
            function brightness_set_to_min_red
                brightness_set_current 0
                D0 xsct 1000
            end
            function brightness_set_to_min_white
                brightness_set_current 0
                D0 xsct 0   #ie 6500
            end
        #
            #bk
                if test "$verbose"
                    echo \t'current state:'
                    echo \t\t'brightness:'  \t$brightness
                    echo \t\t'redness:'     \t$redness
                end
            #
                if test "$brightness" = 'max' -a "$redness" = 'white'
                    #bk
                        test "$verbose"
                        and echo "1 - setting to min_red   ( from max_white )"
                    brightness_set_to_min_red
                else if test "$brightness" = 'min' -a "$redness" = 'red'
                    #bk
                        test "$verbose"
                        and echo "2 - setting to min_white ( from min_red   )"
                    brightness_set_to_min_white
                else if test "$brightness" = 'min' -a "$redness" = 'white'
                    #bk
                        test "$verbose"
                        and echo "3 - setting to max_white ( from min_white )"
                    brightness_set_to_max_white
                else
                    #bk
                        test "$verbose"
                        and echo "4 - setting to max_white ( from other     )"
                    brightness_set_to_max_white
                end
end

and to bind it to a key,
I just put into ~/.xbindkeysrc this content:

"fish -c 'brightness_toggle'"
  Mod4 + less

(Mod4 + less just being what xbindkeys -mk told me it called that key combo when I pressed it)

... oh yeah, except to install xsct you also gotta do
> git clone 'https://github.com/faf0/sct.git'
(while in whatever dir you want the sct dir to end up in)
then
> sudo apt install libxrandr-dev (a dependency you need to compile it)
then (while in that sct dir created by the git clone-ing)
> sudo make install

(
Also, I set up hotkeys to flip which edge of the screen is "up"
(which also relies on that brightness_set_current function cuz, at least for me, using xrandr -o messes with the brightness for some reason)
with fishshell:

function screen_orientation --description 'screen/monitor orientation - possible arguments are normal/left/right/inverted'
    set current_brightness (cat /sys/class/backlight/acpi_video-0/max_brightness)
    xrandr -o $argv
    and brightness_set_current $current_brightness

    # guess i don't need this really?
        # if thnpadd
        #   nitrogen --restore
        #   # and D0 nitrogen --restore
        # end
end

and ~/.xbindkeysrc:

"fish -c 'screen_orientation left'"  
  Mod4 + Left  
"fish -c 'screen_orientation normal'"  
  Mod4 + Up  
"fish -c 'screen_orientation right'"  
  Mod4 + Right  
"fish -c 'screen_orientation inverted'"  
  Mod4 + Down  

)
)))




EDIT_1 ("udev maybe?"):

I found on the archwiki:

By default, only root can change the brightness by this method. To allow users in [for example] the video group to change the brightness, a udev rule such as the following can be used:
[write to this file:]
/etc/udev/rules.d/backlight.rules
[this content:]
ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="acpi_video0", GROUP="video", MODE="0664"

So I did that, then did:
sudo groupadd video
and:
sudo usermod -aG video o1
(
Well, assuming I'm correctly remembering exactly what I did in what order,
but regardless, groups $USER does confirm that I am in the video group.
)

but after restarting, still, trying to write to it like this still gets:
> echo 5 > /sys/class/backlight/acpi_video0/brightness
#=>

warning: An error occurred while redirecting file '/sys/class/backlight/acpi_video0/brightness'  
open: Permission denied  

and this:
> stat /sys/class/backlight/acpi_video0/brightness
#=>

  File: /sys/class/backlight/acpi_video0/brightness  
  Size: 4096            Blocks: 0          IO Block: 4096   regular file  
Device: 16h/22d Inode: 22741       Links: 1  
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)  
Access: 2021-09-24 10:51:53.894540644 -0700  
Modify: 2021-09-24 10:51:53.888124116 -0700  
Change: 2021-09-24 10:51:53.888124116 -0700  
 Birth: -  

which means it's still only root that has write permissions to the file, right?

That udev rule was supposed to... change ownership of the file to the video group, right?
(
Assuming "this file is owned by this group" is getting the concept and/or terminology correct...?
At any rate, it was supposed to give the video group write-permission for the file, right?
)

So why didn't it work?
-- I mean, since I can't exactly hop on arch and give it a try,
I can only assume that what I did would've worked on arch(?),
so how does ubuntu differ?


EDIT_2 ("udev should work??"):

From what I can understand from this udev tutorial,
it should work?
(
Or at any rate, it does say:
Reading rules file: /etc/udev/rules.d/backlight.rules
-- but it doesn't say anything about "GROUP" OR "MODE".
)

(I also tried changing the ='s to :='s (to "make sure that it is not overridden by other rules"), just in case.)

> udevadm info -a /sys/class/backlight/acpi_video0/
#=>

    Udevadm info starts with the device specified by the devpath and then  
    walks up the chain of parent devices. It prints for every device  
    found, all possible attributes in the udev rules key format.  
    A rule to match, can be composed by the attributes of the device  
    and the attributes from one single parent device.

      looking at device '/devices/pci0000:00/0000:00:01.0/backlight/acpi_video0':  
        KERNEL=="acpi_video0"  
        SUBSYSTEM=="backlight"  
        DRIVER==""  
        ATTR{max_brightness}=="15"  
        ATTR{actual_brightness}=="15"  
        ATTR{bl_power}=="0"  
        ATTR{type}=="firmware"  
        ATTR{brightness}=="15"  
        ATTR{scale}=="unknown"

      looking at parent device '/devices/pci0000:00/0000:00:01.0':  
        KERNELS=="0000:00:01.0"  
        SUBSYSTEMS=="pci"  
        DRIVERS=="radeon"  
        ATTRS{local_cpulist}=="0-1"  
        ATTRS{msi_bus}=="1"  
        ATTRS{max_link_width}=="255"  
        ATTRS{consistent_dma_mask_bits}=="40"  
        ATTRS{driver_override}=="(null)"  
        ATTRS{power_dpm_state}=="balanced"  
        ATTRS{revision}=="0x00"  
        ATTRS{device}=="0x9648"  
        ATTRS{local_cpus}=="3"  
        ATTRS{subsystem_device}=="0x21ea"  
        ATTRS{d3cold_allowed}=="1"  
        ATTRS{power_method}=="dpm"  
        ATTRS{numa_node}=="-1"  
        ATTRS{broken_parity_status}=="0"  
        ATTRS{power_state}=="D0"  
        ATTRS{boot_vga}=="1"  
        ATTRS{irq}=="31"  
        ATTRS{current_link_width}=="0"  
        ATTRS{current_link_speed}=="Unknown"  
        ATTRS{class}=="0x030000"  
        ATTRS{power_profile}=="default"  
        ATTRS{dma_mask_bits}=="40"  
        ATTRS{vendor}=="0x1002"  
        ATTRS{subsystem_vendor}=="0x17aa"  
        ATTRS{enable}=="1"  
        ATTRS{power_dpm_force_performance_level}=="auto"  
        ATTRS{ari_enabled}=="0"  
        ATTRS{max_link_speed}=="Unknown"

      looking at parent device '/devices/pci0000:00':  
        KERNELS=="pci0000:00"  
        SUBSYSTEMS==""  
        DRIVERS==""  

and:
> udevadm test --action="add" '/devices/pci0000:00/0000:00:01.0/backlight/acpi_video0'
#=>

    Load module index  
    Parsed configuration file /usr/lib/systemd/network/99-default.link  
    Parsed configuration file /usr/lib/systemd/network/73-usb-net-by-mac.link  
    Created link configuration context.  
    Reading rules file: /usr/lib/udev/rules.d/39-usbmuxd.rules  
    Reading rules file: /usr/lib/udev/rules.d/40-usb-media-players.rules  
    Reading rules file: /usr/lib/udev/rules.d/40-usb_modeswitch.rules  
    Reading rules file: /usr/lib/udev/rules.d/40-vm-hotadd.rules  
    Reading rules file: /usr/lib/udev/rules.d/50-apport.rules  
    Reading rules file: /usr/lib/udev/rules.d/50-firmware.rules  
    Reading rules file: /usr/lib/udev/rules.d/50-udev-default.rules  
    Reading rules file: /usr/lib/udev/rules.d/55-dm.rules  
    Reading rules file: /usr/lib/udev/rules.d/55-ippusbxd.rules  
    Reading rules file: /usr/lib/udev/rules.d/56-hpmud.rules  
    Reading rules file: /usr/lib/udev/rules.d/56-lvm.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-autosuspend-chromiumos.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-block.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-cdrom_id.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-crda.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-drm.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-evdev.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-fido-id.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-input-id.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-inputattach.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-libgphoto2-6.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-libsane.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-pcmcia.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-persistent-alsa.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-persistent-input.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage-dm.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage-tape.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-persistent-v4l.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-sensor.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-serial.rules  
    Reading rules file: /usr/lib/udev/rules.d/60-tpm-udev.rules  
    Reading rules file: /usr/lib/udev/rules.d/61-autosuspend-manual.rules  
    Reading rules file: /usr/lib/udev/rules.d/61-kde-bluetooth-rfkill.rules  
    Reading rules file: /usr/lib/udev/rules.d/61-persistent-storage-android.rules  
    Reading rules file: /usr/lib/udev/rules.d/64-btrfs.rules  
    Reading rules file: /usr/lib/udev/rules.d/64-xorg-xkb.rules  
    Reading rules file: /usr/lib/udev/rules.d/65-libwacom.rules  
    Reading rules file: /usr/lib/udev/rules.d/66-snapd-autoimport.rules  
    Reading rules file: /usr/lib/udev/rules.d/69-cd-sensors.rules  
    Reading rules file: /usr/lib/udev/rules.d/69-libmtp.rules  
    Reading rules file: /usr/lib/udev/rules.d/69-lvm-metad.rules  
    Reading rules file: /usr/lib/udev/rules.d/69-wacom.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-joystick.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-mouse.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-pcspkr-beep.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-power-switch.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-printers.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-spice-vdagentd.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-touchpad.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-u2f.rules  
    Reading rules file: /usr/lib/udev/rules.d/70-uaccess.rules  
    Reading rules file: /usr/lib/udev/rules.d/71-power-switch-proliant.rules  
    Reading rules file: /usr/lib/udev/rules.d/71-seat.rules  
    Reading rules file: /usr/lib/udev/rules.d/71-u-d-c-gpu-detection.rules  
    Reading rules file: /usr/lib/udev/rules.d/73-seat-late.rules  
    Reading rules file: /usr/lib/udev/rules.d/73-special-net-names.rules  
    Reading rules file: /usr/lib/udev/rules.d/75-net-description.rules  
    Reading rules file: /usr/lib/udev/rules.d/75-probe_mtd.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-broadmobi-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-cinterion-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-dell-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-dlink-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-ericsson-mbm.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-fibocom-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-foxconn-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-gosuncn-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-haier-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-huawei-net-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-longcheer-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-mtk-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-nokia-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-pcmcia-device-blacklist.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-qdl-device-blacklist.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-quectel-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-sierra.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-simtech-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-telit-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-tplink-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-ublox-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-usb-device-blacklist.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-usb-serial-adapters-greylist.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-x22x-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/77-mm-zte-port-types.rules  
    Reading rules file: /usr/lib/udev/rules.d/78-graphics-card.rules  
    Reading rules file: /usr/lib/udev/rules.d/78-sound-card.rules  
    Reading rules file: /usr/lib/udev/rules.d/80-debian-compat.rules  
    Reading rules file: /usr/lib/udev/rules.d/80-drivers.rules  
    Reading rules file: /usr/lib/udev/rules.d/80-iio-sensor-proxy.rules  
    Reading rules file: /usr/lib/udev/rules.d/80-libinput-device-groups.rules  
    Reading rules file: /usr/lib/udev/rules.d/80-mm-candidate.rules  
    Reading rules file: /usr/lib/udev/rules.d/80-net-setup-link.rules  
    Reading rules file: /usr/lib/udev/rules.d/80-udisks2.rules  
    Reading rules file: /usr/lib/udev/rules.d/81-net-dhcp.rules  
    Reading rules file: /usr/lib/udev/rules.d/84-nm-drivers.rules  
    Reading rules file: /usr/lib/udev/rules.d/85-hdparm.rules  
    Reading rules file: /usr/lib/udev/rules.d/85-hplj10xx.rules  
    Reading rules file: /usr/lib/udev/rules.d/85-nm-unmanaged.rules  
    Reading rules file: /usr/lib/udev/rules.d/85-regulatory.rules  
    Reading rules file: /usr/lib/udev/rules.d/85-tlp-rdw.rules  
    Reading rules file: /usr/lib/udev/rules.d/85-tlp.rules  
    Reading rules file: /usr/lib/udev/rules.d/90-alsa-restore.rules  
    Reading rules file: /usr/lib/udev/rules.d/90-bolt.rules  
    Reading rules file: /usr/lib/udev/rules.d/90-console-setup.rules  
    Reading rules file: /usr/lib/udev/rules.d/90-fwupd-devices.rules  
    Reading rules file: /usr/lib/udev/rules.d/90-libinput-fuzz-override.rules  
    Reading rules file: /usr/lib/udev/rules.d/90-nm-thunderbolt.rules  
    Reading rules file: /usr/lib/udev/rules.d/90-pulseaudio.rules  
    Reading rules file: /usr/lib/udev/rules.d/95-cd-devices.rules  
    Reading rules file: /usr/lib/udev/rules.d/95-dm-notify.rules  
    Reading rules file: /usr/lib/udev/rules.d/95-upower-csr.rules  
    Reading rules file: /usr/lib/udev/rules.d/95-upower-hid.rules  
    Reading rules file: /usr/lib/udev/rules.d/95-upower-hidpp.rules  
    Reading rules file: /usr/lib/udev/rules.d/95-upower-wup.rules  
    Reading rules file: /usr/lib/udev/rules.d/96-e2scrub.rules  
    Reading rules file: /usr/lib/udev/rules.d/97-hid2hci.rules  
    Reading rules file: /usr/lib/udev/rules.d/99-systemd.rules  
    Reading rules file: /etc/udev/rules.d/backlight.rules  
    Unload module index  
    Unloaded link configuration context.  
    This program is for debugging only, it does not run any program  
    specified by a RUN key. It may show incorrect results, because  
    some values may be different, or not available at a simulation run.

    DEVPATH=/devices/pci0000:00/0000:00:01.0/backlight/acpi_video0  
    ACTION=add  
    SUBSYSTEM=backlight  
    TAGS=:seat:systemd:  
    ID_PATH=pci-0000:00:01.0  
    ID_PATH_TAG=pci-0000_00_01_0  
    ID_FOR_SEAT=backlight-pci-0000_00_01_0  
    SYSTEMD_WANTS=systemd-backlight@backlight:acpi_video0.service  
    USEC_INITIALIZED=2680045  
Score:-1
it flag

This canned answer might help.

Many device access problems can be resolved through group membership changes.

You can find the device name by watching sudo journalctl --follow as you connect your device. OR ls -1 /dev >dev.before, connect the device, wait 10 seconds, ls -1 /dev >dev.after;diff dev.{before,after}.

Specifically, if ls -l shows that the group permissions (the second "rwx" triplet) is "rw" (e.g."-rw-rw----"), then, adding oneself to the group that owns the device will grant rw access.

Here's how:

device="/dev/whatever"
sudo adduser $USER $(stat -c "%G" $device)

This allows you membership in the group that can rw the device, but there is one more step.

To make all your processes members of the new group, logout and login. Group memberships are set up at login time.

To create a single process in the new group (for testing, prior to logout/login):

newgrp $(stat -c "%G" $device)  

or, just type the group name. See man newgrp.

ru flag
"as you connect your device"? It's the laptop's screen ; I don't ever "connect" it myself...???
ru flag
Like, the group that owns it (`stat -c %G /sys/class/backlight/acpi_video0/brightness`) is just `root`, so that answer arguably boils down to "add `$USER` to the group `root`", right? Which is arguably... not even an answer?
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.