1#!/usr/bin/perl 2# Copyright (c) 2013 Apple Inc. All Rights Reserved. 3# 4# IMPORTANT NOTE: This file is licensed only for use on Apple-branded 5# computers and is subject to the terms and conditions of the Apple Software 6# License Agreement accompanying the package this file is a part of. 7# You may not port this file to another platform without Apple's written consent. 8 9# Wrapper script for postgres; waits for dataPath to be mounted before proceeding 10# Reads additional arguments from a plist specified by optional 11# "--apple-configuration" flag. These args are appended to the original ARGV, and 12# the --apple-configuration args are removed, before handing the final set of args 13# to the real postgres executable. 14 15use strict; 16use warnings; 17use Getopt::Std; 18 19my $PLIST_BUDDY = '/usr/libexec/PlistBuddy'; 20my $WAIT4PATH = '/bin/wait4path'; 21 22my $postgres_real_path = '@PATH_TEMPLATE@'; 23my $config_path; 24my $data_directory; 25my $g_child_status; 26my @postgres_argv = @ARGV; 27 28our $opt_D; 29getopt('D:'); 30 31if ( defined $opt_D ) { 32 $data_directory = $opt_D; 33} 34 35for ( my $i = 0; $i < $#postgres_argv; $i++ ) { 36 if ( $postgres_argv[$i] eq '--apple-configuration' ) { 37 if ( !defined $postgres_argv[ $i + 1 ] ) { 38 print "Error: missing required argument for --apple-configuration\n"; 39 exit 1; 40 } 41 $config_path = $postgres_argv[ $i + 1 ]; 42 splice @postgres_argv, $i, 2; 43 last; 44 } 45} 46 47if ( -e $config_path ) { 48 my @config_lines = `$PLIST_BUDDY -c 'Print :ProgramArguments' "$config_path"`; 49 50 # Skipping the first and last lines, which specify the class type. 51 for ( my $i = 1; $i < $#config_lines; $i++ ) { 52 if ( $config_lines[$i] =~ / \A \s* (.+?) \s* \n* \z /xms ) { 53 push @postgres_argv, $1; 54 } 55 if ( !defined $data_directory 56 && $config_lines[$i] =~ / \A \s* -D \s* \n* \z /xms ) 57 { 58 if ( defined $config_lines[ $i + 1 ] 59 && $config_lines[ $i + 1 ] =~ / \A \s* (.+?) \s* \n* \z /xms ) 60 { 61 $data_directory = $1; 62 } 63 } 64 } 65} 66 67if ( defined $data_directory ) { 68 69 # Snip the shared memory block out of the lockfile if no process is running 70 # that matches the PID in the file. Otherwise postgres will fail to start 71 # if it wasn't shut down properly and another process is now using that memory 72 # block. 73 my $postgres_pid_path = $data_directory . '/postmaster.pid'; 74 if ( -e $postgres_pid_path ) { 75 my $FILE; 76 if ( !open $FILE, '+<', $postgres_pid_path ) { 77 print "Error opening lock file: $!\n"; 78 } 79 else { 80 my @lines = <$FILE>; 81 if ( $lines[0] =~ / \A (\d+) \n* \z /xms ) { 82 my $old_pid = $1; 83 my $ret = system 'kill', '-0', $old_pid; 84 if ( $ret != 0 ) { 85 86 # Process is not running 87 print "Clearing shared memory block from lock file\n"; 88 if ( $lines[$#lines] =~ / \A \s* \d+ \s+ \d+ \s* \n* \z /xms ) { 89 my $out = q{}; 90 for ( my $i = 0; $i < $#lines - 1; $i++ ) { 91 $out .= $lines[$i]; 92 } 93 if ( !seek $FILE, 0, 0 ) { 94 print "Error, seek: $!\n"; 95 } 96 else { 97 print $FILE $out; 98 truncate $FILE, tell($FILE); 99 } 100 } 101 } 102 } 103 close $FILE; 104 } 105 } 106 107 system $WAIT4PATH, $data_directory; 108} 109 110exec $postgres_real_path, @postgres_argv; 111exit 0; 112