Ofer Levi
Ofer Levi

Reputation: 41

pclose() on file descriptor opened with popen() returns errno 10 (No child processes)

I'm running linux and I try to do the following:

  1. Run ls on current directory (using popen)
  2. Output the result to buffer (using fread from pipe descriptor)
  3. close pipe (using pclose).

Everything works fine (the buffer is filled correctly with the ls result) but when I check pclose() result it returns -1 and errno is set to 10 (No child processes). Have no idea why this is happening but I can't ignore it (unless there is a reasonable explanation to why this is happening).

My code:

FILE * lsoutput = NULL;
lsoutput = popen("ls -ltr", "r");
if (readFromPipeOrFile(lsOutput, pSendBuf, pSendActualSize) == -1)
{
        printf("readFromPipeOrFile failed.");
        pclose(lsOutput);
        safeFree(pSendBuf);
        return -1;
}

if (pclose(lsOutput) == -1) // No idea why it returns -1 but it does...
{
        printf("pclose failed");
        printf("errno: %d\n", errno);
        printf("strerror: '%s'", strerror(errno));
        return -1;
}

The code for readFromPipeOrFile (the function writing to the buffer):

int readFromPipeOrFile(FILE * pipeOrFile, char ** pSendBuf, size_t * pSendActualSize)
{
     int multiplication = 1;
     char * pSendBufCurrentLocation = NULL;
     ERR_RETURN(pipeOrFile == NULL || pSendBuf == NULL || pSendActualSize == NULL,
                     "No values should be NULL.");
     ERR_RETURN(*pSendBuf != NULL, "*pSendBuf should be NULL");

     *pSendBuf = (char *) calloc (MAX_READ_FROM_STREAM * multiplication, sizeof(char));
     ERR_RETURN(*pSendBuf == NULL, "Failed allocating sendBuf");

     pSendBufCurrentLocation = *pSendBuf;
     while (fread(pSendBufCurrentLocation, MAX_READ_FROM_STREAM, 1, pipeOrFile) == 1)
     {
             ++multiplication;
             *pSendBuf = realloc(*pSendBuf, MAX_READ_FROM_STREAM * multiplication);
             ERR_RETURN(*pSendBuf == NULL, "Failed re-allocating sendBuf");

             pSendBufCurrentLocation = *pSendBuf + (MAX_READ_FROM_STREAM * (multiplication - 1));
             memset(pSendBufCurrentLocation, '\0', MAX_READ_FROM_STREAM);
     }

     ERR_RETURN(!feof(pipeOrFile), "Hasn't reached eof but fread stopped");
     ERR_RETURN(ferror(pipeOrFile), "Error in fread");

     *pSendActualSize = MAX_READ_FROM_STREAM * multiplication;

     return 0;
}

Thanks in advance! EDIT: ERR_RETURN is just a macro that checks if the condition on the first paramter is true and if so, print the string in the second parameter and return -1.

Upvotes: 4

Views: 4344

Answers (2)

ajaxhe
ajaxhe

Reputation: 609

signal(SIGCHLD, SIG_IGN) will cause pclose() result it returns -1 and errno is set to 10 (No child processes).

Upvotes: 2

K Scott Piel
K Scott Piel

Reputation: 4380

According to the documentation for pclose(), it returns -1 if wait4 returns an error. However, it says nothing of setting errno (other than setting ECHILD if it was unable to get a child status) so I'm not so sure you can count on the strerror() string being accurate.

The implication is that ls exited with an error code which would imply that ls had trouble accessing a subdirectory (permission error?). So, you have results because ls returned what it could read, but it is an incomplete read because it could not access a subdirectory in the recursion.

Upvotes: 0

Related Questions