You are not logged in.

#1 2012-06-24 01:35:51

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,033

[solved] Segmentation fault with bash script

I have a bash script that checks if it has to do something, if not it sleeps 15 secs and checks again. It works great except that after ~6hrs of just checking and sleeping it seg faults. I upped the stack limit with ulimit -s and it goes ~12hrs before it seg faults. I have a similar script that I have been using for ages that works for 24hrs no problem and I can't pinpoint where the problem is.
The check it does is to see if a file exists, if it's empty and if not, read the first line of a file and do some date comparisons. It doesn't matter if the file is empty or not the seg fault always happens.
Here's the seg fault causing script - it starts at the bottom

#!/bin/bash

# User defines
declare -i DVB_DEVICE_NUM="0"
declare CHANNELS_CONF="${HOME}/Mychannels.conf"
declare SAVE_FOLDER="${HOME}/TV/tele"
declare SCHED_FILE="$HOME/.sched-tv"
declare ZAP_COMMAND="tzap"
declare -i SLEEP=15

# Program defines
declare -i DAY="0"
declare -i START="0"
declare -i FINISH="0"
declare CHAN="0"
declare NAME="0"
declare -i MINUTES="0"
declare -i REC_START="0"
declare -i REC_HOURS="0"
declare -i REC_MINS="0"
declare -i howlong="0"

declare -i PIDOF_AZAP=0
declare -i PIDOF_CAT=0

red='\033[1;31m'
green='\033[1;32m'
yell='\033[1;33m'
cyan='\033[1;36m'
white='\033[1;37m'
reset='\033[0m'

function remove_entry {
    if [ "$NAME" == "" ]; then
        sed "/$DAY $START $FINISH $CHAN/d" $SCHED_FILE > /tmp/dummy
    else
        sed "/$DAY $START $FINISH $CHAN $NAME/d" $SCHED_FILE > /tmp/dummy
    fi
    mv /tmp/dummy $SCHED_FILE
}

function record_entry {
    ${ZAP_COMMAND} -a ${DVB_DEVICE_NUM} -f ${DVB_DEVICE_NUM} -d ${DVB_DEVICE_NUM} \
        -c $CHANNELS_CONF -r ${CHAN} >/dev/null 2>&1 &
    PIDOF_AZAP=$!

    if [ "$PIDOF_AZAP" == "" ]; then
        printf "$red\tError starting ${ZAP_COMMAND}.\n\tFAILED: $CHAN $START\n"
        remove_entry
        exit 1
    fi
    printf "$green\tSET CHANNEL$cyan ${CHAN}\n"
    REC_MINS=$((${START}%100))
    REC_HOURS=0
    MINUTES=0
    REC_START=$(($START-$REC_MINS))
    while [ $((${REC_START}+${REC_HOURS}+${REC_MINS})) -lt $FINISH ]; do
        ((REC_MINS++))
        ((MINUTES++))
        if [ ${REC_MINS} -ge 60 ]; then
            REC_MINS=0
            ((REC_HOURS+=100))
        fi
    done

    if [ "$NAME" == "" ]; then
        declare FILE_NAME="${SAVE_FOLDER}/TV-`date +%Y%m%d-%H%M`-ch.${CHAN}-${MINUTES}.min.mpg"
    else
        declare FILE_NAME="${SAVE_FOLDER}/TV-${NAME}-${MINUTES}.min.mpg"
    fi
    dd if=/dev/dvb/adapter${DVB_DEVICE_NUM}/dvr${DVB_DEVICE_NUM} \
        of=${FILE_NAME} conv=noerror &
    PIDOF_CAT=$!

    if (( ${PIDOF_CAT} == 0 )); then
        printf "$red\tError Starting Recording.\n\t/dev/dvb/adapter${DVB_DEVICE_NUM}/dvr${DVB_DEVICE_NUM} Unavailable\n"
        kill ${PIDOF_AZAP}
        remove_entry
        exit 1
    fi
    printf "$yell\tRECORDING TO :$cyan ${FILE_NAME}\n"
    sleep ${MINUTES}m

    kill ${PIDOF_CAT} && wait ${PIDOF_CAT} 2> /dev/null

    # pkill $ZAP_COMMAND # && wait ${PIDOF_AZAP} 2> /dev/null
    kill ${PIDOF_AZAP} && wait ${PIDOF_AZAP} 2> /dev/null

    printf "$yell\tFINISHED REC :$cyan ${FILE_NAME}\n$reset"

    remove_entry

    waiting 1
}

