ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/lib/libmport/bundle_read_install_pkg.c
Revision: 12195
Committed: Sat May 25 17:36:04 2019 UTC (4 years, 11 months ago) by laffer1
Content type: text/plain
File size: 29281 byte(s)
Log Message:
add error checks and memory cleanup

File Contents

# Content
1 /*-
2 * Copyright (c) 2013-2015 Lucas Holt
3 * Copyright (c) 2007-2009 Chris Reinhardt
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __MBSDID("$MidnightBSD$");
30
31 #include "mport.h"
32 #include "mport_private.h"
33
34 #include <sys/stat.h>
35 #include <libgen.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <syslog.h>
41 #include <stdarg.h>
42 #include <archive_entry.h>
43
44
45 enum phase { PREINSTALL, ACTUALINSTALL, POSTINSTALL};
46
47 static int do_pre_install(mportInstance *, mportBundleRead *, mportPackageMeta *);
48 static int do_actual_install(mportInstance *, mportBundleRead *, mportPackageMeta *);
49 static int do_post_install(mportInstance *, mportBundleRead *, mportPackageMeta *);
50 static int run_postexec(mportInstance *, mportPackageMeta *);
51 static int run_pkg_install(mportInstance *, mportBundleRead *, mportPackageMeta *, const char *);
52 static int run_mtree(mportInstance *, mportBundleRead *, mportPackageMeta *);
53 static int display_pkg_msg(mportInstance *, mportBundleRead *, mportPackageMeta *);
54 static int get_file_count(mportInstance *, char *, int *);
55 static int create_package_row(mportInstance *, mportPackageMeta *);
56 static int create_categories(mportInstance *mport, mportPackageMeta *pkg);
57 static int create_depends(mportInstance *mport, mportPackageMeta *pkg);
58 static int create_sample_file(mportInstance *mport, char *cwd, const char *file);
59 static char** parse_sample(char *input);
60 static int mark_complete(mportInstance *, mportPackageMeta *);
61 static int mport_bundle_read_get_assetlist(mportInstance *mport, mportPackageMeta *pkg, mportAssetList **alist_p, enum phase);
62
63 /**
64 * This is a wrapper for all bund read install operations
65 */
66 int
67 mport_bundle_read_install_pkg(mportInstance *mport, mportBundleRead *bundle, mportPackageMeta *pkg)
68 {
69 if (do_pre_install(mport, bundle, pkg) != MPORT_OK) {
70 RETURN_CURRENT_ERROR;
71 }
72
73 if (do_actual_install(mport, bundle, pkg) != MPORT_OK) {
74 RETURN_CURRENT_ERROR;
75 }
76
77 if (do_post_install(mport, bundle, pkg) != MPORT_OK) {
78 RETURN_CURRENT_ERROR;
79 }
80
81 syslog(LOG_NOTICE, "%s-%s installed", pkg->name, pkg->version);
82
83 return MPORT_OK;
84 }
85
86
87 /* This does everything that has to happen before we start installing files.
88 * We run mtree, pkg-install PRE-INSTALL, etc...
89 */
90 static int
91 do_pre_install(mportInstance *mport, mportBundleRead *bundle, mportPackageMeta *pkg)
92 {
93 char cwd[FILENAME_MAX];
94 char file[FILENAME_MAX];
95 mportAssetList *alist;
96 mportAssetListEntry *e = NULL;
97
98 /* run mtree */
99 if (run_mtree(mport, bundle, pkg) != MPORT_OK)
100 RETURN_CURRENT_ERROR;
101
102 /* run pkg-install PRE-INSTALL */
103 if (run_pkg_install(mport, bundle, pkg, "PRE-INSTALL") != MPORT_OK)
104 RETURN_CURRENT_ERROR;
105
106 /* Process @preexec steps */
107 if (mport_bundle_read_get_assetlist(mport, pkg, &alist, PREINSTALL) != MPORT_OK)
108 goto ERROR;
109
110 (void) strlcpy(cwd, pkg->prefix, sizeof(cwd));
111
112 if (mport_chdir(mport, cwd) != MPORT_OK)
113 goto ERROR;
114
115 STAILQ_FOREACH(e, alist, next) {
116 switch (e->type) {
117 case ASSET_CWD:
118 (void) strlcpy(cwd, e->data == NULL ? pkg->prefix : e->data, sizeof(cwd));
119 if (mport_chdir(mport, cwd) != MPORT_OK)
120 goto ERROR;
121
122 break;
123 case ASSET_PREEXEC:
124 if (mport_run_asset_exec(mport, e->data, cwd, file) != MPORT_OK)
125 goto ERROR;
126 break;
127 default:
128 /* do nothing */
129 break;
130 }
131 }
132
133 mport_assetlist_free(alist);
134 mport_pkgmeta_logevent(mport, pkg, "preexec");
135
136 return MPORT_OK;
137
138 ERROR:
139 if (alist != NULL)
140 mport_assetlist_free(alist);
141 RETURN_CURRENT_ERROR;
142 }
143
144 /* get the file count for the progress meter */
145 static int
146 get_file_count(mportInstance *mport, char *pkg_name, int *file_total)
147 {
148 __block sqlite3_stmt *count;
149 __block int result = MPORT_OK;
150 __block char *err;
151
152 if (mport_db_prepare(mport->db, &count,
153 "SELECT COUNT(*) FROM stub.assets WHERE (type=%i or type=%i or type=%i or type=%i) AND pkg=%Q",
154 ASSET_FILE, ASSET_SAMPLE, ASSET_SHELL, ASSET_FILE_OWNER_MODE, pkg_name) != MPORT_OK) {
155 sqlite3_finalize(count);
156 RETURN_CURRENT_ERROR;
157 }
158
159 dispatch_sync(mportSQLSerial, ^{
160 switch (sqlite3_step(count)) {
161 case SQLITE_ROW:
162 *file_total = sqlite3_column_int(count, 0);
163 sqlite3_finalize(count);
164 break;
165 default:
166 err = (char *) sqlite3_errmsg(mport->db);
167 result = MPORT_ERR_FATAL;
168 sqlite3_finalize(count);
169 }
170 });
171
172 if (result == MPORT_ERR_FATAL)
173 SET_ERRORX(result, "Error reading file count %s", err);
174 return result;
175 }
176
177 static int
178 create_package_row(mportInstance *mport, mportPackageMeta *pkg)
179 {
180 /* Insert the package meta row into the packages table (We use pack here because things might have been twiddled) */
181 /* Note that this will be marked as dirty by default */
182 if (mport_db_do(mport->db,
183 "INSERT INTO packages (pkg, version, origin, prefix, lang, options, comment, os_release, cpe, locked, deprecated, expiration_date, no_provide_shlib, flavor) VALUES (%Q,%Q,%Q,%Q,%Q,%Q,%Q,%Q,%Q,0,%Q,%ld,%d,%Q)",
184 pkg->name, pkg->version, pkg->origin, pkg->prefix, pkg->lang, pkg->options, pkg->comment,
185 pkg->os_release, pkg->cpe, pkg->deprecated, pkg->expiration_date, pkg->no_provide_shlib, pkg->flavor) != MPORT_OK)
186 RETURN_CURRENT_ERROR;
187
188 return MPORT_OK;
189 }
190
191 static int
192 create_depends(mportInstance *mport, mportPackageMeta *pkg)
193 {
194 /* Insert the depends into the master table */
195 if (mport_db_do(mport->db,
196 "INSERT INTO depends (pkg, depend_pkgname, depend_pkgversion, depend_port) SELECT pkg,depend_pkgname,depend_pkgversion,depend_port FROM stub.depends WHERE pkg=%Q",
197 pkg->name) != MPORT_OK)
198 RETURN_CURRENT_ERROR;
199
200 return MPORT_OK;
201 }
202
203 static int
204 create_categories(mportInstance *mport, mportPackageMeta *pkg)
205 {
206 /* Insert the categories into the master table */
207 if (mport_db_do(mport->db,
208 "INSERT INTO categories (pkg, category) SELECT pkg, category FROM stub.categories WHERE pkg=%Q",
209 pkg->name) != MPORT_OK)
210 RETURN_CURRENT_ERROR;
211
212 return MPORT_OK;
213 }
214
215 static char**
216 parse_sample(char *input)
217 {
218 char **ap, **argv;
219 argv = calloc(3, sizeof(char *));
220
221 if (argv == NULL)
222 return NULL;
223
224 for (ap = argv; (*ap = strsep(&input, " \t")) != NULL;) {
225 if (**ap != '\0') {
226 if (++ap >= &argv[3])
227 break;
228 }
229 }
230
231 return argv;
232 }
233
234 static int
235 create_sample_file(mportInstance *mport, char *cwd, const char *file)
236 {
237 char nonSample[FILENAME_MAX * 2];
238 char secondFile[FILENAME_MAX];
239
240 strlcpy(nonSample, file, FILENAME_MAX * 2);
241 (void) snprintf(nonSample, FILENAME_MAX, "%s%s/%s", mport->root, cwd, file);
242 char** fileargv = parse_sample(nonSample);
243
244 if (fileargv[1] != '\0') {
245 if (fileargv[1][0] == '/')
246 strlcpy(secondFile, fileargv[1], FILENAME_MAX);
247 else
248 (void) snprintf(secondFile, FILENAME_MAX, "%s%s/%s", mport->root, cwd, fileargv[1]);
249
250 if (!mport_file_exists(secondFile)) {
251 if (mport_copy_file(fileargv[0], secondFile) != MPORT_OK)
252 RETURN_CURRENT_ERROR;
253 }
254 } else {
255 /* single file */
256 char *sptr = strcasestr(nonSample, ".sample");
257 if (sptr != NULL) {
258 sptr[0] = '\0'; /* hack off .sample */
259 if (!mport_file_exists(nonSample)) {
260 if (mport_copy_file(file, nonSample) != MPORT_OK)
261 RETURN_CURRENT_ERROR;
262 }
263 }
264 }
265
266 free(fileargv);
267
268 return MPORT_OK;
269 }
270
271 /**
272 * Get the list of assets (plist entries) from the stub attached database (package we are installing)
273 * filtered on entries that are not pre/post exec.
274 */
275 static int
276 mport_bundle_read_get_assetlist(mportInstance *mport, mportPackageMeta *pkg, mportAssetList **alist_p, enum phase state)
277 {
278 __block mportAssetList *alist;
279 __block sqlite3_stmt *stmt = NULL;
280 __block int result = MPORT_OK;
281 __block char *err;
282
283 if ((alist = mport_assetlist_new()) == NULL)
284 RETURN_ERROR(MPORT_ERR_FATAL, "Out of memory.");
285
286 *alist_p = alist;
287
288 if (state == PREINSTALL) {
289 if (mport_db_prepare(mport->db, &stmt,
290 "SELECT type,data,checksum,owner,grp,mode FROM stub.assets WHERE pkg=%Q and type in (%d, %d)",
291 pkg->name, ASSET_CWD, ASSET_PREEXEC) != MPORT_OK) {
292 sqlite3_finalize(stmt);
293 RETURN_CURRENT_ERROR;
294 }
295 } else if (state == ACTUALINSTALL) {
296 if (mport_db_prepare(mport->db, &stmt,
297 "SELECT type,data,checksum,owner,grp,mode FROM stub.assets WHERE pkg=%Q and type not in (%d, %d)",
298 pkg->name, ASSET_PREEXEC, ASSET_POSTEXEC) != MPORT_OK) {
299 sqlite3_finalize(stmt);
300 RETURN_CURRENT_ERROR;
301 }
302 } else if (state == POSTINSTALL) {
303 if (mport_db_prepare(mport->db, &stmt,
304 "SELECT type,data,checksum,owner,grp,mode FROM stub.assets WHERE pkg=%Q and type in (%d, %d)",
305 pkg->name, ASSET_CWD, ASSET_POSTEXEC) != MPORT_OK) {
306 sqlite3_finalize(stmt);
307 RETURN_CURRENT_ERROR;
308 }
309 }
310
311 if (stmt == NULL) {
312 RETURN_ERROR(MPORT_ERR_FATAL, "Statement was null");
313 }
314
315 dispatch_sync(mportSQLSerial, ^{
316 while (1) {
317 mportAssetListEntry *e;
318
319 int ret = sqlite3_step(stmt);
320
321 if (ret == SQLITE_BUSY || ret == SQLITE_LOCKED) {
322 sleep(1);
323 ret = sqlite3_step(stmt);
324 }
325
326 if (ret == SQLITE_DONE)
327 break;
328
329 if (ret != SQLITE_ROW) {
330 err = (char *) sqlite3_errmsg(mport->db);
331 result = MPORT_ERR_FATAL;
332 break; // we finalize below
333 }
334
335 e = (mportAssetListEntry *) calloc(1, sizeof(mportAssetListEntry));
336
337 if (e == NULL) {
338 err = "Out of memory";
339 result = MPORT_ERR_FATAL;
340 break; // we finalize below
341 }
342
343 e->type = (mportAssetListEntryType) sqlite3_column_int(stmt, 0);
344 const unsigned char *data = sqlite3_column_text(stmt, 1);
345 const unsigned char *checksum = sqlite3_column_text(stmt, 2);
346 const unsigned char *owner = sqlite3_column_text(stmt, 3);
347 const unsigned char *group = sqlite3_column_text(stmt, 4);
348 const unsigned char *mode = sqlite3_column_text(stmt, 5);
349
350 e->data = data == NULL ? NULL : strdup((char *) data);
351 if (checksum != NULL)
352 e->checksum = strdup((char *) checksum);
353 if (owner != NULL)
354 e->owner = strdup((char *) owner);
355 if (group != NULL)
356 e->group = strdup((char *) group);
357 if (mode != NULL)
358 e->mode = strdup((char *) mode);
359
360 STAILQ_INSERT_TAIL(alist, e, next);
361 }
362
363 sqlite3_finalize(stmt);
364 });
365
366 if (result == MPORT_ERR_FATAL)
367 SET_ERRORX(result, "Error reading assets %s", err);
368 return result;
369 }
370
371 static int
372 do_actual_install(mportInstance *mport, mportBundleRead *bundle, mportPackageMeta *pkg)
373 {
374 mportAssetList *alist = NULL;
375 __block mportAssetListEntry *e = NULL;
376 int file_total;
377 int file_count = 0;
378 struct archive_entry *entry;
379 char *orig_cwd = NULL;
380 uid_t owner = 0; /* root */
381 gid_t group = 0; /* wheel */
382 mode_t *set = NULL;
383 mode_t newmode;
384 mode_t *dirset = NULL;
385 mode_t dirnewmode;
386 char *mode = NULL;
387 char *mkdirp = NULL;
388 struct stat sb;
389 __block char file[FILENAME_MAX], cwd[FILENAME_MAX];
390 __block sqlite3_stmt *insert = NULL;
391
392 /* sadly, we can't just use abs pathnames, because it will break hardlinks */
393 orig_cwd = getcwd(NULL, 0);
394
395 if (get_file_count(mport, pkg->name, &file_total) != MPORT_OK)
396 goto ERROR;
397
398 mport_call_progress_init_cb(mport, "Installing %s-%s", pkg->name, pkg->version);
399
400 if (mport_bundle_read_get_assetlist(mport, pkg, &alist, ACTUALINSTALL) != MPORT_OK)
401 goto ERROR;
402
403 if (create_package_row(mport, pkg) != MPORT_OK)
404 goto ERROR;
405
406 if (create_depends(mport, pkg) != MPORT_OK)
407 goto ERROR;
408
409 if (create_categories(mport, pkg) != MPORT_OK)
410 goto ERROR;
411
412 /* Insert the assets into the master table (We do this one by one because we want to insert file
413 * assets as absolute paths. */
414 if (mport_db_prepare(mport->db, &insert,
415 "INSERT INTO assets (pkg, type, data, checksum, owner, grp, mode) values (%Q,?,?,?,?,?,?)",
416 pkg->name) != MPORT_OK)
417 goto ERROR;
418
419 (void) strlcpy(cwd, pkg->prefix, sizeof(cwd));
420
421 if (mport_chdir(mport, cwd) != MPORT_OK)
422 goto ERROR;
423
424 mport_db_do(mport->db, "BEGIN TRANSACTION");
425
426 STAILQ_FOREACH(e, alist, next) {
427 switch (e->type) {
428 case ASSET_CWD:
429 (void) strlcpy(cwd, e->data == NULL ? pkg->prefix : e->data, sizeof(cwd));
430 if (mport_chdir(mport, cwd) != MPORT_OK)
431 goto ERROR;
432 break;
433 case ASSET_CHMOD:
434 if (mode != NULL)
435 free(mode);
436 /* TODO: should we reset the mode rather than NULL here */
437 if (e->data == NULL)
438 mode = NULL;
439 else
440 mode = strdup(e->data);
441 break;
442 case ASSET_CHOWN:
443 owner = mport_get_uid(e->data);
444 break;
445 case ASSET_CHGRP:
446 group = mport_get_gid(e->data);
447 break;
448 case ASSET_DIR:
449 case ASSET_DIRRM:
450 case ASSET_DIRRMTRY:
451 case ASSET_DIR_OWNER_MODE:
452 mkdirp = strdup( e->data == NULL ? "" : e->data); /* need a char * here */
453 if (mkdirp == NULL || mport_mkdirp(mkdirp, S_IRWXU | S_IRWXG | S_IRWXO) == 0) {
454 free(mkdirp);
455 SET_ERRORX(MPORT_ERR_FATAL, "Unable to create directory %s", e->data);
456 goto ERROR;
457 }
458 free(mkdirp);
459
460 if (e->mode != NULL && e->mode[0] != '\0') {
461 if ((dirset = setmode(e->mode)) == NULL)
462 goto ERROR;
463 dirnewmode = getmode(dirset, sb.st_mode);
464 free(dirset);
465 if (chmod(e->data, dirnewmode))
466 goto ERROR;
467 }
468 if (e->owner != NULL && e->group != NULL && e->owner[0] != '\0' &&
469 e->group[0] != '\0') {
470 if (chown(e->data, mport_get_uid(e->owner), mport_get_gid(e->group)) == -1) {
471 SET_ERROR(MPORT_ERR_FATAL, "Unable to change owner");
472 goto ERROR;
473 }
474 } else if (e->owner != NULL && e->owner[0] != '\0') {
475 if (chown(e->data, mport_get_uid(e->owner), group) == -1) {
476 SET_ERROR(MPORT_ERR_FATAL, "Unable to change owner");
477 goto ERROR;
478 }
479 } else if (e->group != NULL && e->group[0] != '\0') {
480 if (chown(e->data, owner, mport_get_gid(e->group)) == -1) {
481 SET_ERROR(MPORT_ERR_FATAL, "Unable to change owner");
482 goto ERROR;
483 }
484 }
485
486 break;
487 case ASSET_EXEC:
488 if (mport_run_asset_exec(mport, e->data, cwd, file) != MPORT_OK)
489 goto ERROR;
490 break;
491 case ASSET_FILE_OWNER_MODE:
492 /* FALLS THROUGH */
493 case ASSET_FILE:
494 /* FALLS THROUGH */
495 case ASSET_SHELL:
496 /* FALLS THROUGH */
497 case ASSET_SAMPLE:
498 if (mport_bundle_read_next_entry(bundle, &entry) != MPORT_OK)
499 goto ERROR;
500
501 (void) snprintf(file, FILENAME_MAX, "%s%s/%s", mport->root, cwd, e->data);
502
503 if (e->type == ASSET_SAMPLE)
504 for (int ch = 0; ch < FILENAME_MAX; ch++) {
505 if (file[ch] == '\0')
506 break;
507 if (file[ch] == ' ' || file[ch] == '\t') {
508 file[ch] = '\0';
509 break;
510 }
511 }
512
513 if (entry == NULL) {
514 SET_ERROR(MPORT_ERR_FATAL, "Unexpected EOF with archive file");
515 goto ERROR;
516 }
517
518 archive_entry_set_pathname(entry, file);
519
520 if (mport_bundle_read_extract_next_file(bundle, entry) != MPORT_OK)
521 goto ERROR;
522
523 if (lstat(file, &sb)) {
524 SET_ERRORX(MPORT_ERR_FATAL, "Unable to stat file %s", file);
525 goto ERROR;
526 }
527
528 if (S_ISREG(sb.st_mode)) {
529 if (e->type == ASSET_FILE_OWNER_MODE) {
530 /* Test for owner and group settings, otherwise roll with our default. */
531 if (e->owner != NULL && e->group != NULL && e->owner[0] != '\0' &&
532 e->group[0] != '\0') {
533 #ifdef DEBUG
534 fprintf(stderr, "owner %s and group %s\n", e->owner, e->group);
535 #endif
536 if (chown(file, mport_get_uid(e->owner),
537 mport_get_gid(e->group)) == -1) {
538 SET_ERROR(MPORT_ERR_FATAL, "Unable to change owner");
539 goto ERROR;
540 }
541 } else if (e->owner != NULL && e->owner[0] != '\0') {
542 #ifdef DEBUG
543 fprintf(stderr, "owner %s\n", e->owner);
544 #endif
545 if (chown(file, mport_get_uid(e->owner), group) == -1) {
546 SET_ERROR(MPORT_ERR_FATAL, "Unable to change owner");
547 goto ERROR;
548 }
549 } else if (e->group != NULL && e->group[0] != '\0') {
550 #ifdef DEBUG
551 fprintf(stderr, "group %s\n", e->group);
552 #endif
553 if (chown(file, owner, mport_get_gid(e->group)) == -1) {
554 SET_ERROR(MPORT_ERR_FATAL, "Unable to change owner");
555 goto ERROR;
556 }
557 } else {
558 // use default.
559 if (chown(file, owner, group) == -1) {
560 SET_ERROR(MPORT_ERR_FATAL, "Unable to change owner");
561 goto ERROR;
562 }
563 }
564 } else {
565 /* Set the owner and group */
566 if (chown(file, owner, group) == -1) {
567 SET_ERRORX(MPORT_ERR_FATAL,
568 "Unable to set permissions on file %s", file);
569 goto ERROR;
570 }
571 }
572
573 /* Set the file permissions, assumes non NFSv4 */
574 if (mode != NULL) {
575 if (stat(file, &sb)) {
576 SET_ERRORX(MPORT_ERR_FATAL, "Unable to stat file %s", file);
577 goto ERROR;
578 }
579 if (e->type == ASSET_FILE_OWNER_MODE && e->mode != NULL) {
580 if ((set = setmode(e->mode)) == NULL) {
581 SET_ERROR(MPORT_ERR_FATAL, "Unable to set mode");
582 goto ERROR;
583 }
584 } else {
585 if ((set = setmode(mode)) == NULL) {
586 SET_ERROR(MPORT_ERR_FATAL, "Unable to set mode");
587 goto ERROR;
588 }
589 }
590 newmode = getmode(set, sb.st_mode);
591 free(set);
592 if (chmod(file, newmode)) {
593 SET_ERROR(MPORT_ERR_FATAL, "Unable to set file permissions");
594 goto ERROR;
595 }
596 }
597
598 /* shell registration */
599 if (e->type == ASSET_SHELL && mport_shell_register(file) != MPORT_OK) {
600 goto ERROR;
601 }
602
603 /* for sample files, if we don't have an existing file, make a new one */
604 if (e->type == ASSET_SAMPLE && create_sample_file(mport, cwd, e->data) != MPORT_OK) {
605 SET_ERRORX(MPORT_ERR_FATAL, "Unable to create sample file from %s",
606 file);
607 goto ERROR;
608 }
609 }
610
611 (mport->progress_step_cb)(++file_count, file_total, file);
612
613 break;
614 default:
615 /* do nothing */
616 break;
617 }
618
619 /* insert this asset into the master database */
620 __block int code = MPORT_OK;
621 __block const char *err;
622 __block char *filePtr = strdup(file);
623 __block char *cwdPtr = strdup(cwd);
624 dispatch_sync(mportSQLSerial, ^{
625 char dir[FILENAME_MAX];
626 if (sqlite3_bind_int(insert, 1, (int) e->type) != SQLITE_OK) {
627 code = MPORT_ERR_FATAL;
628 err = sqlite3_errmsg(mport->db);
629 return;
630 }
631 if (e->type == ASSET_FILE || e->type == ASSET_SAMPLE || e->type == ASSET_SHELL ||
632 e->type == ASSET_FILE_OWNER_MODE) {
633 /* don't put the root in the database! */
634 if (sqlite3_bind_text(insert, 2, filePtr + strlen(mport->root), -1, SQLITE_STATIC) !=
635 SQLITE_OK) {
636 code = MPORT_ERR_FATAL;
637 err = sqlite3_errmsg(mport->db);
638 return;
639 }
640
641 if (sqlite3_bind_text(insert, 3, e->checksum, -1, SQLITE_STATIC) != SQLITE_OK) {
642 code = MPORT_ERR_FATAL;
643 err = sqlite3_errmsg(mport->db);
644 return;
645 }
646
647 if (e->owner != NULL) {
648 if (sqlite3_bind_text(insert, 4, e->owner, -1, SQLITE_STATIC) != SQLITE_OK) {
649 code = MPORT_ERR_FATAL;
650 err = sqlite3_errmsg(mport->db);
651 return;
652 }
653 } else {
654 if (sqlite3_bind_null(insert, 4) != SQLITE_OK) {
655 code = MPORT_ERR_FATAL;
656 err = sqlite3_errmsg(mport->db);
657 return;
658 }
659 }
660
661 if (e->group != NULL) {
662 if (sqlite3_bind_text(insert, 5, e->group, -1, SQLITE_STATIC) != SQLITE_OK) {
663 code = MPORT_ERR_FATAL;
664 err = sqlite3_errmsg(mport->db);
665 return;
666 }
667 } else {
668 if (sqlite3_bind_null(insert, 5) != SQLITE_OK) {
669 code = MPORT_ERR_FATAL;
670 err = sqlite3_errmsg(mport->db);
671 return;
672 }
673 }
674
675 if (e->mode != NULL) {
676 if (sqlite3_bind_text(insert, 6, e->mode, -1, SQLITE_STATIC) != SQLITE_OK) {
677 code = MPORT_ERR_FATAL;
678 err = sqlite3_errmsg(mport->db);
679 return;
680 }
681 } else {
682 if (sqlite3_bind_null(insert, 6) != SQLITE_OK) {
683 code = MPORT_ERR_FATAL;
684 err = sqlite3_errmsg(mport->db);
685 return;
686 }
687 }
688 } else if (e->type == ASSET_DIR || e->type == ASSET_DIRRM || e->type == ASSET_DIRRMTRY) {
689 /* if data starts with /, it's most likely an absolute path. Don't prepend cwd */
690 if (e->data != NULL && e->data[0] == '/')
691 (void) snprintf(dir, FILENAME_MAX, "%s", e->data);
692 else
693 (void) snprintf(dir, FILENAME_MAX, "%s/%s", cwdPtr, e->data);
694
695 if (sqlite3_bind_text(insert, 2, dir, -1, SQLITE_STATIC) != SQLITE_OK) {
696 code = MPORT_ERR_FATAL;
697 err = sqlite3_errmsg(mport->db);
698 return;
699 }
700
701 if (sqlite3_bind_null(insert, 3) != SQLITE_OK) {
702 code = MPORT_ERR_FATAL;
703 err = sqlite3_errmsg(mport->db);
704 return;
705 }
706
707 if (sqlite3_bind_null(insert, 4) != SQLITE_OK) {
708 code = MPORT_ERR_FATAL;
709 err = sqlite3_errmsg(mport->db);
710 return;
711 }
712
713 if (sqlite3_bind_null(insert, 5) != SQLITE_OK) {
714 code = MPORT_ERR_FATAL;
715 err = sqlite3_errmsg(mport->db);
716 return;
717 }
718
719 if (sqlite3_bind_null(insert, 6) != SQLITE_OK) {
720 code = MPORT_ERR_FATAL;
721 err = sqlite3_errmsg(mport->db);
722 return;
723 }
724 } else {
725 if (sqlite3_bind_text(insert, 2, e->data, -1, SQLITE_STATIC) != SQLITE_OK) {
726 code = MPORT_ERR_FATAL;
727 err = sqlite3_errmsg(mport->db);
728 return;
729 }
730
731 if (sqlite3_bind_null(insert, 3) != SQLITE_OK) {
732 code = MPORT_ERR_FATAL;
733 err = sqlite3_errmsg(mport->db);
734 return;
735 }
736
737 if (sqlite3_bind_null(insert, 4) != SQLITE_OK) {
738 code = MPORT_ERR_FATAL;
739 err = sqlite3_errmsg(mport->db);
740 return;
741 }
742
743 if (sqlite3_bind_null(insert, 5) != SQLITE_OK) {
744 code = MPORT_ERR_FATAL;
745 err = sqlite3_errmsg(mport->db);
746 return;
747 }
748
749 if (sqlite3_bind_null(insert, 6) != SQLITE_OK) {
750 code = MPORT_ERR_FATAL;
751 err = sqlite3_errmsg(mport->db);
752 return;
753 }
754 }
755
756 if (sqlite3_step(insert) != SQLITE_DONE) {
757 code = MPORT_ERR_FATAL;
758 err = sqlite3_errmsg(mport->db);
759 return;
760 }
761
762 sqlite3_reset(insert);
763 });
764
765 free(filePtr);
766 free(cwdPtr);
767 if (code != MPORT_OK) {
768 SET_ERROR(code, err);
769 goto ERROR;
770 }
771 }
772
773 if (mport_db_do(mport->db, "COMMIT") != MPORT_OK) {
774 SET_ERROR(MPORT_ERR_FATAL, sqlite3_errmsg(mport->db));
775 goto ERROR;
776 }
777 sqlite3_finalize(insert);
778
779 mport_pkgmeta_logevent(mport, pkg, "Installed");
780
781 (mport->progress_free_cb)();
782 (void) mport_chdir(NULL, orig_cwd);
783 free(orig_cwd);
784 mport_assetlist_free(alist);
785 return (MPORT_OK);
786
787 ERROR:
788 sqlite3_finalize(insert);
789 (mport->progress_free_cb)();
790 free(orig_cwd);
791 mport_assetlist_free(alist);
792 RETURN_CURRENT_ERROR;
793 }
794
795
796 #define COPY_METAFILE(TYPE) (void)snprintf(from, FILENAME_MAX, "%s/%s/%s-%s/%s", bundle->tmpdir, MPORT_STUB_INFRA_DIR, pkg->name, pkg->version, TYPE); \
797 if (mport_file_exists(from)) { \
798 (void)snprintf(to, FILENAME_MAX, "%s%s/%s-%s/%s", mport->root, MPORT_INST_INFRA_DIR, pkg->name, pkg->version, TYPE); \
799 if (mport_mkdir(dirname(to)) != MPORT_OK) \
800 RETURN_CURRENT_ERROR; \
801 if (mport_copy_file(from, to) != MPORT_OK) \
802 RETURN_CURRENT_ERROR; \
803 }
804
805 static int
806 mark_complete(mportInstance *mport, mportPackageMeta *pkg)
807 {
808 if (mport_db_do(mport->db, "UPDATE packages SET status='clean' WHERE pkg=%Q", pkg->name) != MPORT_OK) {
809 SET_ERROR(MPORT_ERR_FATAL, "Unable to mark package clean");
810 RETURN_CURRENT_ERROR;
811 }
812
813 return MPORT_OK;
814 }
815
816
817 static int
818 do_post_install(mportInstance *mport, mportBundleRead *bundle, mportPackageMeta *pkg)
819 {
820 char to[FILENAME_MAX], from[FILENAME_MAX]; /* keep these for COPY_METAFILE */
821
822 COPY_METAFILE(MPORT_MTREE_FILE);
823 COPY_METAFILE(MPORT_INSTALL_FILE);
824 COPY_METAFILE(MPORT_DEINSTALL_FILE);
825 COPY_METAFILE(MPORT_MESSAGE_FILE);
826
827 if (run_postexec(mport, pkg) != MPORT_OK)
828 RETURN_CURRENT_ERROR;
829
830 if (display_pkg_msg(mport, bundle, pkg) != MPORT_OK)
831 RETURN_CURRENT_ERROR;
832
833 if (run_pkg_install(mport, bundle, pkg, "POST-INSTALL") != MPORT_OK)
834 RETURN_CURRENT_ERROR;
835
836 return mark_complete(mport, pkg);
837 }
838
839
840 static int
841 run_postexec(mportInstance *mport, mportPackageMeta *pkg)
842 {
843 mportAssetList *alist;
844 mportAssetListEntry *e = NULL;
845 char cwd[FILENAME_MAX];
846
847 /* Process @postexec steps */
848 if (mport_bundle_read_get_assetlist(mport, pkg, &alist, POSTINSTALL) != MPORT_OK)
849 goto ERROR;
850
851 (void) strlcpy(cwd, pkg->prefix, sizeof(cwd));
852
853 if (mport_chdir(mport, cwd) != MPORT_OK)
854 goto ERROR;
855
856 STAILQ_FOREACH(e, alist, next) {
857 char file[FILENAME_MAX];
858 if (e->data == NULL) {
859 snprintf(file, sizeof(file), "%s", mport->root);
860 } else if (e->data[0] == '/') {
861 snprintf(file, sizeof(file), "%s%s", mport->root, e->data);
862 } else {
863 snprintf(file, sizeof(file), "%s%s/%s", mport->root, pkg->prefix, e->data);
864 }
865
866 switch (e->type) {
867 case ASSET_CWD:
868 (void) strlcpy(cwd, e->data == NULL ? pkg->prefix : e->data, sizeof(cwd));
869 if (mport_chdir(mport, cwd) != MPORT_OK)
870 goto ERROR;
871 break;
872 case ASSET_POSTEXEC:
873 if (mport_run_asset_exec(mport, e->data, cwd, file) != MPORT_OK)
874 goto ERROR;
875 break;
876 default:
877 /* do nothing */
878 break;
879 }
880 }
881
882 mport_assetlist_free(alist);
883 mport_pkgmeta_logevent(mport, pkg, "postexec");
884
885 return MPORT_OK;
886
887 ERROR:
888 // TODO: asset list free
889 RETURN_CURRENT_ERROR;
890 }
891
892
893 static int
894 run_mtree(mportInstance *mport, mportBundleRead *bundle, mportPackageMeta *pkg)
895 {
896 char file[FILENAME_MAX];
897 int ret;
898
899 (void) snprintf(file, FILENAME_MAX, "%s/%s/%s-%s/%s", bundle->tmpdir, MPORT_STUB_INFRA_DIR, pkg->name,
900 pkg->version,
901 MPORT_MTREE_FILE);
902
903 if (mport_file_exists(file)) {
904 if ((ret = mport_xsystem(mport, "%s -U -f %s -d -e -p %s >/dev/null", MPORT_MTREE_BIN, file,
905 pkg->prefix)) != 0)
906 RETURN_ERRORX(MPORT_ERR_FATAL, "%s returned non-zero: %i", MPORT_MTREE_BIN, ret);
907 }
908
909 return MPORT_OK;
910 }
911
912
913 static int
914 run_pkg_install(mportInstance *mport, mportBundleRead *bundle, mportPackageMeta *pkg, const char *mode)
915 {
916 char file[FILENAME_MAX];
917 int ret;
918
919 (void) snprintf(file, FILENAME_MAX, "%s/%s/%s-%s/%s", bundle->tmpdir, MPORT_STUB_INFRA_DIR, pkg->name,
920 pkg->version,
921 MPORT_INSTALL_FILE);
922
923 if (mport_file_exists(file)) {
924 if (chmod(file, 755) != 0)
925 RETURN_ERRORX(MPORT_ERR_FATAL, "chmod(%s, 755): %s", file, strerror(errno));
926
927 if ((ret = mport_xsystem(mport, "PKG_PREFIX=%s %s %s %s", pkg->prefix, file, pkg->name, mode)) != 0)
928 RETURN_ERRORX(MPORT_ERR_FATAL, "%s %s returned non-zero: %i", MPORT_INSTALL_FILE, mode, ret);
929 }
930
931 return MPORT_OK;
932 }
933
934
935 static int
936 display_pkg_msg(mportInstance *mport, mportBundleRead *bundle, mportPackageMeta *pkg)
937 {
938 char filename[FILENAME_MAX];
939 char *buf;
940 struct stat st;
941 FILE *file;
942
943 (void) snprintf(filename, FILENAME_MAX, "%s/%s/%s-%s/%s", bundle->tmpdir, MPORT_STUB_INFRA_DIR, pkg->name,
944 pkg->version, MPORT_MESSAGE_FILE);
945
946 if (stat(filename, &st) == -1)
947 /* if we couldn't stat the file, we assume there isn't a pkg-msg */
948 return MPORT_OK;
949
950 if (st.st_size < 1)
951 return MPORT_OK;
952
953 if ((file = fopen(filename, "r")) == NULL)
954 RETURN_ERRORX(MPORT_ERR_FATAL, "Couldn't open %s: %s", filename, strerror(errno));
955
956 if ((buf = (char *) calloc((size_t) (st.st_size + 1), sizeof(char))) == NULL)
957 RETURN_ERROR(MPORT_ERR_FATAL, "Out of memory.");
958
959 if (fread(buf, 1, (size_t) st.st_size, file) != (size_t) st.st_size) {
960 free(buf);
961 RETURN_ERRORX(MPORT_ERR_FATAL, "Read error: %s", strerror(errno));
962 }
963
964 buf[st.st_size] = '\0';
965
966 if (buf[0] != '\0')
967 mport_call_msg_cb(mport, buf);
968
969 free(buf);
970
971 return MPORT_OK;
972 }

Properties

Name Value
svn:keywords MidnightBSD=%H