Fix handling of invalid entries in the score table.
authorAndre Noll <maan@systemlinux.org>
Sun, 18 Nov 2007 19:59:49 +0000 (20:59 +0100)
committerAndre Noll <maan@systemlinux.org>
Sun, 18 Nov 2007 19:59:49 +0000 (20:59 +0100)
It may happen that the score table contains references to files that
no longer exist in the file system. The current code fails badly in
this case.

In open_next_audio_file(), if the file corresponding to the next
entry in the score table can not be opened, delete this entry from
the score table and try the next entry.

If the score table becomes empty, send NO_ADMISSIBLE_FILES back to para_server
and make recv_afs_result() switch to stop mode in this case.

afs.c
afs.h
error.h
vss.c

diff --git a/afs.c b/afs.c
index 353626e..8a60166 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -487,17 +487,26 @@ int open_next_audio_file(void)
        int ret, shmid;
        char buf[8];
        long score;
-
+again:
        PARA_NOTICE_LOG("getting next audio file\n");
        ret = score_get_best(&aft_row, &score);
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+               goto no_admissible_files;
+       }
        ret = open_and_update_audio_file(aft_row, score, &afd);
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+               ret = score_delete(aft_row);
+               if (ret < 0) {
+                       PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+                       goto no_admissible_files;
+               }
+               goto again;
+       }
        shmid = ret;
        if (!write_ok(server_socket)) {
-               PARA_EMERG_LOG("afs_socket not writable\n");
+               ret = -E_AFS_SOCKET;
                goto destroy;
        }
        *(uint32_t *)buf = NEXT_AUDIO_FILE;
@@ -506,10 +515,13 @@ int open_next_audio_file(void)
        close(afd.fd);
        if (ret >= 0)
                return ret;
-       PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
 destroy:
        shm_destroy(shmid);
        return ret;
+no_admissible_files:
+       *(uint32_t *)buf = NO_ADMISSIBLE_FILES;
+       *(uint32_t *)(buf + 4) = (uint32_t)0;
+       return send_bin_buffer(server_socket, buf, 8);
 }
 
 /* Never fails if arg == NULL */
@@ -846,8 +858,10 @@ static void execute_server_command(void)
        PARA_DEBUG_LOG("received: %s\n", buf);
        if (!strcmp(buf, "new")) {
                ret = open_next_audio_file();
-               if (ret < 0)
-                       PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+               if (ret < 0) {
+                       PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
+                       unregister_tasks();
+               }
                return;
        }
        PARA_ERROR_LOG("unknown command\n");
diff --git a/afs.h b/afs.h
index 7aea5cb..977fc40 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -126,6 +126,7 @@ struct audio_file_data {
 
 enum afs_server_code {
        NEXT_AUDIO_FILE,
+       NO_ADMISSIBLE_FILES,
        AFD_CHANGE
 };
 
diff --git a/error.h b/error.h
index 3e4911b..f1a3e41 100644 (file)
--- a/error.h
+++ b/error.h
@@ -84,6 +84,7 @@ extern const char **para_errlist[];
        PARA_ERROR(INPUT_TOO_LARGE, "input too large for stdin command"), \
        PARA_ERROR(AFS_SYNTAX, "afs syntax error"), \
        PARA_ERROR(AFS_SIGNAL, "afs caught deadly signal"), \
+       PARA_ERROR(AFS_SOCKET, "afs socket not writable"), \
        PARA_ERROR(AFS_PARENT_DIED, "fatal: server process terminated"), \
 
 
@@ -314,7 +315,7 @@ extern const char **para_errlist[];
        PARA_ERROR(AUDIO_FORMAT, "audio format not recognized"), \
        PARA_ERROR(CHUNK, "unable to get chunk"), \
        PARA_ERROR(SHORT_AFS_READ, "short read from afs socket"), \
-       PARA_ERROR(BAD_AFS_CODE, "received junk from afs"), \
+       PARA_ERROR(NOFD, "did not receive open fd from afs"), \
 
 
 #define CRYPT_ERRORS \
diff --git a/vss.c b/vss.c
index 46fb319..efd0c5e 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -345,6 +345,7 @@ static int recv_afs_msg(int *fd, uint32_t *code, uint32_t *data)
        struct iovec iov;
        int ret = 0;
 
+       *fd = -1;
        iov.iov_base = buf;
        iov.iov_len = sizeof(buf);
        msg.msg_iov = &iov;
@@ -355,6 +356,7 @@ static int recv_afs_msg(int *fd, uint32_t *code, uint32_t *data)
        ret = recvmsg(afs_socket, &msg, 0);
        if (ret < 0)
                return -ERRNO_TO_PARA_ERROR(errno);
+       afsss = AFS_SOCKET_READY;
        if (iov.iov_len != sizeof(buf))
                return -E_SHORT_AFS_READ;
        *code = *(uint32_t*)buf;
@@ -372,7 +374,7 @@ static int recv_afs_msg(int *fd, uint32_t *code, uint32_t *data)
 
 static void recv_afs_result(void)
 {
-       int ret, passed_fd = -1, shmid;
+       int ret, passed_fd, shmid;
        uint32_t afs_code = 0, afs_data = 0;
        struct stat statbuf;
        struct timeval now;
@@ -380,12 +382,13 @@ static void recv_afs_result(void)
        ret = recv_afs_msg(&passed_fd, &afs_code, &afs_data);
        if (ret < 0)
                goto err;
-       PARA_DEBUG_LOG("got the fd: %d, code: %u, shmid: %u\n",
-               passed_fd, afs_code, afs_data);
-       ret = -E_BAD_AFS_CODE;
+       PARA_DEBUG_LOG("fd: %d, code: %u, shmid: %u\n", passed_fd, afs_code,
+               afs_data);
+       ret = -E_NOFD;
        if (afs_code != NEXT_AUDIO_FILE)
                goto err;
-       afsss = AFS_SOCKET_READY;
+       if (passed_fd < 0)
+               goto err;
        shmid = afs_data;
        ret = load_afd(shmid, &mmd->afd);
        if (ret < 0)
@@ -415,6 +418,7 @@ err:
        if (passed_fd >= 0)
                close(passed_fd);
        PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+       mmd->new_vss_status_flags = VSS_NEXT;
 }
 
 void vss_post_select(fd_set *rfds, fd_set *wfds)