Upload Tizen2.0 source
[framework/base/rpm-installer.git] / backend / src / rpm / rpm-installer.c
1 /*
2  * rpm-installer
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
7  * Jaeho Lee <jaeho81.lee@samsung.com>, Shobhit Srivastava <shobhit.s@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26 #define __USE_GNU
27 #include <sys/wait.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <wait.h>
31 #include <stdio.h>
32 #include <signal.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>              /* for isspace () */
37 #include <pkgmgr_parser.h>
38
39 #include "rpm-installer-util.h"
40 #include "rpm-installer.h"
41 #include "rpm-frontend.h"
42
43 #define PRE_CHECK_FOR_MANIFEST
44 #define INSTALL_SCRIPT          "/usr/bin/install_rpm_package.sh"
45 #define UNINSTALL_SCRIPT        "/usr/bin/uninstall_rpm_package.sh"
46 #define UPGRADE_SCRIPT  "/usr/bin/upgrade_rpm_package.sh"
47 #define RPM2CPIO        "/usr/bin/rpm2cpio"
48
49 enum rpm_request_type {
50         INSTALL_REQ,
51         UNINSTALL_REQ,
52         UPGRADE_REQ,
53 };
54
55 typedef enum rpm_request_type rpm_request_type;
56 extern char *gpkgname;
57
58 static int __rpm_xsystem(const char *argv[]);
59 static void __rpm_process_line(char *line);
60 static void __rpm_perform_read(int fd);
61
62 static void __rpm_process_line(char *line)
63 {
64         char *tok = NULL;
65         tok = strtok(line, " ");
66         if (tok) {
67                 if (!strncmp(tok, "%%", 2)) {
68                         tok = strtok(NULL, " ");
69                         if (tok) {
70                                 _d_msg(DEBUG_INFO, "Install percentage is %s\n",
71                                        tok);
72                                 _ri_broadcast_status_notification(gpkgname,
73                                                                   "install_percent",
74                                                                   tok);
75                                 _ri_stat_cb(gpkgname, "install_percent", tok);
76                         }
77                         return;
78                 }
79         }
80         return;
81 }
82
83 static void __rpm_perform_read(int fd)
84 {
85         char *buf_ptr = NULL;
86         char *tmp_ptr = NULL;
87         int size = 0;
88         static char buffer[1024] = { 0, };
89         static int buffer_position;
90
91         size = read(fd, &buffer[buffer_position],
92                     sizeof(buffer) - buffer_position);
93         buffer_position += size;
94         if (size <= 0)
95                 return;
96
97         /* Process each line of the recieved buffer */
98         buf_ptr = tmp_ptr = buffer;
99         while ((tmp_ptr = (char *)memchr(buf_ptr, '\n',
100                                          buffer + buffer_position - buf_ptr)) !=
101                NULL) {
102                 *tmp_ptr = 0;
103                 __rpm_process_line(buf_ptr);
104                 /* move to next line and continue */
105                 buf_ptr = tmp_ptr + 1;
106         }
107
108         /*move the remaining bits at the start of the buffer
109            and update the buffer position */
110         buf_ptr = (char *)memrchr(buffer, 0, buffer_position);
111         if (buf_ptr == NULL)
112                 return;
113
114         /* we have processed till the last \n which has now become
115            0x0. So we increase the pointer to next position */
116         buf_ptr++;
117
118         memmove(buffer, buf_ptr, buf_ptr - buffer);
119         buffer_position = buffer + buffer_position - buf_ptr;
120 }
121
122 static int __rpm_xsystem(const char *argv[])
123 {
124         int err = 0;
125         int status = 0;
126         pid_t pid;
127         int pipefd[2];
128
129         if (pipe(pipefd) == -1) {
130                 _d_msg(DEBUG_ERR, "pipe creation failed\n");
131                 return -1;
132         }
133         /*Read progress info via pipe */
134         pid = fork();
135
136         switch (pid) {
137         case -1:
138                 _d_msg(DEBUG_ERR, "fork failed\n");
139                 return -1;
140         case 0:
141                 /* child */
142                 {
143                         close(pipefd[0]);
144                         close(1);
145                         close(2);
146                         dup(pipefd[1]);
147                         dup(pipefd[1]);
148                         if (execvp(argv[0], (char *const *)argv) == -1) {
149                                 _d_msg(DEBUG_ERR, "execvp failed\n");
150                         }
151                         _exit(100);
152                 }
153         default:
154                 /* parent */
155                 break;
156         }
157
158         close(pipefd[1]);
159
160         while ((err = waitpid(pid, &status, WNOHANG)) != pid) {
161                 if (err < 0) {
162                         if (errno == EINTR)
163                                 continue;
164                         _d_msg(DEBUG_ERR, "waitpid failed\n");
165                         close(pipefd[0]);
166                         return -1;
167                 }
168
169                 int select_ret;
170                 fd_set rfds;
171                 struct timespec tv;
172                 FD_ZERO(&rfds);
173                 FD_SET(pipefd[0], &rfds);
174                 tv.tv_sec = 1;
175                 tv.tv_nsec = 0;
176                 select_ret =
177                     pselect(pipefd[0] + 1, &rfds, NULL, NULL, &tv, NULL);
178                 if (select_ret == 0)
179                         continue;
180
181                 else if (select_ret < 0 && errno == EINTR)
182                         continue;
183                 else if (select_ret < 0) {
184                         _d_msg(DEBUG_ERR, "select() returned error\n");
185                         continue;
186                 }
187                 if (FD_ISSET(pipefd[0], &rfds))
188                         __rpm_perform_read(pipefd[0]);
189         }
190
191         close(pipefd[0]);
192         /* Check for an error code. */
193         if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) {
194
195                 if (WIFSIGNALED(status) != 0 && WTERMSIG(status) == SIGSEGV) {
196                         printf
197                             ("Sub-process %s received a segmentation fault. \n",
198                              argv[0]);
199                 } else if (WIFEXITED(status) != 0) {
200                         printf("Sub-process %s returned an error code (%u)\n",
201                                argv[0], WEXITSTATUS(status));
202                 } else {
203                         printf("Sub-process %s exited unexpectedly\n", argv[0]);
204                 }
205         }
206         return WEXITSTATUS(status);
207 }
208
209 int _rpm_uninstall_pkg(char *pkgname)
210 {
211         int ret = 0;
212         int err = 0;
213         char buff[256] = {'\0'};
214         const char *argv[] = { UNINSTALL_SCRIPT, pkgname, NULL };
215
216 #ifdef PRE_CHECK_FOR_MANIFEST
217         char *manifest = NULL;
218         manifest = pkgmgr_parser_get_manifest_file(pkgname);
219         if (access(manifest, F_OK)) {
220                 _d_msg(DEBUG_ERR, "No Manifest File Found\n");
221         } else {
222                 pkgmgr_parser_parse_manifest_for_uninstallation(manifest, NULL);
223                 if (manifest) {
224                         free(manifest);
225                         manifest = NULL;
226                 }
227         }
228 #endif
229         ret = __rpm_xsystem(argv);
230         if (ret != 0) {
231                 _d_msg(DEBUG_ERR, "uninstall failed with error(%d)\n", ret);
232                 return ret;
233         }
234         /* Uninstallation Success. Remove the installation time key from vconf*/
235         snprintf(buff, 256, "db/app-info/%s/installed-time", pkgname);
236         err = vconf_unset(buff);
237         if (err) {
238                 _d_msg(DEBUG_ERR, "unset installation time failed\n");
239         }
240         return ret;
241 }
242
243 int _rpm_install_pkg(char *pkgfilepath, char *installoptions)
244 {
245         int err = 0;
246         int ret = 0;
247         time_t cur_time;
248         char buff[256] = {'\0'};
249         const char *argv[] = {
250                 INSTALL_SCRIPT, pkgfilepath, installoptions, NULL
251         };
252 #ifdef PRE_CHECK_FOR_MANIFEST
253         char cwd[1024] = {'\0'};
254         char query[1024] = {'\0'};
255         char manifest[1024] = { '\0'};
256         int m_exist = 0;
257         getcwd(cwd, 1024);
258         if (cwd == NULL) {
259                 _d_msg(DEBUG_ERR, "getcwd() Failed\n");
260                 return -1;
261         }
262         _d_msg(DEBUG_ERR, "Current working directory is %s\n", cwd);
263         err = chdir("/tmp");
264         if (err != 0) {
265                 _d_msg(DEBUG_ERR, "chdir() failed\n");
266                 return -1;
267         }
268         _d_msg(DEBUG_ERR, "Switched to /tmp\n");
269         snprintf(query, 1024, "/usr/bin/rpm2cpio %s | cpio -idmv", pkgfilepath);
270         _d_msg(DEBUG_INFO, "query= %s\n", query);
271         system(query);
272         snprintf(manifest, 1024, "/tmp/opt/share/packages/%s.xml", gpkgname);
273         _d_msg(DEBUG_ERR, "Manifest name is %s\n", manifest);
274         if (access(manifest, F_OK)) {
275                 _d_msg(DEBUG_ERR, "No rw Manifest File Found\n");
276
277                 snprintf(manifest, 1024, "/tmp/usr/share/packages/%s.xml", gpkgname);
278                 _d_msg(DEBUG_ERR, "Manifest ro name is %s\n", manifest);
279
280                 if (access(manifest, F_OK)) {
281                         _d_msg(DEBUG_ERR, "No ro Manifest File Found\n");
282                 } else
283                         m_exist = 1;
284         } else
285                 m_exist = 1;
286
287         _d_msg(DEBUG_ERR, "Manifest exists\n");
288
289         err = chdir(cwd);
290         if (err != 0) {
291                 _d_msg(DEBUG_ERR, "chdir() failed\n");
292                 return -1;
293         }
294
295         if (m_exist) {
296                 err = pkgmgr_parser_check_manifest_validation(manifest);
297                 if(err < 0) {
298                         _d_msg(DEBUG_ERR, "Invalid manifest\n");
299                         return -1;
300                 }
301         }
302 #endif
303         err = __rpm_xsystem(argv);
304         if (err != 0) {
305                 _d_msg(DEBUG_ERR, "install complete with error(%d)\n", err);
306                 return err;
307         }
308
309 #ifdef PRE_CHECK_FOR_MANIFEST
310         if (m_exist) {
311                 err = pkgmgr_parser_parse_manifest_for_installation(manifest, NULL);
312                 if (err < 0) {
313                         _d_msg(DEBUG_ERR, "Parsing Manifest Failed\n");
314                 } else
315                         _d_msg(DEBUG_ERR, "Parsing Manifest Success\n");
316         }
317 #endif
318         /* Install Success. Store the installation time*/
319         cur_time = time(NULL);
320         snprintf(buff, 256, "db/app-info/%s/installed-time", gpkgname);
321         /* The time is stored in time_t format. It can be converted to
322         local time or GMT time as per the need by the apps*/
323         ret = vconf_set_int(buff, cur_time);
324         if(ret) {
325                 _d_msg(DEBUG_ERR, "setting installation time failed\n");
326                 vconf_unset(buff);
327         }
328         return err;
329 }
330
331 int _rpm_upgrade_pkg(char *pkgfilepath, char *installoptions)
332 {
333         int err = 0;
334         const char *argv[] = {
335                 UPGRADE_SCRIPT, pkgfilepath, installoptions, NULL
336         };
337 #ifdef PRE_CHECK_FOR_MANIFEST
338         char cwd[1024] = {'\0'};
339         char query[1024] = {'\0'};
340         char manifest[1024] = { '\0'};
341         int m_exist = 0;
342         getcwd(cwd, 1024);
343         if (cwd == NULL) {
344                 _d_msg(DEBUG_ERR, "getcwd() Failed\n");
345                 return -1;
346         }
347         _d_msg(DEBUG_ERR, "Current working directory is %s\n", cwd);
348         err = chdir("/tmp");
349         if (err != 0) {
350                 _d_msg(DEBUG_ERR, "chdir() failed\n");
351                 return -1;
352         }
353         _d_msg(DEBUG_ERR, "Switched to /tmp\n");
354         snprintf(query, 1024, "/usr/bin/rpm2cpio %s | cpio -idmv", pkgfilepath);
355         _d_msg(DEBUG_INFO, "query= %s\n", query);
356         system(query);
357         snprintf(manifest, 1024, "/tmp/opt/share/packages/%s.xml", gpkgname);
358         _d_msg(DEBUG_ERR, "Manifest name is %s\n", manifest);
359         if (access(manifest, F_OK)) {
360                 _d_msg(DEBUG_ERR, "No rw Manifest File Found\n");
361
362                 snprintf(manifest, 1024, "/tmp/usr/share/packages/%s.xml", gpkgname);
363                 _d_msg(DEBUG_ERR, "Manifest ro name is %s\n", manifest);
364
365                 if (access(manifest, F_OK)) {
366                         _d_msg(DEBUG_ERR, "No ro Manifest File Found\n");
367                 } else
368                         m_exist = 1;
369         } else
370                 m_exist = 1;
371
372         _d_msg(DEBUG_ERR, "Manifest exists\n");
373
374         err = chdir(cwd);
375         if (err != 0) {
376                 _d_msg(DEBUG_ERR, "chdir() failed\n");
377                 return -1;
378         }
379
380         if (m_exist) {
381                 err = pkgmgr_parser_check_manifest_validation(manifest);
382                 if(err < 0) {
383                         _d_msg(DEBUG_ERR, "Invalid manifest\n");
384                         return -1;
385                 }
386         }
387 #endif
388         err = __rpm_xsystem(argv);
389         if (err != 0) {
390                 _d_msg(DEBUG_ERR, "upgrade complete with error(%d)\n", err);
391         }
392
393 #ifdef PRE_CHECK_FOR_MANIFEST
394         if (m_exist) {
395                 err = pkgmgr_parser_parse_manifest_for_upgrade(manifest, NULL);
396                 if (err < 0) {
397                         _d_msg(DEBUG_ERR, "Parsing Manifest Failed\n");
398                 } else
399                         _d_msg(DEBUG_ERR, "Parsing Manifest Success\n");
400         }
401 #endif
402
403         return err;
404 }