source: trunk/debathena/debathena/firefox-wrapper/firefox.sh @ 25134

Revision 25134, 8.7 KB checked in by jdreed, 13 years ago (diff)
In firefox-wrapper: * Use modutil to detect when a user has borked their security database (Trac: #698) * Add dependency on libnss3-tools for the above change
Line 
1#!/bin/sh
2#
3# $Id: firefox.sh,v 1.8 2007-06-22 15:13:03 rbasch Exp $
4# Firefox wrapper script for Athena.
5
6moz_progname=firefox
7
8# Profile directory's parent.
9prof_parent=$HOME/.mozilla/firefox
10
11# testlock is used to test whether the profile directory's lock file
12# is actually locked.
13testlock=/usr/bin/testlock
14
15# Get the profile directory path, by parsing the profiles.ini file.
16get_profdir () {
17  inifile="$prof_parent/profiles.ini"
18  if [ ! -s "$inifile" ]; then
19    return 1
20  fi
21  awk -F= -v parent="$prof_parent" '
22    BEGIN {
23      nprofiles = 0;
24      use_default = 1;
25    }
26 
27    $1 ~ /^\[.*\]$/ {
28      section = substr($1, 2, length($1) - 2);
29      if (section ~ /^Profile[0-9]*$/) {
30        id = section;
31        nprofiles++;
32      }
33    }
34    $1 == "StartWithLastProfile" {
35      if (section == "General")
36        use_default = int($2);
37    }
38    $1 == "Name"       { a[id, "name"] = $2; }
39    $1 == "IsRelative" { a[id, "isrelative"] = $2; }
40    $1 == "Path"       { a[id, "path"] = $2; }
41    $1 == "Default"    { a[id, "default"] = $2; }
42 
43    END {
44      count = 0;
45      default_id = "";
46      for (i = 0; i < nprofiles; i++) {
47        id = "Profile" i;
48        if (a[id, "name"] != "" && a[id, "isrelative"] != "" &&
49            a[id, "path"] != "") {
50          count++;
51          if (int(a[id, "default"]) != 0)
52            default_id = id;
53        }
54      }
55      if (use_default != 0 && default_id != "")
56        id = default_id;
57      else if (nprofiles == 1 && count == 1)
58        id = "Profile0";
59      else
60        id = "";
61      if (id != "") {
62        if (int(a[id, "isrelative"]) == 0)
63          print a[id, "path"];
64        else
65          print parent "/" a[id, "path"];
66      }
67    }' $inifile
68}
69
70# Prompt the user on how to deal with an existing locked profile when
71# no running Firefox window can be found, and take action accordingly.
72# Parameter 1 is the profile directory path.
73# If the function returns, the lock file(s) will have been removed per
74# the user's choice, and the caller should continue.  Otherwise, the
75# process will exit.
76dispose_lock () {
77  lockfile="$1/.parentlock"
78  locklink="$1/lock"
79  # Extract the IP address and PID from the contents of the symlink.
80  # Also note whether firefox used fnctl() to lock .parentlock,
81  # which is indicated with a leading '+' in the PID.
82  eval `ls -l "$locklink" | awk '{
83    if (split($NF, a, ":") == 2)
84      printf("lock_ip=%s ; lock_pid=%d ; use_fcntl=%d\n",
85              a[1], int(a[2]), (substr(a[2], 1, 1) == "+")); }'`
86
87  # If we cannot recognize the link contents, just continue.
88  if [ -z "$lock_ip" ]; then
89    return 0
90  fi
91
92  local=false
93  if [ "$use_fcntl" -ne 0 ]; then
94    # An fcntl()-style lock was acquired; check it.
95    if [ -f "$lockfile" ]; then
96      # testlock tests whether there is a write lock on the file.
97      # If so, it outputs the locker's PID, and exits with status 2.
98      # If the lock is held by a process running on another host, the
99      # PID will be 0.
100      pid=`$testlock "$lockfile" 2>/dev/null`
101      if [ $? -ne 2 ]; then
102        # File is not locked, remove the symlink and continue.
103        rm -f "$locklink"
104        return 0
105      fi
106      # The file is locked.  If the lock is held by a process on
107      # this machine, the locker pid will be non-0.
108      if [ "$pid" -ne 0 ]; then
109        local=true
110      fi
111    fi
112  else
113    # Handle an old-style (symlink) lock.
114    case "$lock_ip" in
115    127.*)
116      if ! /usr/bin/fs whichcell "$locklink" > /dev/null 2>&1 ; then
117        local=true
118      fi
119      ;;
120    *)
121      my_host=`hostname`
122      if [ "$lock_ip" = "`host $my_host | awk '{ print $NF; }'`" ]; then
123        # Lock is held on this machine.
124        local=true
125      fi
126      ;;
127    esac
128  fi
129
130  if [ "$local" = true ]; then
131    # The lock is held by a process on this machine; check if it is
132    # still running.
133    if kill -0 $lock_pid 2>/dev/null ; then
134      # Lock is held by a running process.
135      lock_host="this machine"
136    else
137      # Process is no longer running.  Nuke the lock and continue.
138      rm -f "$lockfile" "$locklink"
139      return 0
140    fi
141  else
142    # The lock is held by a process on another machine.  Get its
143    # host name.
144    case "$lock_ip" in
145    127.*)
146      lock_host="another machine"
147      ;;
148    *)
149      lock_host=`host $lock_ip | \
150        sed -n -e 's/^.*domain name pointer \(.*\)$/\1/p' | \
151        sed -e 's/\.*$//' | tr '[A-Z]' '[a-z]'`
152      ;;
153    esac
154    if [ -z "$lock_host" ]; then
155      lock_host="$lock_ip"
156    fi
157  fi
158
159  dialog_text="
160  Your Firefox profile directory is locked by process $lock_pid 
161  on $lock_host. 
162"
163
164  dialog_text="$dialog_text
165  If you select \"OK\" to continue, the profile will be forcibly 
166  unlocked; if the process holding the lock is still running, 
167  you risk corrupting your profile.
168
169  If you are not certain whether your Firefox process is still
170  running on $lock_host, select \"Cancel\" to exit 
171  without starting Firefox. 
172"
173
174  zenity --title "Firefox profile locked" --question --text "$dialog_text"
175
176  case $? in
177  0)
178    rm -f "$lockfile" "$locklink"
179    ;;
180  *)
181    exit 1
182    ;;
183  esac
184}
185
186# Deal with a corrupted security database
187fix_profile () {
188  dialog_ok_text="
189  Your Firefox profile was corrupted and has been repaired.
190  You will need to obtain new MIT Personal Certificates.
191
192  To avoid this problem in the future, please be sure to
193  completely quit Firefox (File->Quit or Ctrl-Q) before
194  logging out of an Athena workstation.
195
196  To continue using Firefox, click \"OK\".
197"
198  dialog_err_text="
199  Your Firefox profile is corrupted and cannot be repaired.
200  Please try running the following command in the Terminal:
201
202         mv ~/.mozilla ~/.mozilla-old
203
204  Then re-launch Firefox. 
205
206  Be sure to completely quit Firefox before
207  logging out of Athena.
208"
209  dbdir="$1"
210  files="cert8.db key3.db secmod.db"
211  found=0
212  for f in $files; do
213    f="$dbdir/$f"
214    if [ -f "$f" ]; then
215        found=1
216    fi
217    rm -f $f
218  done
219  if ! modutil -create -force -dbdir "$dbdir"; then
220    zenity --error --title "Firefox profile corrupted" --text "$dialog_err_text"
221    exit 1
222  else
223    if [ $found -eq 1 ]; then
224      zenity --info --title "Firefox profile repaired" --text "$dialog_ok_text"
225    fi
226  fi
227}
228
229
230# Give a warning if we're running on a dialup machine.
231if [ -x /etc/athena/dialuptype ]; then
232  cat << \EOF
233
234*** PLEASE DO NOT RUN FIREFOX ON THE DIALUPS! ***
235
236Firefox is a very large and resource-intensive program, and it is
237not appropriate to run it on a dialup machine.
238
239Please run Firefox on your local machine rather than on a dialup.
240
241Thank you.
242
243EOF
244fi
245
246# If this is the first time the user has run firefox, create
247# the top-level profile directory now, so that we can set
248# the ACL appropriately.
249if [ ! -d "$prof_parent" ]; then
250  mkdir -p "$prof_parent"
251  /usr/bin/fs setacl "$prof_parent" "$ATHENA_USER" all \
252    -clear >/dev/null 2>&1
253fi
254
255# We want Firefox to download files for helper applications to
256# /var/tmp instead of /tmp, so that users have a better chance
257# of retrieving them later.
258if [ -z "$TMPDIR" ]; then
259  TMPDIR=/var/tmp
260  export TMPDIR
261fi
262
263# If the user specified any option, skip the check for a running
264# Firefox, and invoke the program now.
265case "$1" in
266-*)
267  exec /usr/bin/firefox.debathena-orig "$@"
268  ;;
269esac
270
271if [ "${MOZ_NO_REMOTE+set}" = "set" ]; then
272  found_running=false
273else
274  # See if there is a running instance of Firefox, by trying to
275  # "ping" it using X properties.
276  user="${LOGNAME:+-u $LOGNAME}"
277  /usr/bin/firefox.debathena-orig $user -a "$moz_progname" -remote \
278    "ping()" >/dev/null 2>&1
279  case $? in
280  0)
281    # We successfully pinged it.
282    found_running=true
283    ;;
284  2)
285    # This is the expected status when there is no running firefox window.
286    found_running=false
287    ;;
288  *)
289    # An unexpected error occurred.
290    found_running=error
291    ;;
292  esac
293fi
294
295# If Firefox is not running, check for a (possibly stale) lock on
296# the profile directory.
297if [ $found_running != true ]; then
298  profdir=`get_profdir`
299  if [ -n "$profdir" ]; then
300    # firefox now uses fcntl()-style locking on .parentlock, but an
301    # apparent openafs bug leaves the lock set after the program exits.
302    # Fortunately, it still maintains the "lock" symlink (which may
303    # also have been left from running a pre-1.5.0 firefox on the
304    # profile), so use its presence to help detect a stale lock.
305    if [ -h "$profdir/lock" ]; then
306      # The symlink exists, so the profile is (potentially) locked.
307      dispose_lock "$profdir"
308    else
309      # The symlink is gone, so just nuke the lock file, to work around
310      # the aforementioned openafs bug.
311      rm -f "$profdir/.parentlock"
312    fi
313    # Now check for corrupted profiles
314    if hash modutil > /dev/null 2>&1 && ! modutil -list -dbdir $profdir > /dev/null 2>&1; then
315        fix_profile "$profdir"
316    fi
317  fi
318fi
319
320exec /usr/bin/firefox.debathena-orig "$@"
Note: See TracBrowser for help on using the repository browser.