int SetFileSystemMountingOption()

in src/common/commonutils/MountUtils.c [199:450]


int SetFileSystemMountingOption(const char* mountDirectory, const char* mountType, const char* desiredOption, OsConfigLogHandle log)
{
    const char* fsMountTable = "/etc/fstab";
    const char* mountTable = "/etc/mtab";
    const char tempFileNameTemplate[] = "/etc/~xtab%d";
    const char* newLineAsIsTemplate = "\n%s %s %s %s %d %d";
    const char* newLineAddNewTemplate = "\n%s %s %s %s,%s %d %d";
    const char* mountAll = "mount -a";

    FILE* fsMountHandle = NULL;
    FILE* mountHandle = NULL;
    char* newLine = NULL;
    char* tempFileNameOne = NULL;
    char* tempFileNameTwo = NULL;
    char* tempFileNameThree = NULL;
    struct mntent* mountStruct = NULL;
    bool matchFound = false;
    int lineNumber = 1;
    int status = 0;

    if (((NULL == mountDirectory) && (NULL == mountType)) || (NULL == desiredOption))
    {
        OsConfigLogError(log, "SetFileSystemMountingOption called with invalid argument(s)");
        return EINVAL;
    }

    if (!FileExists(fsMountTable))
    {
        OsConfigLogInfo(log, "SetFileSystemMountingOption: '%s' not found, no place to set mounting options", fsMountTable);
        return 0;
    }

    if ((NULL == (tempFileNameOne = FormatAllocateString(tempFileNameTemplate, 1))) ||
        (NULL == (tempFileNameTwo = FormatAllocateString(tempFileNameTemplate, 2))) ||
        (NULL == (tempFileNameThree = FormatAllocateString(tempFileNameTemplate, 3))))
    {
        OsConfigLogError(log, "SetFileSystemMountingOption: out of memory");
        status = ENOMEM;
    }

    if (0 == status)
    {
        if (NULL != (fsMountHandle = setmntent(fsMountTable, "r")))
        {
            OsConfigLogInfo(log, "SetFileSystemMountingOption: looking for entries with mount directory '%s' or mount type '%s' in '%s'",
                mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", fsMountTable);

            while (NULL != (mountStruct = getmntent(fsMountHandle)))
            {
                if (((NULL != mountDirectory) && (NULL != mountStruct->mnt_dir) && (NULL != strstr(mountStruct->mnt_dir, mountDirectory))) ||
                    ((NULL != mountType) && (NULL != mountStruct->mnt_type) && (NULL != strstr(mountStruct->mnt_type, mountType))))
                {
                    matchFound = true;

                    if (NULL != hasmntopt(mountStruct, desiredOption))
                    {
                        OsConfigLogInfo(log, "SetFileSystemMountingOption: option '%s' for mount directory '%s' or mount type '%s' already set in '%s' at line %d ('%s')",
                            desiredOption, mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", fsMountTable, lineNumber, mountStruct->mnt_opts);

                        // The option is found, copy this mount entry as-is
                        FREE_MEMORY(newLine);
                        newLine = FormatAllocateString(newLineAsIsTemplate, mountStruct->mnt_fsname, mountStruct->mnt_dir, mountStruct->mnt_type,
                            mountStruct->mnt_opts, mountStruct->mnt_freq, mountStruct->mnt_passno);
                    }
                    else
                    {
                        OsConfigLogInfo(log, "SetFileSystemMountingOption: option '%s' for mount directory '%s' or mount type '%s' missing from file '%s' at line %d ('%s')",
                            desiredOption, mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", fsMountTable, lineNumber, mountStruct->mnt_opts);

                        // The option is not found and is needed for this entry, add the needed option when copying this mount entry
                        FREE_MEMORY(newLine);
                        newLine = FormatAllocateString(newLineAddNewTemplate, mountStruct->mnt_fsname, mountStruct->mnt_dir, mountStruct->mnt_type,
                            mountStruct->mnt_opts, desiredOption, mountStruct->mnt_freq, mountStruct->mnt_passno);
                    }

                    if (NULL != newLine)
                    {
                        if (0 != LineAlreadyExistsInFile(tempFileNameOne, newLine, log))
                        {
                            if (0 != (status = AppendPayloadToFile(tempFileNameOne, newLine, (const int)strlen(newLine), log) ? 0 : ENOENT))
                            {
                                OsConfigLogInfo(log, "SetFileSystemMountingOption: cannot collect entries from '%s'", fsMountTable);
                                break;
                            }
                        }
                    }
                    else
                    {
                        OsConfigLogError(log, "SetFileSystemMountingOption: out of memory");
                        status = ENOMEM;
                        break;
                    }
                }
                else
                {
                    // No match for this mount entry, copy the entire entry as-is
                    FREE_MEMORY(newLine);
                    if (NULL != (newLine = FormatAllocateString(newLineAsIsTemplate, mountStruct->mnt_fsname, mountStruct->mnt_dir, mountStruct->mnt_type,
                        mountStruct->mnt_opts, mountStruct->mnt_freq, mountStruct->mnt_passno)))
                    {
                        if (0 != LineAlreadyExistsInFile(tempFileNameOne, newLine, log))
                        {
                            if (0 != (status = AppendPayloadToFile(tempFileNameOne, newLine, (const int)strlen(newLine), log) ? 0 : ENOENT))
                            {
                                OsConfigLogInfo(log, "SetFileSystemMountingOption: cannot copy existing entries from '%s'", fsMountTable);
                                break;
                            }
                        }
                    }
                    else
                    {
                        OsConfigLogError(log, "SetFileSystemMountingOption: out of memory");
                        status = ENOMEM;
                        break;
                    }
                }

                lineNumber += 1;
            }

            endmntent(fsMountHandle);

            if (false == matchFound)
            {
                OsConfigLogInfo(log, "SetFileSystemMountingOption: mount directory '%s' and/or mount type '%s' not found in '%s'",
                    mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", fsMountTable);

                // No relevant mount entries found in /etc/fstab, try to find and copy entries from /etc/mtab if there are any matching
                if (FileExists(mountTable))
                {
                    if (NULL != (mountHandle = setmntent(mountTable, "r")))
                    {
                        lineNumber = 1;
                        OsConfigLogInfo(log, "SetFileSystemMountingOption: looking for entries with mount directory '%s' or mount type '%s' in '%s'",
                            mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", mountTable);

                        while (NULL != (mountStruct = getmntent(mountHandle)))
                        {
                            if (((NULL != mountDirectory) && (NULL != mountStruct->mnt_dir) && (NULL != strstr(mountStruct->mnt_dir, mountDirectory))) ||
                                ((NULL != mountType) && (NULL != mountStruct->mnt_type) && (NULL != strstr(mountStruct->mnt_type, mountType))))
                            {
                                matchFound = true;

                                if (NULL != hasmntopt(mountStruct, desiredOption))
                                {
                                    OsConfigLogInfo(log, "SetFileSystemMountingOption: option '%s' for mount directory '%s' or mount type '%s' found set in '%s' at line %d ('%s')",
                                        desiredOption, mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", mountTable, lineNumber, mountStruct->mnt_opts);

                                    // Copy this mount entry as-is
                                    FREE_MEMORY(newLine);
                                    newLine = FormatAllocateString(newLineAsIsTemplate, mountStruct->mnt_fsname, mountStruct->mnt_dir, mountStruct->mnt_type,
                                        mountStruct->mnt_opts, mountStruct->mnt_freq, mountStruct->mnt_passno);
                                }
                                else
                                {
                                    OsConfigLogInfo(log, "SetFileSystemMountingOption: option '%s' for mount directory '%s' or mount type '%s' found missing from '%s' at line %d ('%s')",
                                        desiredOption, mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", mountTable, lineNumber, mountStruct->mnt_opts);

                                    // The option is not found and is needed for this entry, add it when copying this entry
                                    FREE_MEMORY(newLine);
                                    newLine = FormatAllocateString(newLineAddNewTemplate, mountStruct->mnt_fsname, mountStruct->mnt_dir, mountStruct->mnt_type,
                                        mountStruct->mnt_opts, desiredOption, mountStruct->mnt_freq, mountStruct->mnt_passno);
                                }

                                if (NULL != newLine)
                                {
                                    if (0 != LineAlreadyExistsInFile(tempFileNameOne, newLine, log))
                                    {
                                        if (0 != (status = AppendPayloadToFile(tempFileNameOne, newLine, (const int)strlen(newLine), log) ? 0 : ENOENT))
                                        {
                                            OsConfigLogInfo(log, "SetFileSystemMountingOption: cannot collect entry from '%s'", mountTable);
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    OsConfigLogError(log, "SetFileSystemMountingOption: out of memory");
                                    status = ENOMEM;
                                    break;
                                }
                            }

                            lineNumber += 1;
                        }

                        endmntent(mountHandle);
                    }
                    else
                    {
                        status = (0 == errno) ? ENOENT : errno;
                        OsConfigLogInfo(log, "SetFileSystemMountingOption: cannot open '%s', setmntent() failed (%d)", mountTable, status);
                    }
                }
            }

            if (false == matchFound)
            {
                OsConfigLogInfo(log, "SetFileSystemMountingOption: mount directory '%s' and/or mount type '%s' not found in either '%s' or '%s', nothing to remediate",
                    mountDirectory ? mountDirectory : "-", mountType ? mountType : "-", fsMountTable, mountTable);
            }
        }
        else
        {
            status = (0 == errno) ? ENOENT : errno;
            OsConfigLogInfo(log, "SetFileSystemMountingOption: cannot open '%s', setmntent() failed (%d)", fsMountTable, status);
        }

        if (matchFound && (0 == status))
        {
            // Copy from the manually built temp mount file one to the temp mount file two using the *mntent API to ensure correct format
            if (0 == (status = CopyMountTableFile(tempFileNameOne, tempFileNameTwo, log)))
            {
                // Optionally, try to preserve the commented out lines from original /etc/fstab
                if (MakeFileBackupCopy(fsMountTable, tempFileNameThree, false, log))
                {
                    // Skip all lines containing either paths or 'UUID' entries
                    if ((0 == ReplaceMarkedLinesInFile(tempFileNameThree, "/", NULL, '#', false, log)) &&
                        (0 == ReplaceMarkedLinesInFile(tempFileNameThree, "UUID", NULL, '#', false, log)))
                    {
                        if (ConcatenateFiles(tempFileNameThree, tempFileNameTwo, false, log))
                        {
                            RenameFile(tempFileNameThree, tempFileNameTwo, log);
                        }
                    }
                }

                // When done assembling the final temp mount file two, move it in an atomic step to real mount file
                if (0 == (status = RenameFileWithOwnerAndAccess(tempFileNameTwo, fsMountTable, log)))
                {
                    // Command may fail when one configured mount point is not present, so ignore failures
                    ExecuteCommand(NULL, mountAll, false, false, 0, 0, NULL, NULL, NULL);
                }
                else
                {
                    OsConfigLogInfo(log, "SetFileSystemMountingOption:  RenameFileWithOwnerAndAccess('%s' to '%s') returned %d", tempFileNameTwo, fsMountTable, status);
                }
            }
        }

        remove(tempFileNameOne);
        remove(tempFileNameTwo);
        remove(tempFileNameThree);
    }

    FREE_MEMORY(newLine);
    FREE_MEMORY(tempFileNameOne);
    FREE_MEMORY(tempFileNameTwo);
    FREE_MEMORY(tempFileNameThree);

    return status;
}