/*************************************************************************** main.cpp - description ------------------- begin : lun mai 22 18:04:54 CEST 2000 copyright : (C) 2000 by François Dupoux email : fdupoux@partimage.org ***************************************************************************/ // $Revision: 1.3 $ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_GETOPT_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include #include #include #define __STDC_FORMAT_MACROS #include #include #include #include #include #include #include #include #include #include #include #include "fs_ext2.h" #include "fs_fat.h" #include "fs_reiser.h" #include "fs_ntfs.h" #include "fs_hpfs.h" #include "fs_jfs.h" #include "fs_xfs.h" #include "fs_hfs.h" #include "fs_ufs.h" #include "partimage.h" #include "common.h" #include "gui_text.h" #include "net.h" #include "misc.h" #include "imginfo.h" #include "buffer.h" #include "exceptions.h" #include "interface_newt.h" #include "interface_none.h" #include "mbr_backup.h" extern char *optarg; extern int optind; extern int opterr; // time time_t g_timeBegin=0; // Beginning of main() time_t g_timeStart=0; // Beginning of the copy, after confirmation time_t g_timeEnd=0; // End of the operation #ifdef HAVE_GETOPT_H static struct option const long_options[] = { {"automnt", required_argument, NULL, 'a'}, {"batch", no_argument, NULL, 'b'}, {"fully-batch", required_argument, NULL, 'B'}, {"nocheck", no_argument, NULL, 'c'}, {"nodesc", no_argument, NULL, 'd'}, {"erase", no_argument, NULL, 'e'}, {"finish", required_argument, NULL, 'f'}, {"debug", required_argument, NULL, 'g'}, {"help", no_argument, NULL, 'h'}, {"compilinfo", no_argument, NULL, 'i'}, {"nombr", no_argument, NULL, 'M'}, {"allowmnt", no_argument, NULL, 'm'}, {"nologin", no_argument, NULL, 'L'}, {"nossl", no_argument, NULL, 'n'}, {"overwrite", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'P'}, {"port", required_argument, NULL, 'p'}, {"simulate", no_argument, NULL, 'S'}, {"server", required_argument, NULL, 's'}, {"username", required_argument, NULL, 'U'}, {"volume", required_argument, NULL, 'V'}, {"version", no_argument, NULL, 'v'}, {"waitvol", no_argument, NULL, 'w'}, {"runshell", no_argument, NULL, 'X'}, {"nosync", no_argument, NULL, 'y'}, {"compress", required_argument, NULL, 'z'}, {NULL, 0, NULL, 0} }; #endif static char finish_last_countfile_lock[]="/tmp/partimageXXXXXX.lock"; static char finish_last_countfile[]="/tmp/partimageXXXXXX"; static char optstring[]="z:oV:ecmdhf:s:p:bwg:vyLnSMa:iU:P:XB:"; FILE * g_fDebug; // debug file FILE * g_fLocalDebug; // debug file CInterface * g_interface; bool g_bSigInt = false; bool g_bSigKill = false; QWORD g_qwCopiedBytesCount=0; WORD g_wEndian=ENDIAN_UNKNOWN; // ======================================================= static void catch_sigint(int signo) { if (signo == SIGTERM) { g_bSigKill = true; delete g_interface; exit(0); } else if (signo == SIGINT) { g_bSigInt = true; } /*else if (signo == SIGSEGV) { delete g_interface; fprintf(stderr, i18n("Segmentation fault. Please report the bug and send the /var/log/partimage-debug.log file to authors\n")); exit(0); }*/ } void ensure_interface_is_non_interactive() { delete g_interface; g_interface = new CInterfaceNone((char *)""); } // ======================================================= int main(int argc, char *argv[]) { int nRes; int nOptCh; int iRet __attribute__ ((unused)) ; COptions options; int nChoice; char szDevice[MAX_DEVICENAMELEN]; char szImageFile[MAXPATHLEN]; char szImageDir[MAXPATHLEN]; char szTemp[2048]; char szTemp2[1024]; char szTemp3[1024]; char szAux[MAXPATHLEN+1]; char szAux2[MAXPATHLEN+1]; char szFileSystem[1024]; // struct sched_param Param; // initialize time g_timeBegin = time(0); setEndianess(false); // initialize options with defaults values memset(&options, 0, sizeof(COptions)); options.bUseSSL = OPTIONS_DEFAULT_SSL; options.bMustLogin = OPTIONS_DEFAULT_LOGIN; options.bBackupMBR = OPTIONS_DEFAULT_BACKUP_MBR; options.bSimulateMode = OPTIONS_DEFAULT_SIMULATE_MODE; options.bOverwrite = OPTIONS_DEFAULT_OVERWRITE; options.qwSplitSize = OPTIONS_DEFAULT_SPLIT_SIZE; options.bEraseWithNull = OPTIONS_DEFAULT_ERASE_EMPTY; options.dwCompression = OPTIONS_DEFAULT_COMPRESS; options.bCheckBeforeSaving = OPTIONS_DEFAULT_CHECK; options.bFailIfMounted = OPTIONS_DEFAULT_FAIL_IF_MOUNTED; options.bAskDesc = OPTIONS_DEFAULT_ASK_DESC; options.dwFinish = OPTIONS_DEFAULT_FINISH; options.dwServerPort = OPTIONS_DEFAULT_SERVERPORT; options.bBatchMode = OPTIONS_DEFAULT_AUTOSTART; options.bSplitWait = OPTIONS_DEFAULT_SPLIT_WAIT; options.bRunShell = OPTIONS_DEFAULT_RUN_SHELL; options.bSync = OPTIONS_DEFAULT_SYNC; options.dwDebugLevel = DEFAULT_DEBUG_LEVEL; // defined by configure.in strncpy(options.szServerName, OPTIONS_DEFAULT_SERVERNAME, MAX_HOSTNAMESIZE); strncpy(options.szFullyBatchMode, OPTIONS_DEFAULT_FULLYBATCHMODE, 2048); strncpy(options.szUserName, OPTIONS_DEFAULT_USERNAME, MAX_USERNAMELEN); strncpy(options.szPassWord, OPTIONS_DEFAULT_PASSWORD, MAX_PASSWORDLEN); *(options.szFullyBatchMode) = 0; // initialize language for i18n setlocale(LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); // Very important: do not remove (else, uncompatible image will be produced) if (checkStructSizes() == -1) return EXIT_FAILURE; // read command line #ifdef HAVE_GETOPT_H while ((nOptCh = getopt_long (argc, argv, optstring, long_options, NULL)) != EOF) #else while ((nOptCh = getopt (argc, argv, optstring)) != -1) #endif { switch(nOptCh) { case 's': // partimaged server's ip addr strncpy(options.szServerName, optarg, MAX_HOSTNAMESIZE); *(options.szServerName+MAX_HOSTNAMESIZE-1) = '\0'; break; case 'a': // auto mount options strncpy(options.szAutoMount, optarg, MAXPATHLEN); *(options.szAutoMount+MAXPATHLEN-1) = '\0'; break; case 'U': // username for serverauth strncpy(options.szUserName, optarg, MAX_USERNAMELEN); *(options.szUserName+MAX_USERNAMELEN-1) = '\0'; break; case 'B': // fully batchmode: don't do any newt or anything strncpy(options.szFullyBatchMode, optarg, 2047); options.bBatchMode = true; break; case 'P': // password for serverauth strncpy(options.szPassWord, optarg, MAX_PASSWORDLEN); *(options.szPassWord+MAX_PASSWORDLEN-1) = '\0'; break; case 'b': // batchmode: don't wait for user action (return) options.bBatchMode = true; break; case 'w': // wait after each new colume options.bSplitWait = true; break; case 'X': // run shell after all volume options.bRunShell = true; break; case 'M': // do not create a backup of the MBR options.bBackupMBR = false; break; case 'y': // no sync at the end options.bSync = false; break; case 'p': // partimaged server's listening port options.dwServerPort = atol(optarg); if ((options.dwServerPort < 1) || (options.dwServerPort > 65535)) { fprintf(stderr, i18n("server's port must be between 1 and " "65535\n")); return EXIT_FAILURE; } break; case 'z': // compression level options.dwCompression = atol(optarg); if ((options.dwCompression < 0) || (options.dwCompression > 2)) { fprintf(stderr, i18n("Compression mode must be 0 (none), " "1(gzip), 2(bzip2)\n")); return EXIT_FAILURE; } break; case 'f': // what to do when finished successfully ? options.dwFinish = atol(optarg); if ((options.dwFinish < 0) || (options.dwFinish > 3)) { fprintf(stderr, i18n("Finish mode must be 0 (wait), " "1(halt), 2(reboot) or 3(quit)\n")); return EXIT_FAILURE; } break; case 'g': // change the debug level options.dwDebugLevel = atol(optarg); if ((options.dwDebugLevel < 0) || (options.dwDebugLevel > 10)) { fprintf(stderr, i18n("The debug level must be 0(none), " "1(user), 2(developer) or 3(debugging)\n")); return EXIT_FAILURE; } break; case 'V': // split image into multiple files options.qwSplitSize = (QWORD)atol(optarg) * 1024 * 1024; fprintf (stderr, i18n("Volume size: %"PRIu64" bytes (%ld MiB)\n"), options.qwSplitSize, atol(optarg)); break; case 'o': // overwrite existring image options.bOverwrite = true; break; case 'e': // erase empty blocks with zero bytes options.bEraseWithNull = true; break; case 'm': // don't fail if mounted options.bFailIfMounted = false; break; case 'c': // don't check partition before saving options.bCheckBeforeSaving = false; break; case 'd': // don't ask any description options.bAskDesc = false; break; case 'h': // help usage(); return EXIT_SUCCESS; break; case 'v': // version printf(i18n("Partition Image version %s (distributed under the" " GNU GPL2).\n"), PACKAGE_VERSION); return EXIT_SUCCESS; break; case 'i': // compilation options formatCompilOptions(szTemp, sizeof(szTemp)); printf("%s\n", szTemp); return EXIT_SUCCESS; break; case 'L': // no login options.bMustLogin = false; break; case 'n': // no ssl options.bUseSSL = false; break; case 'S': // simulate options.bSimulateMode = true; break; } } // debug file g_fDebug = NULL; if (options.dwDebugLevel) { SNPRINTF(szAux2, "%s_latest", PARTIMAGE_LOG); #ifdef APPEND_PID // append pid at the end of PARTIMAGE_LOG filename SNPRINTF(szAux, "%s_%d", PARTIMAGE_LOG, getpid()); #else SNPRINTF(szAux, "%s", PARTIMAGE_LOG); #endif unlink(szAux2); iRet = symlink(szAux, szAux2); g_fDebug = openFileDescriptorSecure(szAux, "a", O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, S_IRUSR | S_IWUSR); g_nDebugThreadMain = getpid(); g_dwDebugLevel = options.dwDebugLevel; pthread_mutex_init(&g_mutexDebug, &g_mutexDebugAttr); } if (!g_fDebug) { g_fDebug = fopen("/dev/null", "w"); if (!g_fDebug) { fprintf(stderr, i18n("Cannot open debug file.\n")); g_fDebug = stderr; } //return EXIT_FAILURE; } else { showDebug(1, "%s: Partition Image version %s (DebugLevel %lu used, " "MainThread=%d)\n",PARTIMAGE_LOG, PACKAGE_VERSION, options.dwDebugLevel, getpid()); showDebug(1, "=========================================================" "==============================\n\n\n"); formatCompilOptions(szTemp, sizeof(szTemp)); showDebug(1, "%s\n\n", szTemp); /* extractFilepathFromFullPath(PARTIMAGE_LOG, szAux); // filepath without filename #ifdef APPEND_PID snprintf(szAux2, MAXPATHLEN, "%s/LATEST_PILOG_IS_%d", szAux, getpid()); #else snprintf(szAux2, MAXPATHLEN, "%s/LATEST_PILOG_IS_nopid", szAux); #endif touchFile(szAux2); */ } //if (fchmod(fileno(g_fDebug), S_IRUSR|S_IWUSR)) // showDebug(1, "can't change debugfile mode to 600: %s\n", strerror(errno)); /* fprintf(g_fDebug, "\ntrying to change priority to -20..."); nRes = nice(-20); if (nRes) fprintf(g_fDebug, " failed: %s\n", strerror(errno)); else fprintf(g_fDebug, " ok\n"); fprintf(g_fDebug, "trying to change scheduling to increase speed\n"); fprintf(g_fDebug, " call to sched_get_priority_max..."); fflush(g_fDebug); Param.sched_priority = sched_get_priority_max(SCHED_FIFO); if (Param.sched_priority < 0) { fprintf(g_fDebug, " failed\n"); fprintf(g_fDebug, "%s\n", strerror(errno)); fprintf(g_fDebug, "scheduler not changed\n"); fflush(g_fDebug); } else { fprintf(g_fDebug, " ok priority_max = %d\n", Param.sched_priority); fprintf(g_fDebug, " call to sched_setscheduler..."); fflush(g_fDebug); nRes = sched_setscheduler(0, SCHED_FIFO, &Param); if (nRes) { fprintf(g_fDebug," failed\n"); fprintf(g_fDebug,"%s\n", strerror(errno)); fprintf(g_fDebug, "scheduler not changed\n"); fflush(g_fDebug); } else { fprintf(g_fDebug," ok policy set to SCHED_FIFO\n"); fprintf(g_fDebug, "scheduler changed\n"); fflush(g_fDebug); } } fprintf(g_fDebug, "\n"); fflush(g_fDebug); */ // init CRC table initCrcTable(g_dwCrcTable); if (!options.szFullyBatchMode || !strlen(options.szFullyBatchMode)) { // signal /*struct sigaction saOld, saNew; saNew.sa_handler = catch_sigint; sigemptyset(&saNew.sa_mask); saNew.sa_flags = 0; sigaction(SIGKILL, &saNew, &saOld); sigaction(SIGINT, &saNew, &saOld);*/ signal(SIGTERM, catch_sigint); signal(SIGINT, catch_sigint); // signal(SIGSEGV, catch_sigint); // segmentation fault } // endianess switch(g_wEndian) { case ENDIAN_UNKNOWN: showDebug(1, "ENDIANESS=ENDIAN_UNKNOWN\n"); break; case ENDIAN_LITTLE: showDebug(1, "ENDIANESS=ENDIAN_LITTLE\n"); break; case ENDIAN_BIG: showDebug(1, "ENDIANESS=ENDIAN_BIG\n"); break; case ENDIAN_PDP: showDebug(1, "ENDIANESS=ENDIAN_PDP\n"); break; } // init interface showDebug(8, "initialize interface\n"); if (!options.szFullyBatchMode || !strlen(options.szFullyBatchMode)) g_interface = new PARTIMAGE_INTERFACE(options.bBatchMode); else g_interface = new CInterfaceNone(options.szFullyBatchMode); showDebug(8, "interface ok\n"); // ----------- check the user is logged as root if (geteuid() != 0) // 0 is the UID of the root { if (g_interface -> ErrorLogAsRoot() == MSGBOX_CANCEL) { delete g_interface; return EXIT_FAILURE; } } showDebug(8, "ok for uid\n"); // check options /*nRes = checkOptions(options); if (nRes == -1) { delete g_interface; return EXIT_FAILURE; } showDebug(8, "ok for options\n"); */ nChoice = -1; memset(szDevice, 0, MAX_DEVICENAMELEN); memset(szImageFile, 0, MAXPATHLEN); // run operations if the command line is full if (argc - optind == 3) // commands with 2 parameters { showDebug(8, "full cmdline with 2 param\n"); strncpy(szDevice, argv[optind+1], MAX_DEVICENAMELEN); strncpy(szImageFile, argv[optind+2], MAXPATHLEN); if (strcmp(argv[optind], "save")==0) // save nChoice = OPERATION_SAVE; else if (strcmp(argv[optind], "restore")==0) // restore nChoice = OPERATION_RESTORE; } if (argc - optind == 2) // commands with 1 parameter { showDebug(8, "full cmdline with 1 param\n"); if (strcmp(argv[optind], "restmbr")==0) // restore an MBR nChoice = OPERATION_RESTMBR; else if (strcmp(argv[optind], "imginfo")==0) // show informations about the imagefile nChoice = OPERATION_IMGINFO; else if (strcmp(argv[optind], "save_all")==0) nChoice = OPERATION_SAVE_ALL; else if (strcmp(argv[optind], "rest_all")==0) nChoice = OPERATION_REST_ALL; else if (strcmp(argv[optind], "save_file")==0) nChoice = OPERATION_SAVE_FILE; else if (strcmp(argv[optind], "rest_file")==0) nChoice = OPERATION_REST_FILE; strncpy(nChoice == OPERATION_REST_ALL || nChoice == OPERATION_SAVE_ALL ? szImageDir : szImageFile, argv[optind+1], MAXPATHLEN); } // check options nRes = checkOptions(options, szDevice, szImageFile); if (nRes == -1) { delete g_interface; return EXIT_FAILURE; } showDebug(8, "ok for options\n"); if ((isDevfsEnabled()) && (!isDevfsMounted())) { g_interface->msgBoxCancel(i18n("Warning"), i18n("You have devfs enabled but not mounted. You have to do it to " "continue. You can also boot with non-devfs kernel if you have " "one.")); delete g_interface; return EXIT_FAILURE; } beginMainWin: // if no command line or invalid action if (nChoice == -1) { showDebug(8, "weird cmdline\n"); strcpy(szDevice, "/dev/"); *szImageFile = 0; // draw main window showDebug(8, "weird cmdline\n"); nChoice = g_interface -> guiInitMainWindow(szDevice, szImageFile, options.szServerName, &(options.dwServerPort), &options.bUseSSL); } showDebug(8, "go on\n"); // run action switch(nChoice) { case OPERATION_SAVE: showDebug(1, "action=SAVE\n"); detectFileSystem(szDevice, szFileSystem); //#ifndef DEVEL_SUPPORT if (isFileSystemSupported(szFileSystem) == true) //#endif // DEVEL_SUPPORT { try { savePartition(szDevice, szImageFile, &options); } catch (CExceptions *excep) { if (excep->GetExcept() == ERR_COMEBACK) { nChoice = -1; goto beginMainWin; } if (options.bBatchMode) ensure_interface_is_non_interactive(); g_interface -> Error(excep, szImageFile, szDevice); showDebug(1, "\nFINAL ERROR\n\n"); nRes = -1; } } //#ifndef DEVEL_SUPPORT else { showDebug(1, "The file system of [%s] is [%s], and is not supported\n", szDevice, szFileSystem); if (options.bBatchMode) ensure_interface_is_non_interactive(); g_interface->msgBoxError(i18n("The file system of [%s] is [%s], and is not supported"), szDevice, szFileSystem); nRes = -1; } //#endif // DEVEL_SUPPORT break; case OPERATION_RESTORE: showDebug(1, "action=RESTORE\n"); try { restorePartition(szDevice, szImageFile, &options); } catch (CExceptions *excep) { if (excep->GetExcept() == ERR_COMEBACK) { nChoice = -1; goto beginMainWin; } if (!options.bBatchMode && !excep->getCaught()) g_interface -> Error(excep, szImageFile); showDebug(1, "\nFINAL ERROR\n\n"); nRes = -1; } break; case OPERATION_RESTMBR: showDebug(1, "action=RESTMBR\n"); try { restoreMbr(szImageFile, &options); } catch (CExceptions *excep) { if (excep->GetExcept() == ERR_COMEBACK) { nChoice = -1; goto beginMainWin; } showDebug(1, "restoreMBR caught exception: %d\n", excep->GetExcept()); if (!options.bBatchMode && !excep->getCaught()) g_interface -> Error(excep, szImageFile); showDebug(1, "\nFINAL ERROR\n\n"); nRes = -1; } break; case OPERATION_SAVE_FILE: showDebug(1, "action=SAVE_FILE\n"); try { save_file(szImageFile, &options); } catch (CExceptions *excep) { showDebug(1, "save_file caught exception: %d\n", excep->GetExcept()); if (options.bBatchMode) ensure_interface_is_non_interactive(); g_interface -> Error(excep, szImageFile, ""); nRes = -1; } break; case OPERATION_REST_FILE: showDebug(1, "action=REST_FILE\n"); try { rest_file(szImageFile, &options); } catch (CExceptions *excep) { showDebug(1, "rest_file caught exception: %d\n", excep->GetExcept()); if (options.bBatchMode) ensure_interface_is_non_interactive(); g_interface -> Error(excep, szImageFile, ""); nRes = -1; } break; case OPERATION_IMGINFO: showDebug(1, "action=IMGINFO\n"); try { showImgInfos(szImageFile, &options); } catch (CExceptions *excep) { showDebug(1, "showimageinfo caught exception: %d\n", excep->GetExcept()); if (!options.bBatchMode && !excep->getCaught()) g_interface -> Error(excep, szImageFile); showDebug(1, "\nFINAL ERROR\n\n"); nRes = -1; } break; case OPERATION_SAVE_ALL: showDebug(1, "action=SAVE_ALL\n"); try { save_all(szImageDir, &options); } catch (CExceptions *excep) { showDebug(1, "caught exception: %d\n", excep->GetExcept()); if (!options.bBatchMode && !excep->getCaught()) g_interface -> Error(excep, szImageFile); showDebug(1, "\nFINAL ERROR\n\n"); nRes = -1; } break; case OPERATION_REST_ALL: showDebug(1, "action=REST_ALL\n"); try { rest_all(szImageDir, &options); } catch (CExceptions *excep) { showDebug(1, "caught exception: %d\n", excep->GetExcept()); if (!options.bBatchMode && !excep->getCaught()) g_interface -> Error(excep, szImageFile); showDebug(1, "\nFINAL ERROR\n\n"); nRes = -1; } break; default: // exit if (options.bBatchMode) fprintf(stderr,"\n\n"); if (options.bSync) { if (options.bBatchMode) fprintf(stderr,"\n\n"); if (!options.bBatchMode) g_interface -> StatusLine(i18n("commiting buffer cache to disk.")); sync(); } closeDebugFiles(); delete g_interface; return EXIT_SUCCESS; break; } showDebug(8, "sync\n"); // update the disk IO if (options.bSync) { if (options.bBatchMode) fprintf(stderr,"\n\n"); g_interface -> StatusLine(i18n("commiting buffer cache to disk.")); sync(); } // ---- statistics about time/CPU infos ---- rusage rusageSelf, rusageChild; time_t timeCopy; DWORD dwTimeTotal, dwTimeUser, dwTimeSys; g_timeEnd = time(0); timeCopy = g_timeEnd - g_timeStart; if ((getrusage(RUSAGE_SELF, &rusageSelf) != -1) && (getrusage(RUSAGE_CHILDREN, &rusageChild) != -1)) { dwTimeUser = rusageSelf.ru_utime.tv_sec + rusageChild.ru_utime.tv_sec + g_dwTimeThreadUser; dwTimeSys = rusageSelf.ru_stime.tv_sec + rusageChild.ru_stime.tv_sec + g_dwTimeThreadSys; dwTimeTotal = dwTimeUser + dwTimeSys; showDebug(1, "\n\n============= TIME and CPU infos ================\n"); showDebug(1, "Total time:...........%s\n", formatTime(timeCopy, szTemp)); showDebug(1, "User time:............%s (main=%s, child=%s)\n", formatTime(dwTimeUser, szTemp), formatTime(rusageSelf.ru_utime.tv_sec, szTemp2), formatTime(rusageChild.ru_utime.tv_sec, szTemp3)); showDebug(1, "System time:..........%s (main=%s, child=%s)\n", formatTime(dwTimeSys, szTemp), formatTime(rusageSelf.ru_stime.tv_sec, szTemp2), formatTime(rusageChild.ru_stime.tv_sec, szTemp3)); showDebug(1, "CPU used:.............%d %%\n", (timeCopy != 0) ? ((dwTimeTotal * 100) / timeCopy) : 0); showDebug(1, "Beginning:............%15ld = %s", g_timeBegin, ctime(&g_timeBegin)); showDebug(1, "Start copy:...........%15ld = %s", g_timeStart, ctime(&g_timeStart)); showDebug(1, "End:..................%15ld = %s", g_timeEnd, ctime(&g_timeEnd)); showDebug(1, "\n============= TIME and CPU infos ================\n\n\n"); } // show result message if (nRes == -1) // FAILED { showDebug(1, "End of operation: FAILED\n"); closeDebugFiles(); delete g_interface; return EXIT_FAILURE; } else // SUCCESS { showDebug(1, "End of operation: SUCCESS\n"); // closeDebugFiles(); // pthread_mutex_destroy(&g_mutexDebug); if (options.dwFinish == FINISH_WAIT) { showDebug(1, "option FINISH_WAIT\n"); if (nChoice == OPERATION_RESTMBR) { SNPRINTF(szTemp, i18n("The MBR was successfully restored")); } else { if (options.bSimulateMode) formatOperationSucessMsg(szTemp, sizeof(szTemp), i18n("Simulation")); else formatOperationSucessMsg(szTemp, sizeof(szTemp), i18n("Operation")); } if (nChoice != OPERATION_IMGINFO) g_interface->msgBoxOk(i18n("Success"), szTemp); delete g_interface; return EXIT_SUCCESS; } else if (options.dwFinish == FINISH_HALT) { showDebug(1, "option FINISH_HALT\n"); delete g_interface; nRes = system("/sbin/shutdown -h now"); nRes = system("/sbin/poweroff"); // if we reach this point, it's because shutdown failed fprintf(stderr, i18n("Error: Cannot halt the computer")); return EXIT_SUCCESS; } else if (options.dwFinish == FINISH_REBOOT) { showDebug(1, "option FINISH_REBOOT\n"); if (options.bSimulateMode) formatOperationSucessMsg(szTemp, sizeof(szTemp), i18n("Simulation")); else formatOperationSucessMsg(szTemp, sizeof(szTemp), i18n("Operation")); if (nChoice != OPERATION_IMGINFO) g_interface->msgBoxOk(i18n("Success"), szTemp); delete g_interface; nRes = system("/sbin/shutdown -r now"); nRes = system("/sbin/reboot"); // if we reach this point, it's because shutdown failed fprintf(stderr, i18n("Error: Cannot reboot the computer")); return EXIT_SUCCESS; } else if (options.dwFinish == FINISH_QUIT) { showDebug(1, "option FINISH_QUIT\n"); delete g_interface; return EXIT_SUCCESS; } else if (options.dwFinish == FINISH_LAST) { showDebug(1, "option FINISH_LAST\n"); int fd_lock, fd_countfile; FILE *fCountFile; FILE *fLockFile; int nValue, nRetries; nRetries = 5; do { if ((fd_lock = mkstemp(finish_last_countfile_lock)) == -1) { --nRetries; sleep(2); continue; } fLockFile = fdopen(fd_lock, "r"); if (fLockFile == NULL) { close(fd_lock); unlink(finish_last_countfile_lock); sleep(2); } } while (fLockFile == NULL && nRetries); if (!nRetries) { delete g_interface; fprintf(stderr, i18n("Error: Cannot count remaining partimages")); return EXIT_SUCCESS; } if ((fd_countfile = mkstemp(finish_last_countfile)) == -1) { fclose(fLockFile); close(fd_lock); unlink(finish_last_countfile_lock); delete g_interface; fprintf(stderr, i18n("Error: Cannot create countfile")); return EXIT_FAILURE; } fCountFile = fdopen(fd_countfile, "r"); if (fCountFile == NULL) { fclose(fLockFile); close(fd_lock); close(fd_countfile); unlink(finish_last_countfile_lock); unlink(finish_last_countfile); delete g_interface; fprintf(stderr, i18n("Error: Cannot count remaining partimages")); return EXIT_SUCCESS; } iRet = fscanf(fCountFile, "%d\n", &nValue); showDebug(1, "RESTANT: %d\n", nValue); if (nValue <= 1) { // we are the last running partimage -> shutdown delete g_interface; fclose(fCountFile); fclose(fLockFile); close(fd_lock); close(fd_countfile); unlink(finish_last_countfile_lock); unlink(finish_last_countfile); // nRes = system("/sbin/shutdown -r now"); // nRes = system("/sbin/reboot"); // if we reach this point, it's because shutdown failed fprintf(stderr, i18n("DEBUG: reboot the computer")); return EXIT_SUCCESS; } else { --nValue; fclose(fCountFile); fCountFile = fdopen(fd_countfile, "w"); if (fCountFile == NULL) { delete g_interface; fprintf(stderr, i18n("Error: Cannot count remaining " "partimages")); return EXIT_SUCCESS; } fprintf(fCountFile, "%d\n", nValue); fclose(fCountFile); fclose(fLockFile); close(fd_lock); close(fd_countfile); unlink(finish_last_countfile_lock); delete g_interface; return EXIT_SUCCESS; } } } } // ======================================================= void closeDebugFiles() { if (g_dwDebugLevel && (g_fDebug != stderr)) fclose(g_fDebug); // local debug } // ======================================================= void usage() { printf("===============================================================================\n"); printf(i18n("Partition Image (http://www.partimage.org/) version %s [%s]\n" "---- distributed under the GPL 2 license (GNU General Public License) ----\n\n" "Supported file systems: Ext2/3, ReiserFS, FAT16/32, HPFS, JFS, XFS,\n" " UFS(beta), HFS(beta), NTFS(experimental)\n\n" "usage: partimage [options] \n" " partimage \n\n" "ex: partimage -z1 -o -d save /dev/hda12 /mnt/backup/redhat-6.2.partimg.gz\n" "ex: partimage restore /dev/hda13 /mnt/backup/suse-6.4.partimg\n" "ex: partimage restmbr /mnt/backup/debian-potato-2.2.partimg.bz2\n" "ex: partimage -z1 -om save /dev/hda9 /mnt/backup/win95-osr2.partimg.gz\n" "ex: partimage imginfo /mnt/backup/debian-potato-2.2.partimg.bz2\n" "ex: partimage -a/dev/hda6#/mnt/partimg#vfat -V1440 save /dev/hda12 /mnt/partimg/redhat-6.2.partimg.gz\n\n" "Arguments:\n" "* :\n" " - save: save the partition datas in an image file\n" " - restore: restore the partition from an image file\n" " - restmbr: restore a MBR of the image file to an hard disk\n" " - imginfo: show informations about the image file\n" "* : partition to save/restore (example: /dev/hda1)\n" "* : file where data will be read/written. Can be very big.\n" " For restore, can have the value 'stdin'. This allows\n" " for providing image files through a pipe.\n\n" "Options:\n" "* -z, --compress (image file compression level):\n" " -z0, --compress=0 don't compress: very fast but very big image file\n" " -z1, --compress=1 compress using gzip: fast and small image file (default)\n" " -z2, --compress=2 compress using bzip2: very slow and very small image file:\n" "* -c, --nocheck don't check the partition before saving\n" "* -o, --overwrite overwrite the existing image file without confirmation\n" "* -d, --nodesc don't ask any description for the image file\n" "* -V, --volume (split image into multiple volumes files)\n" " -VX, --volume=X create volumes with a size of X MiB\n" "* -w, --waitvol wait for a confirmation after each volume change\n" "* -e, --erase erase empty blocks on restore with zero bytes\n" "* -m, --allowmnt don't fail if the partition is mounted. Dangerous!\n" "* -M, --nombr don't create a backup of the MBR (Mast Boot Record) in the image file\n" "* -h, --help show help\n" "* -v, --version show version\n" "* -i, --compilinfo show compilation options used\n" "* -f, --finish (action to do if finished successfully):\n" " -f0, --finish=0 wait: don't make anything\n" " -f1, --finish=1 halt: power off the computer\n" " -f2, --finish=2 reboot: restart the computer\n" " -f3, --finish=3 quit\n" "* -b, --batch batch mode: the GUI won't wait for an user action\n" "* -BX, --fully-batch=X batch mode without GUI, X is a challenge response string\n" "* -y, --nosync don't synchronize the disks at the end of the operation. Dangerous!\n" "* -sX, --server=X give partimaged server's ip address\n" "* -pX, --port=X give partimaged server's listening port\n" "* -g, --debug=X set the debug level to X (default: 1)\n" "* -L, --nologin disable login in network mode\n" "* -n, --nossl disable SSL in network mode\n" "* -S, --simulate simulation of restoration mode\n" "* -aX, --automnt=X automatic mount with X options. Read the doc for more details\n" "* -UX --username=X username to authenticate to server\n" "* -PX --password=X password for authentication of user to server\n"), PACKAGE_VERSION, isVersionStable(PACKAGE_VERSION) ? i18n("stable") : i18n("unstable")); printf("===============================================================================\n"); } // ======================================================= int checkStructSizes() { // ---- check types sizes if (sizeof(DWORD) != 4) { fprintf (stderr, i18n("Error: sizeof(DWORD) != 4 (%zd)\n"), sizeof(DWORD)); goto errcheck; } if (sizeof(QWORD) != 8) { fprintf (stderr, i18n("Error: sizeof(QWORD) != 8 (%zd)\n"), sizeof(QWORD)); goto errcheck; } // ---- check struct sizes // check main header size is 16384 if (sizeof(CMainHeader) != 16384) { fprintf (stderr, i18n("Error: main header size != 16384 (%zd)\n"), sizeof(CMainHeader)); goto errcheck; } // check ext2 header size is 16384 if (sizeof(CInfoExt2Header) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: ext2 header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoExt2Header)); goto errcheck; } // check reiserfs header size is 16384 if (sizeof(CInfoReiserHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: reiserfs header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoReiserHeader)); goto errcheck; } // check fat header size is 16384 if (sizeof(CInfoFatHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: fat header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoFatHeader)); goto errcheck; } // check ntfs header size is 16384 if (sizeof(CInfoNtfsHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: ntfs header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoNtfsHeader)); goto errcheck; } // check hpfs header size is 16384 if (sizeof(CInfoHpfsHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: hpfs header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoHpfsHeader)); goto errcheck; } // check jfs header size is 16384 if (sizeof(CInfoJfsHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: jfs header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoJfsHeader)); goto errcheck; } // check xfs header size is 16384 if (sizeof(CInfoXfsHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: xfs header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoXfsHeader)); goto errcheck; } // check hfs header size is 16384 if (sizeof(CInfoHfsHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: hfs header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoHfsHeader)); goto errcheck; } // check ufs header size is 16384 if (sizeof(CInfoUfsHeader) != INFOS_STRUCT_SIZE) { fprintf (stderr, i18n("Error: jfs header size != %d (%zd)\n"), INFOS_STRUCT_SIZE, sizeof(CInfoUfsHeader)); goto errcheck; } // check tail size is 16384 if (sizeof(CMainTail) != 16384) { fprintf (stderr, i18n("Error: main footer size != 16384 (%zd)\n"), sizeof(CMainTail)); goto errcheck; } // check volume header size is 512 if (sizeof(CVolumeHeader) != 512) { fprintf (stderr, i18n("Error: volume header size != 512 (%zd)\n"), sizeof(CVolumeHeader)); goto errcheck; } // check MBR size is 2048 if (sizeof(CMbr) != 2048) { fprintf (stderr, i18n("Error: MBR size != 2048 (%zd)\n"), sizeof(CMbr)); goto errcheck; } // check volume header size is 512 if (sizeof(CLocalHeader) != 16384) { fprintf (stderr, i18n("Error: local header size != 16384 (%zd)\n"), sizeof(CLocalHeader)); goto errcheck; } return 0; // success errcheck: printf (i18n("This version has been compiled with an uncompatible version of gcc.\n")); //printf("DetailSize: sizeof(DWORD)=%d\n", sizeof(DWORD)); //printf("DetailSize: sizeof(QWORD)=%d\n", sizeof(QWORD)); //printf("DetailSize: sizeof(struct tm)=%d\n", sizeof(struct tm)); RETURN_int(-1); // error } // ======================================================= void formatOperationSucessMsg(char *szMsg, int nMaxLen, char *szOperation) { char szTemp1[2048]; char szTemp2[2048]; char szTemp3[2048]; time_t timeElapsed; QWORD qwBytesPerMin; float fMinElapsed; timeElapsed = time(0) - g_timeStart; fMinElapsed = ((float)timeElapsed) / 60.0; qwBytesPerMin = (QWORD) (((float)g_qwCopiedBytesCount) / fMinElapsed); snprintf(szMsg, nMaxLen, i18n("%s successfully finished:\n\n" "Time elapsed: %s\n" "Speed: %s/min\n" "Data copied: %s"), szOperation, formatTime((DWORD)timeElapsed, szTemp1), formatSize(qwBytesPerMin, szTemp2), formatSize(g_qwCopiedBytesCount, szTemp3)); }