iPhone and Linux

Sunday, February 7, 2010

Minimal video encoding for iPhone

There are countless ways of encoding video for the iPhone, but this is the command I normally use. I don't watch many videos on the phone and my goal is usually to create a video with a small size that doesn't strain the system too much to run. A lower bitrate, 20.98 framerate and 320x240 resolution (which is used on the iPod) would be terrible for watching a hi-def movie, but works great for most videos.

ffmpeg -i infile -f mp4 -vcodec mpeg4 -b 200k -aspect 4:3 -r 20.98 -s 320x240 -acodec libfaac -ar 48000 outfile


The only videos I routinely watch are of The Daily Show, so this little script encodes and renames them from
The.Daily.Show.2010.02.04.Rep.Anthony.Weiner.HDTV.XviD.avi to TDS-02.04.mp4

#! /bin/sh                       
for i in `ls *.avi`
do
name=TDS-$(echo $i | cut -c 21-25).mp4
ffmpeg -i $i -f mp4 -vcodec mpeg4 -b 200k -aspect 4:3 -r 20.98 -s 320x240 -acodec libfaac -ar 48000 $name
done
If you happen to use Prowl and want a notification when it is finished...
num=$(ls | grep mp4 | wc -l)
dir=$(pwd)
url=https://prowl.weks.net/publicapi/add
app="Pod converter"
desc="Finished converting $num Daily Shows in $dir"
curl -k $url -F apikey=XXX -F application=$app -F description=$desc
... or want to transfer them with ssh (using ssh keys):
mkdir mp4s
mv *.mp4 ./mp4s
scp -r -i ~/.ssh/SSH_FILENAME /path/to/mp4s mobile@IP:/var/mobile
Tweak it a bit and you can have a basic method for encoding and automatically syncing your favorite videos while you sleep.

Sunday, January 31, 2010

Simpler iPhone language pack deletion script

My earlier script is a pain. It works fine but I'm not happy with it because it's too much work keeping up with iPhone developers and their screwy names for the language packs.

For some reason, fr.lproj and French.lproj weren't good enough, so there's some fr_FR.lproj popping up, and not only for French, but a variety of languages. The ISO language code for Spanish is "es," so the language pack should be either "Spanish" or "es," but now I'm seeing "sp", "sp_es" and "es_ES." "Sp" isn't an recognized code for any language.

For a script that essentially greps a list of 60 languages in the old format, I don't want to have to add another 30 to deal with these new names popping up. It's easy to add them to the list, but without rewriting the script, it means the user has to be asked "yes or no" for even more languages.

I never thought it would become a project I had to maintain anyway. I will rewrite it so that it's flexible and can handle new languages on it's own, and to lessen the number of times the user has to say yes to each language, but here is a simpler script to use for the time being.

Since most people want to remove everything except English and Japanese anyway, this simple script will do that. It only asks one question "Do you want to delete everything except English and Japanese?" and if you say yes, it does it. It won't have any problem with new language codes because it gets a list of all languages, filters out English and Japanese and deletes everything that is left. Simple. Almost as simple as my very first post on the subject.

Enjoy.

#! /bin/sh
# Thu Feb 4 2010
if [ `id -u` != 0 ]; then echo "Oops, you need to be root to run this script"; exit 0; fi
while [[ $choice != 'y' ]] && [[ $choice != 'n' ]]
do
echo "Do you want to delete all language packs
except English and Japanese (for emoji
keyboards)?
y or n?"
read choice
done
if [[ $choice = 'y' ]]; then
echo "Please wait while I delete the chosen
language packs. This may take a minute
or two..."
updatedb && locate lproj | grep -E lproj$ | grep -v -i ja | grep -v -i English | grep -v -i \/en > .deletelist_fubaya
while read file; do rm -rf "$file"; done < .deletelist_fubaya
num=$(cat .deletelist_fubaya | wc -l)
rm .deletelist_fubaya
echo
echo "$num language pack directories deleted"
fi
[[ $choice = 'n' ]] && echo "Ok, I won't delete anything."; exit 0
# end of script

Friday, January 29, 2010

Copy and paste in MobileTerminal

I've been using this "paste" script for a long time, but put off creating anything to copy as I didn't have much of a need. I finally got interested when it came up on a forum last night. Here is the first draft of working copy and paste.

Both scripts require PasteBaordStacker because, as I have mentioned before, it stores everything as plain text and I've never gotten around to deciphering Apple's PasteBoard.

