title: Why is my Go app not reading from sysfs like the busybox `cat` command?
body: <p>Go 1.12 on <code>Linux 4.19.93 armv6l</code>. 
  Hardware is a raspberypi zero w (BCM2835) running a yocto linux image.</p>
  
  <p>I've got a gpio driven SRF04 proximity sensor driven by the srf04 linux driver.</p>
  
  <p>It works great over sysfs and the busybox shell.</p>
  
  <pre><code># cat /sys/bus/iio/devices/iio:device0/in_distance_raw
  1646
  </code></pre>
  
  <p>I've used Go before with IIO devices that support triggers and buffered output at high sample rates on this hardware platform. However for this application <a href="https://github.com/torvalds/linux/blob/master/drivers/iio/proximity/srf04.c" rel="nofollow noreferrer">the srf04 driver</a> doesn't implement those IIO features. Drat. I don't really feel like adding buffer / trigger support to the driver myself (at this time) since I do not have a need for a 'high' sample rate. A handful of pings per second should suffice for my purpose. I figure I'll calculate mean &amp; std. dev. for a rolling window of data points and 'divine' the signal out of the noise.</p>
  
  <p>So with that - I'd be perfectly happy to Read the bytes from the published sysfs file with Go.</p>
  
  <p>Which brings me to the point of this post.
  When I open the file for reading, and try to Read() any number of bytes, I <em>always</em> get a generic <code>-EIO</code> error.</p>
  
  <pre><code>func (s *Srf04) Read() (int, error) {
      samp := make([]byte, 16)
  
      f, err := os.OpenFile(s.readPath, OS.O_RDONLY, os.ModeDevice)
      if err != nil {
          return 0, err
      }
      defer f.Close()
  
      n, err := f.Read(samp)
      if err != nil {
          // This block is always executed.
          // The error is never a timeout, and always 'input/output error' (-EIO aka -5)
          log.Fatal(err)
      }
      ...
  }
  </code></pre>
  
  <p>This seems like strange behavior to me.
  So I decided to mess with using <code>io.ReadFull</code>. This yielded unreliable results.</p>
  
  <pre><code>func (s *Srf04) Read() (int, error) {
      samp := make([]byte, 16)
  
      f, err := os.OpenFile(s.readPath, OS.O_RDONLY, os.ModeDevice)
      if err != nil {
          return 0, err
      }
      defer f.Close()
  
      for {
          n, err := io.ReadFull(readFile, samp)
          log.Println("ReadFull ", n, " bytes.")
          if err == io.EOF {
              break
          }
          if err != nil {
              log.Println(err)
          }
      }
  
      ...
  
  }
  </code></pre>
  
  <p>I ended up adding it to a loop, as I found behavior changes from 'one-off' reads to multiple read calls subsequent to one another. I have it exiting if it gets an EOF, and repeatedly trying to read otherwise.</p>
  
  <p>The results are straight-up crazy unreliable, seemingly returning random results. Sometimes I get the -5, other times I read between 2 - 5 bytes from the device. Sometimes I get bytes without an eof file before the EOF. The bytes appear to represent character data for numbers (each rune is a rune between [0-9]) -- which I'd expect.</p>
  
  <p>Aside: I expect this is related to file polling and the go blocking IO implementation, but I have no way to really tell.</p>
  
  <p>As a temporary workaround, I decided try using os.exec, and now I get results I'd expect to see.</p>
  
  <pre><code>func (s *Srf04)Read() (int, error) {
      out, err := exec.Command("cat", s.readPath).Output()
      if err != nil  {
         return 0, err
      }
      return strconv.Atoi(string(out))
  }
  </code></pre>
  
  <p>But Yick. <code>os.exec</code>. Yuck.</p>