]> git.tuebingen.mpg.de Git - adu.git/blob - adu.c
cd77fd9f9f4741b7c9f805072737bc4216f1f36e
[adu.git] / adu.c
1 /*
2  * Copyright (C) 2008 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file adu.c \brief The main functions used by all modes of operation. */
8 #include "adu.h"
9 #include <dirent.h> /* readdir() */
10 #include <pwd.h>
11 #include "format.h"
12 #include "user.h"
13 #include "select.cmdline.h"
14 #include "select.h"
15 #include "cmdline.h"
16 #include "fd.h"
17 #include "string.h"
18 #include "error.h"
19
20 DEFINE_ERRLIST;
21
22 /**
23  * The error code of the last osl library function.
24  *
25  * \sa osl().
26  */
27 int osl_errno;
28
29 /** In case a signal is received, its number is stored here. */
30 static int signum;
31
32 /** Command line and config file options. */
33 struct gengetopt_args_info conf;
34
35 /** Options passed to --select-options. */
36 struct select_args_info select_conf;
37
38
39 /**
40  * The table containing the directory names and statistics.
41  */
42 struct osl_table *dir_table = NULL;
43
44 static struct osl_column_description dir_table_cols[] = {
45         [DT_NAME] = {
46                 .storage_type = OSL_MAPPED_STORAGE,
47                 .storage_flags = 0,
48                 .name = "dir",
49         },
50         [DT_NUM] = {
51                 .storage_type = OSL_MAPPED_STORAGE,
52                 .storage_flags = OSL_RBTREE | OSL_FIXED_SIZE | OSL_UNIQUE,
53                 .name = "num",
54                 .compare_function = uint64_compare,
55                 .data_size = sizeof(uint64_t)
56         },
57         [DT_PARENT_NUM] = {
58                 .storage_type = OSL_MAPPED_STORAGE,
59                 .storage_flags = OSL_RBTREE | OSL_FIXED_SIZE | OSL_UNIQUE,
60                 .name = "parent_num",
61                 .compare_function = size_compare,
62                 .data_size = sizeof(uint64_t)
63         },
64         [DT_BYTES] = {
65                 .storage_type = OSL_MAPPED_STORAGE,
66                 .storage_flags =  OSL_RBTREE | OSL_FIXED_SIZE,
67                 .compare_function = size_compare,
68                 .name = "num_bytes",
69                 .data_size = sizeof(uint64_t)
70         },
71         [DT_FILES] = {
72                 .storage_type = OSL_MAPPED_STORAGE,
73                 .storage_flags =  OSL_RBTREE | OSL_FIXED_SIZE,
74                 .compare_function = size_compare,
75                 .name = "num_files",
76                 .data_size = sizeof(uint64_t)
77         }
78 };
79
80 static struct osl_table_description dir_table_desc = {
81         .name = "dir_table",
82         .num_columns = NUM_DT_COLUMNS,
83         .flags = 0,
84         .column_descriptions = dir_table_cols,
85 };
86
87 /**
88  * The log function.
89  *
90  * \param ll Loglevel.
91  * \param fmt Usual format string.
92  *
93  * All XXX_LOG() macros use this function.
94  */
95 __printf_2_3 void __log(int ll, const char* fmt,...)
96 {
97         va_list argp;
98         FILE *outfd;
99         struct tm *tm;
100         time_t t1;
101         char str[255] = "";
102
103         if (ll < conf.loglevel_arg)
104                 return;
105         outfd = stderr;
106         time(&t1);
107         tm = localtime(&t1);
108         strftime(str, sizeof(str), "%b %d %H:%M:%S", tm);
109         fprintf(outfd, "%s ", str);
110         va_start(argp, fmt);
111         vfprintf(outfd, fmt, argp);
112         va_end(argp);
113 }
114
115 static void close_dir_table(void)
116 {
117         int ret;
118
119         if (!dir_table)
120                 return;
121         NOTICE_LOG("closing dir table\n");
122         ret = osl(osl_close_table(dir_table, OSL_MARK_CLEAN));
123         if (ret < 0)
124                 ERROR_LOG("failed to close dir table: %s\n", adu_strerror(-ret));
125         free((char *)dir_table_desc.dir);
126         dir_table = NULL;
127 }
128
129 static void close_all_tables(void)
130 {
131         close_dir_table();
132         close_user_tables();
133 }
134
135 static void signal_handler(int s)
136 {
137         signum = s;
138 }
139
140 /**
141  * Check whether to terminate adu.
142  *
143  * Check whether a signal was caught that should terminate the
144  * adu process. If yes, close all osl tables and exit gracefully.
145  */
146 void check_signals(void)
147 {
148         if (likely(!signum))
149                 return;
150         EMERG_LOG("caught signal %d\n", signum);
151         close_all_tables();
152         exit(EXIT_FAILURE);
153 }
154
155 static int init_signals(void)
156 {
157         if (signal(SIGINT, &signal_handler) == SIG_ERR)
158                 return -E_SIGNAL_SIG_ERR;
159         if (signal(SIGTERM, &signal_handler) == SIG_ERR)
160                 return -E_SIGNAL_SIG_ERR;
161         if (signal(SIGPIPE, &signal_handler) == SIG_ERR)
162                 return -E_SIGNAL_SIG_ERR;
163         return 1;
164 }
165
166 /**
167  * Open the directory table.
168  *
169  * \param create If non-zero, create the table first.
170  *
171  * \return Standard.
172  */
173 int open_dir_table(int create)
174 {
175
176         if (dir_table)
177                 return 1;
178         dir_table_desc.dir = adu_strdup(conf.database_dir_arg);
179
180         if (create) {
181                 NOTICE_LOG("creating dir table\n");
182                 int ret = osl(osl_create_table(&dir_table_desc));
183                 if (ret < 0) {
184                         free((char *)dir_table_desc.dir);
185                         return ret;
186                 }
187         }
188         INFO_LOG("opening dir table\n");
189         return osl(osl_open_table(&dir_table_desc, &dir_table));
190 }
191
192 static int check_args(void)
193 {
194         if (conf.create_given && !conf.base_dir_given)
195                 return -E_SYNTAX;
196
197         /* remove trailing slashes from base-dir arg */
198         if (conf.base_dir_given) {
199                 size_t len = strlen(conf.base_dir_arg);
200                 for (;;) {
201                         if (!len) /* empty string */
202                                 return -ERRNO_TO_ERROR(EINVAL);
203                         if (!--len) /* length 1 is always OK */
204                                 break;
205                         if (conf.base_dir_arg[len] != '/')
206                                 break; /* no trailing slash, also OK */
207                         conf.base_dir_arg[len] = '\0';
208                 }
209         }
210         return 1;
211 }
212
213 static int print_complete_help_and_die(void)
214 {
215         const char **line;
216
217         printf("%s-%s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION);
218         printf("%s\n\n", gengetopt_args_info_purpose);
219         printf("%s\n\n", gengetopt_args_info_usage);
220
221         if (conf.help_given)
222                 line = gengetopt_args_info_help;
223         else
224                 line = gengetopt_args_info_detailed_help;
225         for (; *line; line++)
226                 printf("%s\n", *line);
227
228         if (conf.help_given)
229                 line = select_args_info_help;
230         else
231                 line  = select_args_info_detailed_help;
232         printf("Select options:\n");
233         for (; *line; line++)
234                 printf("%s\n", *line);
235
236         printf("Interactive commands:\n");
237         print_interactive_help();
238         cmdline_parser_free(&conf);
239         select_cmdline_parser_free(&select_conf);
240         exit(EXIT_FAILURE);
241 }
242
243 /**
244  * The main function of adu.
245  *
246  * \param argc Usual argument count.
247  * \param argv Usual argument vector.
248  *
249  * Check command line options, init the signal handlers and
250  * call the main function of the selected mode.
251  *
252  * \return \p EXIT_SUCCESS on success, \p EXIT_FAILURE otherwise.
253  */
254 int main(int argc, char **argv)
255 {
256         int ret;
257         struct cmdline_parser_params params = {
258                 .override = 1,
259                 .initialize = 1,
260                 .check_required = 0,
261                 .check_ambiguity = 0,
262                 .print_errors = 0
263         };
264         select_cmdline_parser_init(&select_conf);
265         cmdline_parser_init(&conf);
266         /* ignore errors and print complete help if --help was given */
267         cmdline_parser_ext(argc, argv, &conf, &params);
268         if (conf.help_given || conf.detailed_help_given)
269                 print_complete_help_and_die();
270         cmdline_parser_free(&conf);
271         params.check_required = 1;
272         params.check_ambiguity = 1;
273         params.print_errors = 1;
274         ret = cmdline_parser_ext(argc, argv, &conf, &params);
275         if (ret)
276                 exit(EXIT_FAILURE);
277
278         ret = check_args();
279         if (ret < 0)
280                 goto out;
281         ret = init_signals();
282         if (ret < 0)
283                 goto out;
284         ret = -E_SYNTAX;
285         if (conf.select_given)
286                 ret = com_select();
287         else if (conf.create_given)
288                 ret = com_create();
289         else
290                 ret = com_interactive();
291         if (ret < 0)
292                 goto out;
293 out:
294         close_all_tables();
295         if (ret < 0) {
296                 ERROR_LOG("%s\n", adu_strerror(-ret));
297                 return -EXIT_FAILURE;
298         }
299         cmdline_parser_free(&conf);
300         select_cmdline_parser_free(&select_conf);
301         return EXIT_SUCCESS;
302 }