예제 #1
0
파일: files_links.c 프로젝트: baptr/core
PromiseResult VerifyLink(EvalContext *ctx, char *destination, const char *source, Attributes attr, const Promise *pp)
{
    char to[CF_BUFSIZE], linkbuf[CF_BUFSIZE], absto[CF_BUFSIZE];
    struct stat sb;

    memset(to, 0, CF_BUFSIZE);

    if ((!IsAbsoluteFileName(source)) && (*source != '.'))        /* links without a directory reference */
    {
        snprintf(to, CF_BUFSIZE - 1, "./%s", source);
    }
    else
    {
        strncpy(to, source, CF_BUFSIZE - 1);
    }

    if (!IsAbsoluteFileName(to))        /* relative path, must still check if exists */
    {
        Log(LOG_LEVEL_DEBUG, "Relative link destination detected '%s'", to);
        strcpy(absto, AbsLinkPath(destination, to));
        Log(LOG_LEVEL_DEBUG, "Absolute path to relative link '%s', '%s'", absto, destination);
    }
    else
    {
        strcpy(absto, to);
    }

    bool source_file_exists = true;

    if (stat(absto, &sb) == -1)
    {
        Log(LOG_LEVEL_DEBUG, "No source file");
        source_file_exists = false;
    }

    if ((!source_file_exists) && (attr.link.when_no_file != cfa_force) && (attr.link.when_no_file != cfa_delete))
    {
        Log(LOG_LEVEL_INFO, "Source %s for linking is absent", absto);
        cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_FAIL, pp, attr, "Unable to create link %s -> %s, no source", destination, to);
        return PROMISE_RESULT_WARN;
    }

    if ((!source_file_exists) && (attr.link.when_no_file == cfa_delete))
    {
        KillGhostLink(ctx, destination, attr, pp);
        return PROMISE_RESULT_CHANGE;
    }

    memset(linkbuf, 0, CF_BUFSIZE);

    if (readlink(destination, linkbuf, CF_BUFSIZE - 1) == -1)
    {

        if (!MakeParentDirectory2(destination, attr.move_obstructions, EnforcePromise(attr.transaction.action)))
        {
            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, attr, "Unable to create parent directory of link %s -> %s (enforce=%d)",
                 destination, to, EnforcePromise(attr.transaction.action));
            return PROMISE_RESULT_FAIL;
        }
        else
        {
            if (!MoveObstruction(ctx, destination, attr, pp))
            {
                cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_FAIL, pp, attr, "Unable to create link %s -> %s", destination, to);
                return PROMISE_RESULT_FAIL;
            }

            return MakeLink(ctx, destination, source, attr, pp) ? PROMISE_RESULT_CHANGE : PROMISE_RESULT_FAIL;
        }
    }
    else
    {
        int ok = false;

        if ((attr.link.link_type == FILE_LINK_TYPE_SYMLINK) && (strcmp(linkbuf, to) != 0) && (strcmp(linkbuf, source) != 0))
        {
            ok = true;
        }
        else if (strcmp(linkbuf, source) != 0)
        {
            ok = true;
        }

        if (ok)
        {
            if (attr.move_obstructions)
            {
                if (!DONTDO)
                {
                    cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, attr, "Overriding incorrect link %s\n", destination);

                    if (unlink(destination) == -1)
                    {
                        cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_FAIL, pp, attr, "Link %s points to %s not %s - error removing link",
                             destination, linkbuf, to);
                        return PROMISE_RESULT_FAIL;
                    }

                    return MakeLink(ctx, destination, source, attr, pp);
                }
                else
                {
                    Log(LOG_LEVEL_ERR, "Must remove incorrect link %s", destination);
                    return PROMISE_RESULT_NOOP;
                }
            }
            else
            {
                cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_FAIL, pp, attr, "Link %s points to %s not %s - not authorized to override",
                     destination, linkbuf, to);
                return true;
            }
        }
        else
        {
            cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, attr, "Link %s points to %s - promise kept", destination, source);
            return PROMISE_RESULT_NOOP;
        }
    }
}
예제 #2
0
static PromiseResult VerifyFileSystem(EvalContext *ctx, char *name, Attributes a, Promise *pp)
{
    struct stat statbuf, localstat;
    Dir *dirh;
    const struct dirent *dirp;
    off_t sizeinbytes = 0;
    long filecount = 0;
    char buff[CF_BUFSIZE];

    Log(LOG_LEVEL_VERBOSE, "Checking required filesystem %s", name);

    if (stat(name, &statbuf) == -1)
    {
        return PROMISE_RESULT_NOOP;
    }

    if (S_ISLNK(statbuf.st_mode))
    {
        KillGhostLink(ctx, name, a, pp);
        return PROMISE_RESULT_NOOP;
    }

    if (S_ISDIR(statbuf.st_mode))
    {
        if ((dirh = DirOpen(name)) == NULL)
        {
            Log(LOG_LEVEL_ERR, "Can't open directory '%s' which checking required/disk. (opendir: %s)", name, GetErrorStr());
            return PROMISE_RESULT_NOOP;
        }

        for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
        {
            if (!ConsiderLocalFile(dirp->d_name, name))
            {
                continue;
            }

            filecount++;

            strcpy(buff, name);

            if (buff[strlen(buff)] != FILE_SEPARATOR)
            {
                strcat(buff, FILE_SEPARATOR_STR);
            }

            strcat(buff, dirp->d_name);

            if (lstat(buff, &localstat) == -1)
            {
                if (S_ISLNK(localstat.st_mode))
                {
                    KillGhostLink(ctx, buff, a, pp);
                    continue;
                }

                Log(LOG_LEVEL_ERR, "Can't stat volume '%s'. (lstat: %s)", buff, GetErrorStr());
                continue;
            }

            sizeinbytes += localstat.st_size;
        }

        DirClose(dirh);

        if (sizeinbytes < 0)
        {
            Log(LOG_LEVEL_VERBOSE, "Internal error: count of byte size was less than zero!");
            return PROMISE_RESULT_NOOP;
        }

        if (sizeinbytes < a.volume.sensible_size)
        {
            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, a, "File system '%s' is suspiciously small! (%jd bytes)", name,
                 (intmax_t) sizeinbytes);
            return PROMISE_RESULT_INTERRUPTED;
        }

        if (filecount < a.volume.sensible_count)
        {
            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, a, "Filesystem '%s' has only %ld files/directories.", name,
                 filecount);
            return PROMISE_RESULT_INTERRUPTED;
        }
    }

    cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "Filesystem '%s' content seems to be sensible as promised", name);
    return PROMISE_RESULT_NOOP;
}
예제 #3
0
int DepthSearch(char *name, struct stat *sb, int rlevel, Attributes attr, Promise *pp)
{
    Dir *dirh;
    int goback;
    const struct dirent *dirp;
    char path[CF_BUFSIZE];
    struct stat lsb;

    if (!attr.havedepthsearch)  /* if the search is trivial, make sure that we are in the parent dir of the leaf */
    {
        char basedir[CF_BUFSIZE];

        CfDebug(" -> Direct file reference %s, no search implied\n", name);
        snprintf(basedir, sizeof(basedir), "%s", name);
        ChopLastNode(basedir);
        chdir(basedir);
        return VerifyFileLeaf(name, sb, attr, pp);
    }

    if (rlevel > CF_RECURSION_LIMIT)
    {
        CfOut(cf_error, "", "WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)", rlevel, name);
        return false;
    }

    if (rlevel > CF_RECURSION_LIMIT)
    {
        CfOut(cf_error, "", "WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)", rlevel, name);
        return false;
    }

    memset(path, 0, CF_BUFSIZE);

    CfDebug("To iterate is Human, to recurse is Divine...(%s)\n", name);

    if (!PushDirState(name, sb))
    {
        return false;
    }

    if ((dirh = OpenDirLocal(".")) == NULL)
    {
        CfOut(cf_inform, "opendir", "Could not open existing directory %s\n", name);
        return false;
    }

    for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
    {
        if (!ConsiderFile(dirp->d_name, name, attr, pp))
        {
            continue;
        }

        strcpy(path, name);
        AddSlash(path);

        if (!JoinPath(path, dirp->d_name))
        {
            CloseDir(dirh);
            return true;
        }

        if (lstat(dirp->d_name, &lsb) == -1)
        {
            CfOut(cf_verbose, "lstat", "Recurse was looking at %s when an error occurred:\n", path);
            continue;
        }

        if (S_ISLNK(lsb.st_mode))       /* should we ignore links? */
        {
            if (!KillGhostLink(path, attr, pp))
            {
                VerifyFileLeaf(path, &lsb, attr, pp);
            }
            else
            {
                continue;
            }
        }

        /* See if we are supposed to treat links to dirs as dirs and descend */

        if (attr.recursion.travlinks && S_ISLNK(lsb.st_mode))
        {
            if (lsb.st_uid != 0 && lsb.st_uid != getuid())
            {
                CfOut(cf_inform, "",
                      "File %s is an untrusted link: cfengine will not follow it with a destructive operation", path);
                continue;
            }

            /* if so, hide the difference by replacing with actual object */

            if (cfstat(dirp->d_name, &lsb) == -1)
            {
                CfOut(cf_error, "stat", "Recurse was working on %s when this failed:\n", path);
                continue;
            }
        }

        if (attr.recursion.xdev && DeviceBoundary(&lsb, pp))
        {
            CfOut(cf_verbose, "", "Skipping %s on different device - use xdev option to change this\n", path);
            continue;
        }

        if (S_ISDIR(lsb.st_mode))
        {
            if (SkipDirLinks(path, dirp->d_name, attr.recursion))
            {
                continue;
            }

            if (attr.recursion.depth > 1 && rlevel <= attr.recursion.depth)
            {
                CfOut(cf_verbose, "", " ->>  Entering %s (%d)\n", path, rlevel);
                goback = DepthSearch(path, &lsb, rlevel + 1, attr, pp);
                PopDirState(goback, name, sb, attr.recursion);
                VerifyFileLeaf(path, &lsb, attr, pp);
            }
            else
            {
                VerifyFileLeaf(path, &lsb, attr, pp);
            }
        }
        else
        {
            VerifyFileLeaf(path, &lsb, attr, pp);
        }
    }

    CloseDir(dirh);
    return true;
}
예제 #4
0
static int VerifyFileSystem(EvalContext *ctx, char *name, Attributes a, Promise *pp)
{
    struct stat statbuf, localstat;
    Dir *dirh;
    const struct dirent *dirp;
    off_t sizeinbytes = 0;
    long filecount = 0;
    char buff[CF_BUFSIZE];

    CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Checking required filesystem %s\n", name);

    if (cfstat(name, &statbuf) == -1)
    {
        return (false);
    }

    if (S_ISLNK(statbuf.st_mode))
    {
        KillGhostLink(ctx, name, a, pp);
        return (true);
    }

    if (S_ISDIR(statbuf.st_mode))
    {
        if ((dirh = DirOpen(name)) == NULL)
        {
            CfOut(OUTPUT_LEVEL_ERROR, "opendir", "Can't open directory %s which checking required/disk\n", name);
            return false;
        }

        for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
        {
            if (!ConsiderFile(ctx, dirp->d_name, name, a, pp))
            {
                continue;
            }

            filecount++;

            strcpy(buff, name);

            if (buff[strlen(buff)] != FILE_SEPARATOR)
            {
                strcat(buff, FILE_SEPARATOR_STR);
            }

            strcat(buff, dirp->d_name);

            if (lstat(buff, &localstat) == -1)
            {
                if (S_ISLNK(localstat.st_mode))
                {
                    KillGhostLink(ctx, buff, a, pp);
                    continue;
                }

                CfOut(OUTPUT_LEVEL_ERROR, "lstat", "Can't stat volume %s\n", buff);
                continue;
            }

            sizeinbytes += localstat.st_size;
        }

        DirClose(dirh);

        if (sizeinbytes < 0)
        {
            CfOut(OUTPUT_LEVEL_VERBOSE, "", "Internal error: count of byte size was less than zero!\n");
            return true;
        }

        if (sizeinbytes < a.volume.sensible_size)
        {
            cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_INTERRUPTED, "", pp, a, " !! File system %s is suspiciously small! (%jd bytes)\n", name,
                 (intmax_t) sizeinbytes);
            return (false);
        }

        if (filecount < a.volume.sensible_count)
        {
            cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_INTERRUPTED, "", pp, a, " !! Filesystem %s has only %ld files/directories.\n", name,
                 filecount);
            return (false);
        }
    }

    cfPS(ctx, OUTPUT_LEVEL_INFORM, PROMISE_RESULT_NOOP, "", pp, a, " -> Filesystem %s's content seems to be sensible as promised\n", name);
    return (true);
}