├── LESSONS.md ├── README.md └── examples ├── LICENSES.md ├── backup_methods.sh ├── bumblebee_install.sh ├── n.sh ├── squid.init.sh └── steam.sh /LESSONS.md: -------------------------------------------------------------------------------- 1 | ## Table of contents 2 | 3 | Some bad #bash error can kill a whole system. Here are some examples, 4 | as food for your future vulnerabilities. They are good lessons, so please 5 | learn them; don't criticize. 6 | 7 | * [2015: squid restarting removes system files](#2015-restarting-squid-31-on-a-rhel-system-removes-all-system-files) 8 | * [2015: steam removes everything](#2015-steam-removes-everything-on-system) 9 | * [2012: backup-manager kills a French company](#2012-backup-manager-kills-a-french-company) 10 | * [2012: a node manager removes system directories](#2012-n-a-node-version-manager-removes-system-directories) 11 | * [2011: a space removes everything under /usr/](#2011-a-space-that-removes-everything-under-usr) 12 | * [2001: itunes installer deletes hard drivers](#2001-itunes-20-installer-deletes-hard-drives) 13 | 14 | ## 2015: Restarting `squid-3.1` on a `RHEL` system removes all system files 15 | 16 | *Lesson*: Removing something is always dangerous. 17 | 18 | Reference: https://bugzilla.redhat.com/show_bug.cgi?id=1202858. 19 | 20 | See discussion on Hacker News: 21 | https://news.ycombinator.com/item?id=9254876. 22 | 23 | *Please note* that this is a bug catched by `QA` team, before 24 | the package is released; that's a luck catch. 25 | `RedHat` team should have fixed their `#bash` coding style. 26 | 27 | The problem may come form a patch https://bugzilla.redhat.com/show_bug.cgi?id=1102343 28 | that tries to clean up `squid`'s `PID` directory: 29 | 30 | restart() { 31 | stop 32 | RETVAL=$? 33 | if [ $RETVAL -eq 0 ] ; then 34 | rm -rf $SQUID_PIDFILE_DIR/* 35 | start 36 | ... 37 | } 38 | 39 | That is similar to this script 40 | https://github.com/mozilla-services/squid-rpm/blob/47880414f17affdbb634b6f0a19a342995fb60f6/SOURCES/squid.init, 41 | whose copy is in `examples/squid.init.sh`. Because `RedHat` doesn't publish 42 | their code, we can only _guess_ that they put `SQUID_PIDFILE_DIR` in some 43 | external configuration file (like `Debian` often uses `/etc/default/`), 44 | and for some `UNKNOWN` reason, `$SQUID_PIDFILE_DIR` is expanded to `empty`. 45 | 46 | ## 2015: `Steam` removes everything on system 47 | 48 | *Lesson*: Removing something is always dangerous. 49 | 50 | Reference: https://github.com/ValveSoftware/steam-for-linux/issues/3671. 51 | 52 | The problem was introduced in the following commit: 53 | https://github.com/indrora/steam_latest/blob/21cc14158c171f5912b04b83abf41205eb804b31/scripts/steam.sh#L359 54 | (a copy of this script can be found at `examples/steam.sh`.) 55 | 56 | If the `steam.sh` script is invoked with `--reset` option, for example, 57 | when there isn't `~/.steam/` directory, it will invoke the internal function 58 | `reset_steam`, in which a `remove-all` command is instructed 59 | 60 | STEAMROOT="$(cd "${0%/*}" && echo $PWD)" 61 | # ... 62 | 63 | reset_steam() { 64 | # ... 65 | rm -rf "$STEAMROOT/"* 66 | # ... 67 | } 68 | 69 | The bad thing happens when `$STEAMROOT` is `/` (when you have `/steam.sh`) 70 | or just empty (when you execute `bash steam.sh`, `$0` is `steam.sh` and 71 | the `cd` command just fails, results in an empty `$STEAMROOT`.) 72 | 73 | Please note that using `set -u` doesn't help here. When `cd` command fails, 74 | `$STEAMROOT` is empty and `set -u` sees no error. It's a problem with 75 | working directory detection, and it's very very hard to do it right. 76 | So forget it; and don't delete anything :) 77 | 78 | ## 2012: `Backup Manager` kills a French company 79 | 80 | *Lesson*: Save `$?` as soon as possible. 81 | 82 | Reference: http://dragula.viettug.org/blogs/675.html. 83 | 84 | This tool uses `$?` to check if an internal backup script fails. 85 | Unfortunately, `$?` is used too late; hence the program always returns 86 | successfully. In 2012, a French company lost all their database backups, 87 | and that took down their internal tools in 1 month. 88 | 89 | You can see the line `189` from the files [`examples/backup_methods.sh`](examples/backup_methods.sh#L180) 90 | for details. 91 | 92 | *Update*: 93 | 94 | 1. This file is shipped with `backup-manager` version `0.7.10.1-2` 95 | on `Ubuntu 14.04-LTS`. 96 | 1. The tool with the same version and bad script is shipped with `Ubuntu 16.04-LTS`. 97 | 98 | ## 2012: `n`, a node version manager, removes system directories 99 | 100 | *Lesson*: Removing something is always dangerous. 101 | 102 | Reference: https://github.com/tj/n/issues/86 . 103 | 104 | There are a lot of funny `.gif`s in this `github` issue. 105 | The code that causes the bug is here 106 | https://github.com/tj/n/pull/85/files. 107 | A copy of the file is found at `examples/n.sh`. 108 | 109 | The author assumes that `nodejs` is installed under `/usr/local/`. 110 | You will find this at the beginning of the script 111 | 112 | VERSION="0.7.3" 113 | N_PREFIX=${N_PREFIX-/usr/local} 114 | VERSIONS_DIR=$N_PREFIX/n/versions 115 | 116 | There is nothing wrong with this, until they decide to remove everything 117 | under `$N_PREFIX`, 118 | 119 | install_node() { 120 | .... 121 | 122 | # symlink everything, purge old copies or symlinks 123 | for d in bin lib share include; do 124 | rm -rf $N_PREFIX/$d 125 | ln -s $dir/$d $N_PREFIX/$d 126 | ... 127 | } 128 | 129 | It's clear that `/usr/local/lib/` (and similar directory) may contain 130 | other system files. 131 | 132 | ## 2011: A space that removes everything under `/usr/` 133 | 134 | *Lesson*: Quoting is important. Quote what you think! 135 | 136 | Reference: 137 | https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/commit/6cd6b2485668e8a87485cb34ca8a0a937e73f16d 138 | 139 | See also https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/issues/123. 140 | A copy of `install.sh` file is `examples/bumblebee_install.sh`. 141 | 142 | The author tries to clean up some directories 143 | 144 | rm -rf /usr /lib/nvidia-current/xorg/xorg 145 | 146 | Unfortunately, because he "was very tired that night", he inserted an 147 | extra space after `/usr`, and every one got bonus: buy one, get two. 148 | 149 | This problem may (slightly) be avoided by using quoting, and listing. 150 | 151 | ## 2001: iTunes 2.0 Installer Deletes Hard Drives 152 | 153 | *Lesson*: Quoting is important. Quote what you think! 154 | 155 | Reference: 156 | http://apple.slashdot.org/story/01/11/04/0412209/itunes-20-installer-deletes-hard-drives 157 | 158 | Anonymous quote: (http://apple.slashdot.org/comments.pl?sid=23365&cid=2518563) 159 | 160 | > In the installer is a small shell script to remove any old copies of iTunes. 161 | > It contained the following line of code: 162 | > 163 | > rm -rf $2Applications/iTunes.app 2 164 | > 165 | > where "$2" is the name of the drive iTunes is being installed on. 166 | > 167 | > The problem is, since the pathname is not in quotes, if the drive name 168 | > has a space, and there are other drives named similarly then the installer 169 | > will delete the similarly named drive (for instance if your drives are: 170 | > "Disk", "Disk 1", and Disk 2" and you install on "Disk 1" 171 | > then the command will become "rm -rf Disk 1/Applications/iTunes.app 2 172 | > 173 | > The new updated version of the installer replaced that line of code with: 174 | > 175 | > rm -rf "$2Applications/iTunes.app" 2 176 | > so things should work fine now. 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Some `Bash` coding conventions and good practices. 2 | 3 | Coding conventions are... just conventions. 4 | They help to have a little fun with scripting, 5 | not to create new war/bias conversations. 6 | 7 | Feel free to break the rules any time you can; it's important 8 | that you will always love what you would have written 9 | because scripts can be too fragile, too hard to maintain, 10 | or so many people hate them... 11 | And it's also important to have a consistent way in your scripts. 12 | 13 | * [Deprecated conventions](#deprecation) 14 | * [`variable name started with an underscore` (`_foo_bar`)](#variable-name-started-with-an-underscore-_foo_bar) 15 | * [Naming and styles](#naming-and-styles) 16 | * [Tabs and Spaces](#tabs-and-spaces) 17 | * [Pipe](#pipe) 18 | * [Variable names](#variable-names) 19 | * [Function names](#function-names) 20 | * [Error handling](#error-handling) 21 | * [Sending instructions](#sending-instructions) 22 | * [Pipe error handling](#pipe-error-handling) 23 | * [Catch up with $?](#catch-up-with-) 24 | * [Automatic error handling](#automatic-error-handling) 25 | * [Set -u](#set--u) 26 | * [Set -e](#set--e) 27 | * [Techniques](#techniques) 28 | * [Keep that in mind](#keep-that-in-mind) 29 | * [A little tracing](#a-little-tracing) 30 | * [Making your script a library](#making-your-script-a-library) 31 | * [Quick self-doc](#quick-self-doc) 32 | * [No excuse](#no-excuse) 33 | * [Meta programming](#meta-programming) 34 | * [Removing with care](#removing-with-care) 35 | * [Shell or Python/Ruby/etc](#shell-or-pythonrubyetc) 36 | * [Contributions](#contributions) 37 | * [Variable names for arrays](#variable-names-for-arrays) 38 | * [Good lessons](#good-lessons) 39 | * [Resources](#resources) 40 | * [Author. License](#author-license) 41 | 42 | ## Naming and Styles 43 | 44 | ### Tabs and Spaces 45 | 46 | Don't use `(smart-)`tabs. Replace a tab by two spaces. 47 | Do not accept any trailing spaces. 48 | 49 | Many editors can't and/or aren't configured to display the differences 50 | between tabs and spaces. Another person's editor is just not your editor. 51 | Having spaces does virtually help a strange reader of your script. 52 | 53 | ### Pipe 54 | 55 | There are `inline` pipe and `display` pipe. Unless your pipe is 56 | short, please use `display` pipe to make things clear. For example, 57 | 58 | 59 | ```bash 60 | 61 | # This is an inline pipe: "$(ls -la /foo/ | grep /bar/)" 62 | 63 | # The following pipe is of display form: every command is on 64 | # its own line. 65 | 66 | foobar="$( \ 67 | ls -la /foo/ \ 68 | | grep /bar/ \ 69 | | awk '{print $NF}')" 70 | 71 | _generate_long_lists \ 72 | | while IFS= read -r line; do 73 | _do_something_fun 74 | done 75 | ``` 76 | 77 | When using `display` form, put pipe symbol (`|`) at the beginning of 78 | of its statement. Don't put `|` at the end of a line, because it's the 79 | job of the line end (`EOL`) character and line continuation (`\`). 80 | 81 | Here is another example 82 | 83 | ```bash 84 | 85 | # List all public images found in k8s manifest files 86 | # ignore some in-house image. 87 | list_public_images() { 88 | find . -type f -iname "*.yaml" -exec grep 'image: ' {} \; \ 89 | | grep -v ecr. \ 90 | | grep -v '#' \ 91 | | sed -e "s#['\"]##g" \ 92 | | awk '{print $NF}' \ 93 | | sort -u \ 94 | | grep -Eve '^(coredns|bflux|kube-proxy|logstash)$' \ 95 | } 96 | ``` 97 | 98 | ### Variable names 99 | 100 | If you are going to have meanful variable name, please use them 101 | for the right purpose. The variable name `country_name` should 102 | not be used to indicate a city name or a person, should they? 103 | So this is bad 104 | 105 | ```bash 106 | 107 | countries="australia germany berlin" 108 | for city in $countries; do 109 | echo "city or country is: $city 110 | done 111 | ``` 112 | 113 | That's very bad example but that is to emphasize the idea. 114 | (FIXME: Add better examples) 115 | 116 | A variable is named according to its scope. 117 | 118 | * If a variable can be changed from its parent environment, 119 | it should be in uppercase; e.g, `THIS_IS_A_USER_VARIABLE`. 120 | * Other variables are in lowercase 121 | * Any local variables inside a function definition should be 122 | declared with a `local` statement. 123 | 124 | Example 125 | 126 | ```bash 127 | 128 | # The following variable can be provided by user at run time. 129 | D_ROOT="${D_ROOT:-}" 130 | 131 | # All variables inside `my_def` are declared with `local` statement. 132 | my_def() { 133 | local d_tmp="/tmp/" 134 | local f_a= 135 | local f_b= 136 | 137 | # This is good, but it's quite a mess 138 | local f_x= f_y= 139 | } 140 | ``` 141 | 142 | Though `local` statement can declare multiple variables, that way 143 | makes your code unreadable. Put each `local` statement on its own line. 144 | 145 | `FIXME`: Add flexibility support. 146 | 147 | ### Function names 148 | 149 | Name of internal functions should be started by an underscore (`_`). 150 | Use underscore (`_`) to glue verbs and nouns. Don't use camel form 151 | (`ThisIsNotMyStyle`; use `this_is_my_style` instead.) 152 | 153 | Use two underscores (`__`) to indicate some very internal methods aka 154 | the ones should be used by other internal functions. 155 | 156 | ## Error handling 157 | 158 | ### Sending instructions 159 | 160 | All errors should be sent to `STDERR`. Never send any error/warning message 161 | to a`STDOUT` device. Never use `echo` directly to print your message; 162 | use a wrapper instead (`warn`, `err`, `die`,...). For example, 163 | 164 | ```bash 165 | 166 | _warn() { 167 | echo >&2 ":: $*" 168 | } 169 | 170 | _die() { 171 | echo >&2 ":: $*" 172 | exit 1 173 | } 174 | ``` 175 | 176 | Do not handle error of another function. Each function should handle 177 | error and/or error message by their own implementation, inside its own 178 | definition. 179 | 180 | ```bash 181 | 182 | _my_def() { 183 | _foobar_call 184 | 185 | if [[ $? -ge 1 ]]; then 186 | echo >&2 "_foobar_call has some error" 187 | _error "_foobar_call has some error" 188 | return 1 189 | fi 190 | } 191 | ``` 192 | 193 | In the above example, `_my_def` is trying to handle error for `_foobar_call`. 194 | That's not a good idea. Use the following code instead 195 | 196 | ```bash 197 | 198 | _foobar_call() { 199 | # do something 200 | 201 | if [[ $? -ge 1 ]]; then 202 | _error "${FUNCNAME[0]} has some internal error" 203 | fi 204 | } 205 | 206 | _my_def() { 207 | _foobar_call || return 1 208 | } 209 | ``` 210 | 211 | ### Catch up with $? 212 | 213 | `$?` is used to get the return code of the *last statement*. 214 | To use it, please make sure you are not too late. The best way is to 215 | save the last return code thanks to some local variable. For example, 216 | 217 | ```bash 218 | 219 | _do_something_critical 220 | local _ret="$?" 221 | 222 | # from now on, $? is zero, because the latest statement (assignment) 223 | # (always) returns zero. 224 | 225 | _do_something_terrible 226 | echo "done" 227 | if [[ $? -ge 1 ]]; then 228 | # Bash will never reach here. Because "echo" has returned zero. 229 | fi 230 | ``` 231 | 232 | `$?` is very useful. But don't trust it. 233 | 234 | Please don't use `$?` with `set -e` ;) 235 | 236 | ### Pipe error handling 237 | 238 | Pipe stores its components' return codes in the `PIPESTATUS` array. 239 | This variable can be used only *ONCE* in the sub-`{shell,process}` 240 | followed the pipe. Be sure you catch it up! 241 | 242 | ```bash 243 | 244 | echo test | fail_command | something_else 245 | local _ret_pipe=( "${PIPESTATUS[@]}" ) 246 | # from here, `PIPESTATUS` is not available anymore 247 | ``` 248 | 249 | When this `_ret_pipe` array contains something other than zero, 250 | you should check if some pipe component has failed. For example, 251 | 252 | ```bash 253 | 254 | # Note: 255 | # This function only works when it is invoked 256 | # immediately after a pipe statement. 257 | _is_good_pipe() { 258 | echo "${PIPESTATUS[@]}" | grep -qE "^[0 ]+$" 259 | } 260 | 261 | _do_something | _do_something_else | _do_anything 262 | _is_good_pipe \ 263 | || { 264 | echo >&2 ":: Unable to do something" 265 | } 266 | ``` 267 | 268 | ### Automatic error handling 269 | 270 | #### Set -u 271 | 272 | Always use `set -u` to make sure you won't use any undeclared variable. 273 | This saves you from a lot of headaches and critical bugs. 274 | 275 | Because `set -u` can't help when a variable is declared and set to empty 276 | value, don't trust it twice. 277 | 278 | It's recommended to emphasize the needs of your variables before your 279 | script actually starts. In the following example, the script just stops 280 | when `SOME_VARIABLE` or `OTHER_VARIABLE` is not defined; these checks 281 | are done just before any execution of the main routine(s). 282 | 283 | ```bash 284 | 285 | : a lot of method definitions 286 | 287 | set -u 288 | 289 | : "${SOME_VARIABLE}" 290 | : "${OTHER_VARIABLE}" 291 | 292 | : your main routine 293 | ``` 294 | 295 | #### Set -e 296 | 297 | Use `set -e` if your script is being used for your own business. 298 | 299 | Be **careful** when shipping `set -e` script to the world. It can simply 300 | break a lot of games. And sometimes you will shoot yourself in the foot. 301 | If possible please have an option for user choice. 302 | 303 | Let's see 304 | 305 | ```bash 306 | 307 | set -e 308 | _do_some_critical_check 309 | 310 | if [[ $? -ge 1 ]]; then 311 | echo "Oh, you will never see this line." 312 | fi 313 | ``` 314 | 315 | If `_do_some_critical_check` fails, the script just exits and the following 316 | code is just skipped without any notice. Too bad, right? The code above 317 | can be refactored as below 318 | 319 | ```bash 320 | 321 | set +e 322 | if _do_some_critical_check; then 323 | echo "Something has gone very well." 324 | fi 325 | echo "You will see this line." 326 | ``` 327 | 328 | Now, if you expect to stop the script when `_do_some_critical_check` fails 329 | (it's the purpose of `set -e`, right?), these lines don't help. Why? 330 | Because `set -e` doesn't work when being used with `if`. Confused? 331 | Okay, these lines are the correct one 332 | 333 | ```bash 334 | 335 | set +e 336 | if _do_some_critical_check; then 337 | echo "All check passed." 338 | else 339 | echo "Something wrong we have to stop here" 340 | exit 1 # or return 1 341 | fi 342 | ``` 343 | 344 | `set -e` doesn't help to improve your code: it just forces you to work hard, 345 | doesn't it? 346 | 347 | Another example, in effect of `set -e`: 348 | 349 | ```bash 350 | 351 | (false && true); echo not here 352 | ``` 353 | 354 | prints nothing, while: 355 | 356 | ```bash 357 | 358 | { false && true; }; echo here 359 | ``` 360 | 361 | prints `here`. 362 | 363 | The result is varied with different shells or even different versions of the same shell. 364 | 365 | In general, don't rely on `set -e` and do proper error handling instead. 366 | 367 | For more details about `set -e`, please read 368 | 369 | > The correct answer to every exercise is actually "because set -e is crap". 370 | 371 | * http://mywiki.wooledge.org/BashFAQ/105/Answers 372 | * [When Bash scripts bite](https://news.ycombinator.com/item?id=14321213) 373 | 374 | ## Techniques 375 | 376 | ### Keep that in mind 377 | 378 | There are lot of shell scripts that don't come with (unit)tests. 379 | It's just not very easy to write tests. Please keep that in mind: 380 | Writing shell scripts is more about dealing with runtime and side effects. 381 | 382 | It's very hard to refactor shell scripts. 383 | Be prepared, and don't hate bash/shell scripts too much ;) 384 | 385 | ### A little tracing 386 | 387 | It would be very helpful if you can show in your script logs some tracing 388 | information of the being-invoked function/method. 389 | 390 | `Bash` has two jiffy variables `LINENO` and `FUNCNAME` that can help. 391 | While it's easy to understand `LINENO`, `FUNCNAME` is a little complex. 392 | It is an array of `chained` functions. Let's look at the following example 393 | 394 | ```bash 395 | 396 | funcA() { 397 | log "This is A" 398 | } 399 | 400 | funcB() { 401 | log "This is B" 402 | funcA 403 | } 404 | 405 | funcC() { 406 | log "This is C" 407 | funcB 408 | } 409 | 410 | : Now, we call funcC 411 | 412 | funcC 413 | ``` 414 | 415 | In this example, we have a chain: `funcC -> funcB -> funcA`. 416 | Inside `funcA`, the runtime expands `FUNCNAME` to 417 | 418 | ```bash 419 | 420 | FUNCNAME=(funcA funcB funcC) 421 | ``` 422 | 423 | The first item of the array is the method per-se (`funcA`), 424 | and the next one is the one who instructs `funcA` (it is `funcB`). 425 | 426 | So, how can this help? Let's define a powerful `log` function 427 | 428 | ```bash 429 | 430 | log() { 431 | echo "(LOGGING) ${FUNCNAME[1]:-unknown}: *" 432 | } 433 | ``` 434 | 435 | You can use this little `log` method everywhere, for example, when `funcB` 436 | is invoked, it will print 437 | 438 | ```bash 439 | 440 | LOGGING funcB: This is B 441 | ``` 442 | 443 | ### Making your script a library 444 | 445 | First thing first: Use `function` if possible. Instead of writting 446 | some direct instructions in your script, you have a wrapper for them. 447 | This is not good 448 | 449 | ```bash 450 | 451 | : do something cool 452 | : do something great 453 | ``` 454 | 455 | Having them in a function is better 456 | 457 | ```bash 458 | 459 | _default_tasks() { 460 | : do something cool 461 | : do something great 462 | } 463 | ``` 464 | 465 | Now in the very last lines of you script, you can execute them 466 | 467 | ```bash 468 | 469 | case "${@:-}" in 470 | ":") echo "File included." ;; 471 | "") _default_tasks ;; 472 | esac 473 | ``` 474 | 475 | From other script you can include the script easily without executing 476 | any code: 477 | 478 | ```bash 479 | 480 | # from other script 481 | source "/path/to_the_previous_script.sh" ":" 482 | ``` 483 | 484 | (When being invoked without any argument the `_default_tasks` is called.) 485 | 486 | By advancing this simple technique, you have more options to debug 487 | your script and/or change your script behavior. 488 | 489 | ### Quick self-doc 490 | 491 | It's possible to generate beautiful self documentation by using `grep`, 492 | as in the following example. You define a strict format and `grep` them: 493 | 494 | ```bash 495 | 496 | _func_1() { #public: Some quick introduction 497 | : 498 | } 499 | 500 | _func_2() { #public: Some other tasks 501 | : 502 | } 503 | 504 | _quick_help() { 505 | LANG=en_US.UTF_8 506 | grep -E '^_.+ #public' "$0" \ 507 | | sed -e 's|() { #public: |☠|g' \ 508 | | column -s"☠" -t \ 509 | | sort 510 | } 511 | ``` 512 | 513 | When you execute `_quick_help`, the output is as below 514 | 515 | ```bash 516 | 517 | _func_1 Some quick introduction 518 | _func_2 Some other tasks 519 | ``` 520 | 521 | ### No excuse 522 | 523 | When someone tells you to do something, you may blindly do as said, 524 | or you would think twice then raise your white flag. 525 | 526 | Similarly, you should give your script a white flag. A backup script 527 | can't be executed on any workstation. A clean up job can't silently 528 | send `rm` commands in any directory. Critical mission script should 529 | 530 | * exit immediately without doing anything if argument list is empty; 531 | * exit if basic constraints are not established. 532 | 533 | Keep this in mind. Always. 534 | 535 | ### Meta programming 536 | 537 | `Bash` has a very powerful feature that you may have known: 538 | It's very trivial to get definition of a defined method. For example, 539 | 540 | ```bash 541 | 542 | my_func() { 543 | echo "This is my function`" 544 | } 545 | 546 | echo "The definition of my_func" 547 | declare -f my_func 548 | 549 | # 550 | ``` 551 | 552 | Why is this important? Your program manipulates them. It's up to your 553 | imagination. 554 | 555 | For example, send a local function to remote and excute them via `ssh` 556 | 557 | ```bash 558 | 559 | { 560 | declare -f my_func # send function definition 561 | echo "my_func" # execution instruction 562 | } \ 563 | | ssh some_server 564 | ``` 565 | 566 | This will help your program and script readable especially when you 567 | have to send a lot of instructions via `ssh`. Please note `ssh` session 568 | will miss interactive input stream though. 569 | 570 | ### Removing with care 571 | 572 | It's hard to remove files and directories **correctly**. 573 | Please consider to use `rm` with `backup` options. If you use some 574 | variables in your `rm` arguments, you may want to make them immutable. 575 | 576 | ```bash 577 | 578 | export temporary_file=/path/to/some/file/ 579 | readonly temporary_file 580 | # 581 | rm -fv "$temporary_file" 582 | ``` 583 | 584 | ### Shell or Python/Ruby/etc 585 | 586 | In many situations you may have to answer to yourself whether you have 587 | to use `Bash` and/or `Ruby/Python/Go/etc`. 588 | 589 | One significant factor is that `Bash` doesn't have a good memory. 590 | That means if you have a bunch of data (in any format) you probably 591 | reload them every time you want to extract some portion from them. 592 | This really makes your script slow and buggy. When your script 593 | needs to interpret any kind of data, it's a good idea to move forward 594 | and rewrite the script in another language, `Ruby/Python/Golang/...`. 595 | 596 | Anyway, probably you can't deny to ignore `Bash`: 597 | it's still very popular and many services are woken up by some shell things. 598 | Keep learning some basic things and you will never have to say sorry. 599 | Before thinking of switching to Python/Ruby/Golang, please consider 600 | to write better Bash scripts first ;) 601 | 602 | ## Contributions 603 | 604 | ### Variable names for arrays 605 | 606 | In #7, Cristofer Fuentes suggests to use special names for arrays. 607 | Personally I don't follow this way, because I always try to avoid 608 | to use Bash array (and/or associative arrays), and in Bash 609 | per-se there are quite a lot of confusion (e.g, `LINENO` is a string, 610 | `FUNCNAME` is array, `BASH_VERSION` is ... another array.) 611 | 612 | However, if your script has to use some array, it's also possible to 613 | have special name for them. E.g, 614 | 615 | ```bash 616 | 617 | declare -A DEPLOYMENTS 618 | DEPLOYMENTS["the1st"]="foo" 619 | DEPLOYMENTS["the2nd"]="bar" 620 | ``` 621 | 622 | As there are two types of arrays, you may need to enforce a better name 623 | 624 | ```bash 625 | 626 | declare -A MAP_DEPLOYMENTS 627 | ``` 628 | 629 | Well, it's just a reflection of some idea from another language;) 630 | 631 | ## Good lessons 632 | 633 | See also in `LESSONS.md` (https://github.com/icy/bash-coding-style/blob/master/LESSONS.md). 634 | 635 | ## Deprecation 636 | 637 | ### `variable name started with an underscore` (`_foo_bar`) 638 | 639 | Deprecated on July 7th 2021 (cf.: https://github.com/icy/bash-coding-style/issues/10). 640 | 641 | To migrate existing code, you may need to list all variables that 642 | followed the deprecated convention. Here is an simple `grep` command: 643 | 644 | ``` 645 | $ grep -RhEoe '(\$_\w+)|(\$\{_[^}]+\})' . | sort -u 646 | 647 | # -R find in all files in the current directory 648 | # -h don't show file name in the command output 649 | # -E enable regular expression 650 | # -o only print variable name that matches our pattern 651 | # -e to specify the pattern (as seen above) 652 | ``` 653 | 654 | ## Resources 655 | 656 | * [Anybody can write good bash with a little effort](https://blog.yossarian.net/2020/01/23/Anybody-can-write-good-bash-with-a-little-effort) 657 | * [Google - Shell Style Guide](https://github.com/google/styleguide/blob/gh-pages/shellguide.md) 658 | * [Defensive Bash programming](https://news.ycombinator.com/item?id=7815190) 659 | * [Shellcheck](https://github.com/koalaman/shellcheck) 660 | * [What exactly was the point of [ “x$var” = “xval” ]?](https://www.vidarholen.net/contents/blog/?p=1035) TLDR; You needed the trick during the mid-to-late 1990s and some times before 2010. Now you can forget that trick. 661 | * [Don't copy paste from a website to a terminal (thejh.net)](http://thejh.net/misc/website-terminal-copy-paste): https://news.ycombinator.com/item?id=10554679 662 | * [Homebrew installation "isssue"](https://github.com/withfig/fig/discussions/300): https://news.ycombinator.com/item?id=27901496 663 | 664 | ## Authors. License 665 | 666 | The original author is Anh K. Huynh and the original work was part of 667 | [`TheSLinux`](http://theslinux.org/doc/bash/coding_style/). 668 | 669 | A few contributors have been helped to fix errors and improve the style. 670 | They are also the authors. 671 | 672 | The work is released under a MIT license. 673 | -------------------------------------------------------------------------------- /examples/LICENSES.md: -------------------------------------------------------------------------------- 1 | I copy all the scripts here just in case the remote/upstream project is taken down. 2 | All lessons are great and they never mean to hurt anyone; however feel free to drop me a message 3 | and/or send a pull request to remove/update the script information if necessary. 4 | 5 | * [n.sh](n.sh): MIT (https://github.com/tj/n/blob/master/LICENSE) 6 | * [bumblebee_install](bumblebee_install.sh): "Red Bull License" (the original licesen information is included in the script) 7 | * [backup_methods.sh](backup_methods.sh): The original license text is included in the script. 8 | * [steam.sh](steam.sh): I couldn't access to the repository now, the only thing available now is https://github.com/indrora/steam_latest/commit/21cc14158c171f5912b04b83abf41205eb804b31 9 | * [squid.init.sh](squid.init.sh): GPLv2+ and (LGPLv2+ and MIT and BSD and Public Domain), https://github.com/mozilla-services/squid-rpm/blob/ea9a11c15092788f270730e0264f01ab5503a82e/SPECS/squid.spec#L11 10 | -------------------------------------------------------------------------------- /examples/backup_methods.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat 1>&2 <<-EOF 4 | This script is not to run on any system. 5 | Anh K. Huynh adds this banner to prevent script from being used. 6 | 7 | The script is part of the backup-manager-0.7.10.1-2 on Ubuntu 14.04-LTS. 8 | It's here as an example of wrong use of $? in Bash. 9 | EOF 10 | 11 | exit 0 12 | 13 | # Copyright (C) 2010 The Backup Manager Authors 14 | # 15 | # See the AUTHORS file for details. 16 | # 17 | # This program is free software; you can redistribute it and/or 18 | # modify it under the terms of the GNU General Public License 19 | # as published by the Free Software Foundation; either version 2 20 | # of the License, or (at your option) any later version. 21 | # 22 | # This program is distributed in the hope that it will be useful, 23 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | # GNU General Public License for more details. 26 | # 27 | # Every method to manage backup are here. 28 | # We should give here as more details we can 29 | # on the specific conffiles to use for the methods. 30 | # 31 | 32 | # This should be called whenever an archive is made, it will dump some 33 | # informations (size, md5sum) and will add the archive in .md5 file. 34 | function commit_archive() 35 | { 36 | file_to_create="$1" 37 | size=$(size_of_path $file_to_create) 38 | str=$(echo_translated "\$file_to_create: ok (\${size}M,") 39 | debug "commit_archive ($file_to_create)" 40 | 41 | # The archive is ok, we can drop the "pending" stuff 42 | debug "rm -f ${bm_pending_incremental_list}.orig" 43 | rm -f "${bm_pending_incremental_list}.orig" 44 | bm_pending_incremental_list="" 45 | bm_pending_archive="" 46 | 47 | base=$(basename $file_to_create) 48 | md5hash=$(get_md5sum $file_to_create) 49 | if [[ "$verbose" = "true" ]]; then 50 | echo "$str ${md5hash})" 51 | fi 52 | 53 | md5file="$BM_REPOSITORY_ROOT/${BM_ARCHIVE_PREFIX}-${TODAY}.md5" 54 | 55 | # Check if the md5file contains already the md5sum of the file_to_create. 56 | # In this case, the new md5sum overwrites the old one. 57 | if grep "$base" $md5file >/dev/null 2>&1 ; then 58 | previous_md5sum=$(get_md5sum_from_file $base $md5file) 59 | sed -e "/$base/s/$previous_md5sum/$md5hash/" -i $md5file 60 | else 61 | echo "$md5hash $base" >> $md5file 62 | fi 63 | 64 | # Now that the file is created, remove previous duplicates if exists... 65 | purge_duplicate_archives $file_to_create || 66 | error "Unable to purge duplicates of \$file_to_create" 67 | 68 | # ownership 69 | chown_archive "$file_to_create" 70 | } 71 | 72 | # security fixes if BM_REPOSITORY_SECURE is set to true 73 | function chown_archive { 74 | file="$1" 75 | if [[ "$BM_REPOSITORY_SECURE" = "true" ]]; then 76 | chown $BM_REPOSITORY_USER:$BM_REPOSITORY_GROUP $file || 77 | warning "Unable to change the owner of \"\$file\"." 78 | chmod $BM_ARCHIVE_CHMOD $file || 79 | warning "Unable to change file permissions of \"\$file\"." 80 | fi 81 | } 82 | 83 | # this is the callback wich is run when backup-manager 84 | # is stopped with a signal like SIGTERM or SIGKILL 85 | # We have to take care of the incomplete builds, in order to leave a repository with 86 | # only trustable archives and friends. 87 | function clean_exit() 88 | { 89 | echo "" 90 | warning "Warning, process interrupted." 91 | if [[ -n "$bm_pending_archive" ]] && [[ -e "$bm_pending_archive" ]]; then 92 | 93 | # remove the archive that is being built (it's incomplete) 94 | warning "Removing archive \"\$bm_pending_archive\" (build interrupted)." 95 | rm -f $bm_pending_archive 96 | 97 | # if we're building incremental stuff, restore the original incremental list file 98 | if [[ -n "$bm_pending_incremental_list" ]]; then 99 | if [[ -e "${bm_pending_incremental_list}.orig" ]]; then 100 | warning "Restoring incremental-building details list: \"\$bm_pending_incremental_list\"." 101 | rm -f $bm_pending_incremental_list 102 | mv "${bm_pending_incremental_list}.orig" $bm_pending_incremental_list 103 | else 104 | warning "Removing incremental-building details list: \"$bm_pending_incremental_list\"." 105 | rm -f $bm_pending_incremental_list 106 | fi 107 | fi 108 | fi 109 | release_lock 110 | bm_dbus_send_progress 100 "Finished" 111 | bm_dbus_send_event "shutdown" "70" 112 | exit 70 113 | } 114 | 115 | function commit_archives() 116 | { 117 | file_to_create="$1" 118 | debug "commit_archives ($file_to_create)" 119 | 120 | if [[ "$BM_TARBALL_FILETYPE" = "dar" ]]; then 121 | for dar_file in $file_to_create.*.dar 122 | do 123 | commit_archive "$dar_file" 124 | done 125 | else 126 | commit_archive "$file_to_create" 127 | fi 128 | } 129 | 130 | function handle_tarball_error() 131 | { 132 | target="$1" 133 | logfile="$2" 134 | debug "handle_tarball_error ($target, $logfile)" 135 | 136 | warning "Unable to create \"\$target\", check \$logfile" 137 | nb_err=$(($nb_err + 1)) 138 | 139 | chown_archive "$target" 140 | } 141 | 142 | function __exec_meta_command() 143 | { 144 | nice="$nice_bin -n $BM_ARCHIVE_NICE_LEVEL" 145 | command="$nice $1" 146 | file_to_create="$2" 147 | compress="$3" 148 | debug "__exec_meta_command ($command, $file_to_create, $compress)" 149 | 150 | if [[ -f $file_to_create ]] && [[ $force != true ]] 151 | 152 | then 153 | warning "File \$file_to_create already exists, skipping." 154 | export BM_RET="" 155 | else 156 | logfile=$(mktemp ${BM_TEMP_DIR}/bm-command.XXXXXX) 157 | 158 | case "$compress" in 159 | "gzip"|"gz"|"bzip"|"bzip2") 160 | if [[ "$compress" = "gzip" ]] || 161 | [[ "$compress" = "gz" ]]; then 162 | compress_bin=$gzip 163 | if [[ -z "$compress_bin" ]]; then 164 | error "gzip is not installed but gzip compression needed." 165 | fi 166 | ext="gz" 167 | fi 168 | if [[ "$compress" = "bzip2" ]] || 169 | [[ "$compress" = "bzip" ]]; then 170 | compress_bin=$bzip 171 | if [[ -z "$compress_bin" ]]; then 172 | error "bzip2 is not installed but bzip2 compression needed." 173 | fi 174 | ext="bz2" 175 | fi 176 | 177 | if [[ -n "$compress_bin" ]] && [[ -x "$compress_bin" ]]; then 178 | debug "$command > $file_to_create 2> $logfile" 179 | tail_logfile "$logfile" 180 | if [[ "$BM_ENCRYPTION_METHOD" = "gpg" ]]; then 181 | $command 2>$logfile | $nice $compress_bin -f -q -9 2>$logfile | $nice $gpg $BM__GPG_HOMEDIR -r "$BM_ENCRYPTION_RECIPIENT" -e > $file_to_create.$ext.gpg 2> $logfile 182 | debug "$command | $nice $compress_bin -f -q -9 | $nice $gpg $BM__GPG_HOMEDIR -r \"$BM_ENCRYPTION_RECIPIENT\" -e > $file_to_create.$ext.gpg 2> $logfile" 183 | file_to_create="$file_to_create.$ext.gpg" 184 | else 185 | $command 2> $logfile | $nice $compress_bin -f -q -9 > $file_to_create.$ext 2> $logfile 186 | file_to_create="$file_to_create.$ext" 187 | fi 188 | 189 | if [[ $? -gt 0 ]]; then 190 | warning "Unable to exec \$command; check \$logfile" 191 | rm -f $file_to_create 192 | else 193 | rm -f $logfile 194 | fi 195 | else 196 | error "Compressor \$compress is needed." 197 | fi 198 | ;; 199 | ""|"uncompressed"|"none") 200 | if [[ "$verbosedebug" == "true" ]]; then 201 | tail -f $logfile & 202 | fi 203 | 204 | debug "$command 1> $file_to_create 2>$logfile" 205 | tail_logfile "$logfile" 206 | if [[ "$BM_ENCRYPTION_METHOD" = "gpg" ]]; then 207 | $command | $nice $gpg $BM__GPG_HOMEDIR -r "$BM_ENCRYPTION_RECIPIENT" -e > $file_to_create.gpg 2> $logfile 208 | file_to_create="$file_to_create.gpg" 209 | else 210 | $command 1> $file_to_create 2>$logfile 211 | fi 212 | 213 | if [[ $? -gt 0 ]]; then 214 | warning "Unable to exec \$command; check \$logfile" 215 | rm -f $file_to_create 216 | else 217 | rm -f $logfile 218 | fi 219 | ;; 220 | *) 221 | error "No such compressor supported: \$compress." 222 | ;; 223 | esac 224 | 225 | # make sure we didn't loose the archive 226 | if [[ ! -e $file_to_create ]]; then 227 | error "Unable to find \$file_to_create" 228 | fi 229 | export BM_RET="$file_to_create" 230 | fi 231 | } 232 | 233 | function __create_file_with_meta_command() 234 | { 235 | debug "__create_file_with_meta_command ()" 236 | 237 | __exec_meta_command "$command" "$file_to_create" "$compress" 238 | file_to_create="$BM_RET" 239 | if [[ -n "$BM_RET" ]]; then 240 | commit_archive "$file_to_create" 241 | fi 242 | chown_archive "$file_to_create" 243 | } 244 | 245 | 246 | # Thanks to Michel Grentzinger for his 247 | # smart ideas/remarks about that function. 248 | function __get_flags_relative_blacklist() 249 | { 250 | switch="$1" 251 | target="$2" 252 | debug "__get_flags_relative_blacklist ($switch, $target)" 253 | 254 | if [ "$target" != "/" ]; then 255 | target=${target%/} 256 | fi 257 | blacklist="" 258 | for pattern in $BM_TARBALL_BLACKLIST 259 | do 260 | # absolute paths 261 | char=$(expr substr $pattern 1 1) 262 | if [[ "$char" = "/" ]]; then 263 | 264 | # we blacklist only absolute paths related to $target 265 | if [[ "${pattern#$target}" != "$pattern" ]]; then 266 | 267 | # making a relative path... 268 | pattern="${pattern#$target}" 269 | length=$(expr length $pattern) 270 | # for $target="/", no spare / is left at the beggining 271 | # after the # substitution; thus take substr from pos 1 272 | if [ "$target" != "/" ]; then 273 | pattern=$(expr substr $pattern 2 $length) 274 | else 275 | pattern=$(expr substr $pattern 1 $length) 276 | fi 277 | 278 | # ...and blacklisting it 279 | blacklist="$blacklist ${switch}${pattern}" 280 | fi 281 | 282 | # relative path are blindly appended to the blacklist 283 | else 284 | blacklist="$blacklist ${switch}${pattern}" 285 | fi 286 | done 287 | 288 | } 289 | 290 | function __get_flags_dar_blacklist() 291 | { 292 | target="$1" 293 | debug "__get_flags_dar_blacklist ($target)" 294 | 295 | __get_flags_relative_blacklist "-P" "$target" 296 | } 297 | 298 | function __get_flags_tar_blacklist() 299 | { 300 | target="$1" 301 | debug "__get_flags_tar_blacklist ($target)" 302 | 303 | __get_flags_relative_blacklist "--exclude=" "$target" 304 | } 305 | 306 | 307 | function __get_flags_zip_dump_symlinks() 308 | { 309 | debug "__get_flags_zip_dump_symlinks" 310 | 311 | export ZIP="" 312 | export ZIPOPT="" 313 | y="-y" 314 | if [[ "$BM_TARBALL_DUMPSYMLINKS" = "true" ]]; then 315 | y="" 316 | fi 317 | echo "$y" 318 | } 319 | 320 | function __get_flags_tar_dump_symlinks() 321 | { 322 | debug "__get_flags_tar_dump_symlinks" 323 | 324 | h="" 325 | if [[ "$BM_TARBALL_DUMPSYMLINKS" = "true" ]]; then 326 | h="-h " 327 | fi 328 | echo "$h" 329 | } 330 | 331 | function __get_file_to_create() 332 | { 333 | target="$1" 334 | debug "__get_file_to_create ($target)" 335 | 336 | dir_name=$(get_dir_name "$target" $BM_TARBALL_NAMEFORMAT) 337 | file_to_create="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$TODAY${master}.$BM_TARBALL_FILETYPE" 338 | 339 | # dar appends itself the ".dar" extension 340 | if [[ "$BM_TARBALL_FILETYPE" = "dar" ]]; then 341 | file_to_create="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$TODAY${master}" 342 | fi 343 | echo "$file_to_create" 344 | } 345 | 346 | function __get_file_to_create_remote() 347 | { 348 | target="$1" 349 | host="$2" 350 | debug "__get_file_to_create_remote ($target, $host)" 351 | 352 | dir_name=$(get_dir_name "$target" $BM_TARBALL_NAMEFORMAT) 353 | file_to_create="$BM_REPOSITORY_ROOT/${host}${dir_name}.$TODAY${master}.$BM_TARBALL_FILETYPE" 354 | 355 | echo "$file_to_create" 356 | } 357 | 358 | function __get_master_day() 359 | { 360 | debug "__get_master_day ()" 361 | 362 | if [[ -z "$BM_TARBALLINC_MASTERDATETYPE" ]]; then 363 | error "No frequency given, set BM_TARBALLINC_MASTERDATETYPE." 364 | fi 365 | 366 | case $BM_TARBALLINC_MASTERDATETYPE in 367 | weekly) 368 | master_day=$(date +'%w') 369 | ;; 370 | monthly) 371 | master_day=$(date +'%-d') 372 | ;; 373 | *) 374 | error "Unknown frequency: \$BM_TARBALLINC_MASTERDATETYPE" 375 | ;; 376 | esac 377 | } 378 | 379 | function __init_masterdatevalue() 380 | { 381 | debug "__init_masterdatevalue ()" 382 | 383 | if [[ -z "$BM_TARBALLINC_MASTERDATEVALUE" ]]; then 384 | BM_TARBALLINC_MASTERDATEVALUE="1" 385 | fi 386 | } 387 | 388 | function __get_flags_tar_incremental() 389 | { 390 | dir_name="$1" 391 | debug "__get_flags_tar_incremental ($dir_name)" 392 | 393 | incremental_list="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.incremental.bin" 394 | bm_pending_incremental_list="$incremental_list" 395 | if [[ -e "${incremental_list}" ]]; then 396 | debug "cp $incremental_list ${incremental_list}.orig" 397 | cp $incremental_list "${incremental_list}.orig" 398 | fi 399 | 400 | incremental="" 401 | __get_master_day 402 | __init_masterdatevalue 403 | 404 | # if master day, we have to purge the incremental list if exists 405 | # so we'll generate a new one (and then, a full backup). 406 | if [[ "$master_day" -eq "$BM_TARBALLINC_MASTERDATEVALUE" ]]; then 407 | info "Building master backup for target: \"\$dir_name\"." 408 | rm -f "$incremental_list" 409 | fi 410 | if [[ -e "$incremental_list" ]]; then 411 | master="" 412 | fi 413 | incremental="--listed-incremental $incremental_list" 414 | } 415 | 416 | # This will set the appropriate dar options for making incremental backups. 417 | function __get_flags_dar_incremental() 418 | { 419 | dir_name="$1" 420 | debug "__get_flags_dar_incremental ($dir_name)" 421 | 422 | incremental="" 423 | 424 | __get_master_day 425 | __init_masterdatevalue 426 | 427 | # looking for the youngest last DAR backup available 428 | for pastdays in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 429 | do 430 | lastday=$(date +'%Y%m%d' --date "$pastdays days ago") 431 | lastday_dar="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$lastday.dar" 432 | lastday_dar_first_slice="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$lastday.1.dar" 433 | lastday_dar_master="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$lastday.master.dar" 434 | lastday_dar_master_first_slice="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$lastday.master.1.dar" 435 | 436 | if [[ -e $lastday_dar ]] || [[ -e $lastday_dar_first_slice ]] || [[ -e $lastday_dar_master ]] || [[ -e $lastday_dar_master_first_slice ]]; then 437 | # we have found a previous dar backup, this one will be used as a reference 438 | # if needed. 439 | break 440 | fi 441 | done 442 | 443 | # If we aren't the "full backup" day, we take the previous backup as 444 | # a reference for the incremental stuff. 445 | # We have to find the previous backup for that... 446 | if [[ "$master_day" != "$BM_TARBALLINC_MASTERDATEVALUE" ]] ; then 447 | 448 | # Either we have a master backup made lastday... 449 | if [[ -e $lastday_dar_master ]] || 450 | [[ -e $lastday_dar_master_first_slice ]] ; then 451 | incremental="--ref $BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$lastday.master" 452 | 453 | # ... Or we have an incremental backup made lastday 454 | elif [[ -e $lastday_dar ]] || [[ -e $lastday_dar_first_slice ]] ; then 455 | incremental="--ref $BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$lastday" 456 | fi 457 | 458 | # if we use some --ref then, it's not a master but an incremental backup. 459 | if [[ -n "$incremental" ]] ; then 460 | master="" 461 | fi 462 | fi 463 | } 464 | 465 | function __get_flags_dar_maxsize() 466 | { 467 | debug "__get_flags_dar_maxsize ()" 468 | 469 | if [[ -n "$BM_TARBALL_SLICESIZE" ]]; then 470 | maxsize="--alter=SI -s $BM_TARBALL_SLICESIZE" 471 | fi 472 | echo "$maxsize" 473 | } 474 | 475 | function __get_flags_dar_overwrite() 476 | { 477 | debug "__get_flags_dar_overwrite" 478 | 479 | if [[ $force = true ]] ; then 480 | overwrite="-w" 481 | fi 482 | 483 | echo "$overwrite" 484 | } 485 | 486 | # FIXME : incremental is not possible remotely 487 | # in the current shape... 488 | function __get_backup_tarball_remote_command() 489 | { 490 | debug "__get_backup_tarball_remote_command ()" 491 | 492 | oldgzip="$GZIP" 493 | export GZIP="-n" 494 | case $BM_TARBALL_FILETYPE in 495 | tar) 496 | __get_flags_tar_blacklist "$target" 497 | command="$tar $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c "$target"" 498 | ;; 499 | tar.gz) 500 | __get_flags_tar_blacklist "$target" 501 | command="$tar $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c -z "$target"" 502 | ;; 503 | tar.bz2|tar.bz) 504 | __get_flags_tar_blacklist "$target" 505 | command="$tar $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c -j "$target"" 506 | ;; 507 | tar.lz) 508 | __get_flags_tar_blacklist "$target" 509 | command="$tar $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c --lzma "$target"" 510 | ;; 511 | *) 512 | error "Remote tarball building is not possible with this archive filetype: \"$BM_TARBALL_FILETYPE\"." 513 | ;; 514 | esac 515 | export GZIP="$oldgzip" 516 | echo "$nice_bin -n $BM_ARCHIVE_NICE_LEVEL $command" 517 | 518 | } 519 | 520 | # This function will take care of changing the behaviour of BM 521 | # regarding the error code given 522 | # 0 is a success case (remove the logfile and commit the archive). 523 | # tar/1 is a warning case (file changed; don't remove the logfile but commit the archive). 524 | # dar/11 is a waring case (file changed; don't remove the logfile but commit the archive). 525 | # >1 is an error code (don't remove the logile, don't commit the archive). 526 | function check_error_code() 527 | { 528 | error_code="$1" 529 | file_to_create="$2" 530 | logfile="$3" 531 | 532 | if [[ -z "$error_code" ]]; then 533 | error_code=0 534 | fi 535 | 536 | # Error checks can depend on the command/error code returned 537 | case "$BM__CURRENT_COMMAND" in 538 | "tar") 539 | if [[ "$error_code" == "1" ]]; then 540 | warning "Tar reported a file changed during archive creation." 541 | commit_archives "$file_to_create" 542 | elif [[ "$error_code" -gt 0 ]]; then 543 | handle_tarball_error "$file_to_create" "$logfile" 544 | else 545 | rm -f $logfile 546 | commit_archives "$file_to_create" 547 | fi 548 | ;; 549 | "dar") 550 | if [[ "$error_code" == "11" ]]; then 551 | warning "Dar reported a file changed during archive creation." 552 | commit_archives "$file_to_create" 553 | elif [[ "$error_code" -gt 0 ]]; then 554 | handle_tarball_error "$file_to_create" "$logfile" 555 | else 556 | rm -f $logfile 557 | commit_archives "$file_to_create" 558 | fi 559 | ;; 560 | *) 561 | if [[ "$error_code" -gt 0 ]]; then 562 | handle_tarball_error "$file_to_create" "$logfile" 563 | else 564 | rm -f $logfile 565 | commit_archives "$file_to_create" 566 | fi 567 | ;; 568 | esac 569 | 570 | # Reset the error code 571 | error_code=0 572 | } 573 | 574 | function __get_backup_tarball_command() 575 | { 576 | debug "__get_backup_tarball_command ()" 577 | 578 | case $BM_TARBALL_FILETYPE in 579 | tar) 580 | __get_flags_tar_blacklist "$target" 581 | command="$tar $incremental $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c -f" 582 | ;; 583 | tar.gz) 584 | __get_flags_tar_blacklist "$target" 585 | command="$tar $incremental $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c -z -f" 586 | ;; 587 | tar.bz2|tar.bz) 588 | if [[ ! -x $bzip ]]; then 589 | error "The archive type \"tar.bz2\" depends on the tool \"\$bzip\"." 590 | fi 591 | __get_flags_tar_blacklist "$target" 592 | command="$tar $incremental $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c -j -f" 593 | ;; 594 | tar.lz) 595 | if [[ ! -x $lzma ]]; then 596 | error "The archive type \"tar.lz\" depends on the tool \"\$lzma\"." 597 | fi 598 | __get_flags_tar_blacklist "$target" 599 | command="$tar $incremental $blacklist $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -p -c --lzma -f" 600 | ;; 601 | zip) 602 | if [[ ! -x $zip ]]; then 603 | error "The archive type \"zip\" depends on the tool \"\$zip\"." 604 | fi 605 | command="$zip $dumpsymlinks $BM_TARBALL_EXTRA_OPTIONS -r" 606 | ;; 607 | dar) 608 | if [[ ! -x $dar ]]; then 609 | error "The archive type \"dar\" depends on the tool \"\$dar\"." 610 | fi 611 | __get_flags_dar_blacklist "$target" 612 | command="$dar $incremental $blacklist $maxsize $overwrite $BM_TARBALL_EXTRA_OPTIONS -z9 -Q -c $file_to_create -R" 613 | ;; 614 | *) 615 | error "The archive type \"\$BM_TARBALL_FILETYPE\" is not supported." 616 | return 1 617 | ;; 618 | esac 619 | echo "$nice_bin -n $BM_ARCHIVE_NICE_LEVEL $command" 620 | } 621 | 622 | function build_clear_archive 623 | { 624 | debug "build_clear_archive ()" 625 | 626 | logfile=$(mktemp ${BM_TEMP_DIR}/bm-tarball.log.XXXXXX) 627 | debug "logfile: $logfile" 628 | 629 | # A couple of archive types have a special command line 630 | case "$BM_TARBALL_FILETYPE" in 631 | 632 | # dar has a special commandline, that cannot fit the common tar way 633 | "dar") 634 | BM__CURRENT_COMMAND="dar" 635 | debug "$command $target> $logfile 2>&1" 636 | tail_logfile "$logfile" 637 | 638 | $command "$target"> $logfile 2>&1 || error_code=$? 639 | check_error_code "$error_code" "$file_to_create" "$logfile" 640 | ;; 641 | 642 | # the common commandline 643 | *) 644 | # tar, tar.gz, tar.bz2, tar.whatever 645 | if [[ "${BM_TARBALL_FILETYPE:0:3}" == "tar" ]] ; then 646 | BM__CURRENT_COMMAND="tar" 647 | else 648 | BM__CURRENT_COMMAND="generic" 649 | fi 650 | debug "$command $file_to_create \"$target\" > $logfile 2>&1" 651 | tail_logfile "$logfile" 652 | debug "$command $file_to_create \"$target\"" 653 | $command $file_to_create "$target" > $logfile 2>&1 || error_code=$? 654 | check_error_code "$error_code" "$file_to_create" "$logfile" 655 | ;; 656 | esac 657 | BM__CURRENT_COMMAND="" 658 | } 659 | 660 | 661 | function build_encrypted_archive 662 | { 663 | debug "build_encrypted_archive" 664 | logfile=$(mktemp ${BM_TEMP_DIR}/bm-tarball.log.XXXXXX) 665 | debug "logfile: $logfile" 666 | 667 | if [[ -z "$BM_ENCRYPTION_RECIPIENT" ]]; then 668 | error "The configuration variable \"BM_ENCRYPTION_RECIPIENT\" must be defined." 669 | fi 670 | 671 | if [[ "$BM_TARBALL_FILETYPE" = "tar.lz" ]] || 672 | [[ "$BM_TARBALL_FILETYPE" = "zip" ]] || 673 | [[ "$BM_TARBALL_FILETYPE" = "dar" ]]; then 674 | error "The encryption is not yet possible with \"\$BM_TARBALL_FILETYPE\" archives." 675 | fi 676 | 677 | file_to_create="$file_to_create.gpg" 678 | 679 | debug "$command - \"$target\" 2>>$logfile | $gpg $BM__GPG_HOMEDIR -r \"$BM_ENCRYPTION_RECIPIENT\" -e > $file_to_create 2>> $logfile" 680 | tail_logfile "$logfile" 681 | 682 | $command - "$target" 2>>$logfile | $gpg $BM__GPG_HOMEDIR -r "$BM_ENCRYPTION_RECIPIENT" -e > $file_to_create 2>> $logfile || error_code=$? 683 | check_error_code "$error_code" "$file_to_create" "$logfile" 684 | } 685 | 686 | function __build_local_archive() 687 | { 688 | target="$1" 689 | dir_name="$2" 690 | debug "__build_local_archive ($target, $dir_name)" 691 | 692 | file_to_create=$(__get_file_to_create "$target") 693 | command="$(__get_backup_tarball_command)" || 694 | error "The archive type \"\$BM_TARBALL_FILETYPE\" is not supported." 695 | 696 | # dar is not like tar, we have to manually check for existing .1.dar files 697 | if [[ $BM_TARBALL_FILETYPE = dar ]]; then 698 | file_to_check="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$dir_name.$TODAY.1.dar" 699 | else 700 | file_to_check="$file_to_create" 701 | fi 702 | 703 | if [[ "$BM_ENCRYPTION_METHOD" = "gpg" ]]; then 704 | file_to_check="$file_to_check.gpg" 705 | fi 706 | 707 | 708 | # let's exec the command 709 | if [[ ! -e "$file_to_check" ]] || [[ "$force" = "true" ]]; then 710 | if [[ "$BM_ENCRYPTION_METHOD" = "gpg" ]]; then 711 | if [[ ! -x $gpg ]]; then 712 | error "The program \"\$gpg\" is needed." 713 | fi 714 | bm_pending_archive="${file_to_check}" 715 | build_encrypted_archive 716 | else 717 | bm_pending_archive="${file_to_check}" 718 | build_clear_archive 719 | fi 720 | else 721 | warning "File \$file_to_check already exists, skipping." 722 | debug "rm -f ${bm_pending_incremental_list}.orig" 723 | rm -f "${bm_pending_incremental_list}.orig" 724 | continue 725 | fi 726 | } 727 | 728 | function __build_remote_archive() 729 | { 730 | target="$1" 731 | dir_name="$2" 732 | debug "__build_remote_archive ($target, $dir_name)" 733 | 734 | for host in $BM_UPLOAD_SSH_HOSTS 735 | do 736 | logfile=$(mktemp ${BM_TEMP_DIR}/bm-tarball.log.XXXXXX) 737 | file_to_create=$(__get_file_to_create_remote "$target" "$host") 738 | 739 | command=$(__get_backup_tarball_remote_command) || 740 | error "The archive type \"\$BM_TARBALL_FILETYPE\" is not supported." 741 | 742 | remote_command="ssh -p ${BM_UPLOAD_SSH_PORT} -i ${BM_UPLOAD_SSH_KEY} -o BatchMode=yes ${BM_UPLOAD_SSH_USER}@${host} $command" 743 | file_to_check="$file_to_create" 744 | 745 | if [[ ! -e "$file_to_check" ]] || [[ $force = true ]]; then 746 | 747 | logfile=$(mktemp ${BM_TEMP_DIR}/bm-tarball.log.XXXXXX) 748 | 749 | debug "$remote_command > $file_to_create 2>$logfile" 750 | tail_logfile "$logfile" 751 | $remote_command > "$file_to_create" 2>$logfile || error_code=$? 752 | check_error_code "$error_code" "$file_to_create" "$logfile" 753 | else 754 | warning "File \$file_to_check already exists, skipping." 755 | continue 756 | fi 757 | done 758 | } 759 | 760 | function __make_remote_tarball_token 761 | { 762 | t="$1" 763 | debug "__make_remote_tarball_token ($t)" 764 | 765 | dir_name=$(get_dir_name "$t" $BM_TARBALL_NAMEFORMAT) 766 | master=".master" 767 | __build_remote_archive "$t" "$dir_name" 768 | } 769 | 770 | function __make_local_tarball_token 771 | { 772 | t="$1" 773 | debug "__make_local_tarball_token ($t)" 774 | 775 | # look for the target in the blacklist... 776 | is_blacklisted="0" 777 | for blacklist_pattern in $BM_TARBALL_BLACKLIST; do 778 | if [[ "$t" == "$blacklist_pattern" ]]; then 779 | is_blacklisted="1" 780 | fi 781 | done 782 | 783 | 784 | # ignore the target if it's blacklisted 785 | if [[ "$is_blacklisted" == "1" ]]; then 786 | info "Target \"\$t\" is found in blacklist, skipping." 787 | 788 | # be sure the target exists 789 | elif [[ ! -e "$t" ]] || [[ ! -r "$t" ]]; then 790 | warning "Target \"\$t\" does not exist, skipping." 791 | nb_err=$(($nb_err + 1)) 792 | 793 | # Everything's OK, do the job 794 | else 795 | # we assume we'll build a master backup (full archive). 796 | # If we make incremental backup, the $master keyword 797 | # will be reset. 798 | dir_name=$(get_dir_name "$t" $BM_TARBALL_NAMEFORMAT) 799 | master=".master" 800 | 801 | # handling of incremental options 802 | incremental="" 803 | 804 | if [[ $method = tarball-incremental ]] 805 | then 806 | case "$BM_TARBALL_FILETYPE" in 807 | "dar") 808 | __get_flags_dar_incremental "$dir_name" 809 | ;; 810 | "tar"|"tar.gz"|"tar.bz2") 811 | __get_flags_tar_incremental "$dir_name" 812 | ;; 813 | esac 814 | fi 815 | __build_local_archive "$t" "$dir_name" 816 | fi 817 | } 818 | 819 | function __make_remote_tarball_archives() 820 | { 821 | debug "__make_remote_tarball_archives" 822 | 823 | nb_err=0 824 | for target in "${BM_TARBALL_TARGETS[@]}" 825 | do 826 | if [[ -z "$target" ]]; then 827 | continue 828 | fi 829 | __make_remote_tarball_token "$target" 830 | done 831 | } 832 | 833 | function __make_local_tarball_archives() 834 | { 835 | debug "__make_local_tarball_archives" 836 | 837 | nb_err=0 838 | for target in "${BM_TARBALL_TARGETS[@]}" 839 | do 840 | if [[ -z "$target" ]]; then 841 | continue 842 | fi 843 | target_expanded="$(eval 'echo $target')" 844 | 845 | # if the target exists, handle it as a single token 846 | if [[ -r "$target_expanded" ]]; then 847 | __make_local_tarball_token "$target_expanded" 848 | 849 | # else try to expand the target in several tokens 850 | else 851 | for t in $target_expanded 852 | do 853 | __make_local_tarball_token "$t" 854 | done 855 | fi 856 | done 857 | } 858 | 859 | # This manages both "tarball" and "tarball-incremental" methods. 860 | # configuration keys: BM_TARBALL_* and BM_TARBALLINC_* 861 | function backup_method_tarball() 862 | { 863 | method="$1" 864 | debug "backup_method_tarball ($method)" 865 | 866 | info "Using method \"\$method\"." 867 | 868 | # build the command line 869 | case $BM_TARBALL_FILETYPE in 870 | tar|tar.bz2|tar.gz) 871 | dumpsymlinks="$(__get_flags_tar_dump_symlinks)" 872 | ;; 873 | zip) 874 | dumpsymlinks="$(__get_flags_zip_dump_symlinks)" 875 | ;; 876 | dar) 877 | maxsize="$(__get_flags_dar_maxsize)" 878 | overwrite="$(__get_flags_dar_overwrite)" 879 | ;; 880 | esac 881 | 882 | if [[ "$BM_TARBALL_OVER_SSH" != "true" ]]; then 883 | __make_local_tarball_archives 884 | else 885 | __make_remote_tarball_archives 886 | fi 887 | 888 | # Handle errors 889 | # since version 0.8, BM's follows up its process even if errors were triggered 890 | # during the archive generation. 891 | if [[ $nb_err -eq 1 ]]; then 892 | warning "1 error occurred during the tarball generation." 893 | elif [[ $nb_err -gt 1 ]]; then 894 | warning "\$nb_err errors occurred during the tarball generation." 895 | fi 896 | } 897 | 898 | function backup_method_pgsql() 899 | { 900 | method="$1" 901 | pgsql_conffile="$HOME/.pgpass" 902 | pgsql_conffile_bm="$HOME/.pgpass.backup-manager.bak" 903 | 904 | debug "backup_method_pgsql ($method)" 905 | 906 | info "Using method \"\$method\"." 907 | if [[ -x $pgdump ]] && [[ -x ${pgdump}all ]]; then 908 | : 909 | else 910 | error "The \"postgresql\" method is chosen, but \$pgdump and/or \$pgdumpall are not found." 911 | fi 912 | 913 | # Allow empty host when connecting to postgress with unix sockets. 914 | 915 | if [[ "X$BM_PGSQL_HOST" = "X" ]]; then 916 | BM_PGSQL_HOSTFLAGS="" 917 | else 918 | BM_PGSQL_HOSTFLAGS="-h$BM_PGSQL_HOST" 919 | fi 920 | opt=" -U$BM_PGSQL_ADMINLOGIN $BM_PGSQL_HOSTFLAGS -p$BM_PGSQL_PORT" 921 | 922 | # We need a second variable, to know if the backup pgpass file was used. 923 | 924 | BM_SHOULD_PURGE_PGPASS="false" 925 | BM_USING_BACKUP_PGPASS="false" 926 | 927 | if [[ -f $pgsql_conffile ]]; then 928 | info "Found existing PgSQL client configuration file: \$pgsql_conffile" 929 | info "Looking for matching credentials in this file..." 930 | if ! grep -qE "(${BM_PGSQL_HOST}|[^:]*):(${BM_PGSQL_PORT}|[^:]*):[^:]*:${BM_PGSQL_ADMINLOGIN}:${BM_PGSQL_ADMINPASS}" $pgsql_conffile; then 931 | info "No matching credentials: inserting our own." 932 | BM_SHOULD_PURGE_PGPASS="true" 933 | BM_USING_BACKUP_PGPASS="true" 934 | mv $pgsql_conffile $pgsql_conffile_bm 935 | touch $pgsql_conffile 936 | chmod 0600 $pgsql_conffile 937 | echo "${BM_PGSQL_HOST}:${BM_PGSQL_PORT}:*:${BM_PGSQL_ADMINLOGIN}:${BM_PGSQL_ADMINPASS}" >> $pgsql_conffile 938 | fi 939 | else 940 | warning "Creating a default PgSQL client configuration file: \$HOME/.pgpass" 941 | touch $pgsql_conffile 942 | chmod 0600 $pgsql_conffile 943 | echo "${BM_PGSQL_HOST}:${BM_PGSQL_PORT}:*:${BM_PGSQL_ADMINLOGIN}:${BM_PGSQL_ADMINPASS}" >> $pgsql_conffile 944 | fi 945 | 946 | compress="$BM_PGSQL_FILETYPE" 947 | 948 | for database in $BM_PGSQL_DATABASES 949 | do 950 | if [[ "$database" = "__ALL__" ]]; then 951 | file_to_create="$BM_REPOSITORY_ROOT/${BM_ARCHIVE_PREFIX}-all-pgsql-databases.$TODAY.sql" 952 | command="${pgdump}all $opt $BM_PGSQL_EXTRA_OPTIONS" 953 | else 954 | file_to_create="$BM_REPOSITORY_ROOT/${BM_ARCHIVE_PREFIX}-pgsql-${database}.$TODAY.sql" 955 | command="$pgdump $opt $database $BM_PGSQL_EXTRA_OPTIONS" 956 | fi 957 | __create_file_with_meta_command 958 | done 959 | 960 | # purge the .pgpass file, if created by Backup Manager 961 | if [[ "$BM_SHOULD_PURGE_PGPASS" == "true" ]]; then 962 | info "Removing default PostgreSQL password file: \$pgsql_conffile" 963 | rm -f $pgsql_conffile 964 | if [[ "$BM_USING_BACKUP_PGPASS" == "true" ]]; then 965 | info "restoring initial \$pgsql_conffile file from backup." 966 | warning "To avoid problems with \$pgsql_conffile, insert the configured host:port:database:user:password inside." 967 | mv $pgsql_conffile_bm $pgsql_conffile 968 | fi 969 | fi 970 | } 971 | 972 | 973 | function backup_method_mysql() 974 | { 975 | method="$1" 976 | mysql_conffile="$HOME/.backup-manager_my.cnf" 977 | 978 | debug "backup_method_mysql ($method)" 979 | 980 | info "Using method \"\$method\"." 981 | if [[ ! -x $mysqldump ]]; then 982 | error "The \"mysql\" method is chosen, but \$mysqldump is not found." 983 | fi 984 | 985 | opt="" 986 | if [[ "$BM_MYSQL_SAFEDUMPS" = "true" ]]; then 987 | opt="--opt" 988 | fi 989 | 990 | # if a MySQL Client conffile exists, the password must be inside 991 | if [[ -f $mysql_conffile ]]; then 992 | info "Using existing MySQL client configuration file: \$mysql_conffile" 993 | BM_SHOULD_PURGE_MYCNF="false" 994 | # we create a default one, just with the password 995 | else 996 | warning "Creating a default MySQL client configuration file: \$mysql_conffile" 997 | echo "[client]" > $mysql_conffile 998 | echo "# The following password will be sent to all standard MySQL clients" >> $mysql_conffile 999 | chmod 600 $mysql_conffile 1000 | echo "password=\"$BM_MYSQL_ADMINPASS\"" >> $mysql_conffile 1001 | BM_SHOULD_PURGE_MYCNF="true" 1002 | fi 1003 | base_command="$mysqldump --defaults-extra-file=$mysql_conffile $opt -u$BM_MYSQL_ADMINLOGIN -h$BM_MYSQL_HOST -P$BM_MYSQL_PORT $BM_MYSQL_EXTRA_OPTIONS" 1004 | compress="$BM_MYSQL_FILETYPE" 1005 | 1006 | for database in $BM_MYSQL_DATABASES 1007 | do 1008 | if [[ "$database" = "__ALL__" ]]; then 1009 | file_to_create="$BM_REPOSITORY_ROOT/${BM_ARCHIVE_PREFIX}-all-mysql-databases.$TODAY.sql" 1010 | command="$base_command --all-databases" 1011 | else 1012 | file_to_create="$BM_REPOSITORY_ROOT/${BM_ARCHIVE_PREFIX}-mysql-${database}.$TODAY.sql" 1013 | command="$base_command $database" 1014 | fi 1015 | __create_file_with_meta_command 1016 | done 1017 | 1018 | # purge the my.cnf file, if created by Backup Manager 1019 | if [[ "$BM_SHOULD_PURGE_MYCNF" == "true" ]]; then 1020 | info "Removing default MySQL client configuration file: \$mysql_conffile" 1021 | rm -f $mysql_conffile 1022 | fi 1023 | } 1024 | 1025 | function backup_method_svn() 1026 | { 1027 | method="$1" 1028 | debug "backup_method_svn ($method)" 1029 | 1030 | info "Using method \"\$method\"." 1031 | if [[ ! -x $svnadmin ]]; then 1032 | error "The \"svn\" method is chosen, but \$svnadmin is not found." 1033 | fi 1034 | 1035 | for repository in $BM_SVN_REPOSITORIES 1036 | do 1037 | if [[ ! -d $repository ]]; then 1038 | warning "SVN repository \"\$repository\" is not valid; skipping." 1039 | else 1040 | archive_name=$(get_dir_name $repository "long") 1041 | file_to_create="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX$archive_name.$TODAY.svn" 1042 | command="$svnadmin -q dump $repository" 1043 | compress="$BM_SVN_COMPRESSWITH" 1044 | __create_file_with_meta_command 1045 | fi 1046 | done 1047 | } 1048 | 1049 | function backup_method_pipe() 1050 | { 1051 | method="$1" 1052 | debug "backup_method_pipe ($method)" 1053 | 1054 | info "Using method \"\$method\"." 1055 | index=0 1056 | 1057 | # parse each BM_PIPE_NAME's 1058 | for archive in ${BM_PIPE_NAME[*]} 1059 | do 1060 | # make sure everything is here for this archive 1061 | if [[ -z "${BM_PIPE_COMMAND[$index]}" ]] || 1062 | [[ -z "${BM_PIPE_FILETYPE[$index]}" ]]; then 1063 | warning "Not enough args for this archive (\$archive), skipping." 1064 | continue 1065 | fi 1066 | command="${BM_PIPE_COMMAND[$index]}" 1067 | filetype="${BM_PIPE_FILETYPE[$index]}" 1068 | file_to_create="$BM_REPOSITORY_ROOT/$BM_ARCHIVE_PREFIX-$archive.$TODAY.$filetype" 1069 | compress="${BM_PIPE_COMPRESS[$index]}" 1070 | __create_file_with_meta_command || error "Cannot create archive." 1071 | 1072 | # update the index mark 1073 | index=$(($index + 1)) 1074 | done 1075 | } 1076 | -------------------------------------------------------------------------------- /examples/bumblebee_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -l 2 | 3 | cat 1>&2 <<-EOF 4 | This script is not to run on any system. 5 | Anh K. Huynh adds this banner to prevent script from being used. 6 | 7 | The original script is here 8 | https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/blob/6cd6b2485668e8a87485cb34ca8a0a937e73f16d/install.sh 9 | EOF 10 | 11 | exit 0 12 | 13 | # ---------------------------------------------------------------------------- 14 | # "Red Bull License" 15 | # wrote this file and is providing free support 16 | # in any spare time. If you need extended support, you can fuel him up by 17 | # donating a Red Bull here to get him through the nights..: 18 | # 19 | # https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mj%40casalogic 20 | # %2edk&lc=US&item_name=The%20Bumblebee%20Project%20by%20Martin%20Juhl&amount= 21 | # 3%2e00¤cy_code=EUR¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateC 22 | # C_LG%2egif%3aNonHosted 23 | # 24 | # ---------------------------------------------------------------------------- 25 | 26 | # 27 | # ---------------------------------------------------------------------------- 28 | # "THE BEER-WARE LICENSE" (Revision 42): 29 | # wrote this file. As long as you retain this notice you 30 | # can do whatever you want with this stuff. If we meet some day, and you think 31 | # this stuff is worth it, you can buy me a beer in return Martin Juhl 32 | # ---------------------------------------------------------------------------- 33 | # 34 | 35 | # This file is part of bumblebee. 36 | # 37 | # bumblebee is free software: you can redistribute it and/or modify 38 | # it under the terms of the GNU General Public License as published by 39 | # the Free Software Foundation, either version 3 of the License, or 40 | # (at your option) any later version. 41 | # 42 | # bumblebee is distributed in the hope that it will be useful, 43 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 44 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 45 | # GNU General Public License for more details. 46 | # 47 | # You should have received a copy of the GNU General Public License 48 | # along with bumblebee. If not, see . 49 | # 50 | BUMBLEBEEVERSION=1.4.29 51 | 52 | 53 | ROOT_UID=0 54 | 55 | #Determine Arch x86_64 or i686 56 | ARCH=`uname -m` 57 | 58 | #Get tools location 59 | LSPCI=`which lspci` 60 | MODPROBE=`which modprobe` 61 | 62 | if [ `cat /etc/issue |grep -nir fedora |wc -l` -gt 0 ]; then 63 | DISTRO=FEDORA 64 | BASHRC=/etc/bashrc 65 | elif [ `cat /etc/issue |grep -nir ubuntu |wc -l` -gt 0 ]; then 66 | DISTRO=UBUNTU 67 | BASHRC=/etc/bash.bashrc 68 | elif [ `cat /etc/issue |grep -nir openSUSE |wc -l` -gt 0 ]; then 69 | DISTRO=OPENSUSE 70 | BASHRC=/etc/bash.bashrc 71 | ROOT_UID=1000 72 | elif [ `cat /etc/issue |grep -nir debian |wc -l` -gt 0 ]; then 73 | DISTRO=DEBIAN 74 | BASHRC=/etc/bash.bashrc 75 | elif [ `cat /etc/issue |grep -nir "Arch Linux" |wc -l` -gt 0 ]; then 76 | DISTRO=ARCH 77 | echo "You are running Arch Linux, please see the buildscript here for support:" 78 | echo 79 | echo "http://aur.archlinux.org/packages.php?ID=48866" 80 | echo 81 | read 82 | exit 0 83 | elif [ `cat /etc/issue |grep -nir "gentoo" |wc -l` -gt 0 ]; then 84 | DISTRO=GENTOO 85 | echo "You are running Gento Linux, please see the ebuild here for support:" 86 | echo 87 | echo "https://github.com/iegor/bumblebee-Gentoo-support" 88 | echo 89 | read 90 | exit 0 91 | fi 92 | 93 | echo 94 | echo $DISTRO" distribution found." 95 | echo 96 | 97 | 98 | if [ $UID != $ROOT_UID ] || [ $HOME = /root ]; then 99 | echo "You don't have sufficient privileges to run this script." 100 | echo 101 | echo "Do not run this script as the root user." 102 | echo 103 | case "$DISTRO" in 104 | FEDORA | DEBIAN) 105 | echo "Please run the script with: sudo -E install.sh" 106 | ;; 107 | *) 108 | echo "Please run the script with: sudo install.sh" 109 | ;; 110 | esac 111 | exit 1 112 | fi 113 | 114 | echo "Welcome to the bumblebee installation v."$BUMBLEBEEVERSION 115 | echo "Licensed under Red Bull, BEER-WARE License and GPL" 116 | echo 117 | echo "This will enable you to utilize both your Intel and nVidia card" 118 | echo 119 | echo "Please note that this script will probably only work with Ubuntu, Debian, OpenSuSE and Fedora Based machines" 120 | echo "and has (by me) only been tested on Ubuntu Natty 11.04 and Fedora 14 but should work on others as well" 121 | echo 122 | echo "Are you sure you want to proceed?? (Y/N)" 123 | 124 | read answer 125 | 126 | case "$answer" in 127 | 128 | y | Y ) 129 | ;; 130 | 131 | *) 132 | exit 0 133 | ;; 134 | esac 135 | 136 | clear 137 | 138 | BUMBLEBEEPWD=$PWD 139 | 140 | echo 141 | echo "Installing needed packages." 142 | echo 143 | 144 | case "$DISTRO" in 145 | 146 | UBUNTU) 147 | VERSION=`cat /etc/issue | cut -f2 -d" "` 148 | if [ $VERSION = 11.04 ]; then 149 | echo 150 | echo "Ubuntu 11.04 Detected." 151 | echo 152 | else 153 | echo 154 | echo "Ubuntu "$VERSION" Detected." 155 | echo "Adding X-Swat Driver Repository." 156 | echo 157 | apt-add-repository ppa:ubuntu-x-swat/x-updates 158 | fi 159 | apt-get update 160 | apt-get -y install nvidia-current screen 161 | if [ $? -ne 0 ]; then 162 | echo 163 | echo "Package manager failed to install needed packages..." 164 | echo 165 | exit 21 166 | fi 167 | ${MODPROBE} -r nouveau 168 | ${MODPROBE} nvidia-current 169 | ;; 170 | 171 | FEDORA) 172 | yum -y install wget binutils gcc kernel-devel mesa-libGL mesa-libGLU 173 | if [ $? -ne 0 ]; then 174 | echo 175 | echo "Package manager failed to install needed packages..." 176 | echo 177 | exit 21 178 | fi 179 | rm -rf /tmp/NVIDIA* 180 | echo "Getting latest NVidia drivers version" 181 | NV_DRIVERS_VERSION=`wget -q -O - http://www.nvidia.com/object/unix.html | grep "Linux x86_64/AMD64/EM64T" | cut -f5 -d">" | cut -f1 -d"<"` 182 | echo "Latest NVidia drivers version is $NV_DRIVERS_VERSION" 183 | if [ "$ARCH" = "x86_64" ]; then 184 | wget http://us.download.nvidia.com/XFree86/Linux-x86_64/${NV_DRIVERS_VERSION}/NVIDIA-Linux-x86_64-${NV_DRIVERS_VERSION}.run -O /tmp/NVIDIA-Linux-driver.run 185 | elif [ "$ARCH" = "i686" ]; then 186 | wget http://us.download.nvidia.com/XFree86/Linux-x86/${NV_DRIVERS_VERSION}/NVIDIA-Linux-x86-${NV_DRIVERS_VERSION}.run -O /tmp/NVIDIA-Linux-driver.run 187 | fi 188 | chmod +x /tmp/NVIDIA-Linux-driver.run 189 | cd /tmp/ 190 | /tmp/NVIDIA-Linux-driver.run -x 191 | if [ "$ARCH" = "x86_64" ]; then 192 | cd /tmp/NVIDIA-Linux-x86_64-${NV_DRIVERS_VERSION}/kernel 193 | elif [ "$ARCH" = "i686" ]; then 194 | cd /tmp/NVIDIA-Linux-x86-${NV_DRIVERS_VERSION}/kernel 195 | fi 196 | make install 197 | cd $BUMBLEBEEPWD 198 | depmod -a 199 | ldconfig 200 | ${MODPROBE} -r nouveau 201 | ${MODPROBE} nvidia 202 | 203 | if [ "$ARCH" = "x86_64" ]; then 204 | rm -rf /usr/lib64/nvidia-current/ 205 | rm -rf /usr/lib/nvidia-current/ 206 | rm -rf /usr/lib32/nvidia-current/ 207 | mkdir -p /usr/lib64/nvidia-current/ 208 | mv /tmp/NVIDIA-Linux-x86_64-${NV_DRIVERS_VERSION}/* /usr/lib64/nvidia-current/ 209 | ln -s /usr/lib64/nvidia-current/32 /usr/lib/nvidia-current 210 | mkdir -p /usr/lib64/nvidia-current/xorg 211 | ln -s /usr/lib64/nvidia-current/libglx.so.${NV_DRIVERS_VERSION} /usr/lib64/nvidia-current/xorg/libglx.so 212 | ln -s /usr/lib64/nvidia-current/nvidia_drv.so /usr/lib64/nvidia-current/xorg/nvidia_drv.so 213 | rm -rf /usr/lib64/nvidia-current/xorg/xorg 214 | ln -s /usr/lib64/nvidia-current/xorg/ /usr/lib/nvidia-current/xorg 215 | rm -rf /usr/lib64/xorg/xorg 216 | ln -s /usr/lib64/xorg/ /usr/lib/xorg 217 | elif [ "$ARCH" = "i686" ]; then 218 | rm -rf /usr/lib/nvidia-current/ 219 | mkdir -p /usr/lib/nvidia-current/ 220 | mv /tmp/NVIDIA-Linux-x86-${NV_DRIVERS_VERSION}/* /usr/lib/nvidia-current/ 221 | mkdir -p /usr/lib/nvidia-current/xorg 222 | ln -s /usr/lib/nvidia-current/libglx.so.${NV_DRIVERS_VERSION} /usr/lib/nvidia-current/xorg/libglx.so 223 | ln -s /usr/lib/nvidia-current/nvidia_drv.so /usr/lib/nvidia-current/xorg/nvidia_drv.so 224 | fi 225 | echo 226 | echo "Regenerating initramfs." 227 | echo 228 | mkinitrd -f /boot/initramfs-$(uname -r).img $(uname -r) 229 | ;; 230 | OPENSUSE) 231 | VERSION=`cat /etc/issue |grep openSUSE | cut -f4 -d" "` 232 | echo "Do you want me to install NVidia repository for openSUSE $VERSION (y/n) ?" 233 | read answer 234 | case "$answer" in 235 | y|Y) 236 | zypper ar -f ftp://download.nvidia.com/opensuse/${VERSION}/nvidia 237 | if [ $? -ne 0 ]; then 238 | echo 239 | echo "Package manager failed to install needed packages..." 240 | echo 241 | exit 21 242 | fi 243 | zypper update 244 | ;; 245 | n|N) 246 | echo "NVidia drivers repository will NOT be installed." 247 | ;; 248 | *) 249 | ;; 250 | esac 251 | echo "What is your NVidia card family ?" 252 | echo "1) GF6 or newer" 253 | echo "2) FX5XXX" 254 | echo "3) GF4 or older" 255 | echo "4) Skip NVidia drivers install (you need to do this by yourself in this case)" 256 | read card 257 | 258 | case $card in 259 | 1) 260 | zypper install x11-video-nvidiaG02 261 | ;; 262 | 2) 263 | zypper install x11-video-nvidiaG01 264 | ;; 265 | 3) 266 | zypper install x11-video-nvidiaG01 267 | ;; 268 | 4) 269 | echo "Skip drivers installation. Please remember that NVidia drivers *HAVE TO BE INSTALLED*" 270 | 271 | ;; 272 | *) 273 | echo 274 | echo "Please choose a valid option, Press any key to try again" 275 | read 276 | ;; 277 | DEBIAN) 278 | apt-get update 279 | apt-get -y install nvidia-kernel-dkms nvidia-glx 280 | apt-get -y --reinstall install xserver-xorg-core 281 | if [ $? -ne 0 ]; then 282 | echo 283 | echo "Package manager failed to install needed packages..." 284 | echo "Please check that you have non-free repository enabled." 285 | echo 286 | exit 21 287 | fi 288 | ;; 289 | esac 290 | ${MODPROBE} -r nouveau 291 | ${MODPROBE} nvidia 292 | esac 293 | 294 | 295 | echo 296 | echo "Backing up Configuration" 297 | echo 298 | 299 | if [ `cat $BASHRC |grep VGL |wc -l` -ne 0 ]; then 300 | cp $BASHRC.optiorig $BASHRC 301 | fi 302 | 303 | cp -n /etc/modules /etc/modules.optiorig 304 | cp -n /etc/X11/xorg.conf /etc/X11/xorg.conf.optiorig 305 | 306 | echo 307 | echo "Installing Optimus Configuration and files" 308 | echo 309 | 310 | cp install-files/xorg.conf.intel /etc/X11/xorg.conf 311 | cp install-files/xorg.conf.nvidia /etc/X11/ 312 | 313 | if [ ! -f install-files/bumblebee-enablecard ]; then 314 | # Not installed 315 | cp install-files/bumblebee-enablecard /usr/local/bin/ 316 | else 317 | # Already Exists 318 | echo 319 | echo "nVidia card enable-script: /usr/local/bin/bumblebee-enablecard, already exists not overwriting" 320 | echo 321 | fi 322 | 323 | if [ ! -f install-files/bumblebee-disablecard ]; then 324 | # Not installed 325 | cp install-files/bumblebee-disablecard /usr/local/bin/ 326 | else 327 | # Already Exists 328 | echo 329 | echo "nVidia card disable-script: /usr/local/bin/bumblebee-disablecard, already exists not overwriting" 330 | echo 331 | fi 332 | 333 | cp -n $BASHRC $BASHRC.optiorig 334 | 335 | case "$DISTRO" in 336 | 337 | UBUNTU) 338 | if [ "$ARCH" = "x86_64" ]; then 339 | echo 340 | echo "64-bit system detected" 341 | echo 342 | dpkg -i install-files/VirtualGL_amd64.deb 343 | elif [ "$ARCH" = "i686" ]; then 344 | echo 345 | echo "32-bit system detected" 346 | echo 347 | dpkg -i install-files/VirtualGL_i386.deb 348 | fi 349 | if [ $? -ne 0 ]; then 350 | echo 351 | echo "Package manager failed to install VirtualGL..." 352 | echo 353 | exit 20 354 | fi 355 | cp install-files/bumblebee.script.ubuntu /etc/init.d/bumblebee 356 | # update-alternatives --remove gl_conf /usr/lib/nvidia-current/ld.so.conf 357 | rm /etc/alternatives/gl_conf 358 | ln -s /usr/lib/mesa/ld.so.conf /etc/alternatives/gl_conf 359 | rm -rf /etc/alternatives/xorg_extra_modules 360 | rm -rf /etc/alternatives/xorg_extra_modules-bumblebee 361 | rm -rf /usr /lib/nvidia-current/xorg/xorg 362 | ln -s /usr/lib/nvidia-current/xorg /etc/alternatives/xorg_extra_modules-bumblebee 363 | ldconfig 364 | ;; 365 | DEBIAN) 366 | rm /etc/alternatives/libglx.so 367 | rm /etc/alternatives/libGL.so 368 | rm /etc/alternatives/libGL.so.1 369 | rm /usr/lib/xorg/modules/drivers/nvidia_drv.so 370 | # rm -rf /usr/lib/xorg/extra-modules 371 | if [ "$ARCH" = "x86_64" ]; then 372 | echo 373 | echo "64-bit system detected" 374 | echo 375 | dpkg -i install-files/VirtualGL_amd64.deb 376 | ln -s /usr/lib64/xorg/modules/extensions/libglx.so /etc/alternatives/libglx.so 377 | ln -s /usr/lib64/libGL.so /etc/alternatives/libGL.so 378 | ln -s /usr/lib64/libGL.so.1 /etc/alternatives/libGL.so.1 379 | elif [ "$ARCH" = "i686" ]; then 380 | echo 381 | echo "32-bit system detected" 382 | echo 383 | ln -s /usr/lib/xorg/modules/extensions/libglx.so /etc/alternatives/libglx.so 384 | ln -s /usr/lib/libGL.so /etc/alternatives/libGL.so 385 | ln -s /usr/lib/libGL.so.1 /etc/alternatives/libGL.so.1 386 | dpkg -i install-files/VirtualGL_i386.deb 387 | fi 388 | if [ $? -ne 0 ]; then 389 | echo 390 | echo "Package manager failed to install VirtualGL..." 391 | echo 392 | exit 20 393 | fi 394 | cp install-files/bumblebee.script.debian /etc/init.d/bumblebee 395 | mkdir /usr/local/lib/bumblebee 396 | ln -s /usr/lib/nvidia/libglx.so /usr/local/lib/bumblebee/libglx.so 397 | ldconfig 398 | ;; 399 | FEDORA) 400 | cp install-files/bumblebee.script.fedora /etc/init.d/bumblebee 401 | if [ "$ARCH" = "x86_64" ]; then 402 | echo 403 | echo "64-bit system detected" 404 | echo 405 | echo $PWD 406 | yum -y --nogpgcheck install install-files/VirtualGL.x86_64.rpm 407 | sed -i 's$/usr/lib/$/usr/lib64/$g' /etc/init.d/bumblebee 408 | elif [ "$ARCH" = "i686" ]; then 409 | echo 410 | echo "32-bit system detected" 411 | echo 412 | yum -y --nogpgcheck install install-files/VirtualGL.i386.rpm 413 | fi 414 | if [ $? -ne 0 ]; then 415 | echo 416 | echo "Package manager failed to install VirtualGL..." 417 | echo 418 | exit 20 419 | fi 420 | ;; 421 | OPENSUSE) 422 | cp install-files/bumblebee.script.openSUSE /etc/init.d/bumblebee 423 | if [ "$ARCH" = "x86_64" ]; then 424 | echo 425 | echo "64-bit system detected" 426 | echo 427 | echo $PWD 428 | zypper --no-gpg-check install -l install-files/VirtualGL.x86_64.rpm 429 | elif [ "$ARCH" = "i686" ]; then 430 | echo 431 | echo "32-bit system detected" 432 | echo 433 | zypper --no-gpg-check install -l install-files/VirtualGL.i386.rpm 434 | fi 435 | if [ $? -ne 0 ]; then 436 | echo 437 | echo "Package manager failed to install VirtualGL..." 438 | echo 439 | exit 20 440 | fi 441 | ;; 442 | esac 443 | 444 | cp install-files/virtualgl.conf /etc/modprobe.d/ 445 | cp install-files/bumblebee-bugreport /usr/local/bin/ 446 | cp install-files/bumblebee-uninstall /usr/local/bin/ 447 | cp install-files/bumblebee-config /usr/local/bin/ 448 | chmod +x /etc/init.d/bumblebee 449 | chmod +x /usr/local/bin/bumblebee-bugreport 450 | chmod +x /usr/local/bin/bumblebee-uninstall 451 | chmod +x /usr/local/bin/bumblebee-config 452 | chmod +x /usr/local/bin/bumblebee-enablecard 453 | chmod +x /usr/local/bin/bumblebee-disablecard 454 | 455 | case "$DISTRO" in 456 | 457 | UBUNTU | OPENSUSE) 458 | if [ "$ARCH" = "x86_64" ]; then 459 | cp install-files/optirun32.ubuntu /usr/local/bin/optirun32 460 | cp install-files/optirun64.ubuntu /usr/local/bin/optirun64 461 | else 462 | cp install-files/optirun64.ubuntu /usr/local/bin/optirun 463 | fi 464 | ;; 465 | 466 | FEDORA) 467 | if [ "$ARCH" = "x86_64" ]; then 468 | cp install-files/optirun32.fedora /usr/local/bin/optirun32 469 | cp install-files/optirun64.fedora /usr/local/bin/optirun64 470 | else 471 | cp install-files/optirun32.fedora /usr/local/bin/optirun 472 | fi 473 | ;; 474 | 475 | DEBIAN) 476 | if [ "$ARCH" = "x86_64" ]; then 477 | cp install-files/optirun32.debian /usr/local/bin/optirun32 478 | cp install-files/optirun64.debian /usr/local/bin/optirun64 479 | else 480 | cp install-files/optirun64.debian /usr/local/bin/optirun 481 | fi 482 | ;; 483 | 484 | esac 485 | 486 | chmod +x /usr/local/bin/optirun* 487 | 488 | case "$DISTRO" in 489 | 490 | UBUNTU) 491 | if [ "`cat /etc/modules |grep "nvidia-current" |wc -l`" -eq "0" ]; then 492 | echo "nvidia-current" >> /etc/modules 493 | fi 494 | ;; 495 | OPENSUSE | DEBIAN | FEDORA) 496 | if [ "`cat /etc/modules |grep "nvidia-current" |wc -l`" -eq "0" ]; then 497 | echo "nvidia" >> /etc/modules 498 | fi 499 | ;; 500 | esac 501 | 502 | if [ "`cat /etc/modprobe.d/blacklist.conf |grep "blacklist nouveau" |wc -l`" -ne "0" ]; then 503 | grep -Ev 'nouveau' /etc/modprobe.d/blacklist.conf > /etc/modprobe.d/blacklist.conf.tmp 504 | mv /etc/modprobe.d/blacklist.conf.tmp /etc/modprobe.d/blacklist.conf 505 | fi 506 | 507 | echo "blacklist nouveau" >> /etc/modprobe.d/nouveau-blacklist.conf 508 | 509 | INTELBUSID=`echo "PCI:"\`${LSPCI} |grep VGA |grep Intel |cut -f1 -d:\`":"\`${LSPCI} |grep VGA |grep Intel |cut -f2 -d: |cut -f1 -d.\`":"\`${LSPCI} |grep VGA |grep Intel |cut -f2 -d. |cut -f1 -d" "\`` 510 | if [ `${LSPCI} |grep VGA |wc -l` -eq 2 ]; then 511 | NVIDIABUSID=`echo "PCI:"\`${LSPCI} |grep VGA |grep nVidia |cut -f1 -d:\`":"\`${LSPCI} |grep VGA |grep nVidia |cut -f2 -d: |cut -f1 -d.\`":"\`${LSPCI} |grep VGA |grep nVidia |cut -f2 -d. |cut -f1 -d" "\`` 512 | elif [ `${LSPCI} |grep 3D |wc -l` -eq 1 ]; then 513 | NVIDIABUSID=`echo "PCI:"\`${LSPCI} |grep 3D |grep nVidia |cut -f1 -d:\`":"\`${LSPCI} |grep 3D |grep nVidia |cut -f2 -d: |cut -f1 -d.\`":"\`${LSPCI} |grep 3D |grep nVidia |cut -f2 -d. |cut -f1 -d" "\`` 514 | else 515 | echo 516 | echo "The BusID of the nVidia card can't be determined." 517 | echo "You must correct this manually in /etc/X11/xorg.conf.nvidia" 518 | echo "Please report this problem.." 519 | echo 520 | echo "Press Any Key to continue." 521 | echo 522 | read 523 | fi 524 | 525 | clear 526 | 527 | echo 528 | echo "Changing Configuration to match your Machine." 529 | echo 530 | 531 | sed -i 's/REPLACEWITHBUSID/'$INTELBUSID'/g' /etc/X11/xorg.conf 532 | sed -i 's/REPLACEWITHBUSID/'$NVIDIABUSID'/g' /etc/X11/xorg.conf.nvidia 533 | 534 | CONNECTEDMONITOR="UNDEFINED" 535 | 536 | echo 537 | echo "Auto-detecting hardware" 538 | echo 539 | 540 | case "$DISTRO" in 541 | 542 | UBUNTU) 543 | if [ `LD_LIBRARY_PATH=/usr/lib/nvidia-current /usr/lib/nvidia-current/bin/nvidia-xconfig --query-gpu-info |grep "Display Devices" |cut -f2 -d":"` -gt 0 ]; then 544 | CONNECTEDMONITOR=`LD_LIBRARY_PATH=/usr/lib/nvidia-current /usr/lib/nvidia-current/bin/nvidia-xconfig --query-gpu-info |grep "Display Device 0" | cut -f2 -d\( | cut -f1 -d\)` 545 | fi 546 | ;; 547 | 548 | esac 549 | 550 | while [ "$CONNECTEDMONITOR" = "UNDEFINED" ]; do 551 | 552 | 553 | echo 554 | echo "Select your Laptop:" 555 | echo "1) Alienware M11X" 556 | echo "2) Dell XPS 15/17" 557 | echo "3) CLEVO W150HNQ" 558 | echo "4) Asus EeePC 1215N" 559 | echo "5) Acer Aspire 5745PG/5742G" 560 | echo "6) Dell Vostro 3300" 561 | echo "7) Dell Vostro 3400/3500" 562 | echo "8) Samsung RF511/RF711/QX410-J01" 563 | echo "9) Toshiba Satellite M645-SP4132L" 564 | echo "10) Asus U30J/U35J/U36JC/U43JC/U35JC/U43JC/U53JC/P52JC/K52JC/X52JC/N53SV/N61JV/X64JV" 565 | echo 566 | echo "97) Manually Set Output to CRT-0" 567 | echo "98) Manually Set Output to DFP-0" 568 | echo "99) Manually Enter Output" 569 | 570 | echo 571 | read machine 572 | echo 573 | 574 | case "$machine" in 575 | 576 | 1) 577 | CONNECTEDMONITOR="CRT-0" 578 | ;; 579 | 580 | 2) 581 | CONNECTEDMONITOR="CRT-0" 582 | ;; 583 | 584 | 3) 585 | CONNECTEDMONITOR="DFP-0" 586 | ;; 587 | 588 | 4) 589 | CONNECTEDMONITOR="DFP-0" 590 | ;; 591 | 592 | 5) 593 | CONNECTEDMONITOR="DFP-0" 594 | ;; 595 | 596 | 6) 597 | CONNECTEDMONITOR="DFP-0" 598 | ;; 599 | 600 | 7) 601 | CONNECTEDMONITOR="CRT-0" 602 | ;; 603 | 604 | 8) 605 | CONNECTEDMONITOR="CRT-0" 606 | ;; 607 | 608 | 9) 609 | CONNECTEDMONITOR="CRT-0" 610 | ;; 611 | 612 | 10) 613 | CONNECTEDMONITOR="CRT-0" 614 | ;; 615 | 616 | 97) 617 | CONNECTEDMONITOR="CRT-0" 618 | ;; 619 | 620 | 98) 621 | CONNECTEDMONITOR="DFP-0" 622 | ;; 623 | 624 | 99) 625 | echo 626 | echo "Enter output device for nVidia Card" 627 | echo 628 | read manualinput 629 | CONNECTEDMONITOR=`echo $manualinput` 630 | ;; 631 | 632 | 633 | *) 634 | echo 635 | echo "Please choose a valid option, Press any key to try again" 636 | read 637 | clear 638 | 639 | ;; 640 | 641 | esac 642 | 643 | done 644 | 645 | echo 646 | echo "Setting output device to: $CONNECTEDMONITOR" 647 | echo 648 | 649 | sed -i 's/REPLACEWITHCONNECTEDMONITOR/'$CONNECTEDMONITOR'/g' /etc/X11/xorg.conf.nvidia 650 | 651 | echo 652 | echo "Enabling Optimus Service" 653 | echo 654 | 655 | case "$DISTRO" in 656 | UBUNTU) 657 | update-rc.d -f bumblebee remove 658 | ;; 659 | DEBIAN) 660 | update-rc.d bumblebee defaults 661 | ;; 662 | FEDORA | OPENSUSE) 663 | chkconfig bumblebee on 664 | ;; 665 | esac 666 | 667 | 668 | echo 669 | echo "Setting up Enviroment variables" 670 | echo 671 | 672 | IMAGETRANSPORT="UNDEFINED" 673 | 674 | while [ "$IMAGETRANSPORT" = "UNDEFINED" ]; do 675 | 676 | clear 677 | 678 | echo 679 | echo "The Image Transport is how the images are transferred from the" 680 | echo "nVidia card to the Intel card, people has different experiences of" 681 | echo "performance, but just select the default if you are in doubt." 682 | echo 683 | echo "I recently found out that yuv and jpeg both has some lagging" 684 | echo "this is only noticable in fast moving games, such as 1st person" 685 | echo "shooters and for me, its only good enough with xv, even though" 686 | echo "xv sets down performance a little bit." 687 | echo 688 | echo "1) YUV" 689 | echo "2) JPEG" 690 | echo "3) PROXY" 691 | echo "4) XV (default)" 692 | echo "5) RGB" 693 | 694 | echo 695 | read machine 696 | echo 697 | 698 | case "$machine" in 699 | 700 | 1) 701 | IMAGETRANSPORT="yuv" 702 | ;; 703 | 704 | 2) 705 | IMAGETRANSPORT="jpeg" 706 | ;; 707 | 708 | 3) 709 | IMAGETRANSPORT="proxy" 710 | ;; 711 | 712 | 4) 713 | IMAGETRANSPORT="xv" 714 | ;; 715 | 716 | 5) 717 | IMAGETRANSPORT="rgb" 718 | ;; 719 | *) 720 | echo 721 | echo "Please choose a valid option, Press any key to try again." 722 | read 723 | clear 724 | 725 | ;; 726 | 727 | esac 728 | done 729 | 730 | echo "VGL_DISPLAY=:1 731 | export VGL_DISPLAY 732 | VGL_COMPRESS=$IMAGETRANSPORT 733 | export VGL_COMPRESS 734 | VGL_READBACK=fbo 735 | export VGL_READBACK" >> $BASHRC 736 | 737 | echo '#!/bin/sh' > /usr/bin/vglclient-service 738 | echo 'vglclient -gl' >> /usr/bin/vglclient-service 739 | chmod +x /usr/bin/vglclient-service 740 | if [ -d $HOME/.kde4/Autostart ]; then 741 | if [ -f $HOME/.kde4/Autostart/vglclient-service ]; then 742 | rm $HOME/.kde4/Autostart/vglclient-service 743 | fi 744 | ln -s /usr/bin/vglclient-service $HOME/.kde4/Autostart/vglclient-service 745 | elif [ -d $HOME/.kde/Autostart ]; then 746 | if [ -f $HOME/.kde/Autostart/vglclient-service ]; then 747 | rm $HOME/.kde/Autostart/vglclient-service 748 | fi 749 | ln -s /usr/bin/vglclient-service $HOME/.kde/Autostart/vglclient-service 750 | fi 751 | if [ -d $HOME/.config/autostart ]; then 752 | if [ -f $HOME/.config/autostart/vglclient-service ]; then 753 | rm $HOME/.config/autostart/vglclient-service 754 | fi 755 | ln -s /usr/bin/vglclient-service $HOME/.config/autostart/vglclient-service 756 | fi 757 | 758 | echo 759 | echo "Starting Services:" 760 | echo 761 | # Should be removed when changes from v.1.4.19+20 has been implemented on Fedora, OpenSuSE and Debian. 762 | 763 | if [ "$DISTRO" != UBUNTU ]; then 764 | /etc/init.d/bumblebee start 765 | /usr/bin/vglclient-service & 766 | fi 767 | 768 | echo 769 | echo "Setting up bumblebee user rights." 770 | echo 771 | #Support for starting/stopping the Bumblebee services ondemand. 772 | case "$DISTRO" in 773 | UBUNTU) 774 | groupadd bumblebee 775 | gpasswd -a `env |grep SUDO_USER |cut -f2 -d=` bumblebee 776 | grep -Ev 'bumblebee' /etc/sudoers > /etc/sudoers.optiorig 777 | mv /etc/sudoers.optiorig /etc/sudoers 778 | echo "%bumblebee ALL=(ALL:ALL) NOPASSWD: /etc/init.d/bumblebee" >> /etc/sudoers 779 | chmod 0440 /etc/sudoers 780 | ;; 781 | esac 782 | 783 | echo 784 | echo 785 | echo 786 | echo "Ok... Installation complete..." 787 | echo 788 | # Should be removed when changes from v.1.4.19+20 has been implemented on Fedora, OpenSuSE and Debian. 789 | 790 | if [ "$DISTRO" != UBUNTU ]; then 791 | echo "Now you need to make sure that the command \"vglclient -gl\" is run after your Desktop Enviroment is started" 792 | echo 793 | echo "In KDE this is done by this script.. Thanks to Peter Liedler." 794 | echo 795 | echo "In GNOME this is done by this script.. Thanks to Peter Liedler." 796 | echo 797 | else 798 | echo "Please logout and back in to activate new groups." 799 | echo 800 | echo "If you want power saving by shutting the nVidia down when not in use. Please adjust the scripts:" 801 | echo "/usr/local/bin/bumblebee-enablecard and /usr/local/bin/bumblebee-disablecard for your machine." 802 | echo 803 | fi 804 | if [ "$ARCH" = "x86_64" ]; then 805 | echo "After that you should be able to start applications with \"optirun32 \" or \"optirun64 \"" 806 | echo "optirun32 can be used for legacy 32-bit applications and Wine Games.. Everything else should work on optirun64" 807 | echo "But... if one doesn't work... try the other." 808 | elif [ "$ARCH" = "i686" ]; then 809 | echo "After that you should be able to start applications with \"optirun \"." 810 | fi 811 | echo 812 | echo "If you have any problems in or after the installation, please try to run the bumblebee-uninstall script and then" 813 | echo "rerun this script... if that doesn't work: please run the bumblebee-bugreport tool and send me a bugreport." 814 | echo 815 | echo "Or even better.. create an issue on github... this really makes bugfixing much easier for me and faster for you." 816 | echo 817 | echo "If you need to reconfigure bumblebee the script bumblebee-config as available." 818 | echo 819 | echo "Good luck... MrMEEE / Martin Juhl" 820 | echo 821 | echo "http://www.martin-juhl.dk, http://twitter.com/martinjuhl, https://github.com/MrMEEE/bumblebee" 822 | 823 | echo "Bumblebee Version: "$BUMBLEBEEVERSION > /etc/bumblebee 824 | 825 | exit 0 826 | -------------------------------------------------------------------------------- /examples/n.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | cat 1>&2 <<-EOF 4 | This script is not to run on any system. 5 | Anh K. Huynh adds this banner to prevent script from being used. 6 | 7 | The original script is here 8 | https://github.com/tj/n/blob/0895ea3e50cbad95ce67460a906323610f1f40a8/bin/n 9 | EOF 10 | 11 | exit 0 12 | 13 | # Library version 14 | 15 | VERSION="0.7.3" 16 | N_PREFIX=${N_PREFIX-/usr/local} 17 | VERSIONS_DIR=$N_PREFIX/n/versions 18 | 19 | # 20 | # Log the given 21 | # 22 | 23 | log() { 24 | printf "\033[90m...\033[0m $@\n" 25 | } 26 | 27 | # 28 | # Exit with the given 29 | # 30 | 31 | abort() { 32 | printf "\033[31mError: $@\033[0m\n" && exit 1 33 | } 34 | 35 | # setup 36 | 37 | test -d $VERSIONS_DIR || mkdir -p $VERSIONS_DIR 38 | 39 | if ! test -d $VERSIONS_DIR; then 40 | abort "Failed to create versions directory ($VERSIONS_DIR), do you have permissions to do this?" 41 | fi 42 | 43 | # curl / wget support 44 | 45 | GET= 46 | 47 | # wget support (Added --no-check-certificate for Github downloads) 48 | which wget > /dev/null && GET="wget --no-check-certificate -q -O-" 49 | 50 | # curl support 51 | which curl > /dev/null && GET="curl -# -L" 52 | 53 | # Ensure we have curl or wget 54 | 55 | test -z "$GET" && abort "curl or wget required" 56 | 57 | # 58 | # Output usage information. 59 | # 60 | 61 | display_help() { 62 | cat <<-help 63 | 64 | Usage: n [options] [COMMAND] [config] 65 | 66 | Commands: 67 | 68 | n Output versions installed 69 | n latest [config ...] Install or activate the latest node release 70 | n stable [config ...] Install or activate the latest stable node release 71 | n [config ...] Install and/or use node 72 | n custom [config ...] Install custom node with [args ...] 73 | n use [args ...] Execute node with [args ...] 74 | n npm [args ...] Execute npm with [args ...] 75 | n bin Output bin path for 76 | n rm Remove the given version(s) 77 | n --latest Output the latest node version available 78 | n --stable Output the latest stable node version available 79 | n ls Output the versions of node available 80 | 81 | Options: 82 | 83 | -V, --version Output current version of n 84 | -h, --help Display help information 85 | 86 | Aliases: 87 | 88 | - rm 89 | which bin 90 | use as 91 | list ls 92 | custom c 93 | 94 | help 95 | exit 0 96 | } 97 | 98 | # 99 | # Output n version. 100 | # 101 | 102 | display_n_version() { 103 | echo $VERSION && exit 0 104 | } 105 | 106 | # 107 | # Check for installed version, and populate $active 108 | # 109 | 110 | check_current_version() { 111 | which node &> /dev/null 112 | if test $? -eq 0; then 113 | active=`node --version` 114 | active=${active#v} 115 | fi 116 | } 117 | 118 | # 119 | # Display current node --version 120 | # and others installed. 121 | # 122 | 123 | display_versions() { 124 | check_current_version 125 | for dir in $VERSIONS_DIR/*; do 126 | local version=${dir##*/} 127 | local config=`test -f $dir/.config && cat $dir/.config` 128 | if test "$version" = "$active"; then 129 | printf " \033[32mο\033[0m $version \033[90m$config\033[0m\n" 130 | else 131 | printf " $version \033[90m$config\033[0m\n" 132 | fi 133 | done 134 | } 135 | 136 | # 137 | # Install node [config ...] 138 | # 139 | 140 | install_node() { 141 | local version=$1; shift 142 | local config=$@ 143 | check_current_version 144 | 145 | # remove "v" 146 | version=${version#v} 147 | 148 | # activate 149 | local dir=$VERSIONS_DIR/$version 150 | if test -d $dir; then 151 | # symlink everything, purge old copies or symlinks 152 | for d in bin lib share include; do 153 | rm -rf $N_PREFIX/$d 154 | ln -s $dir/$d $N_PREFIX/$d 155 | done 156 | # install 157 | else 158 | local tarball="node-v$version.tar.gz" 159 | local url="http://nodejs.org/dist/$tarball" 160 | 161 | # >= 0.5.x 162 | local minor=$(echo $version | cut -d '.' -f 2) 163 | test $minor -ge "5" && url="http://nodejs.org/dist/v$version/$tarball" 164 | 165 | install_tarball $version $url $config 166 | fi 167 | } 168 | 169 | # 170 | # Install node [config ...] 171 | # 172 | 173 | install_tarball() { 174 | local version=$1 175 | local url=$2; shift 2 176 | local config=$@ 177 | 178 | # remove "v" 179 | version=${version#v} 180 | 181 | local dir=$VERSIONS_DIR/$version 182 | local tarball="node-v$version.tar.gz" 183 | local logpath="/tmp/n.log" 184 | 185 | # create build directory 186 | mkdir -p $N_PREFIX/n/node-v$version 187 | 188 | # fetch and unpack 189 | cd $N_PREFIX/n/node-v$version \ 190 | && $GET $url | tar xz --strip-components=1 > $logpath 2>&1 191 | 192 | # see if things are alright 193 | if test $? -gt 0; then 194 | rm $tarball 195 | echo "\033[31mError: installation failed\033[0m" 196 | echo " node version $version does not exist," 197 | echo " n failed to fetch the tarball," 198 | echo " or tar failed. Try a different" 199 | echo " version or view $logpath to view" 200 | echo " error details." 201 | exit 1 202 | fi 203 | 204 | cd "$N_PREFIX/n/node-v$version" \ 205 | && ./configure --prefix $VERSIONS_DIR/$version $config\ 206 | && JOBS=4 make install \ 207 | && cd .. \ 208 | && cleanup $version \ 209 | && mkdir -p $dir \ 210 | && echo $config > "$dir/.config" \ 211 | && n $version \ 212 | && ln -s "$N_PREFIX/n/versions/$version" "$N_PREFIX/n/current" 213 | } 214 | 215 | # 216 | # Cleanup after the given 217 | # 218 | 219 | cleanup() { 220 | local version=$1 221 | local dir="node-v$version" 222 | 223 | if test -d $dir; then 224 | log "removing source" 225 | rm -fr $dir 226 | fi 227 | 228 | if test -f "$dir.tar.gz"; then 229 | log "removing tarball" 230 | rm -fr "$dir.tar.gz" 231 | fi 232 | } 233 | 234 | # 235 | # Remove 236 | # 237 | 238 | remove_version() { 239 | test -z $1 && abort "version(s) required" 240 | local version=${1#v} 241 | while test $# -ne 0; do 242 | rm -rf $VERSIONS_DIR/$version 243 | shift 244 | done 245 | } 246 | 247 | # 248 | # Output bin path for 249 | # 250 | 251 | display_bin_path_for_version() { 252 | test -z $1 && abort "version required" 253 | local version=${1#v} 254 | local bin=$VERSIONS_DIR/$version/bin/node 255 | if test -f $bin; then 256 | printf $bin 257 | else 258 | abort "$1 is not installed" 259 | fi 260 | } 261 | 262 | # 263 | # Execute the given of node 264 | # with [args ...] 265 | # 266 | 267 | execute_with_version() { 268 | test -z $1 && abort "version required" 269 | local version=${1#v} 270 | local bin=$VERSIONS_DIR/$version/bin/node 271 | 272 | shift # remove version 273 | 274 | if test -f $bin; then 275 | $bin $@ 276 | else 277 | abort "$version is not installed" 278 | fi 279 | } 280 | 281 | # 282 | # Execute the given of npm 283 | # with [args ...] 284 | # 285 | 286 | execute_with_npm_version() { 287 | test -z $1 && abort "version required" 288 | local version=${1#v} 289 | local bin=$VERSIONS_DIR/$version/bin 290 | 291 | shift # remove version 292 | 293 | if test -f $bin/npm; then 294 | $bin/node $bin/npm $@ 295 | else 296 | abort "npm is not installed, node.js version must be greater than or equal to 0.6.3" 297 | fi 298 | } 299 | 300 | # 301 | # Display the latest node release version. 302 | # 303 | 304 | display_latest_version() { 305 | $GET 2> /dev/null http://nodejs.org/dist/ \ 306 | | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' \ 307 | | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ 308 | | tail -n1 309 | } 310 | 311 | # 312 | # Display the latest stable node release version. 313 | # 314 | 315 | display_latest_stable_version() { 316 | $GET 2> /dev/null http://nodejs.org/dist/ \ 317 | | egrep -o '[0-9]+\.\d*[02468]\.[0-9]+' \ 318 | | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ 319 | | tail -n1 320 | } 321 | 322 | # 323 | # Display the versions of node available. 324 | # 325 | 326 | list_versions() { 327 | check_current_version 328 | local versions="" 329 | versions=`$GET 2> /dev/null http://nodejs.org/dist/ \ 330 | | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' \ 331 | | sort -u -k 1,1n -k 2,2n -k 3,3n -t . \ 332 | | awk '{ print " " $1 }'` 333 | 334 | for v in $versions; do 335 | if test "$active" = "$v"; then 336 | printf " \033[32mο\033[0m $v \033[0m\n" 337 | else 338 | if test -d $VERSIONS_DIR/$v; then 339 | printf " * $v \033[0m\n" 340 | else 341 | printf " $v\n" 342 | fi 343 | fi 344 | done 345 | } 346 | 347 | # Handle arguments 348 | 349 | if test $# -eq 0; then 350 | display_versions 351 | else 352 | while test $# -ne 0; do 353 | case $1 in 354 | -V|--version) display_n_version ;; 355 | -h|--help|help) display_help ;; 356 | --latest) display_latest_version $2; exit ;; 357 | --stable) display_latest_stable_version $2; exit ;; 358 | bin|which) display_bin_path_for_version $2; exit ;; 359 | as|use) shift; execute_with_version $@; exit ;; 360 | npm) shift; execute_with_npm_version $@; exit ;; 361 | rm|-) remove_version $2; exit ;; 362 | latest) install_node `n --latest`; exit ;; 363 | stable) install_node `n --stable`; exit ;; 364 | ls|list) list_versions $2; exit ;; 365 | c|custom) shift; install_tarball $@; exit ;; 366 | *) install_node $@; exit ;; 367 | esac 368 | shift 369 | done 370 | fi 371 | -------------------------------------------------------------------------------- /examples/squid.init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat 1>&2 <<-EOF 4 | This script is not to run on any system. 5 | Anh K. Huynh adds this banner to prevent script from being used. 6 | 7 | The original script is here 8 | https://github.com/mozilla-services/squid-rpm/blob/47880414f17affdbb634b6f0a19a342995fb60f6/SOURCES/squid.init 9 | EOF 10 | 11 | exit 0 12 | 13 | # chkconfig: - 90 25 14 | # pidfile: /var/run/squid.pid 15 | # config: /etc/squid/squid.conf 16 | # 17 | ### BEGIN INIT INFO 18 | # Provides: squid 19 | # Short-Description: starting and stopping Squid Internet Object Cache 20 | # Description: Squid - Internet Object Cache. Internet object caching is \ 21 | # a way to store requested Internet objects (i.e., data available \ 22 | # via the HTTP, FTP, and gopher protocols) on a system closer to the \ 23 | # requesting site than to the source. Web browsers can then use the \ 24 | # local Squid cache as a proxy HTTP server, reducing access time as \ 25 | # well as bandwidth consumption. 26 | ### END INIT INFO 27 | 28 | 29 | PATH=/usr/bin:/sbin:/bin:/usr/sbin 30 | export PATH 31 | 32 | # Source function library. 33 | . /etc/rc.d/init.d/functions 34 | 35 | # Source networking configuration. 36 | . /etc/sysconfig/network 37 | 38 | if [ -f /etc/sysconfig/squid ]; then 39 | . /etc/sysconfig/squid 40 | fi 41 | 42 | # don't raise an error if the config file is incomplete 43 | # set defaults instead: 44 | SQUID_OPTS=${SQUID_OPTS:-""} 45 | SQUID_PIDFILE_TIMEOUT=${SQUID_PIDFILE_TIMEOUT:-20} 46 | SQUID_SHUTDOWN_TIMEOUT=${SQUID_SHUTDOWN_TIMEOUT:-100} 47 | SQUID_CONF=${SQUID_CONF:-"/etc/squid/squid.conf"} 48 | SQUID_PIDFILE_DIR="/var/run/squid" 49 | SQUID_USER="squid" 50 | SQUID_DIR="squid" 51 | 52 | # determine the name of the squid binary 53 | [ -f /usr/sbin/squid ] && SQUID=squid 54 | 55 | prog="$SQUID" 56 | 57 | # determine which one is the cache_swap directory 58 | CACHE_SWAP=`sed -e 's/#.*//g' $SQUID_CONF | \ 59 | grep cache_dir | awk '{ print $3 }'` 60 | 61 | RETVAL=0 62 | 63 | probe() { 64 | # Check that networking is up. 65 | [ ${NETWORKING} = "no" ] && exit 1 66 | 67 | [ `id -u` -ne 0 ] && exit 4 68 | 69 | # check if the squid conf file is present 70 | [ -f $SQUID_CONF ] || exit 6 71 | } 72 | 73 | start() { 74 | # Check if $SQUID_PIDFILE_DIR exists and if not, lets create it and give squid permissions. 75 | if [ ! -d $SQUID_PIDFILE_DIR ] ; then mkdir $SQUID_PIDFILE_DIR ; chown -R $SQUID_USER.$SQUID_DIR $SQUID_PIDFILE_DIR; fi 76 | probe 77 | 78 | parse=`$SQUID -k parse -f $SQUID_CONF 2>&1` 79 | RETVAL=$? 80 | if [ $RETVAL -ne 0 ]; then 81 | echo -n $"Starting $prog: " 82 | echo_failure 83 | echo 84 | echo "$parse" 85 | return 1 86 | fi 87 | for adir in $CACHE_SWAP; do 88 | if [ ! -d $adir/00 ]; then 89 | echo -n "init_cache_dir $adir... " 90 | $SQUID -z -F -f $SQUID_CONF >> /var/log/squid/squid.out 2>&1 91 | fi 92 | done 93 | echo -n $"Starting $prog: " 94 | $SQUID $SQUID_OPTS -f $SQUID_CONF >> /var/log/squid/squid.out 2>&1 95 | RETVAL=$? 96 | if [ $RETVAL -eq 0 ]; then 97 | timeout=0; 98 | while : ; do 99 | [ ! -f /var/run/squid.pid ] || break 100 | if [ $timeout -ge $SQUID_PIDFILE_TIMEOUT ]; then 101 | RETVAL=1 102 | break 103 | fi 104 | sleep 1 && echo -n "." 105 | timeout=$((timeout+1)) 106 | done 107 | fi 108 | [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SQUID 109 | [ $RETVAL -eq 0 ] && echo_success 110 | [ $RETVAL -ne 0 ] && echo_failure 111 | echo 112 | return $RETVAL 113 | } 114 | 115 | stop() { 116 | echo -n $"Stopping $prog: " 117 | $SQUID -k check -f $SQUID_CONF >> /var/log/squid/squid.out 2>&1 118 | RETVAL=$? 119 | if [ $RETVAL -eq 0 ] ; then 120 | $SQUID -k shutdown -f $SQUID_CONF & 121 | rm -f /var/lock/subsys/$SQUID 122 | timeout=0 123 | while : ; do 124 | [ -f /var/run/squid.pid ] || break 125 | if [ $timeout -ge $SQUID_SHUTDOWN_TIMEOUT ]; then 126 | echo 127 | return 1 128 | fi 129 | sleep 2 && echo -n "." 130 | timeout=$((timeout+2)) 131 | done 132 | echo_success 133 | echo 134 | else 135 | echo_failure 136 | if [ ! -e /var/lock/subsys/$SQUID ]; then 137 | RETVAL=0 138 | fi 139 | echo 140 | fi 141 | rm -rf $SQUID_PIDFILE_DIR/* 142 | return $RETVAL 143 | } 144 | 145 | reload() { 146 | $SQUID $SQUID_OPTS -k reconfigure -f $SQUID_CONF 147 | } 148 | 149 | restart() { 150 | stop 151 | rm -rf $SQUID_PIDFILE_DIR/* 152 | start 153 | } 154 | 155 | condrestart() { 156 | [ -e /var/lock/subsys/squid ] && restart || : 157 | } 158 | 159 | rhstatus() { 160 | status $SQUID && $SQUID -k check -f $SQUID_CONF 161 | } 162 | 163 | 164 | case "$1" in 165 | start) 166 | start 167 | ;; 168 | 169 | stop) 170 | stop 171 | ;; 172 | 173 | reload|force-reload) 174 | reload 175 | ;; 176 | 177 | restart) 178 | restart 179 | ;; 180 | 181 | condrestart|try-restart) 182 | condrestart 183 | ;; 184 | 185 | status) 186 | rhstatus 187 | ;; 188 | 189 | probe) 190 | probe 191 | ;; 192 | 193 | *) 194 | echo $"Usage: $0 {start|stop|status|reload|force-reload|restart|try-restart|probe}" 195 | exit 2 196 | esac 197 | 198 | exit $? 199 | -------------------------------------------------------------------------------- /examples/steam.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat 1>&2 <<-EOF 4 | This script is not to run on any system. 5 | Anh K. Huynh adds this banner to prevent script from being used. 6 | 7 | The original script is here 8 | https://github.com/indrora/steam_latest/blob/21cc14158c171f5912b04b83abf41205eb804b31/scripts/steam.sh 9 | EOF 10 | 11 | exit 0 12 | 13 | # Allow us to debug what's happening in the script if necessary 14 | if [ "$STEAM_DEBUG" ]; then 15 | set -x 16 | fi 17 | export TEXTDOMAIN=steam 18 | 19 | ARCHIVE_EXT=tar.xz 20 | 21 | # figure out the absolute path to the script being run a bit 22 | # non-obvious, the ${0%/*} pulls the path out of $0, cd's into the 23 | # specified directory, then uses $PWD to figure out where that 24 | # directory lives - and all this in a subshell, so we don't affect 25 | # $PWD 26 | 27 | STEAMROOT="$(cd "${0%/*}" && echo $PWD)" 28 | STEAMDATA="$STEAMROOT" 29 | if [ -z $STEAMEXE ]; then 30 | STEAMEXE=`basename "$0" .sh` 31 | fi 32 | # Backward compatibility for server operators 33 | if [ "$STEAMEXE" = "steamcmd" ]; then 34 | echo "***************************************************" 35 | echo "The recommended way to run steamcmd is: steamcmd.sh $*" 36 | echo "***************************************************" 37 | exec "$STEAMROOT/steamcmd.sh" "$@" 38 | echo "Couldn't find steamcmd.sh" >&1 39 | exit 255 40 | fi 41 | cd "$STEAMROOT" 42 | 43 | # The minimum version of the /usr/bin/steam script that we require 44 | MINIMUM_STEAMSCRIPT_VERSION=100020 45 | 46 | # Save the system paths in case we need to restore them 47 | export SYSTEM_PATH="$PATH" 48 | export SYSTEM_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" 49 | 50 | show_license_agreement() 51 | { 52 | LICENSE="$STEAMROOT/steam_install_agreement.txt" 53 | if [ ! -f "$STEAMCONFIG/steam_install_agreement.txt" ]; then 54 | if [ ! -f "$LICENSE" ]; then 55 | exit 1 56 | fi 57 | answer=accepted 58 | if [ "$answer" != "accepted" ]; then 59 | exit 0 60 | fi 61 | fi 62 | } 63 | 64 | distro_description() 65 | { 66 | echo "$(detect_distro) $(detect_release) $(detect_arch)" 67 | } 68 | 69 | detect_distro() 70 | { 71 | if [ -f /etc/lsb-release ]; then 72 | (. /etc/lsb-release; echo $DISTRIB_ID | tr '[A-Z]' '[a-z]') 73 | elif [ -f /etc/os-release ]; then 74 | (. /etc/os-release; echo $ID | tr '[A-Z]' '[a-z]') 75 | elif [ -f /etc/debian_version ]; then 76 | echo "debian" 77 | else 78 | # Generic fallback 79 | uname -s 80 | fi 81 | } 82 | 83 | detect_release() 84 | { 85 | if [ -f /etc/lsb-release ]; then 86 | (. /etc/lsb-release; echo $DISTRIB_RELEASE) 87 | elif [ -f /etc/os-release ]; then 88 | (. /etc/os-release; echo $VERSION_ID) 89 | elif [ -f /etc/debian_version ]; then 90 | cat /etc/debian_version 91 | else 92 | # Generic fallback 93 | uname -r 94 | fi 95 | } 96 | 97 | detect_arch() 98 | { 99 | case $(uname -m) in 100 | *64) 101 | echo "64-bit" 102 | ;; 103 | *) 104 | echo "32-bit" 105 | ;; 106 | esac 107 | } 108 | 109 | detect_platform() 110 | { 111 | # Default to unknown/unsupported distribution, pick something and hope for the best 112 | platform=ubuntu12_32 113 | 114 | # Check for specific supported distribution releases 115 | case "$(detect_distro)-$(detect_release)" in 116 | ubuntu-12.*) 117 | platform=ubuntu12_32 118 | ;; 119 | esac 120 | echo $platform 121 | } 122 | 123 | detect_universe() 124 | { 125 | if test -f "$STEAMROOT/Steam.cfg" && \ 126 | egrep '^[Uu]niverse *= *[Bb]eta$' "$STEAMROOT/Steam.cfg" >/dev/null; then 127 | STEAMUNIVERSE="Beta" 128 | elif test -f "$STEAMROOT/steam.cfg" && \ 129 | egrep '^[Uu]niverse *= *[Bb]eta$' "$STEAMROOT/steam.cfg" >/dev/null; then 130 | STEAMUNIVERSE="Beta" 131 | else 132 | STEAMUNIVERSE="Public" 133 | fi 134 | echo $STEAMUNIVERSE 135 | } 136 | 137 | detect_package() 138 | { 139 | case `detect_universe` in 140 | "Beta") 141 | STEAMPACKAGE="steambeta" 142 | ;; 143 | *) 144 | STEAMPACKAGE="steam" 145 | ;; 146 | esac 147 | echo "$STEAMPACKAGE" 148 | } 149 | 150 | detect_scriptversion() 151 | { 152 | SCRIPT_VERSION=$(fgrep "$2=" "$1") 153 | if [[ "$SCRIPT_VERSION" ]]; then 154 | expr "$SCRIPT_VERSION" : ".*=\(.*\)" 155 | else 156 | echo "0" 157 | fi 158 | } 159 | 160 | # Check a currently installed script against a new script and see if the 161 | # installed one needs to be updated. 162 | check_scriptversion() 163 | { 164 | SCRIPT=$1 165 | VERSION_TOKEN=$2 166 | MINIMUM_VERSION=$3 167 | 168 | VERSION="$(detect_scriptversion "$SCRIPT" $VERSION_TOKEN)" 169 | if [[ "$VERSION" -lt "$MINIMUM_VERSION" ]]; then 170 | return 1 171 | fi 172 | return 0 173 | } 174 | 175 | detect_steamdatalink() 176 | { 177 | # Don't create a link in development 178 | if [ -f "$STEAMROOT/steam_dev.cfg" ]; then 179 | STEAMDATALINK="" 180 | else 181 | STEAMDATALINK="$STEAMCONFIG/`detect_package`" 182 | fi 183 | echo $STEAMDATALINK 184 | } 185 | 186 | detect_bootstrap() 187 | { 188 | if [ -f "$STEAMROOT/bootstrap.tar.xz" ]; then 189 | echo "$STEAMROOT/bootstrap.tar.xz" 190 | else 191 | # This is the default bootstrap install location for the Ubuntu package. 192 | # We use this as a fallback for people who have an existing installation and have never run the new install_bootstrap code in bin_steam.sh 193 | echo "/usr/lib/`detect_package`/bootstraplinux_`detect_platform`.tar.xz" 194 | fi 195 | } 196 | 197 | install_bootstrap() 198 | { 199 | # Don't install bootstrap in development 200 | if [ -f "$STEAMROOT/steam_dev.cfg" ]; then 201 | return 1 202 | fi 203 | 204 | STATUS=0 205 | 206 | # Save the umask and set strong permissions 207 | omask=`umask` 208 | 209 | STEAMBOOTSTRAPARCHIVE=`detect_bootstrap` 210 | if [ -f "$STEAMBOOTSTRAPARCHIVE" ]; then 211 | echo "Installing bootstrap $STEAMBOOTSTRAPARCHIVE" 212 | tar xf "$STEAMBOOTSTRAPARCHIVE" 213 | STATUS=$? 214 | else 215 | STATUS=1 216 | fi 217 | 218 | return $STATUS 219 | } 220 | 221 | runtime_supported() 222 | { 223 | case "$(detect_distro)-$(detect_release)" in 224 | # Add additional supported distributions here 225 | ubuntu-*) 226 | return 0 227 | ;; 228 | *) # Let's try this out for now and see if it works... 229 | return 0 230 | ;; 231 | esac 232 | 233 | # This distro doesn't support the Steam Linux Runtime (yet!) 234 | return 1 235 | } 236 | 237 | download_archive() 238 | { 239 | curl -#Of "$2" 2>&1 240 | } 241 | 242 | extract_archive() 243 | { 244 | echo "$1" 245 | tar -xf "$2" -C "$3" 246 | return $? 247 | } 248 | 249 | has_runtime_archive() 250 | { 251 | # Make sure we have files to unpack 252 | for file in "$STEAM_RUNTIME.$ARCHIVE_EXT".part*; do 253 | if [ ! -f "$file" ]; then 254 | return 1 255 | fi 256 | done 257 | 258 | if [ ! -f "$STEAM_RUNTIME.checksum" ]; then 259 | return 1 260 | fi 261 | 262 | return 0 263 | } 264 | 265 | unpack_runtime() 266 | { 267 | if ! has_runtime_archive; then 268 | if [ -d "$STEAM_RUNTIME" ]; then 269 | # The runtime is unpacked, let's use it! 270 | return 0 271 | fi 272 | return 1 273 | fi 274 | 275 | # Make sure we haven't already unpacked them 276 | if [ -f "$STEAM_RUNTIME/checksum" ] && cmp "$STEAM_RUNTIME.checksum" "$STEAM_RUNTIME/checksum" >/dev/null; then 277 | return 0 278 | fi 279 | 280 | # Unpack the runtime 281 | EXTRACT_TMP="$STEAM_RUNTIME.tmp" 282 | rm -rf "$EXTRACT_TMP" 283 | mkdir "$EXTRACT_TMP" 284 | cat "$STEAM_RUNTIME.$ARCHIVE_EXT".part* >"$STEAM_RUNTIME.$ARCHIVE_EXT" 285 | EXISTING_CHECKSUM="$(cd "$(dirname "$STEAM_RUNTIME")"; md5sum "$(basename "$STEAM_RUNTIME.$ARCHIVE_EXT")")" 286 | EXPECTED_CHECKSUM="$(cat "$STEAM_RUNTIME.checksum")" 287 | if [ "$EXISTING_CHECKSUM" != "$EXPECTED_CHECKSUM" ]; then 288 | echo $"Runtime checksum: $EXISTING_CHECKSUM, expected $EXPECTED_CHECKSUM" >&2 289 | return 2 290 | fi 291 | if ! extract_archive $"Unpacking Steam Runtime" "$STEAM_RUNTIME.$ARCHIVE_EXT" "$EXTRACT_TMP"; then 292 | return 3 293 | fi 294 | 295 | # Move it into place! 296 | if [ -d "$STEAM_RUNTIME" ]; then 297 | rm -rf "$STEAM_RUNTIME.old" 298 | if ! mv "$STEAM_RUNTIME" "$STEAM_RUNTIME.old"; then 299 | return 4 300 | fi 301 | fi 302 | if ! mv "$EXTRACT_TMP"/* "$EXTRACT_TMP"/..; then 303 | return 5 304 | fi 305 | rm -rf "$EXTRACT_TMP" 306 | if ! cp "$STEAM_RUNTIME.checksum" "$STEAM_RUNTIME/checksum"; then 307 | return 6 308 | fi 309 | return 0 310 | } 311 | 312 | get_missing_libraries() 313 | { 314 | if ! ldd "$1" >/dev/null 2>&1; then 315 | # We couldn't run the link loader for this architecture 316 | echo "libc.so.6" 317 | else 318 | ldd "$1" | grep "=>" | grep -v linux-gate | grep -v / | awk '{print $1}' 319 | fi 320 | } 321 | 322 | check_shared_libraries() 323 | { 324 | if [ -f "$STEAMROOT/$PLATFORM/steamui.so" ]; then 325 | MISSING_LIBRARIES=$(get_missing_libraries "$STEAMROOT/$PLATFORM/steamui.so") 326 | else 327 | MISSING_LIBRARIES=$(get_missing_libraries "$STEAMROOT/$PLATFORM/$STEAMEXE") 328 | fi 329 | } 330 | 331 | ignore_signal() 332 | { 333 | : 334 | } 335 | 336 | reset_steam() 337 | { 338 | # Don't wipe development files 339 | if [ -f "$STEAMROOT/steam_dev.cfg" ]; then 340 | echo "Can't reset development directory" 341 | return 342 | fi 343 | 344 | if [ -z "$INITIAL_LAUNCH" ]; then 345 | exit 1 346 | fi 347 | 348 | if [ ! -f "$(detect_bootstrap)" ]; then 349 | exit 2 350 | fi 351 | 352 | STEAM_SAVE="$STEAMROOT/.save" 353 | 354 | # Don't let the user interrupt us, or they may corrupt the install 355 | trap ignore_signal INT 356 | 357 | # Back up games and critical files 358 | mkdir -p "$STEAM_SAVE" 359 | for i in bootstrap.tar.xz ssfn* SteamApps userdata; do 360 | if [ -e "$i" ]; then 361 | mv -f "$i" "$STEAM_SAVE/" 362 | fi 363 | done 364 | for i in "$STEAMCONFIG/registry.vdf"; do 365 | mv -f "$i" "$i.bak" 366 | done 367 | 368 | # Scary! 369 | rm -rf "$STEAMROOT/"* 370 | 371 | # Move things back into place 372 | mv -f "$STEAM_SAVE/"* "$STEAMROOT/" 373 | rmdir "$STEAM_SAVE" 374 | 375 | # Okay, at this point we can recover, so re-enable interrupts 376 | trap '' INT 377 | 378 | # Reinstall the bootstrap and we're done. 379 | install_bootstrap 380 | 381 | echo $"Reset complete!" 382 | exit 383 | } 384 | 385 | #determine platform 386 | UNAME=`uname` 387 | if [ "$UNAME" == "Linux" ]; then 388 | 389 | # identify Linux distribution and pick an optimal bin dir 390 | PLATFORM=`detect_platform` 391 | PLATFORM32=`echo $PLATFORM | fgrep 32` 392 | PLATFORM64=`echo $PLATFORM | fgrep 64` 393 | if [ -z "$PLATFORM32" ]; then 394 | PLATFORM32=`echo $PLATFORM | sed 's/64/32/'` 395 | fi 396 | if [ -z "$PLATFORM64" ]; then 397 | PLATFORM64=`echo $PLATFORM | sed 's/32/64/'` 398 | fi 399 | 400 | # common variables for later 401 | 402 | # We use ~/.steam for bootstrap symlinks so that we can easily 403 | # tell partners where to go to find the Steam libraries and data. 404 | # This is constant so that legacy applications can always find us in the future. 405 | STEAMCONFIG=~/.steam 406 | PIDFILE="$STEAMCONFIG/steam.pid" # pid of running steam for this user 407 | STEAMBIN32LINK="$STEAMCONFIG/bin32" 408 | STEAMBIN64LINK="$STEAMCONFIG/bin64" 409 | STEAMSDK32LINK="$STEAMCONFIG/sdk32" # 32-bit steam api library 410 | STEAMSDK64LINK="$STEAMCONFIG/sdk64" # 64-bit steam api library 411 | STEAMROOTLINK="$STEAMCONFIG/root" # points at the Steam install path for the currently running Steam 412 | STEAMDATALINK="`detect_steamdatalink`" # points at the Steam content path 413 | STEAMSTARTING="$STEAMCONFIG/starting" 414 | 415 | # See if this is the initial launch of Steam 416 | if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE") 2>/dev/null; then 417 | INITIAL_LAUNCH=true 418 | fi 419 | 420 | if [ "$1" = "--reset" ]; then 421 | reset_steam 422 | fi 423 | 424 | if [ "$INITIAL_LAUNCH" ]; then 425 | # Show the license agreement, if needed 426 | show_license_agreement 427 | 428 | # See if we need to update the /usr/bin/steam script 429 | if [ -z "$STEAMSCRIPT" ]; then 430 | STEAMSCRIPT="/usr/bin/`detect_package`" 431 | fi 432 | if [ -f "$STEAMSCRIPT" ]; then 433 | if ! check_scriptversion "$STEAMSCRIPT" STEAMSCRIPT_VERSION "$MINIMUM_STEAMSCRIPT_VERSION"; then 434 | STEAMSCRIPT_OUTOFDATE=1 435 | warn_outofdate 436 | fi 437 | fi 438 | 439 | # Install any additional dependencies 440 | STEAMDEPS="`dirname $STEAMSCRIPT`/`detect_package`deps" 441 | if [ -f "$STEAMDEPS" -a -f "$STEAMROOT/steamdeps.txt" ]; then 442 | "$STEAMDEPS" $STEAMROOT/steamdeps.txt 443 | fi 444 | 445 | # Create symbolic links for the Steam API 446 | if [ ! -e "$STEAMCONFIG" ]; then 447 | mkdir "$STEAMCONFIG" 448 | fi 449 | if [ "$STEAMROOT" != "$STEAMROOTLINK" -a "$STEAMROOT" != "$STEAMDATALINK" ]; then 450 | rm -f "$STEAMBIN32LINK" && ln -s "$STEAMROOT/$PLATFORM32" "$STEAMBIN32LINK" 451 | rm -f "$STEAMBIN64LINK" && ln -s "$STEAMROOT/$PLATFORM64" "$STEAMBIN64LINK" 452 | rm -f "$STEAMSDK32LINK" && ln -s "$STEAMROOT/linux32" "$STEAMSDK32LINK" 453 | rm -f "$STEAMSDK64LINK" && ln -s "$STEAMROOT/linux64" "$STEAMSDK64LINK" 454 | rm -f "$STEAMROOTLINK" && ln -s "$STEAMROOT" "$STEAMROOTLINK" 455 | if [ "$STEAMDATALINK" ]; then 456 | rm -f "$STEAMDATALINK" && ln -s "$STEAMDATA" "$STEAMDATALINK" 457 | fi 458 | fi 459 | 460 | # Temporary bandaid until everyone has the new libsteam_api.so 461 | rm -f ~/.steampath && ln -s "$STEAMCONFIG/bin32/steam" ~/.steampath 462 | rm -f ~/.steampid && ln -s "$PIDFILE" ~/.steampid 463 | rm -f ~/.steam/bin && ln -s "$STEAMBIN32LINK" ~/.steam/bin 464 | # Uncomment this line when you want to remove the bandaid 465 | #rm -f ~/.steampath ~/.steampid ~/.steam/bin 466 | fi 467 | 468 | # Show what we detect for distribution and release 469 | echo "Running Steam on $(distro_description)" 470 | 471 | # The Steam runtime is a complete set of libraries for running 472 | # Steam games, and is intended to continue to work going forward. 473 | # 474 | # The runtime is open source and the scripts used to build it are 475 | # available on GitHub: 476 | # https://github.com/ValveSoftware/steam-runtime 477 | # 478 | # We would like this runtime to work on as many Linux distributions 479 | # as possible, so feel free to tinker with it and submit patches and 480 | # bug reports. 481 | # 482 | if [ "$STEAM_RUNTIME" = "debug" ]; then 483 | # Use the debug runtime if it's available, and the default if not. 484 | export STEAM_RUNTIME="$STEAMROOT/$PLATFORM/steam-runtime" 485 | 486 | if unpack_runtime; then 487 | if [ -z "$STEAM_RUNTIME_DEBUG" ]; then 488 | STEAM_RUNTIME_DEBUG="$(cat "$STEAM_RUNTIME/version.txt" | sed 's,-release,-debug,')" 489 | fi 490 | if [ -z "$STEAM_RUNTIME_DEBUG_DIR" ]; then 491 | STEAM_RUNTIME_DEBUG_DIR="$STEAMROOT/$PLATFORM" 492 | fi 493 | if [ ! -d "$STEAM_RUNTIME_DEBUG_DIR/$STEAM_RUNTIME_DEBUG" ]; then 494 | # Try to download the debug runtime 495 | STEAM_RUNTIME_DEBUG_URL=$(grep "$STEAM_RUNTIME_DEBUG" "$STEAM_RUNTIME/README.txt") 496 | mkdir -p "$STEAM_RUNTIME_DEBUG_DIR" 497 | 498 | STEAM_RUNTIME_DEBUG_ARCHIVE="$STEAM_RUNTIME_DEBUG_DIR/$(basename "$STEAM_RUNTIME_DEBUG_URL")" 499 | if [ ! -f "$STEAM_RUNTIME_DEBUG_ARCHIVE" ]; then 500 | echo $"Downloading debug runtime: $STEAM_RUNTIME_DEBUG_URL" 501 | (cd "$STEAM_RUNTIME_DEBUG_DIR" && \ 502 | download_archive $"Downloading debug runtime..." "$STEAM_RUNTIME_DEBUG_URL") 503 | fi 504 | if ! extract_archive $"Unpacking debug runtime..." "$STEAM_RUNTIME_DEBUG_ARCHIVE" "$STEAM_RUNTIME_DEBUG_DIR"; then 505 | rm -rf "$STEAM_RUNTIME_DEBUG" "$STEAM_RUNTIME_DEBUG_ARCHIVE" 506 | fi 507 | fi 508 | if [ -d "$STEAM_RUNTIME_DEBUG_DIR/$STEAM_RUNTIME_DEBUG" ]; then 509 | echo "STEAM_RUNTIME debug enabled, using $STEAM_RUNTIME_DEBUG" 510 | export STEAM_RUNTIME="$STEAM_RUNTIME_DEBUG_DIR/$STEAM_RUNTIME_DEBUG" 511 | 512 | # Set up the link to the source code 513 | ln -sf "$STEAM_RUNTIME/source" /tmp/source 514 | else 515 | echo $"STEAM_RUNTIME couldn't download and unpack $STEAM_RUNTIME_DEBUG_URL, falling back to $STEAM_RUNTIME" 516 | fi 517 | fi 518 | elif [ "$STEAM_RUNTIME" = "1" ]; then 519 | echo "STEAM_RUNTIME is enabled by the user" 520 | export STEAM_RUNTIME="$STEAMROOT/$PLATFORM/steam-runtime" 521 | elif [ "$STEAM_RUNTIME" = "0" ]; then 522 | echo "STEAM_RUNTIME is disabled by the user" 523 | elif [ -z "$STEAM_RUNTIME" ]; then 524 | if runtime_supported; then 525 | echo "STEAM_RUNTIME is enabled automatically" 526 | export STEAM_RUNTIME="$STEAMROOT/$PLATFORM/steam-runtime" 527 | else 528 | echo "STEAM_RUNTIME is disabled automatically" 529 | fi 530 | else 531 | echo "STEAM_RUNTIME has been set by the user to: $STEAM_RUNTIME" 532 | fi 533 | if [ "$STEAM_RUNTIME" -a "$STEAM_RUNTIME" != "0" ]; then 534 | # Unpack the runtime if necessary 535 | if unpack_runtime; then 536 | case $(uname -m) in 537 | *64) 538 | export PATH="$STEAM_RUNTIME/amd64/bin:$STEAM_RUNTIME/amd64/usr/bin:$PATH" 539 | ;; 540 | *) 541 | export PATH="$STEAM_RUNTIME/i386/bin:$STEAM_RUNTIME/i386/usr/bin:$PATH" 542 | ;; 543 | esac 544 | 545 | export LD_LIBRARY_PATH="$STEAM_RUNTIME/i386/lib/i386-linux-gnu:$STEAM_RUNTIME/i386/lib:$STEAM_RUNTIME/i386/usr/lib/i386-linux-gnu:$STEAM_RUNTIME/i386/usr/lib:$STEAM_RUNTIME/amd64/lib/x86_64-linux-gnu:$STEAM_RUNTIME/amd64/lib:$STEAM_RUNTIME/amd64/usr/lib/x86_64-linux-gnu:$STEAM_RUNTIME/amd64/usr/lib:$LD_LIBRARY_PATH" 546 | else 547 | echo "Unpack runtime failed, error code $?" 548 | fi 549 | fi 550 | 551 | # prepend our lib path to LD_LIBRARY_PATH 552 | export LD_LIBRARY_PATH="$STEAMROOT/$PLATFORM:$LD_LIBRARY_PATH" 553 | 554 | # Check to make sure the user will be able to run steam... 555 | check_shared_libraries 556 | 557 | # disable SDL1.2 DGA mouse because we can't easily support it in the overlay 558 | export SDL_VIDEO_X11_DGAMOUSE=0 559 | fi 560 | 561 | ulimit -n 2048 2>/dev/null 562 | 563 | # Touch our startup file so we can detect bootstrap launch failure 564 | if [ "$UNAME" = "Linux" ]; then 565 | : >"$STEAMSTARTING" 566 | fi 567 | 568 | MAGIC_RESTART_EXITCODE=42 569 | 570 | # and launch steam 571 | STEAM_DEBUGGER=$DEBUGGER 572 | unset DEBUGGER # Don't use debugger if Steam launches itself recursively 573 | if [ "$STEAM_DEBUGGER" == "gdb" ] || [ "$STEAM_DEBUGGER" == "cgdb" ]; then 574 | ARGSFILE=$(mktemp $USER.steam.gdb.XXXX) 575 | 576 | # Set the LD_PRELOAD varname in the debugger, and unset the global version. 577 | if [ "$LD_PRELOAD" ]; then 578 | echo set env LD_PRELOAD=$LD_PRELOAD >> "$ARGSFILE" 579 | echo show env LD_PRELOAD >> "$ARGSFILE" 580 | unset LD_PRELOAD 581 | fi 582 | 583 | $STEAM_DEBUGGER -x "$ARGSFILE" --args "$STEAMROOT/$PLATFORM/$STEAMEXE" "$@" 584 | rm "$ARGSFILE" 585 | elif [ "$STEAM_DEBUGGER" == "valgrind" ]; then 586 | DONT_BREAK_ON_ASSERT=1 G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --error-limit=no --undef-value-errors=no --suppressions=$PLATFORM/steam.supp $STEAM_VALGRIND "$STEAMROOT/$PLATFORM/$STEAMEXE" "$@" 2>&1 | tee steam_valgrind.txt 587 | else 588 | $STEAM_DEBUGGER "$STEAMROOT/$PLATFORM/$STEAMEXE" "$@" 589 | fi 590 | STATUS=$? 591 | 592 | # Restore paths before unpacking the bootstrap if we need to. 593 | export PATH="$SYSTEM_PATH" 594 | export LD_LIBRARY_PATH="$SYSTEM_LD_LIBRARY_PATH" 595 | 596 | if [ "$UNAME" = "Linux" ]; then 597 | if [ "$INITIAL_LAUNCH" -a \ 598 | $STATUS -ne $MAGIC_RESTART_EXITCODE -a \ 599 | -f "$STEAMSTARTING" -a \ 600 | -z "$STEAM_INSTALLED_BOOTSTRAP" -a \ 601 | -z "$STEAMSCRIPT_OUTOFDATE" ]; then 602 | # Launching the bootstrap failed, try reinstalling 603 | if install_bootstrap; then 604 | # We were able to reinstall the bootstrap, try again 605 | export STEAM_INSTALLED_BOOTSTRAP=1 606 | STATUS=$MAGIC_RESTART_EXITCODE 607 | fi 608 | fi 609 | fi 610 | 611 | if [ $STATUS -eq $MAGIC_RESTART_EXITCODE ]; then 612 | exec "$0" "$@" 613 | fi 614 | --------------------------------------------------------------------------------