I'm getting the following compiler warning each time I try and compile an application I'm building:
└─$ gcc -o svr2 common.h launch.c tools.c netops.c
netops.c: In function ‘acceptClient’:
netops.c:138:33: warning: implicit declaration of function ‘displayMenu’ [-Wimplicit-function-declaration]
  138 |                                 displayMenu(clnFd);
      |                                 ^~~~~~~~~~~
The application consists of 4 files:
- Common.h - function prototypes and defines
- Launch.c - main entry point
- Netops.c - Networking functions
- Tools.c - Tools that the server will provide
All .c files have #include "common.h" as their first line. Can someone please have a look and see why it thinks I'm implicitly declaring this function? (If there is any vulnerable code ignore it as this is going to be a CTF binary).
Code base as follows (most code left out for brevity or is incomplete at present):
common.h
#ifndef _COMMON_H_
#define _COMMON_H_
/* System includes here */
/* List of defines here */
/* Function prototypes */
int launchServer();
int acceptClient(int);
int writeToClient(int, char *);
int readFromClient(int, char *);
int b64Encoder(int);
int checkPassword(int);
int printFlag();
int b64Decode(int);
void displayMenu(int);
#endif /* _COMMON_H_ */
netops.c
#include "common.h"
// Some code omitted here
//...
int acceptClient(int svrFd)
{
    struct sockaddr_in cln;
    int result = 0;
    int clnFd = 0;
    int clnPort = 0;
    int pid = 0;
    socklen_t len = 0;
    char *clnIp;
    // Attempt to accept incoming client
    len = sizeof(cln);
    for(;;)
    {
        clnFd = accept(svrFd, (struct sockaddr *)&cln, &len);
        if(SOCKERR == clnFd)
        {
            fprintf(stderr, "[-] Unable to accept incoming client. Error is: %s (%d).\n", strerror(errno), errno);
            close(clnFd);
            continue;
        }
        clnIp = inet_ntoa(cln.sin_addr);
        clnPort = ntohs(cln.sin_port);
        fprintf(stdout, "[*] New connection from client: %s:%d.\n", clnIp, clnPort);
        // Set client socket to non-blocking
        result = fcntl(clnFd, F_SETFL, fcntl(clnFd, F_GETFL) | O_NONBLOCK);
        if(FCNTLERR == result)
        {
            fprintf(stderr, "[-] Unable to set the client port to non-blocking. Attempting to continue. Error is: %s (%d).\n", strerror(errno), errno);
        }
        pid = fork();
        if(pid < 0)
        {
            // Unable to fork
            fprintf(stderr, "[-] Unable to fork new process for %s:%d. Error is: %s (%d).\n", clnIp, clnPort, strerror(errno), errno);
            close(clnFd);
            continue;
        }
        if(pid == 0)
        {
            // This is the client process
            fprintf(stdout, "[*] Forked new process for client: %s:%d.\n", clnIp, clnPort);
            result = checkPassword(clnFd);
            if(CLNERR == result)
            {
                close(clnFd);
                return CLNERR;
            }
            if(CLNCLOSE == result)
            {
                fprintf(stderr, "[-] Client connection %s:%d closed.\n", clnIp, clnPort);
                close(clnFd);
                continue;
            }
            if(PASSCOUNTEXCEED == result)
            {
                fprintf(stderr, "[-] Client %s:%d exceeded the maximum password attempts allowed.\n", clnIp, clnPort);
                close(clnFd);
                continue;
            }
            if(SUCCESS == result)
            {
                // FUNCTION CALLED HERE
                displayMenu(clnFd);
            }
        }
    }
    // Should never hit here. If it does, it means we have broken out of the while loop for an unknown reason.
    close(clnFd);
    return CLNERR;
}
//...
// Some code omitted here
tools.c
#include "common.h"
int b64Encode(int clnFd)
{
    //...
    return SUCCESS;
}
int b64Decode(int clnFd)
{
    return 0;
}
void displayMenu(int clnFd)
{
    // FUNCTION CODE HERE
    int result = SUCCESS;
    result = b64Encode(clnFd);
}
int checkPassword(int clnFd)
{
    int passCount = 0;
    int clnWr = SUCCESS;
    int clnRd = SUCCESS;
    int result = SUCCESS;
    ssize_t len = 0;
    char *readBuff;
    char *writeBuff;
    char *writeText;
    const char *correctPwd = "************";
    // Malloc 1024 bytes to both read and write buffers
    readBuff = (char *)malloc(R_BUFLEN * sizeof(char));
    writeBuff = (char *)malloc(W_BUFLEN * sizeof(char));
    // Request the password
    writeText = "Enter the server password to continue";
    snprintf(writeBuff, W_BUFLEN, "%s (Attempt %d of %d): ", writeText, passCount+1, MAXPASSCOUNT);
    clnWr = writeToClient(clnFd, writeBuff);
    memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
    if(SUCCESS != clnWr)
    {
        free(readBuff);
        free(writeBuff);
        return CLNERR;
    }
    // Read incoming password
    for(;;)
    {
        clnRd = readFromClient(clnFd, readBuff);
        if(READERR == clnRd)
        {
            free(readBuff);
            free(writeBuff);
            return CLNERR;
        }
        if(CLNCLOSE == clnRd)
        {
            free(readBuff);
            free(writeBuff);
            return CLNCLOSE;
        }
        if(SUCCESS == clnRd)
        {
            if(strncmp(correctPwd, readBuff, PASSLEN) == MATCH)
            {
                writeText = "Correct password supplied! Welcome to the server.\n";
                snprintf(writeBuff, W_BUFLEN, "%s", writeText);
                clnWr = writeToClient(clnFd, writeBuff);
                memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
                if(SUCCESS != clnWr)
                {
                    free(readBuff);
                    free(writeBuff);
                    return CLNERR;
                }
                free(readBuff);
                free(writeBuff);
                return SUCCESS;
            }
            else
            {
                passCount++;
                if(MAXPASSCOUNT == passCount)
                {
                    writeText = "Maximum attempts reached. Goodbye!\n";
                    snprintf(writeBuff, W_BUFLEN, "%s", writeText);
                    clnWr = writeToClient(clnFd, writeBuff);
                    memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
                    if(SUCCESS != clnWr)
                    {
                        free(readBuff);
                        free(writeBuff);
                        return CLNERR;
                    }
                    return PASSCOUNTEXCEED;
                }
                else
                {
                    writeText = "Incorrect password supplied.\nEnter the server password to continue";
                    snprintf(writeBuff, W_BUFLEN, "%s (Attempt %d of %d): ", writeText, passCount+1, MAXPASSCOUNT);
                    clnWr = writeToClient(clnFd, writeBuff);
                    memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
                    if(SUCCESS != clnWr)
                    {
                        free(readBuff);
                        free(writeBuff);
                        return CLNERR;
                    }
                }
            }
        }
    }
    // Should never hit here. If it does, it means an unknown error has occurred.
    free(readBuff);
    free(writeBuff);
    return CLNERR;
}
launch.c
#include "common.h"
int main(int argc, char *argv[])
{
    int svrFd = 0;
    int clnFd = 0;
    // Start the server
    svrFd = launchServer();
    if(SVRERR == svrFd)
    {
        fprintf(stderr, "[-] Fatal server error. Exiting.");
        return GENERR;
    }
    // Accept incoming clients
    clnFd = acceptClient(svrFd);
    if(CLNERR == clnFd)
    {
        fprintf(stderr, "[-] Fatal client error. Exiting.");
        return GENERR;
    }
    return 0;
}
 
    