lib.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. ##############################################################################
  2. #
  3. # Library Functions
  4. #
  5. ##############################################################################
  6. init () {
  7. #
  8. # Debug mode shows more verbose output to screen and log files.
  9. # Value: yes or no (y / n)
  10. #
  11. DEBUG=no
  12. #
  13. # Syslog style log messages
  14. #
  15. if ! defined LOGDATEFORMAT
  16. then
  17. LOGDATEFORMAT="%b %e %H:%M:%S"
  18. fi
  19. if ! defined LOG_FILE
  20. then
  21. LOG_FILE=$0.log
  22. fi
  23. #
  24. # Enable / disable logging to a file
  25. # Value: yes or no (y / n)
  26. #
  27. if ! defined LOG_ENABLED
  28. then
  29. LOG_ENABLED=no
  30. fi
  31. if ! defined SYSLOG_ENABLED
  32. then
  33. SYSLOG_ENABLED=no
  34. fi
  35. if ! defined SYSLOG_TAG
  36. then
  37. SYSLOG_TAG=$0
  38. fi
  39. #
  40. # Use colours in output.
  41. #
  42. RED="tput setaf 1"
  43. GREEN="tput setaf 2"
  44. YELLOW="tput setaf 3"
  45. BLUE="tput setaf 4"
  46. MAGENTA="tput setaf 5"
  47. CYAN="tput setaf 6"
  48. LIGHT_BLUE="$CYAN"
  49. BOLD="tput bold"
  50. DEFAULT="tput sgr0"
  51. RED_BG="tput setab 1"
  52. GREEN_BG="tput setab 2"
  53. YELLOW_BG="tput setab 3"
  54. BLUE_BG="tput setab 4"
  55. MAGENTA_BG="tput setab 5"
  56. CYAN_BG="tput setab 6"
  57. #
  58. # Bug fix for Bash, parsing exclamation mark.
  59. #
  60. set +o histexpand
  61. #
  62. # returns 0 if a variable is defined (set)
  63. # returns 1 if a variable is unset
  64. #
  65. }
  66. function defined {
  67. if [ -n "$ZSH_VERSION" ]; then
  68. [ -n "${1+X}" ]
  69. else
  70. [[ ${!1-X} == ${!1-Y} ]]
  71. fi
  72. }
  73. function is_function {
  74. if [ -n "$(type -t $1)" ] && [ "$(type -t $1)" = function ]; then
  75. return 0
  76. else
  77. return 1
  78. fi
  79. }
  80. function is_alias {
  81. if [ -n "$(type -t $1)" ] && [ "$(type -t $1)" = 'alias' ]; then
  82. return 0
  83. else
  84. return 1
  85. fi
  86. }
  87. #
  88. # returns 0 if a variable is defined (set) and value's length > 0
  89. # returns 1 otherwise
  90. #
  91. function has_value {
  92. if [ -n "$ZSH_VERSION" ]; then
  93. # if defined $1; then
  94. # if [[ -n ${!1} ]]; then
  95. # return 0
  96. # fi
  97. # fi
  98. return 1
  99. else
  100. if defined $1; then
  101. if [[ -n ${!1} ]]; then
  102. return 0
  103. fi
  104. fi
  105. return 1
  106. fi
  107. }
  108. #
  109. # returns 0 if a directory exists
  110. # returns 1 otherwise
  111. #
  112. function directory_exists {
  113. if [[ -d "$1" ]]; then
  114. return 0
  115. fi
  116. return 1
  117. }
  118. #
  119. # returns 0 if a (regular) file exists
  120. # returns 1 otherwise
  121. #
  122. function file_exists {
  123. if [[ -f "$1" ]]; then
  124. return 0
  125. fi
  126. return 1
  127. }
  128. function command_exists {
  129. if command -v "$1" > /dev/null 2>&1; then
  130. return 0;
  131. fi
  132. return 1
  133. }
  134. #
  135. # returns lowercase string
  136. #
  137. function tolower {
  138. echo "$1" | tr '[:upper:]' '[:lower:]'
  139. }
  140. #
  141. # returns uppercase string
  142. #
  143. function toupper {
  144. echo "$1" | tr '[:lower:]' '[:upper:]'
  145. }
  146. #
  147. # Only returns the first part of a string, delimited by tabs or spaces
  148. #
  149. function trim {
  150. echo $1
  151. }
  152. #
  153. # Dummy function to provide usage instructions.
  154. # Override this function if required.
  155. #
  156. show_usage () {
  157. MESSAGE="$1"
  158. echo "$MESSAGE"
  159. exit 1
  160. }
  161. #
  162. # Checks if a variable is set to "y" or "yes".
  163. # Usefull for detecting if a configurable option is set or not.
  164. #
  165. option_enabled () {
  166. VAR="$1"
  167. VAR_VALUE=$(eval echo \$$VAR)
  168. if [[ "$VAR_VALUE" == "y" ]] || [[ "$VAR_VALUE" == "yes" ]]
  169. then
  170. return 0
  171. else
  172. return 1
  173. fi
  174. }
  175. #
  176. # The log funcion just puts a string into a file, prepended with a date & time in
  177. # syslog format.
  178. #
  179. log2syslog () {
  180. if option_enabled SYSLOG_ENABLED
  181. then
  182. MESSAGE="$1"
  183. logger -t "$SYSLOG_TAG" " $MESSAGE" #The space is not a typo!"
  184. fi
  185. }
  186. #
  187. # This function writes messages to a log file and/or syslog
  188. # The only argument is a message that has to be logged.
  189. #
  190. log () {
  191. if option_enabled LOG_ENABLED || option_enabled SYSLOG_ENABLED
  192. then
  193. LOG_MESSAGE="$1"
  194. DATE=`date +"$LOGDATEFORMAT"`
  195. if has_value LOG_MESSAGE
  196. then
  197. LOG_STRING="$DATE $LOG_MESSAGE"
  198. else
  199. LOG_STRING="$DATE -- empty log message, no input received --"
  200. fi
  201. if option_enabled LOG_ENABLED
  202. then
  203. echo "$LOG_STRING" >> "$LOG_FILE"
  204. fi
  205. if option_enabled SYSLOG_ENABLED
  206. then
  207. #
  208. # Syslog already prepends a date/time stamp so only the message
  209. # is logged.
  210. #
  211. log2syslog "$LOG_MESSAGE"
  212. fi
  213. fi
  214. }
  215. #
  216. # This function basically replaces the 'echo' function in bash scripts.
  217. # The added functionality over echo is logging and using colors.
  218. #
  219. # The first argument is the string / message that must be displayed.
  220. # The second argument is the text color.
  221. msg () {
  222. MESSAGE="$1"
  223. COLOR="$2"
  224. if ! has_value COLOR
  225. then
  226. COLOR="$DEFAULT"
  227. fi
  228. if has_value "MESSAGE"
  229. then
  230. $COLOR
  231. echo "$MESSAGE"
  232. $DEFAULT
  233. log "$MESSAGE"
  234. else
  235. echo "-- no message received --"
  236. log "$MESSAGE"
  237. fi
  238. }
  239. #
  240. # This function echos a message
  241. # and displays the status at the end of the line.
  242. #
  243. # It can be used to create status messages other
  244. # than the default messages available such as
  245. # OK or FAIL
  246. #
  247. msg_status () {
  248. MESSAGE="$1"
  249. STATUS="$2"
  250. msg "$MESSAGE"
  251. display_status "$STATUS"
  252. }
  253. #
  254. # These functions are just short hand for messages like
  255. # msg_status "this message is ok" OK
  256. #
  257. #
  258. # The following functions are shorthand for
  259. # msg_status "a message" OK
  260. # msg_status "another message" FAIL
  261. msg_emergency () {
  262. MESSAGE="$1"
  263. STATUS="EMERGENCY"
  264. msg_status "$MESSAGE" "$STATUS"
  265. }
  266. msg_alert () {
  267. MESSAGE="$1"
  268. STATUS="ALERT"
  269. msg_status "$MESSAGE" "$STATUS"
  270. }
  271. msg_critical () {
  272. MESSAGE="$1"
  273. STATUS="CRITICAL"
  274. msg_status "$MESSAGE" "$STATUS"
  275. }
  276. msg_error () {
  277. MESSAGE="$1"
  278. STATUS="ERROR"
  279. msg_status "$MESSAGE" "$STATUS"
  280. }
  281. msg_warning () {
  282. MESSAGE="$1"
  283. STATUS="WARNING"
  284. msg_status "$MESSAGE" "$STATUS"
  285. }
  286. msg_notice () {
  287. MESSAGE="$1"
  288. STATUS="NOTICE"
  289. msg_status "$MESSAGE" "$STATUS"
  290. }
  291. msg_info () {
  292. MESSAGE="$1"
  293. STATUS="INFO"
  294. msg_status "$MESSAGE" "$STATUS"
  295. }
  296. msg_debug () {
  297. MESSAGE="$1"
  298. STATUS="DEBUG"
  299. msg_status "$MESSAGE" "$STATUS"
  300. }
  301. msg_ok () {
  302. MESSAGE="$1"
  303. STATUS="OK"
  304. msg_status "$MESSAGE" "$STATUS"
  305. }
  306. msg_not_ok () {
  307. MESSAGE="$1"
  308. STATUS="NOT_OK"
  309. msg_status "$MESSAGE" "$STATUS"
  310. }
  311. msg_fail () {
  312. MESSAGE="$1"
  313. STATUS="FAILED"
  314. msg_status "$MESSAGE" "$STATUS"
  315. }
  316. msg_success () {
  317. MESSAGE="$1"
  318. STATUS="SUCCESS"
  319. msg_status "$MESSAGE" "$STATUS"
  320. }
  321. msg_passed () {
  322. MESSAGE="$1"
  323. STATUS="PASSED"
  324. msg_status "$MESSAGE" "$STATUS"
  325. }
  326. check_status () {
  327. CMD="$1"
  328. STATUS="$2"
  329. if [ "$STATUS" == "0" ]
  330. then
  331. msg_ok "$CMD"
  332. else
  333. msg_fail "$CMD"
  334. fi
  335. }
  336. #
  337. # Private function
  338. #
  339. # This is a function that just positions
  340. # the cursor one row up and to the right.
  341. # It then prints a message with specified
  342. # Color
  343. # It is used for displaying colored status messages on the
  344. # Right side of the screen.
  345. #
  346. # ARG1 = "status message (OK / FAIL)"
  347. # ARG2 = The color in which the status is displayed.
  348. #
  349. raw_status () {
  350. STATUS="$1"
  351. COLOR="$2"
  352. function position_cursor () {
  353. let RES_COL=`tput cols`-12
  354. tput cuf $RES_COL
  355. tput cuu1
  356. }
  357. position_cursor
  358. echo -n "["
  359. $DEFAULT
  360. $BOLD
  361. $COLOR
  362. echo -n "$STATUS"
  363. $DEFAULT
  364. echo "]"
  365. log "Status = $STATUS"
  366. }
  367. #
  368. # This function converts a status message to a particular color.
  369. #
  370. display_status () {
  371. STATUS="$1"
  372. case $STATUS in
  373. EMERGENCY )
  374. STATUS="EMERGENCY"
  375. COLOR="$RED"
  376. ;;
  377. ALERT )
  378. STATUS=" ALERT "
  379. COLOR="$RED"
  380. ;;
  381. CRITICAL )
  382. STATUS="CRITICAL "
  383. COLOR="$RED"
  384. ;;
  385. ERROR )
  386. STATUS=" ERROR "
  387. COLOR="$RED"
  388. ;;
  389. WARNING )
  390. STATUS=" WARNING "
  391. COLOR="$YELLOW"
  392. ;;
  393. NOTICE )
  394. STATUS=" NOTICE "
  395. COLOR="$BLUE"
  396. ;;
  397. INFO )
  398. STATUS=" INFO "
  399. COLOR="$LIGHT_BLUE"
  400. ;;
  401. DEBUG )
  402. STATUS=" DEBUG "
  403. COLOR="$DEFAULT"
  404. ;;
  405. OK )
  406. STATUS=" OK "
  407. COLOR="$GREEN"
  408. ;;
  409. NOT_OK)
  410. STATUS=" NOT OK "
  411. COLOR="$RED"
  412. ;;
  413. PASSED )
  414. STATUS=" PASSED "
  415. COLOR="$GREEN"
  416. ;;
  417. SUCCESS )
  418. STATUS=" SUCCESS "
  419. COLOR="$GREEN"
  420. ;;
  421. FAILURE | FAILED )
  422. STATUS=" FAILED "
  423. COLOR="$RED"
  424. ;;
  425. *)
  426. STATUS="UNDEFINED"
  427. COLOR="$YELLOW"
  428. esac
  429. raw_status "$STATUS" "$COLOR"
  430. }
  431. #
  432. # Exit with error status
  433. #
  434. bail () {
  435. ERROR="$?"
  436. MSG="$1"
  437. if [ ! "$ERROR" = "0" ]
  438. then
  439. msg_fail "$MSG"
  440. exit "$ERROR"
  441. fi
  442. }
  443. #
  444. # This function executes a command provided as a parameter
  445. # The function then displays if the command succeeded or not.
  446. #
  447. cmd () {
  448. COMMAND="$1"
  449. msg "Executing: $COMMAND"
  450. RESULT=`$COMMAND 2>&1`
  451. ERROR="$?"
  452. MSG="Command: ${COMMAND:0:29}..."
  453. tput cuu1
  454. if [ "$ERROR" == "0" ]
  455. then
  456. msg_ok "$MSG"
  457. if [ "$DEBUG" == "1" ]
  458. then
  459. msg "$RESULT"
  460. fi
  461. else
  462. msg_fail "$MSG"
  463. log "$RESULT"
  464. fi
  465. return "$ERROR"
  466. }
  467. #
  468. # These functions can be used for timing how long (a) command(s) take to
  469. # execute.
  470. #
  471. now () {
  472. echo $(date +%s)
  473. }
  474. elapsed () {
  475. START="$1"
  476. STOP="$2"
  477. echo $(( STOP - START ))
  478. }
  479. #
  480. # Prints an error message ($2) to stderr and exits with the return code ($1).
  481. # The message is also logged.
  482. #
  483. function die {
  484. local -r err_code="$1"
  485. local -r err_msg="$2"
  486. local -r err_caller="${3:-$(caller 0)}"
  487. msg_fail "ERROR: $err_msg"
  488. msg_fail "ERROR: At line $err_caller"
  489. msg_fail "ERROR: Error code = $err_code"
  490. exit "$err_code"
  491. } >&2 # function writes to stderr
  492. #
  493. # Check if a return code ($1) indicates an error (i.e. >0) and prints an error
  494. # message ($2) to stderr and exits with the return code ($1).
  495. # The error is also logged.
  496. #
  497. # Die if error code is false.
  498. #
  499. function die_if_false {
  500. local -r err_code=$1
  501. local -r err_msg=$2
  502. local -r err_caller=$(caller 0)
  503. if [[ "$err_code" != "0" ]]
  504. then
  505. die $err_code "$err_msg" "$err_caller"
  506. fi
  507. } >&2 # function writes to stderr
  508. #
  509. # Dies when error code is true
  510. #
  511. function die_if_true {
  512. local -r err_code=$1
  513. local -r err_msg=$2
  514. local -r err_caller=$(caller 0)
  515. if [[ "$err_code" == "0" ]]
  516. then
  517. die $err_code "$err_msg" "$err_caller"
  518. fi
  519. } >&2 # function writes to stderr
  520. #
  521. # Replace some text inside a string.
  522. #
  523. function str_replace () {
  524. local ORIG="$1"
  525. local DEST="$2"
  526. local DATA="$3"
  527. echo "$DATA" | sed "s/$ORIG/$DEST/g"
  528. }
  529. #
  530. # Replace string of text in file.
  531. # Uses the ed editor to replace the string.
  532. #
  533. # arg1 = string to be matched
  534. # arg2 = new string that replaces matched string
  535. # arg3 = file to operate on.
  536. #
  537. function str_replace_in_file () {
  538. local ORIG="$1"
  539. local DEST="$2"
  540. local FILE="$3"
  541. has_value FILE
  542. die_if_false $? "Empty argument 'file'"
  543. file_exists "$FILE"
  544. die_if_false $? "File does not exist"
  545. printf ",s/$ORIG/$DEST/g\nw\nQ" | ed -s "$FILE" > /dev/null 2>&1
  546. return "$?"
  547. }
  548. #
  549. # Prompt a user and if the response is as expected return 0, else 1
  550. #
  551. # arg1 = the prompt for the user
  552. # arg2 = the regex to match against ('yY' default)
  553. #
  554. function prompt_user {
  555. EXPECTED=${2:-yY}
  556. echo -n "$1($EXPECTED)"
  557. read REPLY
  558. echo
  559. if [[ ! $REPLY =~ ^[$EXPECTED]$ ]]
  560. then
  561. return 1
  562. else
  563. return 0
  564. fi
  565. }
  566. #
  567. # Prompt a user to remove a file
  568. #
  569. # arg1 = the file to remove
  570. #
  571. function remove_file_with_prompt {
  572. if file_exists $1; then
  573. if ! prompt_user "Remove exsting $1 file?"; then
  574. echo "Move $1 and rerun"
  575. return 1
  576. fi
  577. echo "Removing $1"
  578. rm $1
  579. fi
  580. }
  581. init