LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   file existnse (https://www.linuxquestions.org/questions/programming-9/file-existnse-4175435271/)

akshay_satish 11-02-2012 08:34 AM

file existnse
 
Hi Guys, I seem to stumble upon something really weird.
Code:

char a[512] = "";
char *dir = NULL;
int k;

if(NULL == dir) {
sprintf(a, "%s/%s", <#def1>,<#def2>);
}

if(access(a, F_OK) == 0) {
k = unlink(a);
if(k != 0) {
printf("unable to del. file %s: %d(%s).\n", a, errno, strerror(errno));
}
}

The output I am getting is ->
unable to del. file /: 2(No such file or directory).

errno 2 indicates ENOENT which is no such file or directory.

Any idea why the o/p is showing the filename as "/" (thoughts??).
Also, i am wondering how it executed the printf(....) statement. If the filename was infact "/", it shouldn't have even tried the "unlink" operation according to the code logic right? It should have exit'd the "if" condition right after "access()".
Kindly help....

dwhitney67 11-02-2012 08:47 AM

Quote:

Originally Posted by akshay_satish (Post 4820486)
Kindly help....

I'm not sure how you were able to get the output you describe based on the code you posted. Surely there must be more to your application than you are indicating. For example, how is the array 'a' ever populated with something other than a Null-string?

Here's a complete program that mimics what you have posted, and it functions correctly.

Code:

#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

int main(int argc, char** argv)
{
    const char* pathname = "";

    if (argc > 1)
    {
        pathname = argv[1];
    }

    if (access(pathname, F_OK) == 0)
    {
        fprintf(stdout, "File %s is accessible.\n", pathname);

        if (unlink(pathname) == 0)
        {
            fprintf(stdout, "File %s has been removed.\n", pathname);
        }
        else
        {
            fprintf(stderr, "Unable to unlink (delete) file %s; reason -- %s [%d]\n", pathname, strerror(errno), errno);
        }
    }
    else
    {
        fprintf(stderr, "Failed to access file '%s'; reason -- %s [%d]\n", pathname, strerror(errno), errno);
    }

    return 0;
}

P.S. Under Linux, a file and a directory can be considered to be the same with respect to being "accessible". If you are looking to delete only files (and not directories), then I suggest you use stat() to determine the attributes of the file (ie. file type, permissions, etc.)

sundialsvcs 11-02-2012 09:26 AM

An empty file-name could possibly be interpreted as "/" but in any case it's a nonsensical situation as-writ.

akshay_satish 11-02-2012 10:07 AM

Thank you DWhitney.. Yes the intent is to delete a file. I think doing a "stat" would be better as you mentioned... Yes in the first few lines of the function there is a do while loop within which if this file "a" is NULL then we break out of the loop and hit the deletion code which I've pasted above.
This confirms the issue right?
thanks again dWhitney. ur thoughts are just priceless..cheerio :)

akshay_satish 11-02-2012 10:35 AM

Quote:

Originally Posted by dwhitney67 (Post 4820500)
I'm not sure how you were able to get the output you describe based on the code you posted. Surely there must be more to your application than you are indicating. For example, how is the array 'a' ever populated with something other than a Null-string?

Here's a complete program that mimics what you have posted, and it functions correctly.

Code:

#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

int main(int argc, char** argv)
{
    const char* pathname = "";

    if (argc > 1)
    {
        pathname = argv[1];
    }

    if (access(pathname, F_OK) == 0)
    {
        fprintf(stdout, "File %s is accessible.\n", pathname);

        if (unlink(pathname) == 0)
        {
            fprintf(stdout, "File %s has been removed.\n", pathname);
        }
        else
        {
            fprintf(stderr, "Unable to unlink (delete) file %s; reason -- %s [%d]\n", pathname, strerror(errno), errno);
        }
    }
    else
    {
        fprintf(stderr, "Failed to access file '%s'; reason -- %s [%d]\n", pathname, strerror(errno), errno);
    }

    return 0;
}

P.S. Under Linux, a file and a directory can be considered to be the same with respect to being "accessible". If you are looking to delete only files (and not directories), then I suggest you use stat() to determine the attributes of the file (ie. file type, permissions, etc.)

I populated the pathname with "/" and performed a stat instead of access but it still hit the unlink's else case. can i know a little more about wht you were saying pls?

dwhitney67 11-02-2012 01:18 PM

Quote:

Originally Posted by akshay_satish (Post 4820628)
I populated the pathname with "/" and performed a stat instead of access but it still hit the unlink's else case. can i know a little more about wht you were saying pls?

stat() can tell you if a file (or directory) exists based on its return value. However, you should pass a 'struct stat' object to the function to obtain additional information about the file you are querying about. For example:
Code:

#include <errno.h>
#include <string.h>
#include <stdio.h>

int main()
{
    const char* pathname = "/";
    struct stat pathInfo;

    if (stat(pathname, &pathInfo) == 0)
    {
        if (S_ISDIR(pathInfo.st_mode))
        {
            fprintf(stdout, "pathname '%s' is a directory.\n", pathname);
        }
        else if (S_ISREG(pathInfo.st_mode))
        {
            fprintf(stdout, "pathname '%s' is a regular file.\n", pathname);
        }
        else /* ... */
        {
            /* ... */
        }
    }
    else
    {
        fprintf(stderr, "Cannot obtain status about '%s'; reason -- %s [%d]\n",
                pathname, strerror(errno), errno);
    }

    return 0;
}

For more comprehensive information about stat(), it actually is more helpful to read the man-page for fstat().

akshay_satish 11-05-2012 12:11 AM

Quote:

Originally Posted by dwhitney67 (Post 4820863)
stat() can tell you if a file (or directory) exists based on its return value. However, you should pass a 'struct stat' object to the function to obtain additional information about the file you are querying about. For example:
Code:

#include <errno.h>
#include <string.h>
#include <stdio.h>

int main()
{
    const char* pathname = "/";
    struct stat pathInfo;

    if (stat(pathname, &pathInfo) == 0)
    {
        if (S_ISDIR(pathInfo.st_mode))
        {
            fprintf(stdout, "pathname '%s' is a directory.\n", pathname);
        }
        else if (S_ISREG(pathInfo.st_mode))
        {
            fprintf(stdout, "pathname '%s' is a regular file.\n", pathname);
        }
        else /* ... */
        {
            /* ... */
        }
    }
    else
    {
        fprintf(stderr, "Cannot obtain status about '%s'; reason -- %s [%d]\n",
                pathname, strerror(errno), errno);
    }

    return 0;
}

For more comprehensive information about stat(), it actually is more helpful to read the man-page for fstat().

Thank you very much. Really appreciate your timely help~ cheerio.

akshay_satish 11-05-2012 04:22 AM

Hi Dwhitney67, i really appreciate your timely response. I have one more connected problem that I need some pointers. Pls assist:

In my header file I have a macro defined as;
Code:

#define QWE 1
....
#ifdef QWE
    #define ABC(params...) {
    fprintf(stderr, params);
    }
