// // "$Id: uninst2.cxx 834 2010-12-30 00:08:36Z mike $" // // ESP Software Removal Wizard main entry for the ESP Package Manager (EPM). // // Copyright 1999-2010 by Easy Software Products. // // 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, 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. // // Contents: // // main() - Main entry for software wizard... // list_cb() - Handle selections in the software list. // load_image() - Load the setup image file (setup.gif/xpm)... // load_readme() - Load the readme file... // log_cb() - Add one or more lines of text to the removal log. // next_cb() - Show software selections or remove software. // remove_dist() - Remove a distribution... // show_installed() - Show the installed software products. // update_size() - Update the total +/- sizes of the installations. // #define _DEFINE_GLOBALS_ #include "uninst.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_PARAM_H # include #endif // HAVE_SYS_PARAM_H #ifdef HAVE_SYS_MOUNT_H # include #endif // HAVE_SYS_MOUNT_H #ifdef HAVE_SYS_STATFS_H # include #endif // HAVE_SYS_STATFS_H #ifdef HAVE_SYS_VFS_H # include #endif // HAVE_SYS_VFS_H #ifdef __osf__ // No prototype for statfs under Tru64... extern "C" { extern int statfs(const char *, struct statfs *); } #endif // __osf__ #ifdef __APPLE__ # include # include AuthorizationRef SetupAuthorizationRef; #endif // __APPLE__ // // Panes... // #define PANE_WELCOME 0 #define PANE_SELECT 1 #define PANE_CONFIRM 2 #define PANE_REMOVE 3 // // Local functions... // void load_image(void); void load_readme(void); void log_cb(int fd, int *fdptr); int remove_dist(const gui_dist_t *dist); void show_installed(void); void update_sizes(void); // // 'main()' - Main entry for software wizard... // int // O - Exit status main(int argc, // I - Number of command-line arguments char *argv[]) // I - Command-line arguments { Fl_Window *w; // Main window... // Use GTK+ scheme for all operating systems... Fl::background(230, 230, 230); Fl::scheme("gtk+"); #ifdef __APPLE__ // OSX passes an extra command-line option when run from the Finder. // If the first command-line argument is "-psn..." then skip it and use the full path // to the executable to figure out the distribution directory... if (argc > 1) { if (strncmp(argv[1], "-psn", 4) == 0) { char *ptr; // Pointer into basedir static char basedir[1024]; // Base directory (static so it can be used below) strlcpy(basedir, argv[0], sizeof(basedir)); if ((ptr = strrchr(basedir, '/')) != NULL) *ptr = '\0'; if ((ptr = strrchr(basedir, '/')) != NULL && !strcasecmp(ptr, "/MacOS")) { // Got the base directory, now add "Resources" to it... *ptr = '\0'; strlcat(basedir, "/Resources", sizeof(basedir)); chdir(basedir); } } } #endif // __APPLE__ w = make_window(); Pane[PANE_WELCOME]->show(); PrevButton->deactivate(); NextButton->deactivate(); gui_get_installed(); show_installed(); load_image(); load_readme(); w->show(); while (!w->visible()) Fl::wait(); #ifdef __APPLE__ OSStatus status; status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &SetupAuthorizationRef); if (status != errAuthorizationSuccess) { fl_alert("You must have administrative priviledges to remove this software!"); return (1); } AuthorizationItem items = { kAuthorizationRightExecute, 0, NULL, 0 }; AuthorizationRights rights = { 1, &items }; status = AuthorizationCopyRights(SetupAuthorizationRef, &rights, NULL, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights, NULL); if (status != errAuthorizationSuccess) { fl_alert("You must have administrative priviledges to remove this software!"); return (1); } #else if (getuid() != 0) { fl_alert("You must be logged in as root to run uninstall!"); return (1); } #endif // __APPLE__ NextButton->activate(); Fl::run(); #ifdef __APPLE__ AuthorizationFree(SetupAuthorizationRef, kAuthorizationFlagDefaults); #endif // __APPLE__ return (0); } // // 'list_cb()' - Handle selections in the software list. // void list_cb(Fl_Check_Browser *, void *) { int i, j, k; gui_dist_t *dist, *dist2; gui_depend_t *depend; if (SoftwareList->nchecked() == 0) { update_sizes(); NextButton->deactivate(); return; } for (i = 0, dist = Installed; i < NumInstalled; i ++, dist ++) if (SoftwareList->checked(i + 1)) { // Check for required/incompatible products... for (j = 0, depend = dist->depends; j < dist->num_depends; j ++, depend ++) switch (depend->type) { case DEPEND_REQUIRES : if ((dist2 = gui_find_dist(depend->product, NumInstalled, Installed)) != NULL) { // Software is in the list, is it selected? k = dist2 - Installed; if (SoftwareList->checked(k + 1)) continue; // Nope, select it unless we're unchecked another selection... if (SoftwareList->value() != (k + 1)) SoftwareList->checked(k + 1, 1); else { SoftwareList->checked(i + 1, 0); break; } } else if ((dist2 = gui_find_dist(depend->product, NumInstalled, Installed)) == NULL) { // Required but not installed or available! fl_alert("%s requires %s to be installed, but it is not available " "for installation.", dist->name, depend->product); SoftwareList->checked(i + 1, 0); break; } break; case DEPEND_INCOMPAT : if ((dist2 = gui_find_dist(depend->product, NumInstalled, Installed)) != NULL) { // Already installed! fl_alert("%s is incompatible with %s. Please remove it before " "installing this software.", dist->name, dist2->name); SoftwareList->checked(i + 1, 0); break; } else if ((dist2 = gui_find_dist(depend->product, NumInstalled, Installed)) != NULL) { // Software is in the list, is it selected? k = dist2 - Installed; // Software is in the list, is it selected? if (!SoftwareList->checked(k + 1)) continue; // Yes, tell the user... fl_alert("%s is incompatible with %s. Please deselect it before " "installing this software.", dist->name, dist2->name); SoftwareList->checked(i + 1, 0); break; } default : break; } } update_sizes(); if (SoftwareList->nchecked()) NextButton->activate(); else NextButton->deactivate(); } // // 'load_image()' - Load the setup image file (setup.gif/xpm)... // void load_image(void) { Fl_Image *img; // New image if (!access("setup.xpm", 0)) img = new Fl_XPM_Image("setup.xpm"); else if (!access("setup.gif", 0)) img = new Fl_GIF_Image("setup.gif"); else img = NULL; if (img) WelcomeImage->image(img); } // // 'load_readme()' - Load the readme file... // void load_readme(void) { ReadmeFile->textfont(FL_HELVETICA); ReadmeFile->textsize(14); if (access("uninst.readme", 0)) { int i; // Looping var gui_dist_t *dist; // Current distribution char *buffer, // Text buffer *ptr; // Pointer into buffer buffer = new char[1024 + NumInstalled * 400]; strcpy(buffer, "This program allows you to remove the following " "software:

\n" "
    \n"); ptr = buffer + strlen(buffer); for (i = NumInstalled, dist = Installed; i > 0; i --, dist ++) { sprintf(ptr, "
  • %s, %s\n", dist->name, dist->version); ptr += strlen(ptr); } strcpy(ptr, "
"); ReadmeFile->value(buffer); delete[] buffer; } else gui_load_file(ReadmeFile, "uninst.readme"); } // // 'log_cb()' - Add one or more lines of text to the removal log. // void log_cb(int fd, // I - Pipe to read from int *fdptr) // O - Pipe to read from { int bytes; // Bytes read/to read char *bufptr; // Pointer into buffer static int bufused = 0; // Number of bytes used static char buffer[8193]; // Buffer bytes = 8192 - bufused; if ((bytes = read(fd, buffer + bufused, bytes)) <= 0) { // End of file; zero the FD to tell the remove_dist() function to // stop... Fl::remove_fd(fd); close(fd); *fdptr = 0; if (bufused > 0) { // Add remaining text... buffer[bufused] = '\0'; RemoveLog->add(buffer); bufused = 0; } } else { // Add bytes to the buffer, then add lines as needed... bufused += bytes; buffer[bufused] = '\0'; while ((bufptr = strchr(buffer, '\n')) != NULL) { *bufptr++ = '\0'; RemoveLog->add(buffer); strcpy(buffer, bufptr); bufused -= bufptr - buffer; } } RemoveLog->bottomline(RemoveLog->size()); } // // 'next_cb()' - Show software selections or remove software. // void next_cb(Fl_Button *, void *) { int i; // Looping var int progress; // Progress so far... int error; // Errors? static char message[1024]; // Progress message... static int removing = 0; // Removing software? Wizard->next(); PrevButton->deactivate(); if (Wizard->value() == Pane[PANE_CONFIRM]) { ConfirmList->clear(); PrevButton->activate(); for (i = 0; i < NumInstalled; i ++) if (SoftwareList->checked(i + 1)) ConfirmList->add(SoftwareList->text(i + 1)); } if (Wizard->value() == Pane[PANE_REMOVE] && !removing) { removing = 1; NextButton->deactivate(); CancelButton->deactivate(); CancelButton->label("Close"); for (i = 0, progress = 0, error = 0; i < NumInstalled; i ++) if (SoftwareList->checked(i + 1)) { sprintf(message, "Removing %s v%s...", Installed[i].name, Installed[i].version); RemovePercent->value(100.0 * progress / SoftwareList->nchecked()); RemovePercent->label(message); Pane[PANE_REMOVE]->redraw(); if ((error = remove_dist(Installed + i)) != 0) break; progress ++; } RemovePercent->value(100.0); if (error) RemovePercent->label("Removal Failed!"); else RemovePercent->label("Removal Complete"); Pane[PANE_REMOVE]->redraw(); CancelButton->activate(); fl_beep(); removing = 0; } else if (Wizard->value() == Pane[PANE_SELECT] && SoftwareList->nchecked() == 0) NextButton->deactivate(); } // // 'remove_dist()' - Remove a distribution... // int // O - Remove status remove_dist(const gui_dist_t *dist) // I - Distribution to remove { char command[1024]; // Command string int fds[2]; // Pipe FDs int status; // Exit status #ifndef __APPLE__ int pid; // Process ID #endif // !__APPLE__ snprintf(command, sizeof(command), "**** %s ****", dist->name); RemoveLog->add(command); if (dist->type == PACKAGE_PORTABLE) snprintf(command, sizeof(command), EPM_SOFTWARE "/%s.remove", dist->product); #ifdef __APPLE__ // Run the remove script using Apple's authorization API... FILE *fp = NULL; char *args[2] = { (char *)"now", NULL }; OSStatus astatus; astatus = AuthorizationExecuteWithPrivileges(SetupAuthorizationRef, command, kAuthorizationFlagDefaults, args, &fp); if (astatus != errAuthorizationSuccess) { RemoveLog->add("Failed to execute remove script!"); return (1); } fds[0] = fileno(fp); #else // Fork the command and redirect errors and info to stdout... pipe(fds); if ((pid = fork()) == 0) { // Child comes here; start by redirecting stdout and stderr... close(1); close(2); dup(fds[1]); dup(fds[1]); // Close the original pipes... close(fds[0]); close(fds[1]); // Execute the command; if an error occurs, return it... if (dist->type == PACKAGE_PORTABLE) execl(command, command, "now", (char *)0); else execlp("rpm", "rpm", "-e", "--nodeps", dist->product, (char *)0); exit(errno); } else if (pid < 0) { // Unable to fork! sprintf(command, "Unable to remove %s:", dist->name); RemoveLog->add(command); sprintf(command, "\t%s", strerror(errno)); RemoveLog->add(command); close(fds[0]); close(fds[1]); return (1); } // Close the output pipe (used by the child)... close(fds[1]); #endif // __APPLE__ // Listen for data on the input pipe... Fl::add_fd(fds[0], (void (*)(int, void *))log_cb, fds); // Show the user that we're busy... UninstallWindow->cursor(FL_CURSOR_WAIT); // Loop until the child is done... while (fds[0]) // log_cb() will close and zero fds[0]... { // Wait for events... Fl::wait(); #ifndef __APPLE__ // Check to see if the child went away... if (waitpid(0, &status, WNOHANG) == pid) break; #endif // !__APPLE__ } #ifdef __APPLE__ fclose(fp); #endif // __APPLE__ if (fds[0]) { // Close the pipe - have all the data from the child... Fl::remove_fd(fds[0]); close(fds[0]); } else { // Get the child's exit status... wait(&status); } // Show the user that we're ready... UninstallWindow->cursor(FL_CURSOR_DEFAULT); // Return... return (status); } // // 'show_installed()' - Show the installed software products. // void show_installed() { int i; // Looping var gui_dist_t *temp; // Pointer to current distribution char line[1024]; // Product name and version... if (NumInstalled == 0) { fl_alert("No software found to remove!"); exit(1); } for (i = 0, temp = Installed; i < NumInstalled; i ++, temp ++) { sprintf(line, "%s v%s", temp->name, temp->version); SoftwareList->add(line, 0); } update_sizes(); } // // 'update_size()' - Update the total +/- sizes of the installations. // void update_sizes(void) { int i; // Looping var gui_dist_t *dist, // Distribution *installed; // Installed distribution int rootsize, // Total root size difference in kbytes usrsize; // Total /usr size difference in kbytes struct statfs rootpart, // Available root partition usrpart; // Available /usr partition int rootfree, // Free space on root partition usrfree; // Free space on /usr partition static char sizelabel[1024];// Label for selected sizes... // Get the sizes for the selected products... for (i = 0, dist = Installed, rootsize = 0, usrsize = 0; i < NumInstalled; i ++, dist ++) if (SoftwareList->checked(i + 1)) { rootsize += dist->rootsize; usrsize += dist->usrsize; if ((installed = gui_find_dist(dist->product, NumInstalled, Installed)) != NULL) { rootsize -= installed->rootsize; usrsize -= installed->usrsize; } } // Get the sizes of the root and /usr partition... #if defined(__sgi) || defined(__svr4__) || defined(__SVR4) || defined(M_XENIX) if (statfs("/", &rootpart, sizeof(rootpart), 0)) #else if (statfs("/", &rootpart)) #endif // __sgi || __svr4__ || __SVR4 || M_XENIX rootfree = 1024; else rootfree = (int)((double)rootpart.f_bfree * (double)rootpart.f_bsize / 1024.0 / 1024.0 + 0.5); #if defined(__sgi) || defined(__svr4__) || defined(__SVR4) || defined(M_XENIX) if (statfs("/usr", &usrpart, sizeof(usrpart), 0)) #else if (statfs("/usr", &usrpart)) #endif // __sgi || __svr4__ || __SVR4 || M_XENIX usrfree = 1024; else usrfree = (int)((double)usrpart.f_bfree * (double)usrpart.f_bsize / 1024.0 / 1024.0 + 0.5); // Display the results to the user... if (rootfree == usrfree) { rootsize += usrsize; if (rootsize >= 1024) snprintf(sizelabel, sizeof(sizelabel), "%+.1fm required, %dm available.", rootsize / 1024.0, rootfree); else snprintf(sizelabel, sizeof(sizelabel), "%+dk required, %dm available.", rootsize, rootfree); } else if (rootsize >= 1024 && usrsize >= 1024) snprintf(sizelabel, sizeof(sizelabel), "%+.1fm required on /, %dm available,\n" "%+.1fm required on /usr, %dm available.", rootsize / 1024.0, rootfree, usrsize / 1024.0, usrfree); else if (rootsize >= 1024) snprintf(sizelabel, sizeof(sizelabel), "%+.1fm required on /, %dm available,\n" "%+dk required on /usr, %dm available.", rootsize / 1024.0, rootfree, usrsize, usrfree); else if (usrsize >= 1024) snprintf(sizelabel, sizeof(sizelabel), "%+dk required on /, %dm available,\n" "%+.1fm required on /usr, %dm available.", rootsize, rootfree, usrsize / 1024.0, usrfree); else snprintf(sizelabel, sizeof(sizelabel), "%+dk required on /, %dm available,\n" "%+dk required on /usr, %dm available.", rootsize, rootfree, usrsize, usrfree); SoftwareSize->label(sizelabel); SoftwareSize->redraw(); } // // End of "$Id: uninst2.cxx 834 2010-12-30 00:08:36Z mike $". //