function check_action {
    [ -e "$SCHED_FILE" ] || waiting $SLEEP
    [ "`cat $SCHED_FILE`" == "" ] && waiting $SLEEP
    DAY="0"; START="0"; FINISH="0"; CHAN="0"; NAME="0"
    TODAY=`date +%Y%m%d`
    NOW=`date +%k%M`
    while read -r DAY START FINISH CHAN NAME; do
        #printf "$DAY $START $FINISH $CHAN $NAME\n"
        break
    done < $SCHED_FILE
    if [ $DAY == $TODAY ] && [ $START -lt $NOW ]; then
        printf "$red\tOld Entry : Removing $CHAN $START\n"
        remove_entry
        waiting 1
    fi
    if [ $DAY == $TODAY ] && [ $START == $NOW ]; then
        record_entry
    else
        waiting $SLEEP
    fi
}

function waiting {
    howlong=$1
    sleep $howlong && check_action
}

check_action

exit 0

And the script that has been working fine 24hrs at a time

#!/bin/bash
echo alarm uses a twelve hour clock
echo Type the time for the alarm to sound as 00-00-?m
echo e.g. 05-35-pm for 5:35pm :: 05-35-am for 5:35am
read TIME
function play {
    A="$(date +%I-%M-%P)"
    if [ $A = $TIME ]; then
      for i in {1..10}; do
        $(aplay -c 1  /home/$USER/alarm/chime.wav); done
        exit
    else
        wait
    fi
}
function wait {
    sleep 15 && play
}
play

I was hoping to have this script idling away in screen with rtorrent, always ready to do something if need be but that's not going to happen unless I can get a clue on what part of the script I need to change to not hit any limits. My websearches are failing me on this...

Last edited by moetunes (2012-06-24 21:41:52)


You're just jealous because the voices only talk to me.

Offline

#2 2012-06-24 02:07:02

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,111
Website

Re: [solved] Segmentation fault with bash script

Your script uses recursion. Eventually, you will always run out of stack and hit the segfault. Use an infinite loop instead.

Offline

#3 2012-06-24 05:02:55

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,033

Re: [solved] Segmentation fault with bash script

Thanks falconindy. I changed to using a while loop.

#!/bin/bash

set -o nounset
shopt -s huponexit

# User defines
declare -i DVB_DEVICE_NUM="0"
declare CHANNELS_CONF="${HOME}/Mychannels.conf"
declare SAVE_FOLDER="${HOME}/TV/tele"
declare SCHED_FILE="$HOME/.sched-tv"
declare ZAP_COMMAND="tzap"
declare -i SLEEP=15

# Program defines
declare -i DAY="0"
declare -i START="0"
declare -i FINISH="0"
declare CHAN="0"
declare NAME="0"
declare -i MINUTES="0"
declare -i REC_START="0"
declare -i REC_HOURS="0"
declare -i REC_MINS="0"
declare -i howlong=$SLEEP

declare -i PIDOF_AZAP=0
declare -i PIDOF_CAT=0

red='\033[1;31m'
green='\033[1;32m'
yell='\033[1;33m'
cyan='\033[1;36m'
white='\033[1;37m'
reset='\033[0m'