#else
    #define ABC(params...) {
    /*writes to a file*/
    }
#endif
....

Now in my C file, I use another macro to log statements either onto the console or into a file.

Code:

void abc() {
....
ABC("something\n");
....
}

int main()
{
abc();
}

From the above code logic, when abc() is called in main(), "something" is printed onto the console due to "STDERR". I need to find a way to log the line to the trace file without actually changing QWE to 0 in the #define. I have a switch case within which each case statements log to the stderr because of the QWE = 1 value. I need to print to the file only for one particular case. I hope u got my intent? Appreciate your response.

dwhitney67 11-05-2012 11:17 AM

fprintf() can be used to write to stdout, stderr, or any other stream (such as a file).

So I'm not sure why you require different implementations for the ABC() function, unless you are doing something drastically different when writing to a file (for example, in lieu of writing the data in ASCII format, you are writing it in binary).

So, if you are not doing anything different, then implement something like the following:
Code:

void ABC(FILE* stream, params...)
{
  fprintf(stream, ...);
}

void abc(FILE* stream)
{
    ...

    ABC(stream, ...);

    ...
}

int main()
{
    abc(stderr);

    FILE* myFile = fopen("SomeFile.txt", "w+");

    abc(myFile);

    fclose(myFile);
}


akshay_satish 11-05-2012 11:45 PM

Quote:

Originally Posted by dwhitney67 (Post 4822724)
fprintf() can be used to write to stdout, stderr, or any other stream (such as a file).

So I'm not sure why you require different implementations for the ABC() function, unless you are doing something drastically different when writing to a file (for example, in lieu of writing the data in ASCII format, you are writing it in binary).

So, if you are not doing anything different, then implement something like the following:
Code:

void ABC(FILE* stream, params...)
{
  fprintf(stream, ...);
}

void abc(FILE* stream)
{
    ...

    ABC(stream, ...);

    ...
}

int main()
{
    abc(stderr);

    FILE* myFile = fopen("SomeFile.txt", "w+");

    abc(myFile);

    fclose(myFile);
}


cool! that was a silly question that shouldnt have been asked. Sorry!

