migration from private to rsa
[external/bash.git] / debian / new / bash.preinst.c
1 /* Copyright (c) 1999 Anthony Towns
2  * Copyright (c) 2000 Matthias Klose
3  *
4  * You may freely use, distribute, and modify this program.
5  */
6
7 // Don't rely on /bin/sh and popen!
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <limits.h>
16 #include <sys/types.h>
17 #include <sys/wait.h>
18
19 /* XXX: evil kludge, deal with arbitrary name lengths */
20 #ifndef PATH_MAX
21 #define PATH_MAX 4096
22 #endif
23
24 int myexec(char *cmd, ...)
25 {
26     va_list ap;
27     pid_t child;
28
29     char *new_argv[10];
30     int new_argc = 0, i;
31
32     new_argv[new_argc++] = cmd;
33     va_start(ap, cmd);
34     while ((new_argv[new_argc++] = va_arg(ap, char *)));
35     va_end(ap);
36
37     switch(child = fork()) {
38       case -1:
39         /* fork failed */
40         return EXIT_FAILURE;
41
42       case 0:
43         /* i'm the child */
44         {
45             execv(cmd, new_argv);
46            _exit(127);
47         }
48
49       default:
50         /* i'm the parent */
51         {
52             int status;
53             pid_t pid;
54             pid = wait(&status);
55             if (pid == child) {
56                 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
57                     return EXIT_SUCCESS;
58                 }
59             }
60         }
61     }
62     return EXIT_FAILURE;
63 }
64
65 int check_predepends(void)
66 {
67     return myexec("/usr/bin/dpkg", "--assert-support-predepends", NULL);
68 }
69
70 int dpkg_compare_versions(char *v1, char *op, char *v2)
71 {
72     return myexec("/usr/bin/dpkg", "--compare-versions", v1, op, v2, NULL);
73 }
74
75 int dpkg_divert_add(char *pkg, char *file)
76 {
77     return myexec("/usr/sbin/dpkg-divert", "--package", pkg, "--add", file, NULL);
78 }
79
80 char *check_diversion(char *diversion_name)
81 {
82     pid_t child;
83     int pipedes[2];
84
85     if (pipe(pipedes))
86         return NULL;
87
88
89     switch(child = fork()) {
90       case -1:
91         /* fork failed */
92         close(pipedes[0]);
93         close(pipedes[1]);
94         return NULL;
95
96       case 0:
97         /* i'm the child */
98         {
99             if (dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
100                 _exit(127);
101             close(pipedes[STDIN_FILENO]);
102             close(pipedes[STDOUT_FILENO]);
103             execl( "/usr/sbin/dpkg-divert", "/usr/sbin/dpkg-divert",
104                    "--list", diversion_name, NULL );
105            _exit(127);
106         }
107
108       default:
109         /* i'm the parent */
110         {
111             static char line[1024];
112             FILE *fd;
113
114             close (pipedes[STDOUT_FILENO]);
115             fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
116             fd = fdopen (pipedes[STDIN_FILENO], "r");
117
118             while (fgets(line, 1024, fd) != NULL) {
119                 line[strlen(line)-1] = '\0';
120                 break;
121             }
122             fclose(fd);
123             return line;
124         }
125     }
126     return NULL;
127 }
128
129 #define FIRST_WITHOUT_SHLINK "2.05b-4"
130
131 const char *msg =
132   "As bash for Debian is destined to provide a working /bin/sh (pointing to\n"
133   "/bin/bash) your link will be overwritten by a default link.\n\n"
134   "If you don't want further upgrades to overwrite your customization,\n"
135   "please read /usr/share/doc/bash/README.Debian for a more permanent solution.\n\n"
136   "[Press RETURN to continue]";
137
138 int main(int argc, char *argv[]) {
139     int targetlen;
140     char target[PATH_MAX+1], answer[1024];
141
142     if (argc < 2) {
143         printf("\nbash/preinst: expected at least one argument\n\n");
144         return EXIT_FAILURE;
145     }
146
147     if (check_predepends() != EXIT_SUCCESS) {
148         printf("\nPlease upgrade to a new version of dpkg\n\n");
149         return EXIT_FAILURE;
150     }
151
152 /*
153     if [ "$1" = upgrade ] && dpkg --compare-versions "$2" lt FIRST_WITHOUT_SHLINK; then
154         div=$(dpkg-divert --list /bin/sh)
155         if [ -z "$div" ]; then
156                 dpkg-divert --package bash --add /bin/sh
157                 ln -sf dash /bin/sh
158         fi
159         div=$(dpkg-divert --list /usr/share/man/man1/sh.1.gz)
160         if [ -z "$div" ]; then
161                 dpkg-divert --package bash --add /usr/share/man/man1/sh.1.gz
162                 ln -sf dash.1.gz /usr/share/man/man1/sh.1.gz
163         fi
164      fi
165 */
166
167     if (strcmp(argv[1], "upgrade") == 0) {
168         if (argc < 3) {
169             printf("\nbash/preinst upgrade: expected at least two arguments\n\n");
170             return EXIT_FAILURE;
171         }
172         if (dpkg_compare_versions(argv[2], "lt", FIRST_WITHOUT_SHLINK) == EXIT_SUCCESS) {
173             char *diversion = check_diversion("/bin/sh");
174
175             if (diversion == NULL)
176                 return EXIT_FAILURE;
177             // printf("diversion: /%s/\n", diversion);
178             if (strcmp(diversion, "") == 0) {
179                 // link is not diverted
180                 dpkg_divert_add("bash", "/bin/sh");
181
182                 unlink("/bin/sh");
183                 symlink("dash", "/bin/sh");
184             }
185
186             diversion = check_diversion("/usr/share/man/man1/sh.1.gz");
187
188             if (diversion == NULL)
189                 return EXIT_FAILURE;
190             // printf("diversion: /%s/\n", diversion);
191             if (strcmp(diversion, "") == 0) {
192                 // link is not diverted
193                 dpkg_divert_add("bash", "/usr/share/man/man1/sh.1.gz");
194
195                 unlink("/usr/share/man/man1/sh.1.gz");
196                 symlink("dash.1.gz", "/usr/share/man/man1/sh.1.gz");
197             }
198
199         }
200     }
201
202 #if 0
203     targetlen = readlink("/bin/sh", target, PATH_MAX);
204     if (targetlen == -1) {
205         // error reading link. Will be overwritten.
206         puts("The bash upgrade discovered that something is wrong with your /bin/sh link.");
207         puts(msg);
208         fgets(answer, 1024, stdin);
209         return EXIT_SUCCESS;
210     }
211     target[targetlen] = '\0';
212     if (strcmp(target, "bash") != 0 && strcmp(target, "/bin/bash") != 0) {
213         char *diversion = check_diversion("/bin/sh");
214
215         if (diversion == NULL)
216             return EXIT_FAILURE;
217         // printf("diversion: /%s/\n", diversion);
218         if (strcmp(diversion, "") != 0)
219             // link is diverted
220             return EXIT_SUCCESS;
221         printf("The bash upgrade discovered that your /bin/sh link points to %s.\n", target);
222         puts(msg);
223         fgets(answer, 1024, stdin);
224         return EXIT_SUCCESS;
225     }
226 #endif
227
228     return EXIT_SUCCESS;
229 }