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