static int rotateLogSet(const struct logInfo *log, int force)
{
    unsigned i, j;
    int hasErrors = 0;
    int *logHasErrors;
    int numRotated = 0;
    struct logState **state;
    struct logNames **rotNames;

    logHasErrors = calloc(log->numFiles, sizeof(int));
    if (!logHasErrors) {
        message_OOM();
        return 1;
    }
    message(MESS_DEBUG, "\nrotating pattern: %s ", log->pattern);
    if (force) {
        message(MESS_DEBUG, "forced from command line ");
    }
    else {
        switch (log->criterium) {
            case ROT_HOURLY:
                message(MESS_DEBUG, "hourly ");
                break;
            case ROT_DAYS:
                message(MESS_DEBUG, "after %jd days ", (intmax_t)log->threshold);
                break;
            case ROT_WEEKLY:
                message(MESS_DEBUG, "weekly ");
                break;
            case ROT_MONTHLY:
                message(MESS_DEBUG, "monthly ");
                break;
            case ROT_YEARLY:
                message(MESS_DEBUG, "yearly ");
                break;
            case ROT_SIZE:
                message(MESS_DEBUG, "%jd bytes ", (intmax_t)log->threshold);
                break;
            default:
                message(MESS_FATAL, "rotateLogSet() does not have case for: %u ",
                        (unsigned) log->criterium);
        }
    }

    if (log->rotateCount > 0)
        message(MESS_DEBUG, "(%d rotations)\n", log->rotateCount);
    else if (log->rotateCount == 0)
        message(MESS_DEBUG, "(no old logs will be kept)\n");

    if (log->oldDir)
        message(MESS_DEBUG, "olddir is %s, ", log->oldDir);

    if (log->flags & LOG_FLAG_IFEMPTY)
        message(MESS_DEBUG, "empty log files are rotated, ");
    else
        message(MESS_DEBUG, "empty log files are not rotated, ");

    if (log->minsize)
        message(MESS_DEBUG, "only log files >= %jd bytes are rotated, ", (intmax_t)log->minsize);

    if (log->maxsize)
        message(MESS_DEBUG, "log files >= %jd are rotated earlier, ", (intmax_t)log->maxsize);

    if (log->rotateMinAge)
        message(MESS_DEBUG, "only log files older than %d days are rotated, ", log->rotateMinAge);

    if (log->logAddress) {
        message(MESS_DEBUG, "old logs mailed to %s\n", log->logAddress);
    } else {
        message(MESS_DEBUG, "old logs are removed\n");
    }

    if (log->numFiles == 0) {
        message(MESS_DEBUG, "No logs found. Rotation not needed.\n");
        free(logHasErrors);
        return 0;
    }

    if (log->flags & LOG_FLAG_SU) {
        if (switch_user(log->suUid, log->suGid) != 0) {
            free(logHasErrors);
            return 1;
        }
    }

    for (i = 0; i < log->numFiles; i++) {
        struct logState *logState;
        logHasErrors[i] = findNeedRotating(log, i, force);
        hasErrors |= logHasErrors[i];

        /* sure is a lot of findStating going on .. */
        if (((logState = findState(log->files[i]))) && logState->doRotate)
            numRotated++;
    }

    if (log->first) {
        if (!numRotated) {
            message(MESS_DEBUG, "not running first action script, "
                    "since no logs will be rotated\n");
        } else {
            message(MESS_DEBUG, "running first action script\n");
            if (runScript(log, log->pattern, NULL, log->first)) {
                message(MESS_ERROR, "error running first action script "
                        "for %s\n", log->pattern);
                hasErrors = 1;
                if (log->flags & LOG_FLAG_SU) {
                    if (switch_user_back() != 0) {
                        free(logHasErrors);
                        return 1;
                    }
                }
                /* finish early, firstaction failed, affects all logs in set */
                free(logHasErrors);
                return hasErrors;
            }
        }
    }

    state = malloc(log->numFiles * sizeof(struct logState *));
    rotNames = malloc(log->numFiles * sizeof(struct logNames *));

    if (state == NULL || rotNames == NULL) {
        message_OOM();
        if (log->flags & LOG_FLAG_SU) {
            switch_user_back();
        }
        free(rotNames);
        free(state);
        free(logHasErrors);
        return 1;
    }

    for (j = 0;
            (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && j < log->numFiles)
            || ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && j < 1); j++) {

        for (i = j;
                ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles)
                || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) {
            state[i] = findState(log->files[i]);
            if (!state[i])
                logHasErrors[i] = 1;

            rotNames[i] = malloc(sizeof(struct logNames));
            if (rotNames[i] == NULL) {
                message_OOM();
                if (log->flags & LOG_FLAG_SU) {
                    switch_user_back();
                }
                free(rotNames);
                free(state);
                free(logHasErrors);
                return 1;
            }
            memset(rotNames[i], 0, sizeof(struct logNames));

            logHasErrors[i] |=
                prerotateSingleLog(log, i, state[i], rotNames[i]);
            hasErrors |= logHasErrors[i];
        }

        if (log->pre
                && (!(
                        (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && (logHasErrors[j] || !state[j]->doRotate))
                        || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS))
                     ))
           ) {
            if (!numRotated) {
                message(MESS_DEBUG, "not running prerotate script, "
                        "since no logs will be rotated\n");
            } else {
                message(MESS_DEBUG, "running prerotate script\n");
                if (runScript(log, (log->flags & LOG_FLAG_SHAREDSCRIPTS) ? log->pattern : log->files[j], NULL, log->pre)) {
                    if (log->flags & LOG_FLAG_SHAREDSCRIPTS)
                        message(MESS_ERROR,
                                "error running shared prerotate script "
                                "for '%s'\n", log->pattern);
                    else {
                        message(MESS_ERROR,
                                "error running non-shared prerotate script "
                                "for %s of '%s'\n", log->files[j], log->pattern);
                    }
                    logHasErrors[j] = 1;
                    hasErrors = 1;
                }
            }
        }

        for (i = j;
                ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles)
                || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) {
            if (! ( (logHasErrors[i] && !(log->flags & LOG_FLAG_SHAREDSCRIPTS))
                        || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) ) ) {
                logHasErrors[i] |=
                    rotateSingleLog(log, i, state[i], rotNames[i]);
                hasErrors |= logHasErrors[i];
            }
        }

        if (log->post
                && (!(
                        (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && (logHasErrors[j] || !state[j]->doRotate))
                        || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS))
                     ))
           ) {
            if (!numRotated) {
                message(MESS_DEBUG, "not running postrotate script, "
                        "since no logs were rotated\n");
            } else {
                char *logfn = (log->flags & LOG_FLAG_SHAREDSCRIPTS) ? log->pattern : log->files[j];

                /* It only makes sense to pass in a final rotated filename if scripts are not shared */
                char *logrotfn = (log->flags & LOG_FLAG_SHAREDSCRIPTS) ? NULL : rotNames[j]->finalName;

                message(MESS_DEBUG, "running postrotate script\n");
                if (runScript(log, logfn, logrotfn, log->post)) {
                    if (log->flags & LOG_FLAG_SHAREDSCRIPTS)
                        message(MESS_ERROR,
                                "error running shared postrotate script "
                                "for '%s'\n", log->pattern);
                    else {
                        message(MESS_ERROR,
                                "error running non-shared postrotate script "
                                "for %s of '%s'\n", log->files[j], log->pattern);
                    }
                    logHasErrors[j] = 1;
                    hasErrors = 1;
                }
            }
        }

        for (i = j;
                ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles)
                || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) {
            if (! ( (logHasErrors[i] && !(log->flags & LOG_FLAG_SHAREDSCRIPTS))
                        || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) ) ) {
                logHasErrors[i] |=
                    postrotateSingleLog(log, i, state[i], rotNames[i]);
                hasErrors |= logHasErrors[i];
            }
        }

    }

    for (i = 0; i < log->numFiles; i++) {
        free(rotNames[i]->firstRotated);
        free(rotNames[i]->disposeName);
        free(rotNames[i]->finalName);
        free(rotNames[i]->dirName);
        free(rotNames[i]->baseName);
        free(rotNames[i]);
    }
    free(rotNames);
    free(state);

    if (log->last) {
        if (!numRotated) {
            message(MESS_DEBUG, "not running last action script, "
                    "since no logs will be rotated\n");
        } else {
            message(MESS_DEBUG, "running last action script\n");
            if (runScript(log, log->pattern, NULL, log->last)) {
                message(MESS_ERROR, "error running last action script "
                        "for %s\n", log->pattern);
                hasErrors = 1;
            }
        }
    }

    if (log->flags & LOG_FLAG_SU) {
        if (switch_user_back() != 0) {
            free(logHasErrors);
            return 1;
        }
    }
    free(logHasErrors);
    return hasErrors;
}