1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/* SPDX-License-Identifier: Apache-2.0 */
/* Copyright 2025 Thorsten Töpper
*
* dir_monitor - print specified stat() information from entries of a given
* directory to stdout. Call it via watch for repeated output to a terminal.
*
* vim:ts=4:sw=4:expandtab
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include "output.h"
#include "list_management.h"
#include "options.h"
/* === DEFINITIONS === */
struct list_head *get_data_from_directory(char *path);
/* === IMPLEMENTATION === */
/* This function contains the only time critical code. The loop over
* the directory content.
*
* Note for future:
* I myself use the dir_monitor in combination with watch on a directory
* containing temporary data, it may happen that a run into an error occurs,
* but it's not tragic. To reduce the chance of the error the first step
* would be to optimize the loop with putting the data into a list in stack
* form and moving the nodes into a sorted list afterwards.
*/
struct list_head *get_data_from_directory(char *path) {
char *fullpath = NULL, *fname_in_path = NULL;
DIR *dir = NULL;
size_t l;
struct dirent *de = NULL;
struct list_node *tmp = NULL;
struct list_head *list = NULL;
struct stat stat_res;
if (path == NULL) {
LOGERR("ERROR: No path given.\n");
return NULL;
}
l = strlen(path);
/* 258 filename and possibly required PATH_SEP and of course string termination */
if ((fullpath = calloc(l+258, sizeof(char))) == NULL) {
LOGERR("ERROR: Failed to allocate memory for list head.\n");
return NULL;
}
sprintf(fullpath, "%s%c", path, ((path[l-1] == PATH_SEP) ? '\0' : PATH_SEP));
fname_in_path = (fullpath[l] == PATH_SEP) ? &(fullpath[l+1]) : &(fullpath[l]) ;
if ((dir = opendir(path)) == NULL) {
LOGERR("ERROR: Failed to open directory '%s': %s (errno %d)\n",
path, strerror(errno), errno);
return NULL;
}
/* TBH: In case those few bytes are not available, the process will be killed anyways */
if ((list = calloc(1, sizeof(struct list_head))) == NULL) {
LOGERR("ERROR: Failed to allocate memory for list head.\n");
closedir(dir);
return NULL;
}
errno = 0;
/* Currently the code is specific UNIXoid, needs to be adjusted in case someone ports it. */
while ((de = readdir(dir)) != NULL) {
if (de->d_name[0] == '.' && option_show_hidden_entries == false)
continue;
sprintf(fname_in_path, "%s", de->d_name);
DBGTRC("DEBUG: fullpath: '%s'\n", fullpath);
if (lstat(fullpath, &stat_res) != 0) {
LOGERR("ERROR: lstat call on '%s' failed: %s (errno %d)\n",
fullpath, strerror(errno), errno);
continue;
}
if ((tmp = create_node(de->d_name, &stat_res)) == NULL) {
LOGERR("ERROR: Skipping entry %s\n", de->d_name);
continue;
}
/* SORT_BY_SIZE is the default value, always check it first. */
switch (option_sort_type) {
case SORT_BY_SIZE:
insert_sorted_by_size(list, tmp);
break;
case SORT_BY_TIME:
insert_sorted_by_time(list, tmp);
break;
};
}
free(fullpath);
closedir(dir);
return list;
}
int main(int argc, char **argv) {
struct list_head *list = NULL;
int path_index = 1;
if (argc < 2) {
usage(argv[0]);
return EXIT_FAILURE;
}
path_index = parse_arguments(argc, argv);
if (path_index == argc) {
usage(argv[0]);
return EXIT_FAILURE;
}
list = get_data_from_directory(argv[path_index]);
print_list(list);
destroy_list(list);
return EXIT_SUCCESS;
}
|