Search code examples
clinuxscreen-brightness

Can read but not write proc file in C


I am writing a C program to change the screen brightness as xbacklight does not work in my circumstance. The solution should be native C (no system() function), because the program should be executable as a normal user via setuid. Calling external shell commands or scripts causes the kernel to ignore this bit.

Reading the proc file that controls the brightness works fine, but writing to it using C produces no result, even if I run the program as root. The fprintf call returns -130, indicating an error. As a sanity check, I included a working solution using system() as a comment.

[...]
const char* brightness = "/sys/class/backlight/intel_backlight/brightness";
f = fopen(brightness, (!strncmp(argv[1], "get", 3)) ? "r" : "rw");
[...]

int get_brightness() {
  int buff;
  fscanf(f, "%d", &buff);
  return buff;
}

int set(int i) {
  i = MAX(0, MIN(255, i));
  fprintf(f, "%d", i);
  printf("%d", i);
  //char *cmd = (char*) malloc(59 *sizeof(char));
  //snprintf(cmd, 59, "echo %d > %s", i, brightness);
  //system(cmd);
  //free(cmd);
}


Solution

  • f = fopen(brightness, (!strncmp(argv[1], "get", 3)) ? "r" : "rw");
    

    "rw" is not a valid argument for the mode argument of fopen(3). To open a file in read/write mode with fopen(3), you should use "r+".

    Using "rw" is undefined behaviour -- in Linux/glibc it will be treated just as a single "r", the file will be opened in read-only mode, and the printf -> write will fail.

    Generally, it's not a very smart idea to use buffered i/o with such tiny files. You should look into dprintf(3), if you need to write formatted data to a file descriptor.

    Also, I would just use a list of fixed values in a setuid program, instead of having to validate arguments, and take care that the validating code don't become itself a liability, etc.