Invalid file type error raised when using 'does exist' and unmonitor

Issue #931 resolved
Roberto Rodriguez created an issue

I have a daemon which depends on the presence of a file. If that file is present, the daemon is not started and should not be monitored either. To solve this problem, I check for the presence of the file as follows:

check process proc with pidfile /var/run/proc.pid
    ...
    depends on myfile-check

check file myfile-check with path /home/checked-file
    if does exist then unmonitor

When the file does not exist, everything goes fine, but when it does exist monit says the file is ‘Invalid Type’, when it is just a regular empty file. The stat result on the fille:

stat /home/checked-file
  File: /home/checked-file
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: 16h/22d Inode: 365         Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-09-09 09:48:16.000000000 +0000
Modify: 2020-09-09 09:48:16.000000000 +0000
Change: 2020-09-09 09:48:16.000000000 +0000
 Birth: -

The monit status is:

File 'myfile-check'
  status                       Invalid type
  monitoring status            Monitored
  monitoring mode              active
  on reboot                    start
  permission                   -
  uid                          -
  gid                          -
  size                         -
  access timestamp             -
  change timestamp             -
  modify timestamp             -
  data collected               Wed, 09 Sep 2020 09:01:48

From the monit output, I obtained the following log:

Sep  9 17:10:22 monit[6595]: 'myfile-check' seeking to the end of the file
Sep  9 17:10:22 monit[6595]: 'myfile-check' file exists
Sep  9 17:10:22 monit[6595]: 'myfile-check' monitoring disabled
Sep  9 17:10:22 monit[6595]: 'myfile-check' is neither a regular file nor a socket
Sep  9 17:10:22 monit[6595]: 'myfile-check' trying to restart
Sep  9 17:10:22 monit[6595]: 'myfile-check' stop skipped -- method not defined
Sep  9 17:10:22 monit[6595]: 'myfile-check' start method not defined
Sep  9 17:10:22 monit[6595]: 'myfile-check' monitoring enabled

Going into the code in validate.c in the check_file function, the file existence is firstly checked and an event is posted. In this case an unmonitor event is launched as shown in the log. However, it seems that the “s->inf.file->mode” field may be written when disabling the monitoring, and the later check “S_ISREG(s->inf.file->mode)” fails, which raises the Invalid Type event and restarts monitoring.

Comments (3)

  1. Lutz Mader

    Hello Roberto,
    nice to see, you are right, the result seems to depend to the called action.

    proc                             Not monitored               Process
    myfile-check                     Invalid type                File
    other-check                      Does exist                  File
    

    I use similar checks to handle some application, but I start scripts in the check file statement.

    check file myfile-check with path /tmp/checked-file
      if does exist then unmonitor
    
    check file other-check with path /tmp/checked-file
      if does exist then alert
    

    The second checks work like expected, the first does not.

    check file myfile-check with path /tmp/checked-file
      if does exist then exec "/usr/local/bin/monit unmonitor myfile-check"
    

    And the third sample works like expected too.
    But, be aware, this will not stop the depend process, it disable the monitoring only.

    With regards,
    Lutz

  2. Lutz Mader

    Hello Tildeslash,
    Roberto is right, a action like start/stop/unmonitor in a “exist” test will damage the collected data/status for a service.
    With a closer look to the following (and all other similar checks).

    State_Type check_file(Service_T s) {
            ASSERT(s);
            struct stat stat_buf;
    :
                    s->inf.file->timestamp.modify = stat_buf.st_mtime;
                    for (NonExist_T l = s->nonexistlist; l; l = l->next) {
                            Event_post(s, Event_NonExist, State_Succeeded, l->action, "file exists");
                    }
    

    This works like suggested, this is the “not exist” test.

    But if a "exist" check was done, the event data/status is corrupted and this data/status is used later.

                    for (Exist_T l = s->existlist; l; l = l->next) {
                            rv = State_Failed;
                            Event_post(s, Event_Exist, State_Failed, l->action, "file exists");
                    }
            }
            if (! S_ISREG(s->inf.file->mode) && ! S_ISSOCK(s->inf.file->mode)) {
                    Event_post(s, Event_Invalid, State_Failed, s->action_INVALID, "is neither a regular file nor a socket");
                    return State_Failed;
            } else {
                    Event_post(s, Event_Invalid, State_Succeeded, s->action_INVALID, "is a regular %s",
                               S_ISSOCK(s->inf.file->mode) ? "socket" : "file");
            }
    

    And in "Event_post" the "count" is set to "1" (see below) and the "if" with "S_ISREG" and "S_ISSOCK" became true (see above).

            e->state_changed = _checkState(e, state);
            /* In the case that the state changed, update it and reset the counter */
            if (e->state_changed) {
                    e->state = state;
                    e->count = 1;
            } else {
                    e->count++;
            }
    

    You can delete the file and enable monitoring, but the status will not changed until you reload or restart the monitor.

    A short overview only,
    Lutz

    p.s.
    I checked this based on Monit 5.27.0.
    The "not exist" check works like expected, but "exist" does not.

  3. Log in to comment