int main(int argc, char *argv[]) { if(argc<2) { std::cout << "Not enough parameters" << std::endl; return 1; } std::string cmd; int mode = 0; if((std::string)argv[1]!="test") { if(argc<3) { std::cout << "Not enough parameters" << std::endl; return 1; } cmd=argv[2]; mode=atoi(argv[1]); } else { cmd=argv[1]; } std::string backupfolder=getBackupfolderPath(mode); if(backupfolder.empty()) { if(mode==mode_btrfs) { std::cout << "Backupfolder not set" << std::endl; } else if(mode==mode_zfs) { std::cout << "ZFS image dataset not set" << std::endl; } else if(mode==mode_zfs_file) { std::cout << "ZFS file dataset not set" << std::endl; } else { std::cout << "Unknown mode: " << mode << std::endl; } return 1; } if(cmd!="test" && mode==mode_zfs_file) { mode=mode_zfs; } #ifndef _WIN32 if(seteuid(0)!=0) { std::cout << "Cannot become root user" << std::endl; return 1; } #endif if(cmd=="create") { if(argc<5) { std::cout << "Not enough parameters for create" << std::endl; return 1; } std::string clientname=handleFilename(argv[3]); std::string name=handleFilename(argv[4]); std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name; return create_subvolume(mode, subvolume_folder)?0:1; } else if(cmd=="mountpoint") { if(argc<5) { std::cout << "Not enough parameters for mountpoint" << std::endl; return 1; } std::string clientname=handleFilename(argv[3]); std::string name=handleFilename(argv[4]); std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name; return get_mountpoint(mode, subvolume_folder)?0:1; } else if(cmd=="snapshot") { if(argc<6) { std::cout << "Not enough parameters for snapshot" << std::endl; return 1; } std::string clientname=handleFilename(argv[3]); std::string src_name=handleFilename(argv[4]); std::string dst_name=handleFilename(argv[5]); std::string subvolume_src_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+src_name; std::string subvolume_dst_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+dst_name; return create_snapshot(mode, subvolume_src_folder, subvolume_dst_folder)?0:1; } else if(cmd=="remove") { if(argc<5) { std::cout << "Not enough parameters for remove" << std::endl; return 1; } std::string clientname=handleFilename(argv[3]); std::string name=handleFilename(argv[4]); std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name; return remove_subvolume(mode, subvolume_folder)?0:1; } else if(cmd=="test") { std::cout << "Testing for btrfs..." << std::endl; std::string clientdir=backupfolder+os_file_sep()+"testA54hj5luZtlorr494"; bool create_dir_rc=os_create_dir(clientdir); if(!create_dir_rc) { remove_subvolume(mode_zfs, clientdir, true); remove_subvolume(mode_btrfs, clientdir+os_file_sep()+"A", true); remove_subvolume(mode_btrfs, clientdir+os_file_sep()+"B", true); os_remove_dir(clientdir); } create_dir_rc = create_dir_rc || os_create_dir(clientdir); if(create_dir_rc) { if(!create_subvolume(mode_btrfs, clientdir+os_file_sep()+"A") ) { std::cout << "TEST FAILED: Creating test btrfs subvolume failed" << std::endl; os_remove_dir(clientdir); return zfs_test(); } bool suc=true; if(!create_snapshot(mode_btrfs, clientdir+os_file_sep()+"A", clientdir+os_file_sep()+"B") ) { std::cout << "TEST FAILED: Creating test snapshot failed" << std::endl; suc=false; } if(suc) { writestring("test", clientdir+os_file_sep()+"A"+os_file_sep()+"test"); if(!os_create_hardlink(clientdir+os_file_sep()+"B"+os_file_sep()+"test", clientdir+os_file_sep()+"A"+os_file_sep()+"test", true, NULL)) { std::cout << "TEST FAILED: Creating cross sub-volume reflink failed. Need Linux kernel >= 3.6." << std::endl; suc=false; } else { if(getFile(clientdir+os_file_sep()+"B"+os_file_sep()+"test")!="test") { std::cout << "TEST FAILED: Cannot read reflinked file" << std::endl; suc=false; } } } if(!remove_subvolume(mode_btrfs, clientdir+os_file_sep()+"A") ) { std::cout << "TEST FAILED: Removing subvolume A failed" << std::endl; suc=false; } if(!remove_subvolume(mode_btrfs, clientdir+os_file_sep()+"B") ) { std::cout << "TEST FAILED: Removing subvolume B failed" << std::endl; suc=false; } if(!os_remove_dir(clientdir)) { std::cout << "TEST FAILED: Removing test clientdir failed" << std::endl; return 1; } if(!suc) { return 1; } } else { std::cout << "TEST FAILED: Creating test clientdir \"" << clientdir << "\" failed" << std::endl; return zfs_test(); } std::cout << "BTRFS TEST OK" << std::endl; return 10 + mode_btrfs; } else if(cmd=="issubvolume") { if(argc<5) { std::cout << "Not enough parameters for issubvolume" << std::endl; return 1; } std::string clientname=handleFilename(argv[3]); std::string name=handleFilename(argv[4]); std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name; return is_subvolume(mode, subvolume_folder)?0:1; } else if(cmd=="makereadonly") { if(argc<5) { std::cout << "Not enough parameters for makereadonly" << std::endl; return 1; } std::string clientname=handleFilename(argv[3]); std::string name=handleFilename(argv[4]); std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name; return make_readonly(mode, subvolume_folder)?0:1; } else { std::cout << "Command not found" << std::endl; return 1; } }
int main(int argc, char *argv[]) { if(argc<2) { std::cout << "Not enough parameters" << std::endl; return 1; } std::string cmd=argv[1]; std::string backupfolder=getBackupfolderPath(); if(backupfolder.empty()) { std::cout << "Backupfolder not set" << std::endl; return 1; } #ifndef _WIN32 if(seteuid(0)!=0) { std::cout << "Cannot become root user" << std::endl; return 1; } #endif if(cmd=="create") { if(argc<4) { std::cout << "Not enough parameters for create" << std::endl; return 1; } std::string clientname=handleFilename(argv[2]); std::string name=handleFilename(argv[3]); std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name; return create_subvolume(subvolume_folder)?0:1; } else if(cmd=="snapshot") { if(argc<5) { std::cout << "Not enough parameters for snapshot" << std::endl; return 1; } std::string clientname=handleFilename(argv[2]); std::string src_name=handleFilename(argv[3]); std::string dst_name=handleFilename(argv[4]); std::string subvolume_src_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+src_name; std::string subvolume_dst_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+dst_name; return create_snapshot(subvolume_src_folder, subvolume_dst_folder)?0:1; } else if(cmd=="remove") { if(argc<4) { std::cout << "Not enough parameters for remove" << std::endl; return 1; } std::string clientname=handleFilename(argv[2]); std::string name=handleFilename(argv[3]); std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name; return remove_subvolume(subvolume_folder)?0:1; } else if(cmd=="test") { std::string clientdir=backupfolder+os_file_sepn()+"testA54hj5luZtlorr494"; if(os_create_dir(clientdir)) { if(!create_subvolume(clientdir+os_file_sepn()+"A") ) { std::cout << "Creating test subvolume failed" << std::endl; os_remove_dir(clientdir); return 1; } bool suc=true; if(!create_snapshot(clientdir+os_file_sepn()+"A", clientdir+os_file_sepn()+"B") ) { std::cout << "Creating test snapshot failed" << std::endl; suc=false; } if(suc) { writestring("test", clientdir+os_file_sepn()+"A"+os_file_sepn()+"test"); if(!os_create_hardlink(clientdir+os_file_sepn()+"B"+os_file_sepn()+"test", clientdir+os_file_sepn()+"A"+os_file_sepn()+"test", true, NULL)) { std::cout << "Cross subvolume reflink failed" << std::endl; suc=false; } if(getFile(clientdir+os_file_sepn()+"B"+os_file_sepn()+"test")!="test") { std::cout << "Cannot read reflinked file" << std::endl; suc=false; } } if(!remove_subvolume(clientdir+os_file_sepn()+"A") ) { std::cout << "Removing subvolume A failed" << std::endl; suc=false; } if(!remove_subvolume(clientdir+os_file_sepn()+"B") ) { std::cout << "Removing subvolume B failed" << std::endl; suc=false; } if(!os_remove_dir(clientdir)) { std::cout << "Removing test clientdir failed" << std::endl; return 1; } if(!suc) { return 1; } } else { std::cout << "Creating test clientdir \"" << clientdir << "\" failed" << std::endl; return 1; } return 0; } else if(cmd=="issubvolume") { if(argc<4) { std::cout << "Not enough parameters for issubvolume" << std::endl; return 1; } std::string clientname=handleFilename(argv[2]); std::string name=handleFilename(argv[3]); std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name; return is_subvolume(subvolume_folder)?0:1; } else { std::cout << "Command not found" << std::endl; return 1; }
bool remove_subvolume(int mode, std::string subvolume_folder, bool quiet=false) { #ifdef _WIN32 return os_remove_nonempty_dir(widen(subvolume_folder)); #else if(mode==mode_btrfs) { int compat_rc = exec_wait(find_btrfs_cmd(), false, "subvolume", "delete", "-c", NULL); if(compat_rc==1) { compat_rc = exec_wait("/bin/sh", false, "-c", (find_btrfs_cmd() + " subvolume delete -c 2>&1 | grep \"ERROR: error accessing '-c'\"").c_str(), NULL); if(compat_rc==0) { compat_rc=12; } } int rc; if(compat_rc==12) { rc=exec_wait(find_btrfs_cmd(), !quiet, "subvolume", "delete", subvolume_folder.c_str(), NULL); } else { rc=exec_wait(find_btrfs_cmd(), !quiet, "subvolume", "delete", "-c", subvolume_folder.c_str(), NULL); } return rc==0; } else if(mode==mode_zfs) { zfs_elevate(); exec_wait(find_zfs_cmd(), false, "destroy", (subvolume_folder+"@ro").c_str(), NULL); int rc = exec_wait(find_zfs_cmd(), false, "destroy", subvolume_folder.c_str(), NULL); if(rc!=0) { std::cout << "Destroying subvol " << subvolume_folder << " failed. Promoting dependencies..." << std::endl; std::string rename_name = ExtractFileName(subvolume_folder); if(exec_wait(find_zfs_cmd(), true, "rename", (subvolume_folder+"@ro").c_str(), (subvolume_folder+"@"+rename_name).c_str(), NULL)!=0 && is_subvolume(mode, subvolume_folder+"@ro") ) { return false; } std::vector<std::string> dependencies; if(!promote_dependencies(subvolume_folder+"@"+rename_name, dependencies)) { return false; } rc = exec_wait(find_zfs_cmd(), true, "destroy", subvolume_folder.c_str(), NULL); if(rc==0) { for(size_t i=0;i<dependencies.size();++i) { if(is_subvolume(mode, dependencies[i]+"@"+rename_name)) { rc = exec_wait(find_zfs_cmd(), true, "destroy", (dependencies[i]+"@"+rename_name).c_str(), NULL); if(rc!=0) { break; } } } } } return rc==0; } return false; #endif }