Advertisement
Guest User

backup module

a guest
Apr 17th, 2013
184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.13 KB | None | 0 0
  1. #include "postgres.h"
  2. #include "fmgr.h"
  3. #include "miscadmin.h"
  4. #include "commands/dbcommands.h"
  5. #include "utils/builtins.h"
  6.  
  7. #include <unistd.h>
  8. #include <sys/types.h>
  9. #include <sys/wait.h>
  10.  
  11. #ifdef PG_MODULE_MAGIC
  12. PG_MODULE_MAGIC;
  13. #endif
  14.  
  15. // remember to pfree returned pointer
  16. // the contents variable must not be used after being passed in
  17. // only the return value is guaranteed to have a pointer to valid memory
  18. char* read_to_end(int fd, char* contents)
  19. {
  20.     char buf[1024];
  21.     char* tmp = NULL;
  22.     int sz = 0;
  23.     int n = 0;
  24.     while ((n = read(fd, buf, 1024)) > 0)
  25.     {
  26.         tmp = contents;
  27.         contents = (char*) palloc(sz+1024);
  28.         memcpy(contents, tmp, sz);
  29.         memcpy(contents+sz, buf, n);
  30.         if (tmp != NULL)
  31.           pfree(tmp);
  32.         sz+=n;
  33.     }
  34.     return contents;
  35. }
  36.  
  37. PG_FUNCTION_INFO_V1(replicon_pgdump);
  38.  
  39. Datum
  40. replicon_pgdump(PG_FUNCTION_ARGS)
  41. {
  42.     pid_t pid, wpid;
  43.     FunctionCallInfoData fcid;
  44.     char port[16];
  45.     char *targetPath, *sourceSchema, *dbname, *username, *format;
  46.    
  47.     if (PG_ARGISNULL(0))
  48.       ereport(ERROR, (errmsg("parameter 0 (targetPath) must not be null")));
  49.     if (PG_ARGISNULL(2))
  50.       ereport(ERROR, (errmsg("parameter 2 (format) must not be null")));
  51.    
  52.     targetPath = TextDatumGetCString(PG_GETARG_TEXT_P(0));
  53.     sourceSchema = NULL;
  54.     if (!PG_ARGISNULL(1))
  55.       sourceSchema = TextDatumGetCString(PG_GETARG_TEXT_P(1));
  56.     format = TextDatumGetCString(PG_GETARG_TEXT_P(2));
  57.     dbname = get_database_name(MyDatabaseId);
  58.     username = GetUserNameFromId(GetUserId());
  59.  
  60.     MemSet(&fcid, 0, sizeof(fcid));
  61.     snprintf(port, 16, "%i", (int) inet_server_port(&fcid));
  62.      
  63.     pid = fork();
  64.     if (pid < 0)
  65.     {
  66.         // handle error
  67.         ereport(ERROR, (errmsg("fork failed (%d)", pid)));
  68.     }
  69.     else if (pid == 0) // child process
  70.     {
  71.         char* argv[32];
  72.         int i=0;
  73.         argv[i++] = PG_BINDIR "/pg_dump";
  74.         argv[i++] = "--no-password";
  75.         argv[i++] = "-p";
  76.         argv[i++] = &port[0];
  77.         argv[i++] = "-f";
  78.         argv[i++] = targetPath;
  79.         argv[i++] = "-F";
  80.         argv[i++] = format;
  81.         argv[i++] = "-U";
  82.         argv[i++] = username;
  83.        
  84.         if (sourceSchema != NULL && sourceSchema[0] != 0)
  85.         {
  86.             argv[i++] = "-n";
  87.             argv[i++] = sourceSchema;
  88.         }
  89.        
  90.         argv[i++] = dbname;
  91.         argv[i++] = NULL;
  92.    
  93.         execv(PG_BINDIR "/pg_dump", argv);
  94.        
  95.         exit(-1);
  96.     }
  97.     else // parent process
  98.     {
  99.         int status;
  100.         do
  101.         {
  102.             wpid = waitpid(pid, &status, WUNTRACED);
  103.             if (wpid == -1)
  104.                 ereport(ERROR, (errmsg("waitpid failed")));
  105.             else
  106.             {
  107.                 if (WIFEXITED(status))
  108.                 {
  109.                     int exitCode = WEXITSTATUS(status);
  110.                     if (exitCode != 0)
  111.                     {
  112.                         ereport(ERROR, (errmsg("child exited with status=%d", exitCode)));
  113.                     }
  114.                 }
  115.                 else if (WIFSIGNALED(status))
  116.                 {
  117.                     ereport(ERROR, (errmsg("child killed with signal %d", WTERMSIG(status))));
  118.                 }
  119.                 else if (WIFSTOPPED(status))
  120.                 {
  121.                     ereport(ERROR, (errmsg("child stopped with signal %d", WSTOPSIG(status))));
  122.                 }
  123.                 else
  124.                 {
  125.                     ereport(ERROR, (errmsg("unexpected status (0x%x)", status)));
  126.                 }
  127.             }
  128.         }
  129.         while (!WIFEXITED(status) && !WIFSIGNALED(status));
  130.     }
  131.  
  132.     PG_RETURN_NULL();
  133. }
  134.  
  135. PG_FUNCTION_INFO_V1(replicon_pgrestore);
  136.  
  137. Datum
  138. replicon_pgrestore(PG_FUNCTION_ARGS)
  139. {
  140.     pid_t pid, wpid;
  141.     FunctionCallInfoData fcid;
  142.     char port[16];
  143.     char *sourcePath, *sourceSchema, *dbname, *username;
  144.    
  145.     if (PG_ARGISNULL(0))
  146.       ereport(ERROR, (errmsg("parameter 0 (sourcePath) must not be null")));
  147.              
  148.     sourcePath = TextDatumGetCString(PG_GETARG_TEXT_P(0));
  149.     sourceSchema = NULL;
  150.     if (!PG_ARGISNULL(1))
  151.       sourceSchema = TextDatumGetCString(PG_GETARG_TEXT_P(1));
  152.     dbname = get_database_name(MyDatabaseId);
  153.     username = GetUserNameFromId(GetUserId());
  154.  
  155.     MemSet(&fcid, 0, sizeof(fcid));
  156.     snprintf(port, 16, "%i", (int) inet_server_port(&fcid));
  157.      
  158.     pid = fork();
  159.     if (pid < 0)
  160.     {
  161.         // handle error
  162.         ereport(ERROR, (errmsg("fork failed (%d)", pid)));
  163.     }
  164.     else if (pid == 0) // child process
  165.     {
  166.         char* argv[32];
  167.         int i=0;
  168.         argv[i++] = PG_BINDIR "/pg_restore";
  169.         argv[i++] = "--no-password";
  170.         argv[i++] = "--no-owner";
  171.         argv[i++] = "--exit-on-error";
  172.         argv[i++] = "-p";
  173.         argv[i++] = &port[0];
  174.         argv[i++] = "-U";
  175.         argv[i++] = username;
  176.         argv[i++] = "-d";
  177.         argv[i++] = dbname;
  178.        
  179.         if (sourceSchema != NULL && sourceSchema[0] != 0)
  180.         {
  181.             argv[i++] = "-n";
  182.             argv[i++] = sourceSchema;
  183.             argv[i++] = "--create";
  184.         }
  185.         else
  186.         {
  187.             argv[i++] = "--create";
  188.         }
  189.        
  190.         argv[i++] = sourcePath;
  191.         argv[i++] = NULL;
  192.    
  193.         execv(PG_BINDIR "/pg_restore", argv);    
  194.        
  195.         exit(-1);
  196.     }
  197.     else // parent process
  198.     {
  199.         int status;
  200.         do
  201.         {
  202.             wpid = waitpid(pid, &status, WUNTRACED);
  203.             if (wpid == -1)
  204.                 ereport(ERROR, (errmsg("waitpid failed")));
  205.             else
  206.             {
  207.                 if (WIFEXITED(status))
  208.                 {
  209.                     int exitCode = WEXITSTATUS(status);
  210.                     if (exitCode != 0)
  211.                     {
  212.                         ereport(ERROR, (errmsg("child exited with status=%d", exitCode)));
  213.                     }
  214.                 }
  215.                 else if (WIFSIGNALED(status))
  216.                 {
  217.                     ereport(ERROR, (errmsg("child killed with signal %d", WTERMSIG(status))));
  218.                 }
  219.                 else if (WIFSTOPPED(status))
  220.                 {
  221.                     ereport(ERROR, (errmsg("child stopped with signal %d", WSTOPSIG(status))));
  222.                 }
  223.                 else
  224.                 {
  225.                     ereport(ERROR, (errmsg("unexpected status (0x%x)", status)));
  226.                 }
  227.             }
  228.         }
  229.         while (!WIFEXITED(status) && !WIFSIGNALED(status));
  230.     }
  231.  
  232.     PG_RETURN_NULL();
  233. }
  234.  
  235. PG_FUNCTION_INFO_V1(replicon_backupcontainsschema);
  236.  
  237. Datum
  238. replicon_backupcontainsschema(PG_FUNCTION_ARGS)
  239. {
  240.     pid_t pid, wpid;
  241.     FunctionCallInfoData fcid;
  242.     int fd[2];
  243.     char port[16];
  244.     char schemaSearch[1024];
  245.     char *sourcePath, *sourceSchema, *dbname, *username, *contents = NULL;
  246.     bool retval = false;
  247.    
  248.     if (PG_ARGISNULL(0))
  249.       ereport(ERROR, (errmsg("parameter 0 (sourcePath) must not be null")));
  250.     if (PG_ARGISNULL(1))
  251.       ereport(ERROR, (errmsg("parameter 1 (schemaName) must not be null")));
  252.    
  253.     sourcePath = TextDatumGetCString(PG_GETARG_TEXT_P(0));
  254.     sourceSchema = TextDatumGetCString(PG_GETARG_TEXT_P(1));
  255.     dbname = get_database_name(MyDatabaseId);
  256.     username = GetUserNameFromId(GetUserId());
  257.  
  258.     MemSet(&fcid, 0, sizeof(fcid));
  259.     snprintf(port, 16, "%i", (int) inet_server_port(&fcid));
  260.  
  261.     snprintf(schemaSearch, 1024, "SCHEMA - %s ", sourceSchema);
  262.      
  263.     pipe(fd);
  264.      
  265.     pid = fork();
  266.     if (pid < 0)
  267.     {
  268.         // handle error
  269.         ereport(ERROR, (errmsg("fork failed (%d)", pid)));
  270.     }
  271.     else if (pid == 0) // child process
  272.     {
  273.         char* argv[32];
  274.         int i=0;
  275.  
  276.         close(fd[0]); //close child read end of pipes
  277.        
  278.         dup2(fd[1], 1); //redirect stdout to pipe
  279.    
  280.         argv[i++] = PG_BINDIR "/pg_restore";
  281.         argv[i++] = "--no-password";
  282.         argv[i++] = "--list";
  283.         argv[i++] = "--exit-on-error";
  284.         argv[i++] = "-p";
  285.         argv[i++] = &port[0];
  286.         argv[i++] = "-U";
  287.         argv[i++] = username;
  288.         argv[i++] = sourcePath;
  289.         argv[i++] = NULL;
  290.    
  291.         execv(PG_BINDIR "/pg_restore", argv);    
  292.        
  293.         exit(-1);
  294.     }
  295.     else // parent process
  296.     {  
  297.         int status;
  298.        
  299.         close(fd[1]); //close write end of pipe
  300.         do
  301.         {
  302.             wpid = waitpid(pid, &status, WUNTRACED | WNOHANG);
  303.             if (wpid == -1)
  304.                 ereport(ERROR, (errmsg("waitpid failed")));
  305.             else if (wpid != 0)
  306.             {
  307.                 if (WIFEXITED(status))
  308.                 {
  309.                     int exitCode = WEXITSTATUS(status);
  310.                     if (exitCode != 0)
  311.                     {
  312.                         ereport(ERROR, (errmsg("child exited with status=%d", exitCode)));
  313.                     }
  314.                 }
  315.                 else if (WIFSIGNALED(status))
  316.                 {
  317.                     ereport(ERROR, (errmsg("child killed with signal %d", WTERMSIG(status))));
  318.                 }
  319.                 else if (WIFSTOPPED(status))
  320.                 {
  321.                     ereport(ERROR, (errmsg("child stopped with signal %d", WSTOPSIG(status))));
  322.                 }
  323.                 else
  324.                 {
  325.                     ereport(ERROR, (errmsg("unexpected status (0x%x)", status)));
  326.                 }
  327.             }
  328.             else
  329.             {          
  330.               // continue reading from pipe while process is running to ensure we
  331.               // don't get hung by filling the buffer
  332.               contents = read_to_end(fd[0], contents);
  333.               sleep(0.01); //sleep for 10ms just to avoid a busy loop
  334.             }
  335.         }
  336.         while (wpid == 0 || (!WIFEXITED(status) && !WIFSIGNALED(status)));
  337.        
  338.         // read from pipe
  339.         contents = read_to_end(fd[0], contents);      
  340.         close(fd[0]); // close read end of pipe    
  341.         if (contents != NULL) {        
  342.           retval = strstr(contents, schemaSearch) != NULL;        
  343.           pfree(contents);
  344.         }
  345.     }
  346.    
  347.     PG_RETURN_BOOL(retval);
  348. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement