Szybet
Szybet

Reputation: 21

Reading stderr from a linux device, after writing to it from c++

When i write to a linux driver / device, in this case i want to put the embedded linux device to sleep:

echo "mem" > /sys/power/state

I get an error on the terminal if the above command fails

[ 2593.061030] dpm_run_callback(): elan_touch_suspend+0x0/0x114 returns 1
[ 2593.067578] PM: Device 0-0015 failed to suspend: error 1
[ 2593.072994] PM: Some devices failed to suspend, or early wake event detected
[ 2593.107845] ==== calc_soc_by_voltageMethod E60U22 ====

And i do this the same in c++:

int fd2 = open("/sys/power/state", O_RDWR);
write(fd2, "mem", 3);
close(fd2);

If the above command fails, i get the same error on the terminal. now i want to get this error as a string in c++, in shell i can do something like this:

echo "mem" > /sys/power/state 2>/tmp/sleep_error

But i cant figure this out in c++, I need to to try one more time if it fails

What I tryied:

Capturing cerr of the whole program, with freopen doesn't work. When I write to the device from another terminal, and do cat /dev/stderr from another, i get the output in the second one, I tryied to use it:

char byte[1000];
int stderrdevice = open("/dev/stderr", O_RDONLY | O_NOCTTY);
int fd2 = open("/sys/power/state", O_RDWR);
write(fd2, "mem", 3);
close(fd2);

ssize_t size = read(stderrdevice, &byte, 1000);

printf("Read byte %s\n", byte);

This doesn't work too. Any resources, documentation related to this are welcome

Upvotes: 1

Views: 259

Answers (1)

Szybet
Szybet

Reputation: 21

Thanks everyone for help and responding. user17732522 and Nate Eldredge were right. What i was trying to get was the kernel ring buffer, that was printing out to the serial connection. The same thing was in dmesg. I ended up using klogctl to get the errors. I couldn't get only the last line of dmesg with other klogctl options, and the code is a bit chaotic, but here is what I finally used:

bool continueSleeping = true;
  int count = 0;
  while (continueSleeping == true) {
    // https://linux.die.net/man/3/klogctl
    klogctl(5, NULL, 0);

    log("Trying sleep");
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    int fd2 = open("/sys/power/state", O_RDWR);
    int status = write(fd2, "mem", 3);
    close(fd2);

    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    log("After sleep");

    // get dmesg, and then only lines containing <3>
    char *logs_data;
    ssize_t len = klogctl(10, NULL, 0);
    logs_data = (char *)malloc(len);
    klogctl(3, logs_data, len);
    vector<string> dmesgErrorsVec;
    boost::split(dmesgErrorsVec, logs_data, boost::is_any_of("\n"),
                 boost::token_compress_on);

    // to show whole dmesg
    //log("dmesg: " + (string)logs_data);

    free(logs_data);
    string dmesgErrors;
    for (string line : dmesgErrorsVec) {
      if (line.find("<3>") != std::string::npos) {
        // tesdt
        dmesgErrors.append(line);
        dmesgErrors.append("\n");
      }
    }
    dmesgErrorsVec.clear();
    if (status == -1 or
        dmesgErrors.find("PM: Some devices failed to suspend") != std::string::npos) {
      log("Failed to suspend, dmesg errors:\n" + dmesgErrors);
      log("status: " + to_string(status));
      CEG();
      count = count + 1;
      if (count == 5) {
        log("5 failed attemts at suspending, sleep a little longer...");
        smartWait(10000);
      } else if (count == 15) {
        log("15 failed attempts at sleeping...");
        // Write to fbink here a sad message
      } else {
        smartWait(3000);
      }
    } else {
      // Exiting this sleeping hell
      log("Tryied going to sleep " + to_string(count) + "times");
      continueSleeping = false;
    }
  }

  log("Sleep finished, Exiting going to sleep");

Upvotes: 1

Related Questions