akshay_satish 11-05-2012 11:55 PM

Quote:

Originally Posted by dwhitney67 (Post 4820863)
stat() can tell you if a file (or directory) exists based on its return value. However, you should pass a 'struct stat' object to the function to obtain additional information about the file you are querying about. For example:
Code:

#include <errno.h>
#include <string.h>
#include <stdio.h>

int main()
{
    const char* pathname = "/";
    struct stat pathInfo;

    if (stat(pathname, &pathInfo) == 0)
    {
        if (S_ISDIR(pathInfo.st_mode))
        {
            fprintf(stdout, "pathname '%s' is a directory.\n", pathname);
        }
        else if (S_ISREG(pathInfo.st_mode))
        {
            fprintf(stdout, "pathname '%s' is a regular file.\n", pathname);
        }
        else /* ... */
        {
            /* ... */
        }
    }
    else
    {
        fprintf(stderr, "Cannot obtain status about '%s'; reason -- %s [%d]\n",
                pathname, strerror(errno), errno);
    }

    return 0;
}

For more comprehensive information about stat(), it actually is more helpful to read the man-page for fstat().

Okay so my actual problem here really is pathname should be getting a file. I am surprised why it is getting a directory!

dwhitney67 11-06-2012 05:08 AM

Quote:

Originally Posted by akshay_satish (Post 4823135)
Okay so my actual problem here really is pathname should be getting a file. I am surprised why it is getting a directory!

Getting a file (name/path) from where? From the user, from another file, through a network socket??

If you are referring to '/', then that is a directory. It is the root (not to be confused with the user 'root') directory of a Linux/Unix system.

akshay_satish 11-20-2012 04:37 AM

Hello I would to get confirmation on this piece of code that I've written. I am basically trying do an "scp" and trying to log useful information onto the console if it fails:

Code:

