1//
2//  A simple symlink test
3//
4
5#define _GNU_SOURCE
6
7#include <sys/stat.h>
8#include <unistd.h>
9#include <stdlib.h>
10#include <errno.h>
11#include <stdio.h>
12#include <string.h>
13
14//
15// Creates symlink [new-path] to [old-path], checks it,
16// returnes  0 - if everything looks fine and
17//  1 - otherwise.
18// mongo_slinks reads arguments from stdin.
19
20int main(int argc, char *argv[])
21{
22	char *old_path;
23	char *new_path;
24
25	struct stat statbuf;
26
27	int num;
28	char *buffer = NULL;
29	char *line_buffer = NULL;
30	size_t line_buffer_size = 0;
31	int size = 1;
32
33	if ((buffer = malloc(size + 1)) == NULL) {
34		perror("checklink: malloc failed");
35		return 1;
36	}
37
38	while (getline(&line_buffer, &line_buffer_size, stdin) != -1) {
39
40		old_path = strtok(line_buffer, "\t ");
41		new_path = strtok(NULL, "\t\n ");
42
43		if (!old_path || !new_path)	/* empty lines at the end of file */
44			break;
45
46		// Create symlink
47		if (symlink(old_path, new_path) != 0) {
48			perror("checklink : symlink failed ");
49			return 1;
50		}
51		// stat data of symlink itself
52		if (lstat(new_path, &statbuf) == -1) {
53			perror("checklink: lstat failed");
54			return 1;
55		}
56
57		if (!(S_ISLNK(statbuf.st_mode))) {
58			printf("checklink : file %s is not a symbol link\n",
59			       new_path);
60			return 1;
61		}
62		// Test readlink
63		//
64		// Increase size of buffer to readlink untile whole symlink body will be read.
65		// Check readlink result on every iteration.
66
67		while (1) {
68			memset(buffer, 0, size + 1);
69			num = readlink(new_path, buffer, size);
70			if (num < 1 || num > size) {
71				perror("checklink: readlink failed");
72				free(buffer);
73				return 1;
74			}
75			// Make sure that readlink did not break things
76			if (buffer[num] != 0) {
77				printf
78				    ("checklink : readlink corrupts memory\n");
79				free(buffer);
80				return 1;
81			}
82			// Whole expected symlink body is read
83			if (num < size)
84				break;
85
86			// Only part of symlink body was read. So we  make a bigger buffer
87			// and call `readlink' again.
88			size *= 2;
89			if ((buffer = realloc(buffer, size + 1)) == NULL) {
90				perror("checklink: realloc failed");
91				return 1;
92			}
93		}
94	}
95	free(buffer);
96	free(line_buffer);
97	return 0;
98}
99