1 /* cmd-grab.c
2 *
3 ****************************************************************
4 * Copyright (C) 2003 Tom Lord, Mark Thomas
5 *
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
9
10
11 #include "config-options.h"
12 #include "hackerlab/bugs/panic.h"
13 #include "hackerlab/char/str.h"
14 #include "hackerlab/cmd/main.h"
15 #include "hackerlab/fs/file-names.h"
16 #include "hackerlab/fs/cwd.h"
17 #include "hackerlab/vu/safe.h"
18 #include "tla/libarch/archive.h"
19 #include "tla/libarch/namespace.h"
20 #include "tla/libarch/build-revision.h"
21 #include "tla/libarch/pfs-dav.h"
22 #include "tla/libfsutils/file-contents.h"
23 #include "tla/libfsutils/rmrf.h"
24 #include "tla/libfsutils/tmp-files.h"
25 #include "tla/libarch/archives.h"
26 #include "tla/libarch/cmd-grab.h"
27 #include "tla/libarch/configs.h"
28 #include "tla/libarch/cmd.h"
29 #include "tla/libarch/cmd-build-config.h"
30 #include "tla/libarch/project-tree.h"
31
32
33
34 /* __STDC__ prototypes for static functions */
35 static void arch_grab (int chatter_fd, t_uchar *location);
36 t_uchar * find_latest_revision (t_uchar *archive_name, t_uchar *revision);
37
38
39
40 static t_uchar * usage = "[options] location";
41 static t_uchar * version_string = (cfg__std__package " from regexps.com\n"
42 "\n"
43 "Copyright 2003 Tom Lord\n"
44 "\n"
45 "This is free software; see the source for copying conditions.\n"
46 "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
47 "PARTICULAR PURPOSE.\n"
48 "\n"
49 "Report bugs to " cfg__tla_bug_mail ".\n"
50 "\n"
51 cfg__std__release_id_string
52 "\n");
53
54 #define OPTS(OP) \
55 OP (opt_help_msg, "h", "help", 0, \
56 "Display a help message and exit.") \
57 OP (opt_long_help, "H", 0, 0, \
58 "Display a verbose help message and exit.") \
59 OP (opt_version, "V", "version", 0, \
60 "Display a release identifier string\n" \
61 "and exit.")
62
63 t_uchar arch_cmd_grab_help[] = ("grab a published revision\n"
64 "Grabs a published revision from LOCATION.\n");
65
66 enum options
67 {
68 OPTS (OPT_ENUM)
69 };
70
71 static struct opt_desc opts[] =
72 {
73 OPTS (OPT_DESC)
74 {-1, 0, 0, 0, 0}
75 };
76
77
78
79 int
arch_cmd_grab(t_uchar * program_name,int argc,char * argv[])80 arch_cmd_grab (t_uchar * program_name, int argc, char * argv[])
81 {
82 int o;
83 struct opt_parsed * option;
84 t_uchar * errname;
85 t_uchar * location;
86
87 errname = "grab";
88
89 safe_buffer_fd (1, 0, O_WRONLY, 0);
90
91 option = 0;
92
93 while (1)
94 {
95 o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv, program_name, usage, version_string, arch_cmd_grab_help, opt_help_msg, opt_long_help, opt_version);
96 if (o == opt_none)
97 break;
98 switch (o)
99 {
100 default:
101 safe_printfmt (2, "unhandled option `%s'\n", option->opt_string);
102 panic ("internal error parsing arguments");
103
104 usage_error:
105 opt_usage (2, argv[0], program_name, usage, 1);
106 exit (1);
107
108 /* bogus_arg: */
109 safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string);
110 goto usage_error;
111
112 }
113 }
114
115 if (argc != 2)
116 goto usage_error;
117
118 location = str_save (0, argv[1]);
119
120 arch_grab (1, location);
121
122 lim_free (0, location);
123
124 return 0;
125 }
126
127
128
129 void
arch_grab(int chatter_fd,t_uchar * location)130 arch_grab (int chatter_fd, t_uchar * location)
131 {
132 t_uchar * publication = NULL;
133 t_uchar * archive_name = NULL;
134 t_uchar * archive_location = NULL;
135 t_uchar * target_revision = NULL;
136 t_uchar * target_directory = NULL;
137 t_uchar * target_config = NULL;
138 t_uchar * current_directory = NULL;
139 t_uchar * target_full_directory = NULL;
140 t_uchar * tmp_tail;
141 t_uchar * tmp_directory = NULL;
142 t_uchar * line = NULL;
143 t_uchar * colon = NULL;
144 t_uchar * eol = NULL;
145 t_uchar * name = NULL;
146 t_uchar * value = NULL;
147 t_uchar * final_revision;
148 t_uchar * uri = NULL;
149 t_uchar * path = NULL;
150 struct arch_pfs_session * session;
151
152
153 if (str_chr_index (location, ':'))
154 {
155 /************************************************************
156 * grab from http location
157 */
158
159 path = location + 7;
160 path = str_chr_index(path, '/');
161 if (path)
162 {
163 uri = str_save_n (0, location, path - location);
164 path = str_save (0, path);
165 }
166 else
167 {
168 path = str_save (0, "/");
169 uri = str_save (0, location);
170 }
171
172 session = arch_pfs_connect ( uri);
173 publication = arch_pfs_file_contents(session, path, 0);
174
175 }
176 else
177 {
178 /************************************************************
179 * try local file system
180 */
181 publication = file_contents (location);
182 }
183
184 if (publication == NULL)
185 {
186 safe_printfmt (2, "could not obtain publication data from %s.\n", location);
187 return;
188 }
189
190 /****************************************************************
191 * parse the publication
192 */
193 line = publication;
194 while (*line)
195 {
196 while (*line == '\n')
197 ++line;
198
199 /************************************************************
200 * split the line up
201 */
202 colon = str_chr_index (line, ':');
203 eol = str_chr_index (line, '\n');
204
205 if (!eol)
206 eol = line + str_length (line);
207
208 if (!colon || colon > eol)
209 {
210 line = eol;
211 continue;
212 }
213
214 name = str_save_trimming_n (0, line, colon - line);
215 value = str_save_trimming_n (0, colon + 1, eol - colon - 1);
216
217 /************************************************************
218 * save any useful values
219 */
220 if (str_cmp (name, "Archive-Name") == 0 && !archive_name)
221 archive_name = value;
222 else if (str_cmp (name, "Archive-Location") == 0 && !archive_location)
223 archive_location = value;
224 else if (str_cmp (name, "Target-Revision") == 0 && !target_revision)
225 target_revision = value;
226 else if (str_cmp (name, "Target-Directory") == 0 && !target_directory)
227 target_directory = value;
228 else if (str_cmp (name, "Target-Config") == 0 && !target_config)
229 target_config = value;
230 else
231 lim_free (0, value);
232
233 lim_free (0, name);
234 line = eol;
235 }
236
237 lim_free (0, publication);
238
239
240 if (!archive_name || !archive_location || !target_revision)
241 {
242 safe_printfmt (2, "Invalid publication file at %s.\n", location);
243 return;
244 }
245 else
246 {
247 struct arch_archive *archive;
248
249 if (target_directory)
250 {
251 /********************************************************
252 * perform sanity check on target dir
253 * we don't want to allow any old target dir (to avoid
254 * "/etc" or "../../../etc" exploits), so we only take
255 * the tail of the specified target directory.
256 */
257 t_uchar * target_directory_file = file_name_from_directory (0, target_directory);
258 t_uchar * target_directory_tail = file_name_tail (0, target_directory_file);
259 lim_free (0, target_directory);
260 lim_free (0, target_directory_file);
261 if (str_length (target_directory_tail) == 0)
262 {
263 lim_free (0, target_directory_tail);
264 target_directory_tail = NULL;
265 }
266 target_directory = target_directory_tail;
267 }
268
269 if (target_directory == NULL)
270 {
271 target_directory = str_save (0, target_revision);
272 }
273
274 current_directory = safe_current_working_directory ();
275
276 tmp_tail = str_alloc_cat_many (0, ",,grab.", target_directory, str_end);
277 target_full_directory = file_name_in_vicinity (0, current_directory, target_directory);
278 tmp_directory = tmp_file_name (current_directory, tmp_tail);
279 rmrf_file (tmp_directory);
280 safe_mkdir (tmp_directory, 0777);
281
282
283 safe_printfmt(1, "Grabbing: %s/%s\n", archive_name, archive_location);
284 safe_printfmt(1, "Source: %s, Dest: %s\n", archive_location, target_directory);
285 if (target_config)
286 safe_printfmt(1, "Config: %s\n", target_config);
287
288
289 /********************
290 * Time to grab the archive
291 */
292 arch_set_archive_location(archive_name, archive_location, 0, ARCH_REG_FAIL_QUIET);
293
294 final_revision = find_latest_revision (archive_name, target_revision);
295 archive = arch_archive_connect (archive_name, 0);
296
297 arch_build_revision (chatter_fd, tmp_directory, archive, archive_name, final_revision, current_directory);
298
299 arch_archive_close (archive);
300
301 safe_rename (tmp_directory, target_full_directory);
302
303 /****************
304 * Time to config, if we should
305 */
306
307 if (target_config)
308 {
309 t_uchar *tree_root;
310 t_uchar *tree_version;
311 t_uchar *def_archive = NULL;
312 struct arch_build_config_params config_params = {0, };
313
314
315 if (!arch_valid_config_name (target_config))
316 {
317 safe_printfmt(2, "grab: given invalid config name '%s'\n", target_config);
318 exit(1);
319 }
320
321 tree_root = arch_tree_root (0, target_full_directory, 0);
322 if (! tree_root)
323 panic("grab: Not in a valid tree root");
324
325 tree_version = arch_tree_version (tree_root);
326
327 if (tree_version)
328 {
329 def_archive = arch_parse_package_name (arch_ret_archive, 0, tree_version);
330 lim_free(0, tree_version);
331 }
332
333 arch_build_config (tree_root, target_config, &config_params , def_archive);
334 lim_free (0, tree_root);
335 lim_free (0, def_archive);
336
337 }
338
339 }
340
341 lim_free (0, archive_name);
342 lim_free (0, archive_location);
343 lim_free (0, target_revision);
344 lim_free (0, target_directory);
345 lim_free (0, current_directory);
346 lim_free (0, target_full_directory);
347 lim_free (0, tmp_directory);
348 lim_free (0, tmp_tail);
349 }
350
351
352
find_latest_revision(t_uchar * archive_name,t_uchar * revision)353 t_uchar * find_latest_revision (t_uchar *archive_name, t_uchar *revision)
354 {
355 t_uchar *oldrevision;
356 t_uchar *workrevision;
357
358 struct arch_archive *archive;
359
360 if (! arch_valid_package_name (revision, arch_no_archive, arch_req_package, 1))
361 {
362 panic("Invalid Package");
363 }
364
365 archive = arch_archive_connect(archive_name, 0);
366
367
368 workrevision = str_save(0, revision);
369
370 if (! arch_valid_package_name (workrevision, arch_no_archive, arch_req_version, 1))
371 {
372 rel_table versions = rel_table_nil;
373
374 versions = arch_archive_versions (archive, revision);
375 if (!rel_n_records (versions))
376 {
377 panic("No versions for that package exist in the archive");
378 }
379 arch_sort_table_by_name_field (1, versions, 0);
380
381 oldrevision = workrevision;
382 workrevision = str_save(0, rel_peek_str (versions, 0, 0));
383 lim_free(0, oldrevision);
384 rel_free_table (versions);
385 }
386
387 if (! arch_valid_package_name (workrevision, arch_no_archive, arch_req_patch_level, 1))
388 {
389 oldrevision = workrevision;
390 workrevision = str_alloc_cat_many (0, workrevision, "--",
391 arch_archive_latest_revision(archive, workrevision, 0),
392 str_end);
393 lim_free(0, oldrevision);
394 }
395
396 return workrevision;
397 }
398
399
400 /* tag: Mark Thomas Tue Jul 29 22:32:52 BST 2003 (cmd-grab.c)
401 */
402