Skip to content

Mac OSX 10.8.x Broken links in Frameworks and Application Crashes

September 5, 2013

I stil haven’t figured out why, but my Mac OSX 10.8.4, and lower keeps corrupting file system links all over the place. As you can read in my Microsoft Office posts this problem has plagued me since I first installed 10.8, and happens without any apparent reason.
The only symptoms are that some applications, like Office, QuickTime, Skype and others just don’t start and crash all the time.

Skype gives out an interesting message saying that it needs QuickTime version X to run and crashes, and when I tried to run QuickTime it crashed too.
This happened right after I installed Adobe Air and Salesforce Chatter.

The one thing these crashes have in common is the error they issue. In the crash report you should see something like this:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000

Before you spend your day reinstalling the OS and applications from ZERO, try this:

sudo find -L /Applications -type l
sudo find -L /System/ -type l
sudo find -L ~/Library -type l

These commands will search for and report all broken links in the Applications, System, and User Library directories, and you should see a bunch of output like this

/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework/Headers
/System/Library/Frameworks/ApplicationServices.framework/Frameworks/LangAnalysis.framework/Headers
/System/Library/Frameworks/ApplicationServices.framework/Frameworks/PrintCore.framework/Headers
/System/Library/Frameworks/ApplicationServices.framework/Frameworks/QD.framework/Headers
/System/Library/Frameworks/ApplicationServices.framework/Frameworks/SpeechSynthesis.framework/Headers
/System/Library/Frameworks/ApplicationServices.framework/Headers

Once you fix all these broken links your applications will start working once again

Here is a perl script that can automate the process.

#!/usr/bin/perl
# This script fixes broken Apple Mac OSX 10.8 framework links
# Author:  BigDiver
# Version 1.0
# Date: 09/04/2013
use strict;

my $base_dir = $ARGV[0];
my $test = $ARGV[1];

use File::Find ();
use File::Find::Rule;

die("Dir not found: " . $base_dir) if( ! -d $base_dir );
my %broken;
my $user = `whoami`;
chomp $user;

if( $user !~ /root/i ) {
    print "Script running as user $user\n";
    print "You must run this script as root. Try sudo $0\n";
    exit(-1);
}
    
print "Scan Directory: $base_dir\n";

# Calling wanted subroutine which use stat function to match broken links
File::Find::find({wanted => \&find_broken_links}, $base_dir); 

foreach my $d (keys %broken) {
    print "Fixin $d\n";
    
    foreach my $broken_link ( @{ $broken{$d} }) {
        
        if ($broken_link =~ /Current$/) {
            my $versions_dir = $d . "/Versions";
            
            # Current link is damaged lets point it back to the latest version
            my @dirs = get_all_directories( $versions_dir);
            
            if ( scalar @dirs == 0 ) {
                print "There are no versions available\n";
                next;
            }
            
            # Get highest version
            my $top_version = $dirs[0];  # Directories sorted in reverse order...
                
            #print "Working on $versions_dir\n";
            chdir($versions_dir);
            
            print "$top_version -> $broken_link\n";
            if ( !$test) {
                unlink $broken_link
                    or die "Could not unlink $broken_link";
            
                symlink $top_version, $broken_link
                    or die "Could not link $broken_link";
            }
            
        }
        else {
            my $l = readlink $broken_link;
            
            my $broken_path = $broken_link;
            $broken_path =~ s/\/[^\/]+$//;
            
            
            if( $broken_path eq $d && $l !~ /Versions/) {
                # if not pointing to the current version lets fix it
                
                $broken_link =~ /\/([^\/]+)$/;
                my $whats_broken = $1;
                
                #print "Working on $d\n";
                chdir($d);
                
                print "Versions/Current/$whats_broken -> $broken_link\n";
                if ( !$test) {
                    unlink $broken_link
                        or die "Could not unlink $broken_link";
                    symlink "Versions/Current/$whats_broken", $broken_link
                        or die "Could not link $broken_link";
                }
                
            }    
        }
    }
    
}
print "Done\n";


sub find_broken_links {
    my $file = $_;
    if (-l $file) {
        my $target = readlink $file;
        if ( ! -e $target && ! -l $target ) {
            my $dir = $File::Find::dir;
            $dir =~ s/\.framework((?!framework).)+$/\.framework/;
            if ($dir =~ /\.framework/ ) {
                push @{ $broken{$dir} }, $File::Find::dir . "/" . $file;
            }
        }
    }
}

sub get_all_directories {
    my ($root) = @_;
    
    my $rule = File::Find::Rule->new;  
    my @dirs = $rule
        ->maxdepth(1)
        ->not(File::Find::Rule->new->name(qr/^\.\.?$/))
        ->directory
        ->relative
        ->in($root);
    
    return reverse sort @dirs;
}

Save it to a file, say fixlinks.pl, and make it executable like this

chmod 755 fixlinks.pl

Now you can run fixlinks.pl with the directory you want to scan and fix broken links.

sudo ./fixlinks.pl /System
sudo ./fixlinks.pl /Applications
sudo ./fixlinks.pl ~/Library

If you just want to test what the script would do, but not actually do it run it like this:

sudo ./fixlinks.pl /System 1

Notice the ‘1’ as the last argument. This disables all system changes.

I am not responsible for any data loss, so use this at your own risk. If it works great, if it doesn’t keep Googling for a solution 🙂

Advertisements

From → Apple, MAC OS, Perl

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: