2 * This program executes du(1) via pipe(2), then parses
3 * the resulted output and populates a dictionary which
17 * It then gets a reference to the child dictionary
18 * pertaining to `.' path and extracts all <key, value>
19 * pairs before it prints them to stdout.
22 * gcc prop_parse_du.c -o prop_parse_du -lprop -Wall -W -Wextra -ansi
29 #include <prop/proplib.h>
30 #include <sys/stat.h> /* for lstat(2) */
32 #define INIT_ROOT_CAPACITY 100 /* root's dict initial capacity */
33 #define INIT_CHILD_CAPACITY 3 /* child's dict initial capacity */
40 struct stat sb
; /* for lstat(2) */
41 prop_dictionary_t prd
; /* root dictionary */
42 prop_dictionary_t pcd
; /* child dictionary */
43 prop_string_t ps
; /* path name */
44 prop_number_t pn
; /* size in bytes */
45 prop_bool_t pb
; /* true = dir */
47 char *tokens
[MAX_TOKENS
]; /* for du(1) output parse */
53 * Initiate pipe stream to du(1)
54 * -a flag: Display an entry for each file in the file hierarchy.
55 * -P flag: No symbolic links are followed.
57 fp
= popen("du -a -P", "r");
59 err(EXIT_FAILURE
, "popen()");
61 /* Create root dictionary */
62 prd
= prop_dictionary_create_with_capacity(INIT_ROOT_CAPACITY
);
64 err(EXIT_FAILURE
, "prop_dictionary_create_with_capacity()");
66 /* Read from stream */
67 while (fgets(str
, MAX_STR
, fp
) != NULL
) {
68 /* Parse output of du(1) command */
70 p
= strtok_r(str
, "\t", &last
);
71 while (p
&& i
< MAX_TOKENS
- 1) {
73 p
= strtok_r(NULL
, "\t", &last
);
77 /* Create child dictionary */
78 pcd
= prop_dictionary_create_with_capacity(INIT_CHILD_CAPACITY
);
80 err(EXIT_FAILURE
, "prop_dictionary_create_with_capacity()");
83 * tokens[0] holds the size in bytes
85 * We use a signed prop_number_t object, so that
86 * when externalized it will be represented as decimal
87 * (unsigned numbers are externalized in base-16).
89 * Note: atoi(3) does not detect errors, but we trust
90 * du(1) to provide us with valid input. Otherwise,
91 * we should use strtol(3) or sscanf(3).
93 pn
= prop_number_create_integer(atoi(tokens
[0]));
95 err(EXIT_FAILURE
, "prop_number_create_integer()");
97 /* tokens[1] holds the path (trim '\n') */
98 (tokens
[1])[strlen(tokens
[1]) - 1] = '\0';
99 ps
= prop_string_create_cstring(tokens
[1]);
101 err(EXIT_FAILURE
, "prop_string_create_cstring()");
103 /* Is it a directory ? Find out with lstat(2) */
104 if (lstat(tokens
[1], &sb
) == -1)
105 err(EXIT_FAILURE
, "lstat()");
107 pb
= prop_bool_create(sb
.st_mode
& S_IFDIR
? true : false);
109 err(EXIT_FAILURE
, "prop_bool_create()");
111 /* Add path, size and type to child dictionary */
112 if ((prop_dictionary_set(pcd
, "path", ps
) == false)
113 || (prop_dictionary_set(pcd
, "size in bytes", pn
) == false)
114 || (prop_dictionary_set(pcd
, "is it dir?", pb
) == false))
115 err(EXIT_FAILURE
, "prop_dictionary_set()");
117 /* Add child dictionary to root dictionary */
118 if (prop_dictionary_set(prd
, tokens
[1], pcd
) == false)
119 err(EXIT_FAILURE
, "prop_dictionary_set()");
121 /* Release all objects except for the root dictionary */
122 prop_object_release(pn
);
123 prop_object_release(ps
);
124 prop_object_release(pb
);
125 prop_object_release(pcd
);
128 /* Externalize root dictionary to file in XML representation */
129 if (prop_dictionary_externalize_to_file(prd
, "./data.xml") == false)
130 err(EXIT_FAILURE
, "prop_dictionary_externalize_to_file()");
132 /* Get child dictionary pertaining to `.' path */
133 po
= prop_dictionary_get(prd
, ".");
135 err(EXIT_FAILURE
, "prop_dictionary_get()");
137 /* Extract all <key, value> pairs and print them to stdout */
138 printf("Path: %s\nSize in bytes: %lld\nIs it dir?: %s\n",
140 prop_dictionary_get(po
, "path")),
141 prop_number_integer_value(
142 prop_dictionary_get(po
, "size in bytes")),
144 prop_dictionary_get(po
, "is it dir?")) == true ?
147 /* Release root dictionary */
148 prop_object_release(prd
);
150 /* Close pipe stream */
151 if (pclose(fp
) == -1)
152 err(EXIT_FAILURE
, "pclose()");