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