Paste also requires awk. The awk line may be familiar, it has been so useful it's probably in half the scripts on this blog. Copy uses sed, but I think sed is already installed on a jailbroken iPhone.

Edit Feb 7 2010: added the sed lines to convert the characters <, >, and & which get automatically encoded.

Paste
#! /bin/sh
file=/var/mobile/Library/Preferences/com.hitoriblog.pasteboardstacker.plist
awk 'BEGIN{ RS="</string>"}{gsub(/.*<string>/,"");print;exit}' $file | sed '
s/&lt;/</g
s/&gt;/>/g
s/&amp;/\&/g'


Copy
#! /bin/sh
in=$(cat -)
text=$(echo '<string>'"$in"'</string>')
file=/var/mobile/Library/Preferences/com.hitoriblog.pasteboardstacker.plist
sed -i "7i\\
$text" $file


Usage:
Paste can be used in a variety of ways, but there are two standard methods that are most useful. 1) You can type "paste" on the command line and it will output the last thing you copied on the system. 2) You can use it in a subshell to paste an argument to another program. Example, copy a link to a file in Safari then type wget $(paste) in Terminal. Since the subshell is executed first, the resulting command that is executed is wget www.example.com/file.txt

Copy is a little rough. Since I used PasteBoardStacker, that means text isn't copied directly into the Apple PasteBoard. You have to select the text in PasteBoardStacker first, which is done by double tapping the status bar, then tapping the text you want from the pop-up list. It takes an extra step but it's still a good way to copy text from Terminal, and other than directing the output to a file, opening it and copying, it's the only way I am aware of. Copy handles piped input so if you run this command: echo "Hello world" | copy, you can then select "Hello world" in PasteBoardStacker and paste into another app.

Copy also requires you to escape some special characters with a backslash. echo "Hello world!" | copy won't work because the shell will try to interpret the exclamation point. echo "Hello world\!" | copy is what you need to use. Edit: D'oh, this was a poor example because it's normal shell behavior and not related to copy, but the sed line in copy still can't handle some characters like "<"without escaping.

Friday, January 22, 2010

iPhone/Linux "Network Printing"

This hack may be useful if you have a non-network printer attached to your Linux box and want to print text remotely from your iPhone.

There are actually several ways to accomplish this. You can simply create a text file and scp that file to your linux box, or pipe it over ssh then execute a print command, but neither worked right for me. The first requires you to create the text file, put something in it, save, then send to print. As for the second method, I can't get text to pipe over ssh from my phone like it should, and even if I could, I'm not certain it would work with slogin and ssh keys. Nothing seemed to work for me, so I went with tapping an icon to automatically print the clipboard contents. This way, you don't have to fool with any files, and if you do want to print a file, you can open it, copy the text, and print it.

Requirements:
On the iPhone, you need PasteBoardStacker and ssh (preferrably set up with ssh keys). PasteBoardStacker is used because it's easy to get the plain text from it and I've never gotten around to decoding the Apple pasteboard. Maybe I'll tackle that one someday.

On your Linux box, you need a to be able to print from the command line, which should already be possible as long as your printer works. In my example, I also use enscript to format the text before piping the text to the lpr print command. Enscript should be present on most systems, and I can't imagine anyone actually prints text that isn't word wrapped.

