def read_pid(self):
        """Reads the pid file and returns the process id contained in it.

        This also verifies as best as it can that the process returned is running and is really an agent
        process.

        Note, if the agent is just in the process of starting, this might still return None due to race conditions.

        @return The id of the agent process or None if there is none or it cannot be read.
        @rtype: int or None
        """
        # The current invariants on the pidfile:
        #    - Contents: "$pid locked\n" where $pid is the process of the running agent.
        #          We used "locked" to distinguish that the agent is using the new method of locking the pidfile
        #          by holding a flock on it.  Finally, it is really important we terminate it with a newline
        #          because when we read the file, it is how we know if the file has been finished being written.
        #    - While the agent is running:
        #       * holds an exclusive flock on the pid file.
        #    - When the agent terminates:
        #       * the flock is released and the file is deleted.  Note, due to crashes, the file may not be
        #         actually deleted.
        #
        # Note, we do have to handle legacy pidfiles with this code base -- after all, when we upgrade,
        # we need the new agent to understand that the old one is still running.
        # So, if the pidfile does not have 'locked' in it, we fall back to the scheme where we look to see if the
        # pid is still running using a kill call.
        pf = None
        self._log_debug('Reading pidfile')
        try:
            # Read the pidfile
            try:
                pf = file(self.__pidfile, 'r')
                raw_contents = pf.read()
            except IOError:
                self._log('Checked pidfile: does not exist')
                return None

            if not '\n' in raw_contents:
                # This means the write to the pidfile is half-finished, so we just pretend like the file
                # did not exist.  This means the higher level code will think the agent isn't running, but
                # that's ok because this can have false negatives (and the agent is just starting, so who's to
                # say that we looked before it had even written the file).
                self._log('Checked pidfile: not finished writing')
                return None
            contents = raw_contents.strip().split()

            # Attempt to get a lock on it to see if the agent process is actually still holding a lock on it.
            try:
                fcntl.flock(pf, fcntl.LOCK_SH | fcntl.LOCK_NB)
                was_locked = False
                try:
                    fcntl.flock(pf, fcntl.LOCK_UN)
                except IOError, e:
                    self._log_debug('Unexpected error seen releasing lock: %s' % str(e))
            except IOError, e:
                # Triggered if the LOCK_SH call fails, indicating another process holds the lock.
                if (e.errno == errno.EAGAIN) or (e.errno == errno.EACCES):
                    was_locked = True
                else:
                    self._log_debug(str(e) % 'Unexpected error seen checking on lock status: %s')
                    was_locked = False
            pf.close()
            pf = None

        finally:
            if pf is not None:
                pf.close()

        pid = int(contents[0])

        # If the pid file was locked, we know the agent is still running.
        if was_locked:
            self._log('Checked pidfile: exists')
            return pid

        # If we see 'locked' in the pidfile, then we know a new agent did write it, but it's no longer running
        # (since the file was not locked).
        if len(contents) == 2 and contents[1] == 'locked':
            self._log('Checked pidfile: missing-')
            return None

        # We have a legacy agent pid file.  We see if the process is still alive on the pid in the pidfile.
        try:
            os.kill(pid, 0)
        except OSError, e:
            # ESRCH indicates the process is not running, in which case we ignore the pidfile.
            if e.errno == errno.ESRCH:
                self._log('Checked pidfile: missing+')
                return None
            # EPERM indicates the current user does not have permission to signal the process.. so, we just assume
            # it is the agent.
            elif e.errno != errno.EPERM:
                raise e

        self._log('Checked pidfile: exists*')
        return pid
dataset/ETHPy150Open scalyr/scalyr-agent-2/scalyr_agent/platform_posix.py/PidfileManager.read_pid/swapped operands of `%`