1 /* diffs.c:
2  *
3  ****************************************************************
4  * Copyright (C) 2003 Tom Lord
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/os/sys/wait.h"
14 #include "hackerlab/os/signal.h"
15 #include "hackerlab/mem/mem.h"
16 #include "hackerlab/char/str.h"
17 #include "hackerlab/arrays/ar.h"
18 #include "hackerlab/vu/safe.h"
19 #include "hackerlab/fs/file-names.h"
20 #include "tla/libarch/exec.h"
21 #include "tla/libarch/inode-sig.h"
22 #include "tla/libarch/diffs.h"
23 
24 
25 
26 int
arch_binary_files_differ(const t_uchar * a,const t_uchar * b,const t_uchar * id,assoc_table inode_sig_shortcuts_of_b)27 arch_binary_files_differ (const t_uchar * a, const t_uchar * b, const t_uchar * id, assoc_table inode_sig_shortcuts_of_b)
28 {
29   struct stat a_stat;
30   struct stat b_stat;
31 
32   int answer;
33 
34   safe_stat (a, &a_stat);
35   safe_stat (b, &b_stat);
36 
37   answer = arch_file_stats_differ (&a_stat, &b_stat);
38   if (answer == 0)
39     return answer;
40   answer = arch_inode_sigs_differ (&b_stat, id, inode_sig_shortcuts_of_b);
41   if (answer == 0)
42     return answer;
43 
44   return arch_filename_contents_differ (a, b);
45 }
46 
47 
48 int
arch_file_stats_differ(struct stat * a_stat,struct stat * b_stat)49 arch_file_stats_differ (struct stat *a_stat, struct stat *b_stat)
50 {
51   if (a_stat->st_size != b_stat->st_size)
52     return 1;
53 
54   if (a_stat->st_ino == b_stat->st_ino && a_stat->st_dev == b_stat->st_dev )
55     return 0;
56   return -1;
57 }
58 
59 int
arch_inode_sigs_differ(struct stat * b_stat,const t_uchar * id,assoc_table inode_sig_shortcuts_of_b)60 arch_inode_sigs_differ (struct stat *b_stat, const t_uchar * id, assoc_table inode_sig_shortcuts_of_b)
61 {
62   if (id && inode_sig_shortcuts_of_b)
63     {
64       t_uchar * b_sig = arch_statb_inode_sig (b_stat);
65       const t_uchar * b_goal = assoc_get_str_taking (inode_sig_shortcuts_of_b, rel_make_field_str (id));
66       int shortcut_applies = !str_cmp (b_sig, b_goal);
67 
68       lim_free (0, b_sig);
69       if (shortcut_applies)
70         return 0;
71     }
72 
73   return -1;
74 }
75 
76 int
arch_filename_contents_differ(const t_uchar * a,const t_uchar * b)77 arch_filename_contents_differ (const t_uchar * a, const t_uchar * b)
78 {
79   int a_fd;
80   int b_fd;
81   int answer;
82 
83   a_fd = safe_open (a, O_RDONLY, 0);
84   b_fd = safe_open (b, O_RDONLY, 0);
85   answer = arch_file_contents_differ (a_fd, b_fd);
86 
87   safe_close (a_fd);
88   safe_close (b_fd);
89 
90   return answer;
91 }
92 
93 int
arch_file_contents_differ(int a_fd,int b_fd)94 arch_file_contents_differ (int a_fd, int b_fd)
95 {
96   static t_uchar a_buf[65536];
97   static t_uchar b_buf[sizeof (a_buf)];
98   long a_amt;
99   long b_amt;
100   int answer = 0;
101 
102   while (1)
103     {
104       a_amt = safe_read_retry (a_fd, a_buf, sizeof (a_buf));
105       b_amt = safe_read_retry (b_fd, b_buf, sizeof (b_buf));
106 
107       if ((a_amt != b_amt) || mem_cmp (a_buf, b_buf, a_amt))
108         {
109           answer = 1;
110           break;
111         }
112 
113       if (!a_amt)
114         break;
115     }
116 
117   return answer;
118 }
119 
120 
121 int
arch_invoke_diff(int output_fd,const char * orig_path,const char * orig_loc,const char * mod_path,const char * mod_loc,t_uchar * id,assoc_table inode_sig_shortcuts_of_mod)122 arch_invoke_diff (int output_fd,
123                   const char * orig_path, const char * orig_loc,
124                   const char * mod_path, const char * mod_loc,
125                   t_uchar * id,
126                   assoc_table inode_sig_shortcuts_of_mod)
127 {
128   if (!arch_binary_files_differ (orig_path, mod_path, id, inode_sig_shortcuts_of_mod))
129     return 0;
130   return arch_really_invoke_diff (output_fd, orig_path, orig_loc, mod_path, mod_loc, NULL);
131 }
132 
133 int
arch_really_invoke_diff(int output_fd,const char * orig_path,const char * orig_loc,const char * mod_path,const char * mod_loc,const char ** extraopts)134 arch_really_invoke_diff (int output_fd,
135                          const char * orig_path, const char * orig_loc,
136                          const char * mod_path, const char * mod_loc, const char **extraopts)
137 {
138   char * orig_label = 0;
139   char * mod_label = 0;
140   int pid;
141 
142   if (orig_loc)
143     {
144       orig_label = file_name_in_vicinity (0, "orig", orig_loc + 2);
145     }
146   if (mod_loc)
147     {
148       mod_label = file_name_in_vicinity (0, "mod", mod_loc + 2);
149     }
150 
151   safe_flush (output_fd);
152 
153   pid = fork ();
154   if (pid == -1)
155     panic ("unable to fork for diff");
156 
157   if (pid)
158     {
159       int status;
160       int wait_pid;
161 
162       wait_pid = waitpid (pid, &status, 0);
163       if (wait_pid < 0)
164         {
165           panic_msg ("error waiting for subprocess");
166           kill (0, SIGKILL);
167           panic ("error waiting for subprocess");
168         }
169       if (WIFSIGNALED (status))
170         {
171           safe_printfmt (2, "\n");
172           safe_printfmt (2, "diff subprocess killed by signal %d\n", WTERMSIG (status));
173           safe_printfmt (2, "\n");
174           exit (2);
175         }
176       else if (!WIFEXITED (status))
177         {
178           panic_msg ("waitpid returned for a non-exited process");
179           kill (0, SIGKILL);
180           panic ("waitpid returned for a non-exited process");
181         }
182       else
183         {
184           int exit_status;
185 
186           exit_status = WEXITSTATUS (status);
187 
188           if (exit_status && (exit_status != 1) && (exit_status != 2))
189             {
190               safe_printfmt (2, "\n");
191               safe_printfmt (2, "encountered error diffing files\n");
192               safe_printfmt (2, "  orig: %s\n", orig_path);
193               safe_printfmt (2, "  mod: %s\n", mod_path);
194               safe_printfmt (2, "  diff exit status: %d\n", exit_status);
195               safe_printfmt (2, "\n");
196               exit (2);
197             }
198           if (orig_label)
199             {
200               lim_free (0, orig_label);
201             }
202           if (mod_label)
203             {
204               lim_free (0, mod_label);
205             }
206           return exit_status;
207         }
208     }
209   else
210     {
211       int errn;
212       t_uchar ** argv = 0;
213 
214       if (0 > vu_move_fd (&errn, output_fd, 1))
215         panic ("unable to redirect stdout for diff");
216 
217 
218       /* `const' discarded before `exec'
219        */
220 
221       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = cfg__gnu_diff;
222       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "--binary";
223       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "-u";
224       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "-L";
225       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = orig_label ? (char *)orig_label : (char *)orig_path;
226       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "-L";
227       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = mod_label ? (char *)mod_label : (char *)mod_path;
228       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = (char *)orig_path;
229       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = (char *)mod_path;
230       if (extraopts != NULL)
231         {
232           t_uchar ** opt;
233           for (opt = extraopts; *opt != NULL; ++opt)
234             {
235               *(t_uchar **) ar_push ((void*) &argv, 0, sizeof(t_uchar*)) = *opt;
236 
237             }
238         }
239 
240       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = 0;
241 
242       arch_util_execvp (cfg__gnu_diff, argv);
243 
244       panic ("execvp for diff returned to caller");
245 
246       exit (2);
247     }
248   panic ("arch_invoke_diff: not reached");
249   return 1;
250 }
251 
252 
253 
254 
255 /* tag: Tom Lord Mon May 19 18:00:23 2003 (diffs.c)
256  */
257