Here is the script that goes on the phone. If you want to run it by tapping an icon on SpringBoard, you need to set up ssh keys and follow these directions. If you want to run it from MobileTerminal and type your ssh password in every time, change the scp line to "scp ispool USER@IP:/PATH/TO/PUT/FILE." This script can be named anything you like. (Update: I changed the first command, which was really long, to make two shorter lines)
#! /bin/sh
cd /var/mobile
file=/var/mobile/Library/Preferences/com.hitoriblog.pasteboardstacker.plist
text=$(awk 'BEGIN{ RS="</string>"}{gsub(/.*<string>/,"");print;exit}' $file | sed '
s/&lt;/</g
s/&gt;/>/g
s/&amp;/\&/g')
echo $text | tr -d  > ispool
scp -i ~/.ssh/KEYFILE ./ispool USER@IP:/PATH/TO/PUT/FILE
rm ispool
ssh USER@IP iprint

This goes on the Linux box and is called "iprint." If you want to name it something else, change "iprint" on the last line of the previous script to the new name. This uses enscript, but that's optional and you can change that whole line to "cat ispool | lpr" if you like.

#! /bin/sh
cd /PATH/TO/FILE
cat ispool | enscript -h -B -1 --word-wrap --media=A4
rm ispool

Or, if you would like a Prowl notification of the print job...
#! /bin/sh
cd /PATH/TO/FILE
cat ispool | enscript -h -B -1 --word-wrap --media=A4> tmpspool 2>&1
job=$(cat ispool)
output=$(cat tmpspool)
rm ispool tmpspool
curl -k https://prowl.weks.net/publicapi/add -F apikey=xxxxx -F application="Print job:" -F description="$output $job"


Update: I found that piping over ssh does work as it should. I don't know why it wasn't working for me the other day, except maybe because I was figuring out this whole print thing at 2 in the morning. That's what happens when you lay in bed and think "I'd like to print this out but don't want to get up." Anyway, this script can be ran on the phone to print the contents of the clipboard. I still like the above method because it allow me to get the output via Prowl notification, but this is simpler:
#! /bin/sh
file=/var/mobile/Library/Preferences/com.hitoriblog.pasteboardstacker.plist
text=$(awk 'BEGIN{ RS="</string>"}{gsub(/.*<string>/,"");print;exit}' $file

echo $text | tr -d  | slogin -i ~/.ssh/KEYFILE USER@IP lpr

Sunday, December 13, 2009

Need more room on your iPhone's root partition?

I always move all my fonts after every update. It frees up about 100mb of space.
mv /System/Library/Fonts /private/var/ && ln -s /private/var/Fonts /System/Library/Fonts

Saturday, December 12, 2009

Script for disabling some iPhone launch daemons

#! /bin/sh

# test for root
if [ `id -u` != 0 ]; then echo "Oops, you need to be root to run this script"; exit 0; fi

echo "Made by fubaya using description of the daemons by jdys_1991 at http://modmyi.com/forums/file-mods/682255-speed-up-your-iphone-ipod-removing-launch-daemons.html.
Press enter to continue..."
read

echo "This script only works on daemons listed as "Safe", "Conditional", or "Jailbreak" by jdys_1991 on the modmyi forum post. It will list them one by one and ask if you want to disable them by moving them to /var/mobile/LaunchDaemonsBackup.
Press enter to continue..."
read

script=$0
mkdir /var/mobile/LaunchDaemonsBackup
backupdir=/var/mobile/LaunchDaemonsBackup/
daemondir=/System/Library/LaunchDaemons/
ls $daemondir > .daemonlist

###################################################
function daemon {
# edited Dec-12 to send unnecessary output to /dev/null
if echo $1 | grep -i -f .daemonlist > /dev/null
then
echo -------------------------------------
echo $1 | grep -i "# $1" $script
echo
# edited Dec-12 to change "delete" to "disable"
echo "Do you want to disable $1?" y or n?
echo -------------------------------------
read choice
# edited Dec-12 to add confirmation that file was moved
[ $choice = "y" ] && mv $daemondir$1 $backupdir && echo "$1 successfully disabled"
[ $choice = "n" ] && echo "$1 not disabled"
fi
}
daemon com.apple.DumpPanic.plist
daemon com.apple.ReportCrash.DirectoryService.plist
daemon com.apple.ReportCrash.Jetsam.plist
daemon com.apple.ReportCrash.SafetyNet.plist
daemon com.apple.ReportCrash.SimulateCrash.plist
daemon com.apple.ReportCrash.plist
daemon com.apple.CrashHousekeeping.plist
daemon com.apple.aslmanager.plist
daemon com.apple.syslogd.plist
daemon com.apple.powerlog.plist
daemon com.apple.stackshot.server.plist
daemon com.apple.tcpdump.server.plist
daemon com.apple.iqagent.plist
daemon com.apple.mobile.profile_janitor.plist
daemon com.apple.chud.chum.plist
daemon com.apple.chud.pilotfish.plist
daemon com.apple.AddressBook.plist
daemon com.apple.accessoryd.plist
daemon com.apple.apsd.plist
daemon com.apple.dataaccess.dataaccessd.plist
daemon com.apple.datamigrator.plist
daemon com.apple.racoon.plist
daemon com.apple.MobileInternetSharing.plist
daemon com.apple.aggregated.plist
daemon com.apple.AOSNotification.plist
daemon com.apple.AdminLite.plist
daemon com.bigboss.sbsettingsd.plist
daemon com.imalc.insomnia.plist
daemon com.mxweas.MxT2d.plist
daemon com.saurik.Cydia.Startup.plist
daemon org.nodomain.scrobbled.plist
###################################################
rm .daemonlist
num=$(ls $backupdir | wc -l)
echo
echo "$num daemons have been moved to $backupdir. Please reboot for changes to take effect. Do you want me to
delete myself? y or n?"
read choice
[ $choice = "y" ] && echo "Deleting myself..." && sleep 1.5 && echo "blarg.. I'm dead" && exec rm $0
echo "Phwew, Thank you! I'm too young to die. I'll be here at `pwd`/`basename $0` if you need me."
###################################################
# Safe Daemons - These can be deleted by any user, with no adverse effects on the device
# com.apple.DumpPanic.plist (Safe)- Dumps crashes for evaluation by Apple.
# com.apple.ReportCrash.plist (Safe)- Collects data about what caused a crash, what programs were running at the time, etc.
# com.apple.ReportCrash.DirectoryService.plist (Safe)- Collects data about what caused a crash, what programs were running at the time, etc.
# com.apple.ReportCrash.Jetsam.plist (Safe)- Collects data about what caused a crash, what programs were running at the time, etc.
# com.apple.ReportCrash.SafetyNet.plist (Safe)- Collects data about what caused a crash, what programs were running at the time, etc.
# com.apple.ReportCrash.SimulateCrash.plist (Safe)- Collects data about what caused a crash, what programs were running at the time, etc.
# com.apple.CrashHouseKeeping.plist (Safe)- Also deals with crashes.
# com.apple.aslmanager.plist (Safe)- This daemon manages system logs.
# com.apple.syslogd.plist (Safe)- Logs system events.
# com.apple.powerlog.plist (Safe)- This is used to monitor any incompatibilities with 3rd party chargers.
# com.apple.stackshot.server.plist (Safe)- This daemon's function is currently unknown, but removing it has no adverse effects on one's device. Some more information can be found here, although the page is quite technical and isn't very useful to an end-user.
# com.apple.tcpdump.server.plist (Safe)- This daemon is apparently used to dump traffic on a network. Removing this daemon has no adverse effects on one's device.
# com.apple.iqagent.plist (Safe)- This daemon's function is currently unknown, but removing it has no adverse effects on one's device.
# com.apple.mobile.profile_janitor.plist (Safe)- This daemon's function is currently unknown, but removing it has no adverse effects on one's device.
# com.apple.chud.chum.plist (Safe)- This daemon is thought to relate to Apple's CHUD (Computer Hardware Understanding Developer) tools. Removing this daemon will have no adverse effects on your device, unless you are a developer.
# com.apple.chud.pilotfish.plist (Safe)- This daemon is also thought to relate to Apple's CHUD tools. Removing this daemon will have no adverse effects on your device, unless you are a developer.

# Conditional Daemons - These daemons can be disabled by certain users who have no need for some features of their device.
# com.apple.AddressBook.plist (Conditional)- If removed, Contacts in the Phone application will load slightly slower. Disable this if you don't care about that.
# com.apple.accessoryd.plist (Conditional)- If removed, disables accessories like FM radio transmitters, iPhone docks, and AV cables. Accessories will be able to charge your device, but that is all they will be able to do. Remove this if you don't use any of these accessories.
# com.apple.apsd.plist (Conditional)- If removed, Push Notifications will no longer work. Disable this if you don't use Push Notifications.
# com.apple.dataaccess.dataaccessd.plist (Conditional)- If removed, contacts will no longer sync via Exchange or Google Sync. Disable this if you don't use those services.
# com.apple.datamigrator.plist (Conditional)- Used to transfer contacts from SIM card to phone. iPod touch users can delete this.
# com.apple.racoon.plist (Conditional)- Used for Virtual Private Networks. Disable this daemon if you do not use any VPNs.
# com.apple.MobileInternetSharing.plist (Conditional)- Used for Internet Tethering. Disable this if you have an iPod touch or if you aren't interested in tethering.
# com.apple.aggregated.plist (Conditional)- It is believed that this performs some function related to Audio-In. If you have an iPod touch and do not intend to use Audio-In, disable this. iPhone users should leave this alone.
# com.apple.AOSNotification.plist (Conditional)- This daemon deals with MobileMe syncing. If you do not use the MobileMe service, you can disable this.
# com.apple.AdminLite.plist (Conditional)- This daemon tries to return control of your device to you if it thinks that you are waiting for a lengthly process to respond. It does this by force-quitting the process, so if you're tired of your apps crashing and you would rather wait a few seconds for them to finish what they're doing, disable this daemon.

# Jailbreak Daemons - These are daemons installed by jailbreak applications.
# com.bigboss.sbsettingsd.plist (Jailbreak)- Related to SBSettings. I would suggest leaving it alone.
# com.imalc.insomnia.plist (Jailbreak)- Used to keep Insomnia running through resprings and reboots. If you don't want it to do that, disable this. (note from fubaya: disabling this causes the Insomnia toggle to disappear from SBSettings)
# com.mxweas.MxT2d.plist (Jailbreak)- The daemon that allows MxTube to download videos in the background. If disabled, the application will need to be reinstalled; however, if you don't use MxTube and are too lazy to uninstall it, you can disable this daemon.
# com.saurik.Cydia.Startup.plist (Jailbreak)- It's believed that this daemon deals with the AutoInstall trick for installing .deb files. If you don't know what that is and you don't use it, you can disable this daemon.
# org.nodomain.scrobbled.plist (Jailbreak)- The Scrobbler daemon.

Thursday, December 10, 2009

"Free memory"

Nothing is free.

A lot of iPhone users are obsessed with the amount of free memory they have. Apps like SBSettings will show how many megabytes of free memory you have and even allow you to free up more. A script is going around that allows you to free memory every time it drops by 2 megabytes!

This may go against conventional wisdom, but free memory isn't all it's cracked up to be. There is an old unix saying "free memory is wasted memory." The system keeps inactive data in memory in order to make things faster to look up if it's needed again later. This makes your amount of free memory look low, but it's nothing to worry about. If the memory is needed by another program, the kernel will instantly free it.

Example, you run an app which uses a certain library. That library is loaded into memory. You close the app, but the library stays in memory, just hanging out, doing nothing, making your free memory number go lower. If you load another app that uses that library, it will be faster to look up and will cause the app to load faster, but if the memory has been freed, it will be a little slower as the system has to read the library into memory from disk to use it with the app.

You may be able to see and hear an example of this on your home computer. I have 2GB ram on a Linux system that only needs 500MB, but if I boot my computer and open Firefox, it takes a few seconds to load and I will hear my hard drive clicking as it reads information from the disk. If I close it and open it again, it opens instantly with no drive clicking. That's because everything the system needed to run Firefox was still in memory. If I free the pagecache (echo 1 > /proc/sys/vm/drop_caches) my free memory goes up, but if I open Firefox again, it takes longer and my hard drive clicks the same as it did the first time.

Another example closer to topic is the mail app on the iPhone. Open it up and close it with the home button. Open and close it a couple more times and you should see that it opens almost instantly. Now go to SBSettings, free the memory and open mail again. It will be jerkier and slower than normal.

If you don't see a difference, open an email. It will probably take a couple of seconds to load the email. Once it's loaded, go back to your inbox. Now open the email again and it will open instantly. Go back and forth from your inbox to the email a couple of times and the email should open almost instantly every time. Now, without closing mail, use SBSettings to free memory. Then click the email and it will take a while to load. Again, the data in memory has been dumped and it has to be read anew.

This isn't to say that all free memory is bad, obviously. I have a 3G and wish I had as much free memory as the 3Gs guys. If an app needs X amount of memory and the system can't free that much, something will crash. Having extra memory is a good thing, but freeing memory to get the "free memory" number up means the system isn't using the memory the way it was designed. Things aren't being buffered and will need to be read from disk more often, and that's always slower.

But maybe there is some advantage to clearing out the memory before opening a large app. It would keep the system from having to flush the memory and write to disk while the app is opening and could make for a more stable app launch, but I suspect everything else will be slightly slower in general.

Saturday, December 5, 2009

ssh tricks and security

If you have a jailbroken iPhone with ssh installed, you've probably heard about the handful of worms going around that exploits the fact that people don't change their default iPhone passwords.

Of course, the fix is simple. Change your damn password! As an added bit of security, if you have SBSettings, you can get an ssh toggle to turn off ssh access when you're not using it. That should be good enough, but why not go a little further?

First, set up ssh keys using this how-to. It may seem confusing the first time, but it's really very simple. I've done it twice. The first time took a few minutes and the second time took about 30 seconds. I set up keys to login to my computer from my iPhone, and also keys to login to my phone from my computer.

(As a side note; if you have ssh keys setup on a phone or computer that gets lost, you will need to remove it's entry in authorized_keys on the other computer and delete the key.)

Simply setting up ssh keys doesn't help with security yet. We'll get to that, but right now let's look at the tricks you can do with ssh keys, mainly the convenience of being able to login with without a password. Instead, the computers are authenticated with the keys. You can login with slogin:
slogin -i ~/.ssh/SSH_FILENAME user@IP
You can also put that in a script and simply run the script to login.

Another command that works with ssh keys is scp, which is ssh's copy command that copies files between computers:
scp -i ~/.ssh/SSH_FILENAME FILE_TO_COPY user@IP:/PATH/TO/COPY/TO
You can also modify that a little to put it in a script and run the script with the file you want to copy as an argument:
scp -i ~/.ssh/SSH_FILENAME $1 user@IP:/PATH/TO/COPY/TO
Another script to transfer directories:
scp -r -i ~/.ssh/SSH_FILENAME $1 user@IP:/PATH/TO/COPY/TO
You can put all of these on your iPhone and computer and perhaps name the ssh scripts "sshcomp" and "sshphone", the scp scripts "tocomp" and "tophone", and the "ssh -r" scripts to recursively copy a directory "tocompr" and "tophoner" and never have to worry about typing in long ssh or scp commands again.

Now, let's get back to ssh security. Once the keys are working, let's look at the ssh setup. The file we want to have a look at should be located at /etc/ssh/sshd_config.

There are a few lines that can greatly enhance our security. They are probably commented out and look like "# Something", so you will need to remove the "#" in order for the option to take effect. These are the options we want to look at:

Port 22 - The default port for ssh is 22 and everyone knows it. Anyone port scanning your computer or phone will probably probe ports for common services like email, web server and ssh, and it may only take one or two seconds to scan the common ports. Well, computers have 65535 ports, so why run ssh on the ssh port? Pick a random port!

(EDIT: I found that editing /etc/ssh/sshd_config didn't change the port on the iPhone. After a little google work, I found that launchd overides the port configuration, but you can change the phone's ssh listening port by editing /etc/services. You will see two lines "ssh 22/udp" and "ssh 22/tcp". Change both "22"s to whatever port you want to use.)

Don't forget to allow that port in firewalls and routers and specify it when using scp or ssh. To specify ports for those programs, use -P for scp and -p for slogin. Examples using port 5555:
scp -i ~/.ssh/SSH_FILENAME -P 5555 $1 user@IP:/PATH/TO/COPY/TO
slogin -i ~/.ssh/SSH_FILENAME -p 5555 user@IP
PermitRootLogin no - Set this as no and login as a regular user and use "su" instead.
PubkeyAuthentication yes - These are the ssh keys I've been talking about. We want to use those.
PasswordAuthentication no - This is how you normally login through ssh. You can turn this off so the only way to login is with the ssh keys. Even if someone knows your password, they can't get in without the keys.

Once you're finished editing the config file on your computer, restart the ssh daemon by running:
/etc/rc.d/rc.sshd stop
/etc/rc.d/rc.sshd start
I'm not certain how to do this on the iPhone. sshd is launched demand by launchd and I'm not sure when the config file is read. I would assume it's read at launch and that you can turn ssh off and back on in SBSettings, but I'm not familiar enough with launchd and ssh on the phone to say for sure, so you may have to reboot the phone.

(EDIT: I found that flipping the SBSettings ssh toggle off and back on will load the new preferences)

Once you're all finished, enjoy being more secure!

Thursday, December 3, 2009

Script for deleting iPhone language packs

This script is outdated, please see the script here. Also, don't use the version of this script found on sinful iphone forums by Monsieurtalbot. He made a few ugly edits to the echo commands and claimed to have written the script. When called out, he then claimed to have rewritten it and fixed a bug that made Terminal crash, but a simple look at the code shows no rewrite. It's the same (outdated) script except uglier due to poorly formatted echos.

#! /bin/sh
# Feb 9 2010
echo
# test for root
if [ `id -u` != 0 ]; then echo "Oops, you need to be root to run this script"; exit 0; fi

echo "Let's delete a few thousand language packs.
You will have several chances to back out
before anything is deleted but if you want
to stop at any time hit ctrl c. On the
iPhone keyboard, control is a black dot
that is found on the far right when you
tap 123 then # =."
echo
echo "If you want to see how it runs without
making any changes, just answer no when it
asks you which languages to delete."
echo
echo "Press enter to begin."
read

echo "Please contact me at ijdmas at gmail dotcom
if this script asks you to delete a language
but doesn't list that language. It will
look like this:
\"Do you want to delete:? y or n?\""
echo
echo "This is due to someone using the long name
for a language which Ive not seen yet.
Example, if Vulcan used to be vu.lproj
and someone starts using Vulcan.lproj,
it will cause that problem. If it
happens, it is safe to answer no and
continue."
echo
echo "Press enter to begin."
read

# create temp files
touch .langlist_fubaya .keeplist_fubaya .deletelist_fubaya .alllist_fubaya

# update database, locate all lproj, and grep directories minus English
echo "Searching for language packs. Please wait..."
updatedb && locate lproj | grep -E lproj$ | grep -v -i English | grep -v -i \/en > .alllist_fubaya

# get a list of all languages
cat .alllist_fubaya | while read file; do basename "$file"; done | grep -E lproj$ | sort | uniq > .langlist_fubaya
echo ---------------- >> langpack.log
echo langlist >> langpack.log
cat .langlist_fubaya >> langpack.log

# display true names beside the language codes
# ask user if they want to keep them or not, put keepers in ".keeplist_fubaya" file
echo ---------------- >> langpack.log
for i in $(cat .langlist_fubaya) ; do
q=$(cat $0 | grep -i "\# $i" | tr -d \#)
[ -n "$q" ] && echo "Delete:$q? y or n?" || echo "Delete: $i (unrecognized)? y or n?"
read choice

# make sure "y" or "n" was entered, else keep repeating the question
while [[ $choice != 'y' ]] && [[ $choice != 'n' ]]
do
[ -n "$q" ] && echo "Delete:$q?" y or n? || echo "Delete: $i (unrecognized)?" y or n?
read choice
done

echo "delete:$i: $choice" >> langpack.log
[ $choice = "n" ] && echo $i >> .keeplist_fubaya
echo
done
echo ---------------- >> langpack.log
echo keeplist >> langpack.log
cat .keeplist_fubaya >> langpack.log

# put master list into delete list, filtering out keepers
cat .alllist_fubaya | grep -v -f ./.keeplist_fubaya > .deletelist_fubaya
# show final list of lang packs and confirm the user wants to delete them
echo
echo "Please wait while I compile a list of languages to delete. You will be asked for confirmation before anything is deleted"
echo ---------------- >> langpack.log
echo deletelist >> langpack.log
cat .deletelist_fubaya >> langpack.log
echo
echo -------------------------------------
cat .deletelist_fubaya | while read file; do basename "$file"; done | grep -E lproj$ | sort | uniq | tr '\n' ' '
echo
echo -------------------------------------
echo "This is your last chance. Are you sure you want to delete the language packs listed? Type y or n"

read choice
if [ $choice = "y" ]
then
# do the deed
echo ---------------- >> langpack.log
echo "final confirmation: $choice" >> langpack.log
echo ---------------- >> langpack.log
echo "Please wait while I delete the chosen language packs..." && while read file; do rm -rf "$file"; done < .deletelist_fubaya

# how many did we delete?
num=$(cat .deletelist_fubaya | wc -l)
# clean up temp files
rm .langlist_fubaya .keeplist_fubaya .deletelist_fubaya .alllist_fubaya

echo
echo "$num language pack directories have been
deleted. A log file has been created at
`pwd`/langpack.log. Please hang on to
that until you are sure there are no
problems. My contact information is at
the top of the log file. The only other
thing left is me, this script located at
`pwd`/`basename $0`. Do you want me to
delete myself? y or n?"

read choice
[ $choice = "y" ] && echo "Deleting myself..." && sleep 1.5 && echo "blarg.. I'm dead" && exec rm $0
echo "Phwew, Thank you! I'm too young to die. I'll be here at `pwd`/`basename $0` if you need me."

else # if user selected "n" to deleting the language packs
rm .langlist_fubaya .keeplist_fubaya .deletelist_fubaya .alllist_fubaya
echo "Ok, I won't delete anything. If you made a mistake, just run me again."
fi

# Arabic.lproj
# Chinese.lproj
# Croatian.lproj
# Czech.lproj
# Danish.lproj
# Dutch.lproj
# Finnish.lproj
# French.lproj
# German.lproj
# Greek.lproj
# Hebrew.lproj
# Indonesian.lproj
# Italian.lproj
# Japanese.lproj
# Korean.lproj
# Malay.lproj
# Norwegian.lproj
# Polish.lproj
# Portuguese.lproj
# Romanian.lproj
# Russian.lproj
# Slovak.lproj
# Spanish.lproj
# Swedish.lproj
# Thai.lproj
# Turkish.lproj
# Ukrainian.lproj
# ar.lproj (Arabic)
# cs.lproj (Czech)
# cs_CZ.lproj (Czech)
# da.lproj (Danish)
# da_DK.lproj (Danish)
# de.lproj (German)
# de_DE.lproj (German)
# el.lproj (Greek)
# el_GR.lproj (Greek)
# es.lproj (Spanish)
# es_419.lproj (Spanish)
# es_ES.lproj (Spanish)
# fi.lproj (Finnish)
# fi_FI.lproj (Finnish)
# fr.lproj (French)
# fr_CA.lproj (French)
# fr_FR.lproj (French)
# he.lproj (Hebrew)
# hr.lproj (Croatian)
# hr_HR.lproj (Croatian)
# hu.lproj (Hungary)
# id.lproj (Indonesian)
# it.lproj (Italian)
# it_IT.lproj (Italian)
# ja.lproj (Japanese)
# ko.lproj (Korean)
# ms.lproj (Malay)
# nl.lproj (Dutch)
# nl_NL.lproj (Dutch)
# no.lproj (Norwegian)
# no_NO.lproj (Norwegian)
# pl.lproj (Polish)
# pl_PL.lproj (Polish)
# pt.lproj (Portuguese)
# pt_PT.lproj (Portuguese)
# ro.lproj (Romanian)
# ro_RO.lproj (Romanian)
# ru.lproj (Russian)
# ru_RU.lproj (Russian)
# rus.lproj (Russian)
# sk.lproj (Slovak)
# sk_SK.lproj (Slovak)
# sp.lproj (Spanish)
# sp_es.lproj (Spanish)
# sv.lproj (Swedish)
# sv_SE.lproj (Swedish)
# th.lproj (Thai)
# tr.lproj (Turkish)
# tr_TR.lproj (Turkish)
# uk.lproj (Ukranian)
# zh-Hans.lproj (Chinese)
# zh-Hant.lproj (Chinese)
# zh_CN.lproj (Chinese)
# zh_HK.lproj (Chinese)
# zh_TW.lproj (Chinese)
# end of script

Monday, November 23, 2009

Deleting iPhone language packs

Every iPhone application has the option of including language packs. There come in the form of a seperate directory for every language the app supports. Inside those directories are files with various strings in that language that the app may use. Some apps may not support any additional languages and some may support 20.

They say (and I don't know who *they* are) that removing them can increase the phone's performance. I don't know how accurate that is, but it obviously does increase free space on the phone.

So here is one way to remove them from MobileTerminal, or any other command line program that can run commands on the phone.

First, log in as root by whatever means you wish. Either su in MobileTerminal, ssh root@IP, or whatever.

Run this command to update the locate database: updatedb

Now, we want to build a list of directories to delete by using the locate command to find all the language packs. Luckily, they are all found in *.lproj directories, so we start with locate lproj.

The output will include all the files in an .lproj directory, so let's use a grep regular expression to get only the directories. locate lproj | grep -E lproj$ will output only files that end with lproj, so it will output English.lproj, but not English.lproj/somefile.txt

Now we want to filter out the directories we want to keep. In my case, all I want to keep is English. On the iPhone, English can be either en.lproj or English.lproj so I piped the output to grep -v to filter out both: grep -E -v -i '(en.l|English)'

It may be simpler to grep the one at a time with -v and -i. "-v" is like a 'reverse grep' which displays everything except the string you specify and "-i" makes it case insensitive.

The official iPhone apps usually use long names like "English" and "Italian" while other apps will often use "en" and "it", so be sure to look for long and short names.

So, if you wanted to keep German, you could run this to save it to a text file:
locate lproj | grep -E proj$ | grep -v -i "XXXXXX.lproj" > langpacks.txt
Just add | grep -v -i "XXXXXX.lproj" for any languages you don't want deleted, and remember to add a grep for both long and short names.

Once you're sure everything looks safe to delete, then run this command:
while read file; do rm -rf "$file"; done < langpacks.txt
To recap: if you're certain you only want English languages on your phone, run this:
updatedb 
locate lproj | grep -E proj$ | grep -E -v -i '(en.l|English)' > langpacks.txt
while read file; do rm -rf "$file"; done < langpacks.txt
I deleted over 3000 language pack directories with this, and I only have less than 2 pages of apps installed.

Blog Archive