#include "cdk.h" #ifdef HAVE_XCURSES char *XCursesProgramName="vinstall"; #endif /* * Written by: Mike Glover * Purpose: * This is a fairly basic install interface. */ /* Declare global types and prototypes. */ char *FPUsage = "-f filename [-s source directory] [-d destination directory] [-t title] [-o Output file] [-q]"; typedef enum {vCanNotOpenSource, vCanNotOpenDest, vOK } ECopyFile; ECopyFile copyFile (CDKSCREEN *cdkScreen, char *src, char *dest); int verifyDirectory (CDKSCREEN *screen, char *directory, int quiet); int main(int argc, char **argv) { /* Declare variables. */ WINDOW *cursesWin = (WINDOW *)NULL; CDKSCREEN *cdkScreen = (CDKSCREEN *)NULL; CDKSWINDOW *installOutput = (CDKSWINDOW *)NULL; CDKENTRY *sourceEntry = (CDKENTRY *)NULL; CDKENTRY *destEntry = (CDKENTRY *)NULL; CDKLABEL *titleWin = (CDKLABEL *)NULL; CDKHISTOGRAM *progressBar = (CDKHISTOGRAM *)NULL; char *sourcePath = (char *)NULL; char *destPath = (char *)NULL; char *sourceDir = (char *)NULL; char *destDir = (char *)NULL; char *filename = (char *)NULL; char *title = (char *)NULL; char *output = (char *)NULL; int quiet = FALSE; int errors = 0; int sWindowHeight = 0; char *titleMessage[10], *fileList[2000], *mesg[20]; char oldPath[512], newPath[512], temp[2000]; char *files[10]; int count, chunks, ret, x, y; /* Parse up the command line. */ while (1) { ret = getopt (argc, argv, "d:s:f:t:o:q"); if (ret == -1) { break; } switch (ret) { case 's' : sourcePath = strdup (optarg); break; case 'd' : destPath = strdup (optarg); break; case 'f' : filename = strdup (optarg); break; case 't' : title = strdup (optarg); break; case 'o' : output = strdup (optarg); break; case 'q' : quiet = TRUE; break; } } /* Make sure have everything we need. */ if (filename == (char *)NULL) { fprintf (stderr, "Usage: %s %s\n", argv[0], FPUsage); exit (-1); } /* Open the file list file and read it in. */ count = readFile (filename, fileList, 2000); if (count == 0) { fprintf (stderr, "%s: Input filename <%s> is empty.\n", argv[0], filename); exit (-1); } /* * Cycle through what was given to us and save it. */ for (x=0; x < count; x++) { /* Strip white space from the line. */ stripWhiteSpace (vBOTH, fileList[x]); } /* Set up CDK. */ cursesWin = initscr(); cdkScreen = initCDKScreen (cursesWin); /* Start color. */ initCDKColor(); /* Create the title label. */ titleMessage[0] = "<#HL(30)>"; if (title == (char *)NULL) { sprintf (temp, "CDK Installer"); } else { sprintf (temp, "%s", title); } titleMessage[1] = copyChar (temp); titleMessage[2] = "<#HL(30)>"; titleWin = newCDKLabel (cdkScreen, CENTER, TOP, titleMessage, 3, FALSE, FALSE); freeChar (titleMessage[1]); /* Allow them to change the install directory. */ if (sourcePath == (char *)NULL) { sourceEntry = newCDKEntry (cdkScreen, CENTER, 8, NULL, "Source Directory :", A_NORMAL, '.', vMIXED, 40, 0, 256, TRUE, FALSE); } if (destPath == (char *)NULL) { destEntry = newCDKEntry (cdkScreen, CENTER, 11, NULL, "Destination Directory:", A_NORMAL, '.', vMIXED, 40, 0, 256, TRUE, FALSE); } /* Get the source install path. */ if (sourceEntry != (CDKENTRY *)NULL) { drawCDKScreen (cdkScreen); sourceDir = copyChar (activateCDKEntry (sourceEntry, NULL)); } else { sourceDir = copyChar (sourcePath); } /* Get the destination install path. */ if (destEntry != (CDKENTRY *)NULL) { drawCDKScreen (cdkScreen); destDir = copyChar (activateCDKEntry (destEntry, NULL)); } else { destDir = copyChar (destPath); } /* Destroy the path entry fields. */ if (sourceEntry != (CDKENTRY *)NULL) { destroyCDKEntry (sourceEntry); } if (destEntry != (CDKENTRY *)NULL) { destroyCDKEntry (destEntry); } /* * Verify that the source directory is valid. */ if (verifyDirectory (cdkScreen, sourceDir, quiet) != 0) { /* Clean up and leave. */ freeChar (destDir); freeChar (sourceDir); destroyCDKLabel (titleWin); destroyCDKScreen (cdkScreen); endCDK(); /* Clean up the file list information. */ for (x=0; x < count; x++) { freeChar (fileList[x]); } exit (-1); } /* * Verify that the source directory is valid. */ if (verifyDirectory (cdkScreen, destDir, quiet) != 0) { /* Clean up and leave. */ freeChar (destDir); freeChar (sourceDir); destroyCDKLabel (titleWin); destroyCDKScreen (cdkScreen); endCDK(); /* Clean up the file list information */ for (x=0; x < count; x++) { freeChar (fileList[x]); } exit (-2); } /* Create the histogram. */ progressBar = newCDKHistogram (cdkScreen, CENTER, 5, 3, 0, HORIZONTAL, "Install Progress", TRUE, FALSE); /* Set the top left/right characters of the histogram.*/ setCDKHistogramLLChar (progressBar, ACS_LTEE); setCDKHistogramLRChar (progressBar, ACS_RTEE); /* Set the initial value of the histogram. */ setCDKHistogram (progressBar, vPERCENT, TOP, A_BOLD, 1, count, 1, COLOR_PAIR (24) | A_REVERSE | ' ', TRUE); /* Determine the height of the scrolling window. */ if (LINES >= 16) { sWindowHeight = LINES - 13; } else { sWindowHeight = 3; } /* Create the scrolling window. */ installOutput = newCDKSwindow (cdkScreen, CENTER, BOTTOM, sWindowHeight, 0, "Install Results", 2000, TRUE, FALSE); /* Set the top left/right characters of the scrolling window.*/ setCDKSwindowULChar (installOutput, ACS_LTEE); setCDKSwindowURChar (installOutput, ACS_RTEE); /* Draw the screen. */ drawCDKScreen (cdkScreen); /* Start copying the files. */ for (x=0; x < count; x++) { /* * If the 'file' list file has 2 columns, the first is * the source filename, the second being the destination * filename. */ chunks = splitString (fileList[x], files, ' '); if (chunks == 2) { /* Create the correct paths. */ sprintf (oldPath, "%s/%s", sourceDir, files[0]); sprintf (newPath, "%s/%s", destDir, files[1]); } else { /* Create the correct paths. */ sprintf (oldPath, "%s/%s", sourceDir, fileList[x]); sprintf (newPath, "%s/%s", destDir, fileList[x]); } /* Clean up the memory. */ for (y=0; y < chunks; y++) { freeChar (files[y]); } /* Copy the file from the source to the destination. */ ret = copyFile (cdkScreen, oldPath, newPath); if (ret == vCanNotOpenSource) { sprintf (temp, "Error: Can not open source file %s", oldPath); errors++; } else if (ret == vCanNotOpenDest) { sprintf (temp, "Error: Can not open destination file %s", newPath); errors++; } else { sprintf (temp, "%s -> %s", oldPath, newPath); } /* Add the message to the scrolling window. */ addCDKSwindow (installOutput, temp, BOTTOM); drawCDKSwindow (installOutput, installOutput->box); /* Update the histogram. */ setCDKHistogram (progressBar, vPERCENT, TOP, A_BOLD, 1, count, x+1, COLOR_PAIR (24) | A_REVERSE | ' ', TRUE); /* Update the screen. */ drawCDKHistogram (progressBar, TRUE); } /* * If there were errors, inform the user and allow them to look at the * errors in the scrolling window. */ if (errors != 0) { /* Create the information for the dialog box. */ char *buttons[] = {"Look At Errors Now", "Save Output To A File", "Ignore Errors"}; mesg[0] = "There were errors in the installation."; mesg[1] = "If you want, you may scroll through the"; mesg[2] = "messages of the scrolling window to see"; mesg[3] = "what the errors were. If you want to save"; mesg[4] = "the output of the window you may press s"; mesg[5] = "while in the window, or you may save the output"; mesg[6] = "of the install now and look at the install"; mesg[7] = "history at a later date."; /* Popup the dialog box. */ ret = popupDialog (cdkScreen, mesg, 8, buttons, 3); if (ret == 0) { activateCDKSwindow (installOutput, NULL); } else if (ret == 1) { injectCDKSwindow (installOutput, 's'); } } else { /* * If they specified the name of an output file, then save the * results of the installation to that file. */ if (output != (char *)NULL) { dumpCDKSwindow (installOutput, output); } else { /* Ask them if they want to save the output of the scrolling window. */ if (quiet == FALSE) { char *buttons[] = {"No", "Yes"}; mesg[0] = "Do you want to save the output of the"; mesg[1] = "scrolling window to a file?"; if (popupDialog (cdkScreen, mesg, 2, buttons, 2) == 1) { injectCDKSwindow (installOutput, 's'); } } } } /* Clean up. */ destroyCDKLabel (titleWin); destroyCDKHistogram (progressBar); destroyCDKSwindow (installOutput); destroyCDKScreen (cdkScreen); endCDK(); /* Clean up the file list. */ for (x=0; x < count; x++) { freeChar (fileList[x]); } exit (0); } /* * This copies a file from one place to another. (tried rename * library call, but it is equivalent to mv) */ ECopyFile copyFile (CDKSCREEN *cdkScreen, char *src, char *dest) { char command[2000]; FILE *fd; /* Make sure we can open the source file. */ if ((fd = fopen (src, "r")) == NULL) { return vCanNotOpenSource; } fclose (fd); /* * Remove the destination file first, just in case it already exists. * This allows us to check if we can write to the desintation file. */ sprintf (command, "rm -f %s", dest); system (command); /* Try to open the destination. */ if ((fd = fopen (dest, "w")) == NULL) { return vCanNotOpenDest; } fclose (fd); /* * Copy the file. There has to be a better way to do this. I * tried rename and link but they both have the same limitation * as the 'mv' command that you can not move across partitions. * Quite limiting in an install binary. */ sprintf (command, "rm -f %s; cp %s %s; chmod 444 %s", dest, src, dest, dest); system (command); return vOK; } /* * This makes sure that the directory given exists. If it * doesn't then it will make it. * THINK */ int verifyDirectory (CDKSCREEN *cdkScreen, char *directory, int quiet) { char *buttons[] = {"Yes", "No"}; int status = 0; mode_t dirMode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH; struct stat fileStat; char *mesg[10]; char *error[10]; char temp[200]; /* Stat the directory. */ if (lstat (directory, &fileStat) != 0) { /* The directory does not exist. */ if (errno == ENOENT) { /* Create the question. */ mesg[0] = "The directory "; sprintf (temp, "%s", directory); mesg[1] = copyChar (temp); mesg[2] = "Does not exist. Do you want to"; mesg[3] = "create it?"; /* Ask them if they want to create the directory. */ if (popupDialog (cdkScreen, mesg, 4, buttons, 2) == 0) { /* Create the directory. */ if (mkdir (directory, dirMode) != 0) { /* Create the error message. */ error[0] = "Could not create the directory"; sprintf (temp, "%s", directory); error[1] = copyChar (temp); #ifdef NOSTRERR sprintf (temp, "Check the permissions and try again."); #else sprintf (temp, "%s", strerror (errno)); #endif error[2] = copyChar (temp); /* Pop up the error message. */ popupLabel (cdkScreen, error, 3); /* Clean up and set the error status. */ freeChar (error[1]); freeChar (error[2]); status = -1; } } else { /* Create the message. */ error[0] = "Installation aborted."; /* Pop up the error message. */ popupLabel (cdkScreen, error, 1); /* Set the exit status. */ status = -1; } /* Clean up. */ freeChar (mesg[1]); } } return status; }