attempting to get parms with spaces to still pass on through as single parameters...
[feisty_meow.git] / scripts / core / functions.sh
1 #!/bin/bash
2
3 # This defines some general, useful functions.
4
5 # test whether we've been here before or not.
6 skip_all=
7 function_sentinel &>/dev/null
8 if [ $? -eq 0 ]; then
9   # there was no error, so we can skip the inits.
10   if [ ! -z "$SHELL_DEBUG" ]; then
11     echo skipping functions.sh because already defined.
12   fi
13   skip_all=yes
14 fi
15
16 if [ -z "$skip_all" ]; then
17   if [ ! -z "$SHELL_DEBUG" ]; then
18     echo function definitions begin...
19   fi
20   
21   # a handy little method that can be used for date strings.  it was getting
22   # really tiresome how many different ways the script did the date formatting.
23   function date_stringer() {
24     local sep="$1"; shift
25     if [ -z "$sep" ]; then sep='_'; fi
26     date +"%Y$sep%m$sep%d$sep%H%M$sep%S" | tr -d '/\n/'
27   }
28   
29   # makes a directory of the name specified and then tries to change the
30   # current directory to that directory.
31   function mcd() {
32     if [ ! -d "$1" ]; then mkdir -p "$1"; fi
33     cd "$1"
34   }
35
36   # checks the result of the last command that was run, and if it failed,
37   # then this complains and exits from bash.  the function parameters are
38   # used as the message to print as a complaint.
39   function check_result()
40   {
41     if [ $? -ne 0 ]; then
42       echo -e "failed on: $*"
43       exit 1
44     fi
45   }
46
47   # locates a process given a search pattern to match in the process list.
48   function psfind() {
49     local PID_DUMP="$(mktemp "$TMP/zz_pidlist.XXXXXX")"
50     local PIDS_SOUGHT=()
51     local patterns=($*)
52     if [ "$OS" == "Windows_NT" ]; then
53       # needs to be a windows format filename for 'type' to work.
54       if [ ! -d c:/tmp ]; then
55         mkdir c:/tmp
56       fi
57       # windows7 magical mystery tour lets us create a file c:\\tmp_pids.txt, but then it's not really there
58       # in the root of drive c: when we look for it later.  hoping to fix that problem by using a subdir, which
59       # also might be magical thinking from windows perspective.
60       tmppid=c:\\tmp\\pids.txt
61       # we have abandoned all hope of relying on ps on windows.  instead
62       # we use wmic to get full command lines for processes.
63       # this does not exist on windows home edition.  we are hosed if that's
64       # what they insist on testing on.
65       wmic /locale:ms_409 PROCESS get processid,commandline </dev/null >"$tmppid"
66       local flag='/c'
67       if [ ! -z "$(uname -a | grep "^MING" )" ]; then
68         flag='//c'
69       fi
70       # we 'type' the file to get rid of the unicode result from wmic.
71       cmd $flag type "$tmppid" >$PID_DUMP
72       \rm "$tmppid"
73       local CR='\r'  # embedded carriage return.
74       local appropriate_pattern="s/^.*  *\([0-9][0-9]*\)[ $CR]*\$/\1/p"
75       for i in "${patterns[@]}"; do
76         PIDS_SOUGHT+=$(cat $PID_DUMP \
77           | grep -i "$i" \
78           | sed -n -e "$appropriate_pattern")
79         if [ ${#PIDS_SOUGHT[*]} -ne 0 ]; then
80           # we want to bail as soon as we get matches, because on the same
81           # platform, the same set of patterns should work to find all
82           # occurrences of the genesis java.
83           break;
84         fi
85       done
86     else
87       /bin/ps $extra_flags wuax >$PID_DUMP
88       # pattern to use for peeling off the process numbers.
89       local appropriate_pattern='s/^[-a-zA-Z_0-9][-a-zA-Z_0-9]*  *\([0-9][0-9]*\).*$/\1/p'
90       # remove the first line of the file, search for the pattern the
91       # user wants to find, and just pluck the process ids out of the
92       # results.
93       for i in "${patterns[@]}"; do
94         PIDS_SOUGHT=$(cat $PID_DUMP \
95           | sed -e '1d' \
96           | grep -i "$i" \
97           | sed -n -e "$appropriate_pattern")
98         if [ ${#PIDS_SOUGHT[*]} -ne 0 ]; then
99           # we want to bail as soon as we get matches, because on the same
100           # platform, the same set of patterns should work to find all
101           # occurrences of the genesis java.
102           break;
103         fi
104       done
105     fi
106     if [ ! -z "$PIDS_SOUGHT" ]; then echo "$PIDS_SOUGHT"; fi
107     /bin/rm $PID_DUMP
108   }
109   
110   # finds all processes matching the pattern specified and shows their full
111   # process listing (whereas psfind just lists process ids).
112   function psa() {
113     if [ -z "$1" ]; then
114       echo "psa finds processes by pattern, but there was no pattern on the command line."
115       return 1
116     fi
117     p=$(psfind "$1")
118     if [ -z "$p" ]; then
119       # no matches.
120       return 0
121     fi
122     echo ""
123     echo "Processes containing \"$1\"..."
124     echo ""
125     if [ -n "$IS_DARWIN" ]; then
126       unset fuzil_sentinel
127       for i in $p; do
128         # only print the header the first time.
129         if [ -z "$fuzil_sentinel" ]; then
130           ps $i -w -u
131         else
132           ps $i -w -u | sed -e '1d'
133         fi
134         fuzil_sentinel=true
135       done
136     else 
137       # cases besides mac os x's darwin.
138       extra_flags=
139       if [ "$OS" = "Windows_NT" ]; then
140         # special case for windows.
141         extra_flags=-W
142         ps | head -1
143         for curr in $p; do
144           ps $extra_flags | grep "$curr" 
145         done
146       else
147         # normal OSes can handle a nice simple query.
148         ps wu $p
149       fi
150     fi
151   }
152   
153   # an unfortunately similarly named function to the above 'ps' as in process
154   # methods, but this 'ps' stands for postscript.  this takes a postscript file
155   # and converts it into pcl3 printer language and then ships it to the printer.
156   # this mostly makes sense for an environment where one's default printer is
157   # pcl.  if the input postscript causes ghostscript to bomb out, there has been
158   # some good success running ps2ps on the input file and using the cleaned
159   # postscript file for printing.
160   function ps2pcl2lpr() {
161     for $i in $*; do
162       gs -sDEVICE=pcl3 -sOutputFile=- -sPAPERSIZE=letter "$i" | lpr -l 
163     done
164   }
165   
166   function fix_alsa() {
167     sudo /etc/init.d/alsasound restart
168   }
169   
170   # switches from a /X/path form to an X:/ form.  this also processes cygwin paths.
171   function unix_to_dos_path() {
172     # we usually remove dos slashes in favor of forward slashes.
173     if [ ! -z "$SERIOUS_SLASH_TREATMENT" ]; then
174       # unless this flag is set, in which case we force dos slashes.
175       echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/' | sed -e 's/\//\\/g'
176     else
177       echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/'
178     fi
179   }
180   
181   # switches from an X:/ form to an /X/path form.
182   function dos_to_unix_path() {
183     # we always remove dos slashes in favor of forward slashes.
184     echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\([a-zA-Z]\):\/\(.*\)/\/\1\/\2/'
185   }
186
187   # returns a successful value (0) if this system is debian or ubuntu.
188   function debian_like() {
189     # decide if we think this is debian or ubuntu or a variant.
190     DEBIAN_LIKE=$(if [ ! -z "$(grep -i debian /etc/issue)" \
191         -o ! -z "$(grep -i ubuntu /etc/issue)" ]; then echo 1; else echo 0; fi)
192     if [ $DEBIAN_LIKE -eq 1 ]; then
193       # success; this is debianish.
194       return 0
195     else
196       # this seems like some other OS.
197       return 1
198     fi
199   }
200   
201   # su function: makes su perform a login.
202   # for some OSes, this transfers the X authority information to the new login.
203   function su() {
204     if debian_like; then
205       # debian currently requires the full version which imports X authority
206       # information for su.
207   
208       # get the x authority info for our current user.
209       source $FEISTY_MEOW_SCRIPTS/x_win/get_x_auth.sh
210   
211       if [ -z "$X_auth_info" ]; then
212         # if there's no authentication info to pass along, we just do a normal su.
213         /bin/su -l $*
214       else
215         # under X, we update the new login's authority info with the previous
216         # user's info.
217         (unset XAUTHORITY; /bin/su -l $* -c "$X_auth_info ; export DISPLAY=$DISPLAY ; bash")
218       fi
219     else
220       # non-debian supposedly doesn't need the extra overhead any more.
221       # or at least suse doesn't, which is the other one we've tested on.
222       /bin/su -l $*
223     fi
224   
225     # relabel the console after returning.
226     bash $FEISTY_MEOW_SCRIPTS/tty/label_terminal_with_infos.sh
227   }
228   
229   # sudo function wraps the normal sudo by ensuring we replace the terminal
230   # label if they're doing an su with the sudo.
231   function sudo() {
232     local first_command="$1"
233     /usr/bin/sudo "$@"
234     if [ "$first_command" == "su" ]; then
235       # yep, they were doing an su, but they're back now.
236       bash $FEISTY_MEOW_SCRIPTS/tty/label_terminal_with_infos.sh
237     fi
238   }
239   
240   # trashes the .#blah files that cvs and svn leave behind when finding conflicts.
241   # this kind of assumes you've already checked them for any salient facts.
242   function clean_cvs_junk() {
243     for i in $*; do
244       find $i -follow -type f -iname ".#*" -exec perl $FEISTY_MEOW_SCRIPTS/files/safedel.pl {} ";" 
245     done
246   }
247
248   # overlay for nechung binary so that we can complain less grossly about it when it's missing.
249   function nechung() {
250     local wheres_nechung=$(which nechung 2>/dev/null)
251     if [ -z "$wheres_nechung" ]; then
252       echo "The nechung oracle program cannot be found.  You may want to consider"
253       echo "rebuilding the feisty meow applications with this command:"
254       echo "bash $FEISTY_MEOW_SCRIPTS/generator/bootstrap_build.sh"
255     else
256       $wheres_nechung
257     fi
258   }
259   
260   # recreates all the generated files that the feisty meow scripts use.
261   function regenerate() {
262     bash $FEISTY_MEOW_SCRIPTS/core/bootstrap_shells.sh
263     echo
264     nechung
265   }
266
267   # generates a random password where the first parameter is the number of characters
268   # in the password (default 20) and the second parameter specifies whether to use
269   # special characters (1) or not (0).
270   # found function at http://legroom.net/2010/05/06/bash-random-password-generator
271   function random_password()
272   {
273     [ "$2" == "0" ] && CHAR="[:alnum:]" || CHAR="[:graph:]"
274     cat /dev/urandom | tr -cd "$CHAR" | head -c ${1:-32}
275     echo
276   }
277
278   # a wrapper for the which command that finds items on the path.  some OSes
279   # do not provide which, so we want to not be spewing errors when that
280   # happens.
281   function whichable()
282   {
283     to_find="$1"; shift
284     which which &>/dev/null
285     if [ $? -ne 0 ]; then
286       # there is no which command here.  we produce nothing due to this.
287       echo
288     fi
289     echo $(which $to_find)
290   }
291
292   # copies a set of custom scripts into the proper location for feisty meow
293   # to merge their functions and aliases with the standard set.
294   function recustomize()
295   {
296     user="$1"; shift
297     if [ -z "$user" ]; then
298       # use our default example user if there was no name provided.
299       user=fred
300     fi
301     if [ ! -d "$FEISTY_MEOW_DIR/customizing/$user" ]; then
302       echo "The customization folder provided for $user should be:"
303       echo "  '$FEISTY_MEOW_DIR/customizing/$user'"
304       echo "but that folder does not exist.  Skipping customization."
305       return 1
306     fi
307     regenerate >/dev/null
308     pushd "$FEISTY_MEOW_GENERATED/custom" &>/dev/null
309     local incongruous_files="$(bash "$FEISTY_MEOW_SCRIPTS/files/list_non_dupes.sh" "$FEISTY_MEOW_DIR/customizing/$user" "$FEISTY_MEOW_GENERATED/custom")"
310     if [ ${#incongruous_files} -ge 1 ]; then
311       echo "cleaning unknown older overrides..."
312       perl "$FEISTY_MEOW_SCRIPTS/files/safedel.pl" $incongruous_files
313       echo
314     fi
315     popd &>/dev/null
316     echo "copying custom overrides for $user"
317     mkdir "$FEISTY_MEOW_GENERATED/custom" 2>/dev/null
318     perl "$FEISTY_MEOW_SCRIPTS/text/cpdiff.pl" "$FEISTY_MEOW_DIR/customizing/$user" "$FEISTY_MEOW_GENERATED/custom"
319     regenerate
320   }
321
322   function add_cygwin_drive_mounts() {
323     for i in c d e f g h q z ; do
324       ln -s /cygdrive/$i $i
325     done
326   }
327
328
329   # takes a file to modify, and then it will replace any occurrences of the
330   # pattern provided as the second parameter with the text in the third
331   # parameter.
332   function replace_pattern_in_file()
333   {
334     local file="$1"; shift
335     local pattern="$1"; shift
336     local replacement="$1"; shift
337     if [ -z "$file" -o -z "$pattern" -o -z "$replacement" ]; then
338       echo "replace_pattern_in_file: needs a filename, a pattern to replace, and the"
339       echo "text to replace that pattern with."
340       return 1
341     fi
342     sed -i -e "s%$pattern%$replacement%g" "$file"
343   }
344
345   function function_sentinel() { return 0; }
346   
347   if [ ! -z "$SHELL_DEBUG" ]; then echo function definitions end....; fi
348   
349 fi
350