error = WEXITSTATUS(status);
                if (WIFEXITED(status) && error == 0) {
                    "blah blah"
                } else {
                    "blah blah"
 
                    switch (...) {
                    case a:
                    case b:
                        printf("WHOOPS: scp exited with status %d\n", error);
                        break;
                    default:
                        break;

now the return value for error at the last line is 1 which means WEXITSTATUS failed and returned 1. I am basically trying to do an scp.
Now i want to make the error more readable not throw a print saying "scp exited with status 1"...
is this better?->
Code:

printf( "WHOOPS: scp exited with status %s\n", strerror(error));
With this I get an error saying, "operation is not permitted".. I wanted to get your thoughts whether I am doing the right thing by using strerror or am I printing a string that is not coherent with the return value?

dwhitney67 11-20-2012 05:09 AM

akshay_satish -

You should have created a new thread for your latest query; it is unrelated to the one that you used to open this thread.

But to answer your question, the command 'scp' returns 0 on success, and some number greater than 0 (this could be any number!) on a failure. If a failure occurs, I don't believe the error number corresponds to anything other than to denote that an error occurred. Thus the use of strerror() would not be wise in this situation.

On my system, a failed 'scp' request, using the system() command, returns a status of 256; this translates to "Unknown error" when passed to strerror().

My recommendation is to avoid using system(), and instead use popen() so that you may read the output produced by the system command.

akshay_satish 11-20-2012 07:14 AM

I am extremely sorry DWhitney67.. Should I create one more now or can you forgive me for this question? I'll make sure to create unique threads for separate questions. Thank you very again for your valuable thoughts...Adding on...
Actually this is how I am doing the scp;

Code:

//argv will contain the scp cmd
      ret = posix_spawnp(
            &pid,
            argv[0],
            NULL, NULL,
            argv,
            NULL);                      //After this i perform a waitpid();

ret = waitpid(pid,&status,0);
if(ret != pid) {
/*failed*/
}
else{
error = WEXITSTATUS(status);
                if (WIFEXITED(status) && error == 0) {
                    "blah blah"
                } else {
                    "blah blah" //failed the downld.
 
                    switch (...) {
                    case a:
                    case b:
                        printf("WHOOPS: scp exited with status %d\n", error);
                        break;
                    default:
                        break;
}
}

Can you pls suggest now. You examples are always intriguing.. thanks again for your help. Hi, I am not able to see my replies or ur new replies anymore, i.e., page 2 onwards. has it been removed?

dwhitney67 11-20-2012 07:21 AM

Quote:

Originally Posted by akshay_satish (Post 4833238)
Code:

      ret = posix_spawnp(
            &pid,
            argv[0],
            NULL, NULL,
            argv,
            NULL);                      //After this i perform a waitpid();


The code above seems to suggest that you have having your program, which name is stored in argv[0], launch itself again.

Did you define your own argv array to contain a reference to the scp command and associated arguments?

akshay_satish 11-20-2012 07:25 AM

yes, i used my own argv array which is why I thought I could use strerror() and thought posix_spawnp will give me the correct status:
SCP Return Codes
0
Operation was successful
1
General error in file copy
2
Destination is not directory, but it should be
3
Maximum symlink level exceeded
4
Connecting to host failed.
5
Connection broken
6
File does not exist
7
No permission to access file.
8
General error in sftp protocol
9
File transfer protocol mismatch
10
No file matches a given criteria
65
Host not allowed to connect
66
General error in ssh protocol
67
Key exchange failed
68
Reserved
69
MAC error
70
Compression error
71
Service not available
72
Protocol version not supported
73
Host key not verifiable
74
Connection failed
75
Disconnected by application
76
Too many connections
77
Authentication cancelled by user
78
No more authentication methods available
79
Invalid user name

Code:

  argv[0] = "scp";
  argv[1] = "-q";
    argv[2] = "-o StrictHostKeychecking=no";
    argv[3] = "some_path";
    argv[4] = dst_path;
    argv[5] = NULL;


dwhitney67 11-20-2012 08:14 AM

Again, according to the man-page of scp, 0 is returned on success, and a number > 0 is returned on the occurrence of an error.

I do not know where you obtained the list of status values; it does not appear on the man-page for 'scp', and I have taken the effort to check on Linux, HP-UX, and a Mac. Are you on a different OS?

akshay_satish 11-20-2012 08:17 AM

Quote:

Originally Posted by dwhitney67 (Post 4833272)
Again, according to the man-page of scp, 0 is returned on success, and a number > 0 is returned on the occurrence of an error.

I do not know where you obtained the list of status values; it does not appear on the man-page for 'scp', and I have taken the effort to check on Linux, HP-UX, and a Mac. Are you on a different OS?

whoops i am sorry, actually i did the same exercise as you performed and couldnt get the error status. I am using linux..i found this on google.. sorry i should have mentioned the source, my bad!! So with my implementation , you dont recommend using strerror??

dwhitney67 11-20-2012 08:39 AM

Quote:

Originally Posted by akshay_satish (Post 4833274)
whoops i am sorry, actually i did the same exercise as you performed and couldnt get the error status. I am using linux..i found this on google.. sorry i should have mentioned the source, my bad!! So with my implementation , you dont recommend using strerror??

I recommend using popen(); use it to read any output that 'scp' may return. For example:
Code:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

int main(int argc, char** argv)
{
    const char* scp_cmd = "/usr/bin/scp";
    const char* scp_src = (argc > 1 ? argv[1] : "/etc/hosts");
    const char* scp_dst = "localhost:";

    char cmd[1024] = {0};

    snprintf(cmd, sizeof(cmd), "%s -q -o StrictHostKeychecking=no %s %s 2>&1", scp_cmd, scp_src, scp_dst);

    FILE* cmd_fp = popen(cmd, "r");

    if (cmd_fp)
    {
        char output[256] = {0};

        fgets(output, sizeof(output), cmd_fp);

        if (strlen(output) == 0)
        {
          fprintf(stdout, "Transfer completed successfully.\n");
        }
        else
        {
            fprintf(stderr, "Error: %s", output);
        }

        pclose(cmd_fp);
    }
    else
    {
        fprintf(stderr, "Command failed; reason is %s [%d]\n", strerror(errno), errno);
        return errno;
    }

    return 0;
}


akshay_satish 11-20-2012 09:05 AM

Quote:

Originally Posted by dwhitney67 (Post 4833282)
I recommend using popen(); use it to read any output that 'scp' may return. For example:
Code:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

int main(int argc, char** argv)
{
    const char* scp_cmd = "/usr/bin/scp";
    const char* scp_src = (argc > 1 ? argv[1] : "/etc/hosts");
    const char* scp_dst = "localhost:";

    char cmd[1024] = {0};

    snprintf(cmd, sizeof(cmd), "%s -q -o StrictHostKeychecking=no %s %s 2>&1", scp_cmd, scp_src, scp_dst);

    FILE* cmd_fp = popen(cmd, "r");

    if (cmd_fp)
    {
        char output[256] = {0};

        fgets(output, sizeof(output), cmd_fp);

        if (strlen(output) == 0)
        {
          fprintf(stdout, "Transfer completed successfully.\n");
        }
        else
        {
            fprintf(stderr, "Error: %s", output);
        }

        pclose(cmd_fp);
    }
    else
    {
        fprintf(stderr, "Command failed; reason is %s [%d]\n", strerror(errno), errno);
        return errno;
    }

    return 0;
}


this is great..thanks a lot!!.... Appreciated.

akshay_satish 11-20-2012 12:56 PM

Quote:

Originally Posted by akshay_satish (Post 4833296)
this is great..thanks a lot!!.... Appreciated.

I understand why my code doesnt work clearly after running your example. Yours works like a charm mate... thanks!! but just a thought:
I am giving a wrong scp command on purpose (this is how it would be stored internally in "cmd" per your code):
Code:

scp -p  -o StrictHostKeychecking=no aks@something.com:/test/tmp /tmp
This is actually giving me the print saying Transfer completed successfully!! I am wondering how..
coudl you pls explain the below 2 lines pls:
Code:

fgets(output, sizeof(output), cmd_fp);

        if (strlen(output) == 0)

So this is code doesnt work for me for an invalid scp syntax. Just a little new to this concept. would really appreciate your help.. m 80% done :)

dwhitney67 11-20-2012 01:46 PM

Quote:

Originally Posted by akshay_satish (Post 4833460)
I understand why my code doesnt work clearly after running your example. Yours works like a charm mate... thanks!! but just a thought:
I am giving a wrong scp command on purpose (this is how it would be stored internally in "cmd" per your code):
Code:

scp -p  -o StrictHostKeychecking=no aks@something.com:/test/tmp /tmp
This is actually giving me the print saying Transfer completed successfully!! I am wondering how..

This is the error I get when running the command on my system:
Code:

/usr/bin/scp -p -o StrictHostKeychecking=no aks@something.com:/test/tmp /tmp
ssh: Could not resolve hostname something.com: Name or service not known

If I modify the code I provided earlier to adjust the scp_src and the scp_dst, I get the following error:
Code:

Error: ssh: Could not resolve hostname something.com: Name or service not known
Quote:

Originally Posted by akshay_satish (Post 4833460)
coudl you pls explain the below 2 lines pls:
Code:

fgets(output, sizeof(output), cmd_fp);

        if (strlen(output) == 0)


fgets() reads from the stream cmd_fp, up to a certain amount of characters. If there is nothing to read, then it is assumed the command (that is, scp) succeeded. This of course only works if scp is passed the -q option.

P.S. Here's the modified code I tested with:
Code:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

int main(int argc, char** argv)
{
    const char* scp_cmd = "/usr/bin/scp";
/*
    const char* scp_src = (argc > 1 ? argv[1] : "/etc/hosts");
    const char* scp_dst = "localhost:";
*/
    const char* scp_src = "aks@something.com:/test/tmp";
    const char* scp_dst = "/tmp";

    char cmd[1024] = {0};

    snprintf(cmd, sizeof(cmd), "%s -p -q -o StrictHostKeychecking=no %s %s 2>&1", scp_cmd, scp_src, scp_dst);

    fprintf(stdout, "Executing the following command:\n%s\n", cmd);

    FILE* cmd_fp = popen(cmd, "r");

    if (cmd_fp)
    {
        char output[256] = {0};

        fgets(output, sizeof(output), cmd_fp);

        if (strlen(output) == 0)
        {
          fprintf(stdout, "Transfer completed successfully.\n");
        }
        else
        {
            fprintf(stderr, "Error: %s", output);
        }

        pclose(cmd_fp);
    }
    else
    {
        fprintf(stderr, "Command failed; reason is %s [%d]\n", strerror(errno), errno);
        return errno;
    }

    return 0;
}

-----------

EDIT: I'm wagering that you forgot to place this at the end of your command buffer in your code: "2>&1". This directs standard-error to standard-out, thus enabling the fgets() to do its job.

akshay_satish 11-20-2012 07:26 PM

Hi dwhitney, i see you have replied but I am able to view only one page on this thread.. has this been lost or something?

dwhitney67 11-21-2012 09:23 AM

Quote:

Originally Posted by akshay_satish (Post 4833677)
Hi dwhitney, i see you have replied but I am able to view only one page on this thread.. has this been lost or something?

It has been restored. Apparently LQ had DB problems yesterday.

akshay_satish 11-23-2012 04:13 AM

Quote:

Originally Posted by dwhitney67 (Post 4834078)
It has been restored. Apparently LQ had DB problems yesterday.

thanks a lot.. i've acquired a lot of knowledge from u.. i hope u dont mind some of my trivial doubts.. thanks again DWhitney!!cheers.


All times are GMT -5. The time now is 04:38 PM.