/* * GEM MINE - The ROCK Linux Package Manager * Copyright (C) 2002-2005 Clifford Wolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include "cdb.h" #include "bzlib.h" #include "libtar.h" #include "mine.h" #include "md5sum.h" #include "cksum.h" #include "memdb.h" int glob_check(char ** patterns, char * filename) { /*Parse through the patterns passed*/ int i=0; while(patterns[i]!=NULL) { /*For now, no options just default*/ if(! fnmatch(patterns[i], filename, 0)) return 1; i++; } return 0; } unsigned int get_filesize(char* root, char* filename) { struct stat statbuf; char buffer[1024]; snprintf(buffer, sizeof(buffer), "%s/%s", root, filename); if(lstat(buffer, &statbuf) == 0) return (unsigned int) statbuf.st_size; else return 0; } int gem_install(char * root, int mode_test, int mode_verbose, int mode_force, char * package, char ** patterns) { int gem2bunzip[2] = { -1, -1 }; int bunzip2tar[2] = { -1, -1 }; char *pname = NULL, *pbasename = NULL; int gem_fd = -1; struct cdb c; int pos, len; int rc; char *filename = 0; char buffer[1024]; char buffer2[1024]; char buffer3[1024]; // used in legacy package creation struct memdb_t old_flist_index; struct memdb_t old_cksum_index; struct memdb_t old_md5sum_index; TAR *t = NULL; BZFILE *b = NULL; if ( ! mode_force ) md5sum_initdb(root, mode_verbose); if ( (gem_fd = open(package, O_RDONLY)) < 0 ) goto error_errno; cdb_init(&c, gem_fd); rc = cdb_find(&c, "pkg_name", 8); if ( rc <= 0 ) goto error; pos = cdb_datapos(&c); len = cdb_datalen(&c); pname = malloc(len+1); pname[len] = 0; if (cdb_read(&c, pname, len, pos) == -1) goto error; if ((pbasename = strchr(pname, ':')) != NULL) { int baselen = (pbasename - pname); pbasename = malloc(baselen+1); snprintf (pbasename, baselen+1, pname); pbasename[baselen] = 0; } else pbasename = pname; pipe(gem2bunzip); pipe(bunzip2tar); /* * Extract tar.bz2 from GEM file */ if (!fork()) { close(gem2bunzip[0]); close(bunzip2tar[0]); close(bunzip2tar[1]); rc = cdb_find(&c, "pkg_tarbz2", 10); if ( rc <= 0 ) exit(1); pos = cdb_datapos(&c); len = cdb_datalen(&c); if (len <= 0) exit(1); while (len > 0) { if ( cdb_read(&c, buffer, len>512 ? 512 : len, pos) == -1 ) goto error; write(gem2bunzip[1], buffer, len > 512 ? 512 : len); pos += len > 512 ? 512 : len; len -= 512; } cdb_free(&c); close(gem_fd); exit(0); } /* * Bunzip tar.bz2 file */ if (!fork()) { close(gem2bunzip[1]); close(bunzip2tar[0]); b = BZ2_bzdopen(gem2bunzip[0], "r"); while ( (rc=BZ2_bzread(b, buffer, 512)) > 0 ) write(bunzip2tar[1], buffer, rc); BZ2_bzclose(b); exit(0); } /* * Install the tar file */ close(gem2bunzip[0]); close(gem2bunzip[1]); close(bunzip2tar[1]); if (tar_fdopen(&t, bunzip2tar[0], "pipe", NULL, O_RDONLY, 0, 0) == -1) goto error_errno; if ( mode_test && mode_verbose ) printf("-- %s --\n", pname); FILE *logfile = NULL; if ( ! mode_test ) { char postinst[1024]; snprintf(postinst, 1024, "%s/var/adm/postinstall/%s-install.XXXXXX", root, pname); if ( mkstemp(postinst) != -1 ) logfile = fopen(postinst, "w"); if ( mode_verbose ) { if ( logfile == NULL ) printf("Not writing postinstall log\n"); else printf("Writing postinstall log to %s\n", postinst); } } memdb_init(&old_flist_index); memdb_init(&old_cksum_index); memdb_init(&old_md5sum_index); // if there are old flist, cksums and md5sums, index them in memdbs snprintf(buffer, sizeof(buffer), "%s/var/adm/flists/%s", root, pname); if(access(buffer,R_OK) == 0) { FILE *old_flist = fopen(buffer, "r"); while( fgets(buffer, 1024, old_flist) != NULL) { strtok(buffer," "); char* file = strtok(NULL,"\n"); snprintf(buffer2, 1024, "%s:legacy: %s\n", pbasename, file); memdb_put(&old_flist_index, file, buffer2); } fclose(old_flist); snprintf(buffer, sizeof(buffer), "%s/var/adm/cksums/%s", root, pname); if(access(buffer,R_OK) == 0) { FILE *old_cksums = fopen(buffer, "r"); while( fgets(buffer, 1024, old_cksums) != NULL) { char* line = strdup(buffer); strtok(buffer," \n"); strtok(NULL, " "); char* file = strdup(strtok(NULL," \n")); memdb_put_noalloc(&old_cksum_index, file, line); } fclose(old_cksums); } snprintf(buffer, sizeof(buffer), "%s/var/adm/md5sums/%s", root, pname); if(access(buffer,R_OK) == 0) { FILE *old_md5sums = fopen(buffer, "r"); while( fgets(buffer, 1024, old_md5sums) != NULL) { char* line = strdup(buffer); strtok(buffer," \n"); char* file = strdup(strtok(NULL," \n")); memdb_put_noalloc(&old_md5sum_index, file, line); } fclose(old_md5sums); } } filename = 0; while (th_read(t) == 0) { filename = th_get_pathname(t); snprintf(buffer, sizeof(buffer), "%s/%s", root, filename); snprintf(buffer2, sizeof(buffer), "%s.GEMnew", buffer); snprintf(buffer3, sizeof(buffer), "%s.GEMold", buffer); if ( ! mode_test ) { unlink(buffer2); unlink(buffer3); } int result = 0; if (patterns && glob_check(patterns, filename)) { if ( mode_verbose ) { printf("Exclude glob " "file %s\n", filename); if (mode_test) th_print_long_ls(t); } if (TH_ISREG(t) && tar_skip_regfile(t) != 0) goto error_errno; } else if ( ! mode_force && (result = md5sum_check(root, filename)) ) { if ( ! mode_test || ! mode_verbose ) printf("%s: ", pname); printf("WARNING: Skip "); switch (result) { case MD5SUM_CHECK_DUPLICATE: printf("duplicate "); break; case MD5SUM_CHECK_MODIFIED: printf("modified "); break; case MD5SUM_CHECK_SHARED: printf("shared "); break; } printf("file %s", filename); if ( mode_test && mode_verbose ) { printf(":\n"); th_print_long_ls(t); } else printf(".\n"); if ( mode_test ) { if (TH_ISREG(t) && tar_skip_regfile(t) != 0) goto error_errno; } else { if (tar_extract_file(t, buffer2) != 0) goto error_errno; } } else if ( mode_test ) { if ( mode_verbose ) th_print_long_ls(t); else printf("%s: %s\n", pname, filename); if (TH_ISREG(t) && tar_skip_regfile(t) != 0) goto error_errno; } else { if ( mode_verbose ) printf("%s: %s\n", pname, filename); rename(buffer, buffer3); if (tar_extract_file(t, buffer) != 0) goto error_errno; unlink(buffer3); if ( logfile != NULL ) fprintf(logfile, "%s: %s\n", pname, filename); } } /* now, remove everyting in the new flist from old_flist_index, and add the remainders to a :legacy package! using the 'internal' memdb struct isn't nice, i know, but hey, this isn't C++, i can access whatever i like ;-) */ snprintf(buffer, sizeof(buffer), "%s/var/adm/flists/%s", root, pname); FILE *new_flist = fopen(buffer, "r"); while( fgets(buffer, 1024, new_flist) != NULL) { strtok(buffer," \n"); char* file = strtok(NULL,"\n"); memdb_remove(&old_flist_index, file); memdb_remove(&old_cksum_index, file); memdb_remove(&old_md5sum_index, file); } fclose(new_flist); if(old_flist_index.first != NULL) { unsigned long int legacy_size = 0; unsigned int legacy_count = 4; // cksum, flist, md5sum and packages file // initially create :legacy package snprintf(buffer, sizeof(buffer), "%s/var/adm/flists/%s:legacy", root, pbasename); FILE* legacy_flist = fopen(buffer, "a"); snprintf(buffer, sizeof(buffer), "%s/var/adm/cksums/%s:legacy", root, pbasename); FILE* legacy_cksums = fopen(buffer, "a"); snprintf(buffer, sizeof(buffer), "%s/var/adm/md5sums/%s:legacy", root, pbasename); FILE* legacy_md5sums = fopen(buffer, "a"); // now walk the remainders struct memdb_entry_t *old_entry; old_entry = old_flist_index.first; while(old_entry != NULL) { snprintf(buffer, sizeof(buffer), "%s/%s", root, old_entry->key); struct stat statbuf; if (stat (buffer, &statbuf) != 0) { /* Ignore */ } fprintf(legacy_flist, "%s", old_entry->value); legacy_size += get_filesize(root,old_entry->key); if (! S_ISDIR(statbuf.st_mode)) { fprintf(legacy_cksums, "%s", memdb_get(&old_cksum_index,old_entry->key)); fprintf(legacy_md5sums, "%s", memdb_get(&old_md5sum_index,old_entry->key)); } legacy_count++; old_entry = old_entry->next; } // finish up :legacy package snprintf(buffer, sizeof(buffer), "%s:legacy: var/adm/cksums/%s:legacy\n", pbasename, pbasename); fprintf(legacy_flist, buffer); snprintf(buffer, sizeof(buffer), "%s:legacy: var/adm/flists/%s:legacy\n", pbasename, pbasename); fprintf(legacy_flist, buffer); snprintf(buffer, sizeof(buffer), "%s:legacy: var/adm/md5sums/%s:legacy\n", pbasename, pbasename); fprintf(legacy_flist, buffer); snprintf(buffer, sizeof(buffer), "%s:legacy: var/adm/packages/%s:legacy\n", pbasename, pbasename); fprintf(legacy_flist, buffer); fclose(legacy_flist); snprintf(buffer, sizeof(buffer), "var/adm/flists/%s:legacy", pbasename); legacy_size += get_filesize(root,buffer); snprintf(buffer, sizeof(buffer), "%s/var/adm/packages/%s:legacy", root, pbasename); FILE *legacy_packages = fopen(buffer, "w"); snprintf(buffer, sizeof(buffer), "%s/var/adm/packages/%s", root, pname); FILE *packages = fopen(buffer, "r"); snprintf(buffer, sizeof(buffer), "Package Name and Version: %s:legacy 0000 0\n", pbasename); fputs(buffer, legacy_packages); double size = legacy_size; size = size / 1048576; if(size < 0.01) size = 0.01; snprintf(buffer, sizeof(buffer), "Package Size: %.2f MB, %u files\n", size, legacy_count); fputs(buffer, legacy_packages); fgets(buffer, 1024, packages); fgets(buffer, 1024, packages); while (fgets(buffer, 1024, packages)) { if (fputs(buffer, legacy_packages) == EOF) goto error_errno; } fclose(packages); fclose(legacy_packages); snprintf(buffer2, sizeof(buffer2), "var/adm/flists/%s:legacy", pbasename); snprintf(buffer, sizeof(buffer), "%s %s\n", md5sum_create(root, buffer2), buffer2); fprintf(legacy_md5sums, buffer); snprintf(buffer2, sizeof(buffer2), "var/adm/packages/%s:legacy", pbasename); snprintf(buffer, sizeof(buffer), "%s %s\n", md5sum_create(root, buffer2), buffer2); fprintf(legacy_md5sums, buffer); snprintf(buffer2, sizeof(buffer2), "var/adm/md5sums/%s:legacy", pbasename); snprintf(buffer, sizeof(buffer), "X %s\n", buffer2); fprintf(legacy_md5sums, buffer); snprintf(buffer2, sizeof(buffer2), "var/adm/cksums/%s:legacy", pbasename); snprintf(buffer, sizeof(buffer), "X %s\n", buffer2); fprintf(legacy_md5sums, buffer); fclose(legacy_md5sums); snprintf(buffer2, sizeof(buffer2), "%s/var/adm/flists/%s:legacy", root, pbasename); cksum(buffer2, buffer); snprintf(buffer2, sizeof(buffer2), "var/adm/flists/%s:legacy", pbasename); snprintf(buffer3, sizeof(buffer3), "%s %s\n", buffer, buffer2); fprintf(legacy_cksums, buffer3); snprintf(buffer2, sizeof(buffer2), "%s/var/adm/packages/%s:legacy", root, pbasename); cksum(buffer2, buffer); snprintf(buffer2, sizeof(buffer2), "var/adm/packages/%s:legacy", pbasename); snprintf(buffer3, sizeof(buffer3), "%s %s\n", buffer, buffer2); fprintf(legacy_cksums, buffer3); snprintf(buffer2, sizeof(buffer2), "var/adm/md5sums/%s:legacy", pbasename); snprintf(buffer, sizeof(buffer), "X %u %s\n", get_filesize(root, buffer2), buffer2); fprintf(legacy_cksums, buffer); fclose(legacy_cksums); } memdb_free(&old_flist_index); memdb_free(&old_cksum_index); memdb_free(&old_md5sum_index); tar_close(t); close(bunzip2tar[0]); cdb_free(&c); close(gem_fd); if ( logfile != NULL ) fclose(logfile); if (pname != pbasename) free(pbasename); free(pname); return 0; error: errno = 0; error_errno: fprintf(stderr, "While installing GEM file %s%s%s%s: %s\n", package, filename?" (":"", filename?filename:"", filename?")":"", errno ? strerror(errno) : "Unknown error"); if ( t != NULL) tar_close(t); if ( gem_fd != -1 ) { cdb_free(&c); close(gem_fd); } if ( gem2bunzip[0] != -1 ) close(gem2bunzip[0]); if ( gem2bunzip[1] != -1 ) close(gem2bunzip[1]); if ( bunzip2tar[0] != -1 ) close(bunzip2tar[0]); if ( bunzip2tar[1] != -1 ) close(bunzip2tar[1]); return 1; }