function remove_entry {
    if [ "$NAME" == "" ]; then
        sed "/$DAY $START $FINISH $CHAN/d" $SCHED_FILE > /tmp/dummy
    else
        sed "/$DAY $START $FINISH $CHAN $NAME/d" $SCHED_FILE > /tmp/dummy
    fi
    mv /tmp/dummy $SCHED_FILE
}

function record_entry {
    ${ZAP_COMMAND} -a ${DVB_DEVICE_NUM} -f ${DVB_DEVICE_NUM} -d ${DVB_DEVICE_NUM} \
        -c $CHANNELS_CONF -r ${CHAN} >/dev/null 2>&1 &
    PIDOF_AZAP=$!

    if [ "$PIDOF_AZAP" == "" ]; then
        printf "$red\tError starting ${ZAP_COMMAND}.\n\tFAILED: $CHAN $START\n"
        remove_entry
        exit 1
    fi
    printf "$green\tSET CHANNEL$cyan ${CHAN}\n"
    REC_MINS=$((${START}%100))
    REC_HOURS=0
    MINUTES=0
    REC_START=$(($START-$REC_MINS))
    while [ $((${REC_START}+${REC_HOURS}+${REC_MINS})) -lt $FINISH ]; do
        ((REC_MINS++))
        ((MINUTES++))
        if [ ${REC_MINS} -ge 60 ]; then
            REC_MINS=0
            ((REC_HOURS+=100))
        fi
    done

    if [ "$NAME" == "" ]; then
        declare FILE_NAME="${SAVE_FOLDER}/TV-`date +%Y%m%d-%H%M`-ch.${CHAN}-${MINUTES}.min.mpg"
    else
        declare FILE_NAME="${SAVE_FOLDER}/TV-${NAME}-${MINUTES}.min.mpg"
    fi
    dd if=/dev/dvb/adapter${DVB_DEVICE_NUM}/dvr${DVB_DEVICE_NUM} \
        of=${FILE_NAME} conv=noerror &
    PIDOF_CAT=$!

    if (( ${PIDOF_CAT} == 0 )); then
        printf "$red\tError Starting Recording.\n\t/dev/dvb/adapter${DVB_DEVICE_NUM}/dvr${DVB_DEVICE_NUM} Unavailable\n"
        kill ${PIDOF_AZAP}
        remove_entry
        exit 1
    fi
    printf "$yell\tRECORDING TO :$cyan ${FILE_NAME}\n"
    sleep ${MINUTES}m

    kill ${PIDOF_CAT} && wait ${PIDOF_CAT} 2> /dev/null

    # pkill $ZAP_COMMAND # && wait ${PIDOF_AZAP} 2> /dev/null
    kill ${PIDOF_AZAP} && wait ${PIDOF_AZAP} 2> /dev/null

    printf "$yell\tFINISHED REC :$cyan ${FILE_NAME}\n$reset"

    remove_entry
}

while true; do
    sleep $howlong
    howlong=$SLEEP
    [ -e "$SCHED_FILE" ] || continue
    [ "`cat $SCHED_FILE`" == "" ] && continue
    TODAY=`date +%Y%m%d`
    NOW=`date +%k%M`
    while read -r DAY START FINISH CHAN NAME; do
        #printf "$DAY $START $FINISH $CHAN $NAME\n"
        break
    done < $SCHED_FILE
    if [ $DAY == $TODAY ] && [ $START -lt $NOW ]; then
        printf "$red\tOld Entry : Removing $CHAN $START\n"
        remove_entry
        howlong=1
        continue
    fi
    if [ $DAY == $TODAY ] && [ $START == $NOW ]; then
        record_entry
    fi
done

exit 0

I think that should be ok now.


You're just jealous because the voices only talk to me.

Offline

#4 2012-06-24 21:41:20

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,033

Re: [solved] Segmentation fault with bash script

It's been 13hrs without a seg fault and I'm an optimist, so I'm calling this solved.
Thanks again falconindy.


You're just jealous because the voices only talk to me.

Offline

Board footer

Powered by FluxBB