Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if soft link exists or not

Tags:

c

linux

symlink

user: ls -lt
lrwxrwxrwx 1 user sw-team    9 Jun 18 19:01 new_link -> test/file

I have a soft link like mentioned above. I want to check whether new_link(not the linked file) exists or not. I tried all the below but all are checking only if the final destination file (test/file) exists or not.

access(filename,F_OK)
stat()
open()
fopen()

I want to find it in C language not in shell script.Please tell me how to find if new_link exists before checking the linked file?

like image 596
user1762571 Avatar asked Jun 19 '14 02:06

user1762571


2 Answers

Use lstat - get symbolic link status:

The lstat() function shall be equivalent to stat(), except when path refers to a symbolic link. In that case lstat() shall return information about the link, while stat() shall return information about the file the link references.

(Emphasis mine.)

lstat will return non-zero, and errno will be set to ENOENT if the link (or any other part of the path) does not exist.

Example:

#include <stdio.h>
#include <stdbool.h>
#include <sys/stat.h>

bool symlink_exists(const char* path)
{
    struct stat buf;
    int result;

    result = lstat(path, &buf);

    return (result == 0);
}

void test(const char* path)
{
    bool exists = symlink_exists(path);

    printf("%s does%s exist.\n", path, exists ? "" : " not");
}

int main(int argc, char** argv)
{
    test("/bin/sh");
    test("/etc/no_such_thing");
    return 0;
}

Output:

/bin/sh does exist.
/etc/no_such_thing does not exist.
like image 197
Jonathon Reinhart Avatar answered Nov 14 '22 10:11

Jonathon Reinhart


You need lstat to get link status and readlink to read the value of symlink. I have modified Jonthon's code. Check this:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/stat.h>

bool symlink_exists(const char* path)
{
    struct stat buf;
    int ret = 0;
    char *linkname;


    if (lstat(path, &buf) == 0) {
       // TODO: Add error handling
       linkname = malloc(buf.st_size + 1);
       readlink(path, linkname, buf.st_size + 1);
       linkname[buf.st_size] = '\0';
       printf("---> '%s' points to '%s'\n", path, linkname);
       if (stat(linkname, &buf) == 0)
           ret = 1;
    }
    return ret;
}

void test(const char* path)
{
    bool exists = symlink_exists(path);

    printf("%s does%s exist.\n", path, exists ? "" : " *not*");
}

int main(int argc, char** argv)
{
   test("/bin/sh");            //Normal link using relative path - NOT WORKING
   test("/etc/no_such_thing"); //Broken file
   test("tmpp");               //Normal link using absolute path - WORKING 
   test("tmppp");              //Broken link  
   return 0; 
}

Use absolute path to create your links. Otherwise you have to convert it to relative paths.

like image 44
Sanket Parmar Avatar answered Nov 14 '22 11:11

Sanket Parmar