diff --git a/2ano1/SO/aula02/aula02e01-v2.sh b/2ano1/SO/aula02/aula02e01-v2.sh new file mode 100755 index 0000000..6a04426 --- /dev/null +++ b/2ano1/SO/aula02/aula02e01-v2.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Este é o meu primeiro script +msg="O meu segundo script em bash!" +echo msg diff --git a/2ano1/SO/aula02/aula02e01.sh b/2ano1/SO/aula02/aula02e01.sh new file mode 100755 index 0000000..ceb9fd5 --- /dev/null +++ b/2ano1/SO/aula02/aula02e01.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Este é o meu primeiro script +msg="O meu primeiro script em bash!" +echo $msg diff --git a/2ano1/SO/aula02/aula02e02.sh b/2ano1/SO/aula02/aula02e02.sh new file mode 100755 index 0000000..637f3e2 --- /dev/null +++ b/2ano1/SO/aula02/aula02e02.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Atenção aos espaços +echo Este e um teste +echo "Este e um teste" diff --git a/2ano1/SO/aula02/aula02e03.sh b/2ano1/SO/aula02/aula02e03.sh new file mode 100755 index 0000000..957cee2 --- /dev/null +++ b/2ano1/SO/aula02/aula02e03.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env -S bash -i +# O comando type permite saber o tipo de um comando +type rm +type cd +type for +type ll +type dequote diff --git a/2ano1/SO/aula02/aula02e04-b.sh b/2ano1/SO/aula02/aula02e04-b.sh new file mode 100755 index 0000000..bce74fa --- /dev/null +++ b/2ano1/SO/aula02/aula02e04-b.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +echo "Todos os items em /etc:" +find /etc -maxdepth 1 -printf "%f\n" + +printf "\n" + +echo "Começam por a:" +find /etc -maxdepth 1 -name "a*" -printf "%f\n" + +printf "\n" + +echo "Começam por a e têm mais que 3 caracteres": +find /etc -maxdepth 1 -regextype egrep -regex ".*/a.{3,}" -printf "%f\n" + +printf "\n" + +echo "Contêm conf no nome": +find /etc -maxdepth 1 -name "*conf*" -printf "%f\n" diff --git a/2ano1/SO/aula02/aula02e04.sh b/2ano1/SO/aula02/aula02e04.sh new file mode 100755 index 0000000..4324fb9 --- /dev/null +++ b/2ano1/SO/aula02/aula02e04.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env -S bash +echo "O meu editor por omissão BASH $BASH \$BASH" +echo 'O meu editor por omissão BASH $BASH \$BASH' +echo $(( 5 + 5 )) +(( 5 > 0 )) && echo "cinco é maior do que zero" +today=$(date); echo $today diff --git a/2ano1/SO/aula02/aula02e05.sh b/2ano1/SO/aula02/aula02e05.sh new file mode 100755 index 0000000..4af114a --- /dev/null +++ b/2ano1/SO/aula02/aula02e05.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +echo "$#" +echo "Arg 1: $1" +echo "Arg 2: $2" +echo "$*" +echo "$@" diff --git a/2ano1/SO/aula02/aula02e05d.sh b/2ano1/SO/aula02/aula02e05d.sh new file mode 100755 index 0000000..e8958e7 --- /dev/null +++ b/2ano1/SO/aula02/aula02e05d.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +echo using '$*:' $* +for i in $*; do echo "$i"; done + +echo using '$@:' $@ +for i in $@; do echo "$i"; done + +echo using '"$*":' "$*" +for i in "$*"; do echo "$i"; done + +echo using '"$@":' "$@" +for i in "$@"; do echo "$i"; done diff --git a/2ano1/SO/aula02/aula02e06.sh b/2ano1/SO/aula02/aula02e06.sh new file mode 100755 index 0000000..71212c5 --- /dev/null +++ b/2ano1/SO/aula02/aula02e06.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Parameter Expansion +file="$HOME/.bashrc" +echo "File path: $file" +echo "File name: ${file##*/}" +echo "Directory name: ${file%/*}" diff --git a/2ano1/SO/aula02/aula02e07.sh b/2ano1/SO/aula02/aula02e07.sh new file mode 100755 index 0000000..b21b9fe --- /dev/null +++ b/2ano1/SO/aula02/aula02e07.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Brace Expansion +echo {1..9} +echo {0,1}{0..9} diff --git a/2ano1/SO/aula02/aula02e08.sh b/2ano1/SO/aula02/aula02e08.sh new file mode 100755 index 0000000..87b183d --- /dev/null +++ b/2ano1/SO/aula02/aula02e08.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Exit status +ping -c 1 www.ua.pt +echo "Exit code: $?" # $? gives exit code of last process +ping -c 1 wwwww.ua.pt +echo "Exit code: $?" diff --git a/2ano1/SO/aula02/aula02e09.sh b/2ano1/SO/aula02/aula02e09.sh new file mode 100755 index 0000000..77b45aa --- /dev/null +++ b/2ano1/SO/aula02/aula02e09.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +mkdir d && cd d && pwd +echo "----------------" +pwd && rm xpto || echo "I couldn't remove the file" diff --git a/2ano1/SO/aula02/c10param.sh b/2ano1/SO/aula02/c10param.sh new file mode 100755 index 0000000..318e152 --- /dev/null +++ b/2ano1/SO/aula02/c10param.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +touch "$1"{0..9}.dat diff --git a/2ano1/SO/aula02/c10xpto.sh b/2ano1/SO/aula02/c10xpto.sh new file mode 100755 index 0000000..2c7dc5b --- /dev/null +++ b/2ano1/SO/aula02/c10xpto.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +touch xpto0{0..9}.dat diff --git a/2ano1/SO/aula02/exitfile.sh b/2ano1/SO/aula02/exitfile.sh new file mode 100755 index 0000000..1d7c685 --- /dev/null +++ b/2ano1/SO/aula02/exitfile.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +file -E "$1" +echo "Exit code: $?" diff --git a/2ano1/SO/aula02/px.sh b/2ano1/SO/aula02/px.sh new file mode 100755 index 0000000..df92a34 --- /dev/null +++ b/2ano1/SO/aula02/px.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +chmod +x "$@" diff --git a/2ano1/SO/aula02/soma2.sh b/2ano1/SO/aula02/soma2.sh new file mode 100755 index 0000000..3f08dd3 --- /dev/null +++ b/2ano1/SO/aula02/soma2.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +if [[ "$#" -ne "2" ]]; then + echo "Usage: $0 num1 num2" + exit 1 +fi + +echo $(("$1" + "$2")) diff --git a/2ano1/SO/aula03/aula03e01.sh b/2ano1/SO/aula03/aula03e01.sh new file mode 100755 index 0000000..3129f96 --- /dev/null +++ b/2ano1/SO/aula03/aula03e01.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Agrupamento de comandos na Bash +{ + i=0 + while read line; do + echo $i: $line + i=$(($i+1)) + done +} < $1 diff --git a/2ano1/SO/aula03/aula03e02a.sh b/2ano1/SO/aula03/aula03e02a.sh new file mode 100755 index 0000000..2c1e42c --- /dev/null +++ b/2ano1/SO/aula03/aula03e02a.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Conditional block if +if $1; then + echo "Verdadeiro" +else + echo "Falso" +fi diff --git a/2ano1/SO/aula03/aula03e02b.sh b/2ano1/SO/aula03/aula03e02b.sh new file mode 100755 index 0000000..48eb8b0 --- /dev/null +++ b/2ano1/SO/aula03/aula03e02b.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Conditional block if +if [[ $1 = $2 ]] ; then + echo "O arg1 é igual ao arg2" +else + echo "Os args são diferentes" +fi diff --git a/2ano1/SO/aula03/aula03e02c.sh b/2ano1/SO/aula03/aula03e02c.sh new file mode 100755 index 0000000..998b3b2 --- /dev/null +++ b/2ano1/SO/aula03/aula03e02c.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Conditional block if +if [ $1 = $2 ]; then + echo "O arg1 é igual ao arg2" +else + echo "Os args são diferentes" +fi diff --git a/2ano1/SO/aula03/aula03e02d.sh b/2ano1/SO/aula03/aula03e02d.sh new file mode 100755 index 0000000..55f8133 --- /dev/null +++ b/2ano1/SO/aula03/aula03e02d.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Conditional block if +if [ "$1" = "$2" ]; then + echo "O arg1 é igual ao arg2" +else + echo "Os args são diferentes" +fi diff --git a/2ano1/SO/aula03/aula03e02e.sh b/2ano1/SO/aula03/aula03e02e.sh new file mode 100755 index 0000000..657ec6b --- /dev/null +++ b/2ano1/SO/aula03/aula03e02e.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# Conditional block if +if [ "$1" -gt 5 ] && [ "$1" -lt 10 ]; then + echo "número maior do que 5 e menor do que 10" +fi diff --git a/2ano1/SO/aula03/aula03e03.sh b/2ano1/SO/aula03/aula03e03.sh new file mode 100755 index 0000000..a8e06c1 --- /dev/null +++ b/2ano1/SO/aula03/aula03e03.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# This script checks the existence of a file + +if [ "$#" -ne 1 ]; then + if [ "$#" -lt 1 ]; then + >&2 echo "Error: Not enough arguments" + else + >&2 echo "Error: Too many arguments" + fi + + >&2 echo "Usage: $0 file" + exit 1; +fi + +echo "Checking..." +if [[ -f "$1" ]] ; then + echo "$1 existe." +else + echo "$1 não existe" +fi +echo "...done." diff --git a/2ano1/SO/aula03/aula03e03b.sh b/2ano1/SO/aula03/aula03e03b.sh new file mode 100755 index 0000000..cf754d7 --- /dev/null +++ b/2ano1/SO/aula03/aula03e03b.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# This script checks the existence of a file + +if [ "$#" -ne 1 ]; then + if [ "$#" -lt 1 ]; then + >&2 echo "Error: Not enough arguments" + else + >&2 echo "Error: Too many arguments" + fi + + >&2 echo "Usage: $0 file" + exit 1; +fi + +echo "Checking..." + +if ! [ -e "$1" ]; then + echo "$1 não existe." + exit 1 +fi + +TYPE="unknown file" + +if [ -f "$1" ]; then TYPE="regular file" +elif [ -b "$1" ]; then TYPE="block dev file" +elif [ -c "$1" ]; then TYPE="char dev file" +elif [ -d "$1" ]; then TYPE="directory" +fi + +echo "$1 is a $TYPE" + +PERMS="" + +if [ -r "$1" ]; then PERMS="${PERMS}r"; else PERMS="${PERMS}-"; fi +if [ -w "$1" ]; then PERMS="${PERMS}w"; else PERMS="${PERMS}-"; fi +if [ -x "$1" ]; then PERMS="${PERMS}x"; else PERMS="${PERMS}-"; fi + +echo "$1 permissions: $PERMS" + +echo "...done." diff --git a/2ano1/SO/aula03/aula03e03c.sh b/2ano1/SO/aula03/aula03e03c.sh new file mode 100755 index 0000000..c2f19c5 --- /dev/null +++ b/2ano1/SO/aula03/aula03e03c.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Testa se ano dado (ou ano actual, se nenhum for dado) +# é bissexto ou comum. +if [[ $# = 1 ]]; then + year=$1 +else + year=$(date +%Y) +fi + +if [[ $(($year % 400)) -eq "0" ]]; then + echo "Ano bissexto. Fevereiro tem 29 dias." +elif [[ $(($year % 4)) -eq 0 ]]; then + if [[ $(($year % 100)) -ne 0 ]]; then + echo " Ano bissexto. Fevereiro tem 29 dias." + else + echo "Ano comum. Fevereiro tem 28 dias." + fi +else + echo " Ano comum. Fevereiro tem 28 dias." +fi diff --git a/2ano1/SO/aula03/aula03e04.sh b/2ano1/SO/aula03/aula03e04.sh new file mode 100755 index 0000000..cd275df --- /dev/null +++ b/2ano1/SO/aula03/aula03e04.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +#This script does a very simple test for checking disk space. + +# `df -h`, report file system space usage in human readable format +# `awk '{print $5}'` - Print the fifth column (white space separated columns) +# `grep %` - Remove lines without the % symbol +# `grep -v Use` - Remove lines with the `Use` word +# `sort -n` - Sort lines numerically +# `tail -1` - Select the last line +# `cut -d "%" -f1 -` - Run the command `cut` reading from stdin (`-`) with the delimiter % +# and selecting the first field. +space=$(df -h | awk '{print $5}' | grep % | grep -v use | sort -n \ + | tail -1 | cut -d "%" -f1 - | awk '{printf("%02d\n", $1)}') + +echo "largest occupied space = $space%" +case $space in + [0-6][0-9]) # espaço < 70% + Message="All OK." + ;; + [7-8][0-9] ) # 70% <= espaço < 90% + Message="Cleaning out. One partition is $space % full." + ;; + 9[0-8] ) # 90% <= espaço < 99% + Message="Better buy a new disk. One partition is $space % full." + ;; + 99 ) # espaço = 99% + Message="I'm drowning here! There's a partition at $space %!" + ;; + * ) + Message="I seem to be running with a non-existent disk..." + ;; +esac +echo $Message diff --git a/2ano1/SO/aula03/aula03e04b.sh b/2ano1/SO/aula03/aula03e04b.sh new file mode 100755 index 0000000..dc4d068 --- /dev/null +++ b/2ano1/SO/aula03/aula03e04b.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +#This script does a very simple test for checking disk space. + +# `df -h`, report file system space usage in human readable format +# `awk '{print $5}'` - Print the fifth column (white space separated columns) +# `grep %` - Remove lines without the % symbol +# `grep -v Use` - Remove lines with the `Use` word +# `sort -n` - Sort lines numerically +# `tail -1` - Select the last line +# `cut -d "%" -f1 -` - Run the command `cut` reading from stdin (`-`) with the delimiter % +# and selecting the first field. +space=$(df -h | awk '{print $5}' | grep % | grep -v Use | sort -n \ + | tail -1 | cut -d "%" -f1 -) + +echo "largest occupied space = $space%" + +largest=$(df | awk '{print $2 " " $1}' | tail -n +2 | sort -n -k1 \ + | tail -1 | awk '{print $2 ": " $1}' | numfmt --field=2 --to=iec --from-unit=1024 ) + +echo "Largest partition $largest" +case $space in + [0-6][0-9]) # espaço < 70% + Message="All OK." + ;; + [7-8][0-9] ) # 70% <= espaço < 90% + Message="Cleaning out. One partition is $space % full." + ;; + 9[0-8] ) # 90% <= espaço < 99% + Message="Better buy a new disk. One partition is $space % full." + ;; + 99 ) # espaço = 99% + Message="I'm drowning here! There's a partition at $space %!" + ;; + * ) + Message="I seem to be running with a non-existent disk..." + ;; +esac +echo $Message diff --git a/2ano1/SO/aula03/aula03e04c.sh b/2ano1/SO/aula03/aula03e04c.sh new file mode 100755 index 0000000..393f694 --- /dev/null +++ b/2ano1/SO/aula03/aula03e04c.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +shopt -s extglob + +case "$1|$2" in + ?([0-9])[0-9]"|"sec*) + echo "Válido." + ;; + * ) + echo "Não é válido" + ;; +esac diff --git a/2ano1/SO/aula03/aula03e05a.sh b/2ano1/SO/aula03/aula03e05a.sh new file mode 100755 index 0000000..b33ec49 --- /dev/null +++ b/2ano1/SO/aula03/aula03e05a.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# For all the files in a folder, show their properties +for f in $1/*; do + file "$f" +done diff --git a/2ano1/SO/aula03/aula03e05b.sh b/2ano1/SO/aula03/aula03e05b.sh new file mode 100755 index 0000000..ab97b77 --- /dev/null +++ b/2ano1/SO/aula03/aula03e05b.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +if [ "$#" -ne 1 ]; then + if [ "$#" -lt 1 ]; then + >&2 echo "Error: Not enough arguments" + else + >&2 echo "Error: Too many arguments" + fi + + >&2 echo "Usage: $0 dir" + exit 1; +fi +# For all the files in a folder, show their properties +for f in $1/*; do + file "$f" +done diff --git a/2ano1/SO/aula03/aula03e05c.sh b/2ano1/SO/aula03/aula03e05c.sh new file mode 100755 index 0000000..c9c7e18 --- /dev/null +++ b/2ano1/SO/aula03/aula03e05c.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +PROGRAM_NAME="$0" + +POSITIONAL_ARGS=() + +REMOVE_PREFIX=false + +help() { + if [ ! -z "$1" ]; then + >&2 echo "Error: $1" + fi + + >&2 echo "Usage: $PROGRAM_NAME [options] dir" + >&2 printf "\n" + >&2 echo "Options:" + >&2 echo -e "\t-h, --help:\tShows this message" + >&2 echo -e "\t-r, --remove:\tDoesn't add the \`new_\` prefix to the folder" + + if [ -z "$1" ]; then + exit 0; + else + exit 1; + fi +} + +for arg in "$@"; do + if [[ $arg == --* ]]; then + case "${arg#--}" in + help) + help + ;; + remove) + REMOVE_PREFIX=true + ;; + * ) + help "Unknown option ${arg}" + ;; + esac + elif [[ $arg == -* ]]; then + for (( i=1; i<${#arg}; i++ )); do + case "${arg:$i:1}" in + h) + help + ;; + r) + REMOVE_PREFIX=true + ;; + * ) + help "Unknown option ${arg:$i:1}" + ;; + esac + done + else + POSITIONAL_ARGS+=("$arg"); + fi +done + +POSITIONAL_ARGS_LENGTH="${#POSITIONAL_ARGS[@]}" + +if [ "$POSITIONAL_ARGS_LENGTH" -ne 1 ]; then + if [ "$POSITIONAL_ARGS_LENGTH" -lt 1 ]; then + help "Not enough arguments" + else + help "Too many arguments" + fi +fi + +PREFIX="new_" + +if [ "$REMOVE_PREFIX" = true ]; then + PREFIX="" +fi + +# For all the files in a folder, show their properties +for f in "$PREFIX${POSITIONAL_ARGS[0]}"/*; do + file "$f" +done diff --git a/2ano1/SO/aula03/aula03e06.sh b/2ano1/SO/aula03/aula03e06.sh new file mode 100755 index 0000000..d1cae7a --- /dev/null +++ b/2ano1/SO/aula03/aula03e06.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +#This script opens 4 terminal windows. +i="0" +while [[ $i -lt 4 ]]; do + kitty & + i=$(($i+1)) +done diff --git a/2ano1/SO/aula03/aula03e06a.sh b/2ano1/SO/aula03/aula03e06a.sh new file mode 100755 index 0000000..82b6641 --- /dev/null +++ b/2ano1/SO/aula03/aula03e06a.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Wait for a host, given as argument, to come back online. +host=$1 +until ping -c 1 "$host" >& /dev/null; do + echo "$host is still unavailable." + sleep 5 +done; +echo -e "$host is available again.\a" diff --git a/2ano1/SO/aula03/aula03e07.sh b/2ano1/SO/aula03/aula03e07.sh new file mode 100755 index 0000000..4f8c769 --- /dev/null +++ b/2ano1/SO/aula03/aula03e07.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Calculate the sum of a series of numbers. +SCORE="0" +SUM="0" +while true; do + echo -n "Enter your score [0-10] ('q' to quit): " + read SCORE; + if (("$SCORE" < "0")) || (("$SCORE" > "10")); then + echo "Try again: " + elif [[ "$SCORE" == "q" ]]; then + echo "Sum: $SUM." + break + else + SUM=$((SUM + SCORE)) + fi +done +echo "Exiting." diff --git a/2ano1/SO/aula03/aula03e07a.sh b/2ano1/SO/aula03/aula03e07a.sh new file mode 100755 index 0000000..e83b52e --- /dev/null +++ b/2ano1/SO/aula03/aula03e07a.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Calculate the sum of a series of numbers. +SCORE="0" +SUM="0" +SCORES="0" +while true; do + echo -n "Enter your score [0-10] ('q' to quit): " + read SCORE; + if (("$SCORE" < "0")) || (("$SCORE" > "10")); then + echo "Try again: " + elif [[ "$SCORE" == "q" ]]; then + echo "Sum: $SUM." + echo "Average: $(awk "BEGIN { printf(\"%.2f\", $SUM / $SCORES) }")." + break + else + SUM=$((SUM + SCORE)) + SCORES=$((SCORES + 1)); + fi +done +echo "Exiting." diff --git a/2ano1/SO/aula03/aula03e07b.sh b/2ano1/SO/aula03/aula03e07b.sh new file mode 100755 index 0000000..41fe5bd --- /dev/null +++ b/2ano1/SO/aula03/aula03e07b.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Calculate the sum of a series of numbers. +SCORE="0" +SUM="0" +SCORES="0" +while true; do + echo -n "Enter your score [0-10] ('q' to quit, 'r' to reset): " + read SCORE; + if (("$SCORE" < "0")) || (("$SCORE" > "10")); then + echo "Try again: " + elif [[ "$SCORE" == "q" ]]; then + echo "Sum: $SUM." + echo "Average: $(awk "BEGIN { printf(\"%.2f\", $SUM / $SCORES) }")." + break + elif [[ "$SCORE" == "r" ]]; then + SUM="0" + SCORES="0" + else + SUM=$((SUM + SCORE)) + SCORES=$((SCORES + 1)); + fi +done +echo "Exiting." diff --git a/2ano1/SO/aula03/aula03e08.sh b/2ano1/SO/aula03/aula03e08.sh new file mode 100755 index 0000000..299b182 --- /dev/null +++ b/2ano1/SO/aula03/aula03e08.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# select structure to create menus +select arg in $@; do + echo "You picked $arg ($REPLY)." +done diff --git a/2ano1/SO/aula03/aula03e08a.sh b/2ano1/SO/aula03/aula03e08a.sh new file mode 100755 index 0000000..8c19669 --- /dev/null +++ b/2ano1/SO/aula03/aula03e08a.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# select structure to create menus +PS3="Oi mate, choose an option ayeh: " +select arg in $@ +do + echo "You picked $arg ($REPLY)." +done diff --git a/2ano1/SO/aula03/aula03e08b.sh b/2ano1/SO/aula03/aula03e08b.sh new file mode 100755 index 0000000..3a4f33b --- /dev/null +++ b/2ano1/SO/aula03/aula03e08b.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# select structure to create menus +PS3="Oi mate, choose an option ayeh: " +select arg in $@ +do + if [ -z "$arg" ]; then + exit 1 + fi + + echo "You picked $arg ($REPLY)." +done diff --git a/2ano1/SO/aula03/words.txt b/2ano1/SO/aula03/words.txt new file mode 100644 index 0000000..1711246 --- /dev/null +++ b/2ano1/SO/aula03/words.txt @@ -0,0 +1,6 @@ +a +b +c +d +e +f diff --git a/2ano1/SO/aula04/aula04e01a.sh b/2ano1/SO/aula04/aula04e01a.sh new file mode 100755 index 0000000..c7feb9c --- /dev/null +++ b/2ano1/SO/aula04/aula04e01a.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +function imprime_msg() +{ + echo "A minha primeira funcao" + return 0 +} +imprime_msg diff --git a/2ano1/SO/aula04/aula04e01b.sh b/2ano1/SO/aula04/aula04e01b.sh new file mode 100755 index 0000000..e59f0db --- /dev/null +++ b/2ano1/SO/aula04/aula04e01b.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +function imprime_msg() +{ + echo "A minha primeira funcao" + return 0 +} + +function imprime_info() +{ + echo "Data: $(date)" + echo "PC: $(hostname)" + echo "Utilizador: $(whoami)" + return 0 +} + +imprime_msg +imprime_info diff --git a/2ano1/SO/aula04/aula04e01c.sh b/2ano1/SO/aula04/aula04e01c.sh new file mode 100755 index 0000000..44f4fa6 --- /dev/null +++ b/2ano1/SO/aula04/aula04e01c.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +source ./functions.sh + +imprime_msg +imprime_info diff --git a/2ano1/SO/aula04/aula04e02.sh b/2ano1/SO/aula04/aula04e02.sh new file mode 100755 index 0000000..7952271 --- /dev/null +++ b/2ano1/SO/aula04/aula04e02.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +function numeric_to_string() +{ + case "$1" in + 1) + echo "Um" + ;; + 2) + echo "Dois" + ;; + 3) + echo "Três" + ;; + *) + echo "Outro numero" + esac + return 0 +} +numeric_to_string $1 diff --git a/2ano1/SO/aula04/aula04e02b.sh b/2ano1/SO/aula04/aula04e02b.sh new file mode 100755 index 0000000..cd5dcd3 --- /dev/null +++ b/2ano1/SO/aula04/aula04e02b.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +function numeric_to_string() +{ + case "$1" in + 1) + echo "Um" + ;; + 2) + echo "Dois" + ;; + 3) + echo "Três" + ;; + *) + echo "Outro numero" + esac + return "$1" +} +numeric_to_string $1 +echo "O número passado foi $?" diff --git a/2ano1/SO/aula04/aula04e02c.sh b/2ano1/SO/aula04/aula04e02c.sh new file mode 100755 index 0000000..354bc40 --- /dev/null +++ b/2ano1/SO/aula04/aula04e02c.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +ret() { + test_return() { return "$1"; } + + for i in {-1000..0}; do + test_return "$i" + if [ "$?" -eq "$i" ]; then + echo "Lower bound: $i" + break + fi + done + + for i in {0..1000}; do + test_return "$i" + if [ "$?" -ne "$i" ]; then + echo "Upper bound: $(($i - 1))" + break + fi + done +} + +ret diff --git a/2ano1/SO/aula04/aula04e02d.sh b/2ano1/SO/aula04/aula04e02d.sh new file mode 100755 index 0000000..9a5894c --- /dev/null +++ b/2ano1/SO/aula04/aula04e02d.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +function cmp { + if [ "$1" -eq "$2" ]; then + return 1 + elif [ "$1" -lt "$2" ]; then + return 0 + else + return 2 + fi +} + +cmp "$1" "$2" +case $? in + 0) + echo "$1 é menor que $2" + ;; + 1) + echo "$1 é igual a $2" + ;; + 2) + echo "$1 é maior que $2" +esac diff --git a/2ano1/SO/aula04/aula04e02e.sh b/2ano1/SO/aula04/aula04e02e.sh new file mode 100755 index 0000000..d69aa48 --- /dev/null +++ b/2ano1/SO/aula04/aula04e02e.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +function cmp { + if [ "$1" -eq "$2" ]; then + return 1 + elif [ "$1" -lt "$2" ]; then + return 0 + else + return 2 + fi +} + +read -p "Insira o primeiro número: " first +read -p "Insira o segundo número: " second + +cmp "$first" "$second" +case $? in + 0) + echo "$first é menor que $second" + ;; + 1) + echo "$first é igual a $second" + ;; + 2) + echo "$first é maior que $second" +esac diff --git a/2ano1/SO/aula04/aula04e03a.sh b/2ano1/SO/aula04/aula04e03a.sh new file mode 100755 index 0000000..a95aa00 --- /dev/null +++ b/2ano1/SO/aula04/aula04e03a.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +lista=( {1..10} ) +for i in "${lista[@]}"; do + echo "$i" +done diff --git a/2ano1/SO/aula04/aula04e03b.sh b/2ano1/SO/aula04/aula04e03b.sh new file mode 100755 index 0000000..e441751 --- /dev/null +++ b/2ano1/SO/aula04/aula04e03b.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +lista=( $(seq 2 3 15) ) + +echo vals ${lista[@]} +echo count ${#lista[@]} +echo index ${!lista[@]} + +for ((i = 0; i < ${#lista[@]}; i++)); do + lista[i]=$((${lista[i]}+1)) + echo "$i: ${lista[i]}" +done + +unset lista[1] +unset lista[3] + +echo count ${#lista[@]} + +for i in ${!lista[@]}; do + echo "$i: ${lista[i]}" +done diff --git a/2ano1/SO/aula04/aula04e03c.sh b/2ano1/SO/aula04/aula04e03c.sh new file mode 100755 index 0000000..407c5f7 --- /dev/null +++ b/2ano1/SO/aula04/aula04e03c.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +declare -A assArray + +assArray[Aveiro]=10 +assArray[Porto]=NA +assArray+=([Lisboa]=5) + +echo vals ${assArray[@]} +echo count ${#assArray[@]} +echo index ${!assArray[@]} + +echo val Lisboa ${assArray[Lisboa]} diff --git a/2ano1/SO/aula04/aula04e03d.sh b/2ano1/SO/aula04/aula04e03d.sh new file mode 100755 index 0000000..7a26320 --- /dev/null +++ b/2ano1/SO/aula04/aula04e03d.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +if [ "$#" -ne 1 ]; then + echo "Usage: $0 [file]" + exit 1 +fi + +numeros=() + +while read -r line +do + numeros+=("$line") +done < "$1" + +last_idx=$(("${#numeros[@]}" - 1)) + +for i in $(seq 0 $last_idx); do + small_idx="$i" + + for j in $(seq $((i + 1)) $last_idx); do + if [ "${numeros[$j]}" -lt "${numeros[$small_idx]}" ]; then + small_idx="$j" + fi + done + + if [ "$i" -ne "$small_idx" ]; then + tmp="${numeros[$i]}" + numeros["$i"]="${numeros[$small_idx]}" + numeros["$small_idx"]="$tmp" + fi +done + +echo "${numeros[@]}" diff --git a/2ano1/SO/aula04/functions.sh b/2ano1/SO/aula04/functions.sh new file mode 100644 index 0000000..ce11ab9 --- /dev/null +++ b/2ano1/SO/aula04/functions.sh @@ -0,0 +1,14 @@ +function imprime_msg() +{ + echo "A minha primeira funcao" + return 0 +} + +function imprime_info() +{ + echo "Data: $(date)" + echo "PC: $(hostname)" + echo "Utilizador: $(whoami)" + return 0 +} + diff --git a/2ano1/SO/aula04/guiao.norg b/2ano1/SO/aula04/guiao.norg new file mode 100644 index 0000000..4865558 --- /dev/null +++ b/2ano1/SO/aula04/guiao.norg @@ -0,0 +1,190 @@ +@document.meta +title: Aula 04 +description: Funções e arrays em bash +author: João Capucho +@end + +* Exercício 1 + +** Parte A + + > Crie o script `aula04e01.sh` com o conteúdo seguinte; execute-o e + interprete o resultado. + + @code sh + #!/usr/bin/env bash + function imprime_msg() + { + echo "A minha primeira funcao" + return 0 + } + imprime_msg + @end + +** Parte B + + > Acrescente ao script anterior uma função que permita mostrar a data de + hoje, o nome do PC onde está a trabalhar e o nome do utilizador. + + @code sh + #!/usr/bin/env bash + function imprime_msg() + { + echo "A minha primeira funcao" + return 0 + } + + function imprime_info() + { + echo "Data: $(date)" + echo "PC: $(hostname)" + echo "Utilizador: $(whoami)" + return 0 + } + + imprime_msg + imprime_info + @end + +** Parte C + + > Altere o script anterior de modo a implementar as funções num ficheiro + separado. + + No ficheiro `functions.sh`: + + @code sh + function imprime_msg() + { + echo "A minha primeira funcao" + return 0 + } + + function imprime_info() + { + echo "Data: $(date)" + echo "PC: $(hostname)" + echo "Utilizador: $(whoami)" + return 0 + } + @end + + Depois no script: + + @code sh + #!/usr/bin/env bash + source ./functions.sh + + imprime_msg + imprime_info + @end + +** Parte D + + > Defina a função `dw()`, na própria bash do terminal (sem criar um script), + que executa os comandos `date` e `who` em sequência. + + @code sh + [capucho@capucho:~]$ dw() { + > date + > who + > } + [capucho@capucho:~]$ dw + Thu Oct 12 03:20:47 PM WEST 2023 + capucho tty3 2023-10-12 14:06 + @end + +* Exercício 2 + +** Parte A + + > Crie o script `aula04e02.sh` com o seguinte conteúdo; execute-o passando + um número entre 1 e 5 e interprete o resultado. + + @code sh + #!/usr/bin/env bash + function numeric_to_string() + { + case "$1" in + 1) + echo "Um" + ;; + 2) + echo "Dois" + ;; + 3) + echo "Três" + ;; + *) + echo "Outro numero" + esac + return 0 + } + + numeric_to_string $1 + @end + +** Parte B + + > Com base no que já aprendeu sobre a utilização do valor de retorno de um + comando ($?), como acha que pode avaliar o valor de retorno de uma função? + + > Altere a função anterior de modo a que esta devolva, através do valor de + retorno, um número igual ao valor passado como argumento e mostre como + acede a esse valor após a chamada à função. + + @code sh + function numeric_to_string() + { + case "$1" in + 1) + echo "Um" + ;; + 2) + echo "Dois" + ;; + 3) + echo "Três" + ;; + *) + echo "Outro numero" + esac + return "$1" + } + + numeric_to_string $1 + echo "O número passado foi $?" + @end + +** Parte C + + > Defina a função `ret()`, na própria bash do terminal (sem criar um + script), que lhe permita, através de vários testes, determinar a gama de + valores de retorno de uma função bash. + + @code sh + [capucho@capucho:~]$ function ret { + > test_return() { return "$1"; } + > + > for i in {-1000..0}; do + > test_return "$i" + > if [ "$?" -eq "$i" ]; then + > echo "Lower bound: $i" + > break + > fi + > done + > + > for i in {0..1000}; do + > test_return "$i" + > if [ "$?" -ne "$i" ]; then + > echo "Upper bound: $(($i - 1))" + > break + > fi + > done + > } + [capucho@capucho:~]$ ret + Lower bound: 0 + Upper bound: 255 + @end + + > Qual é essa gama? diff --git a/2ano1/SO/aula04/numeros b/2ano1/SO/aula04/numeros new file mode 100644 index 0000000..70b1e9d --- /dev/null +++ b/2ano1/SO/aula04/numeros @@ -0,0 +1,14 @@ +2 +5 +1 +7 +4 +2 +4 +5 +3 +7 +7 +5 +6 +4 diff --git a/2ano1/SO/aula05/altobaixo.c b/2ano1/SO/aula05/altobaixo.c new file mode 100644 index 0000000..91e1941 --- /dev/null +++ b/2ano1/SO/aula05/altobaixo.c @@ -0,0 +1,90 @@ +#include +#include +#include + +int main(int argc, char **argv) { + int lower_limit = 0; + int upper_limit = 100; + + if (argc == 3) { + char *rest = NULL; + lower_limit = strtol(argv[1], &rest, 10); + if (rest != NULL && *rest != '\0') { + fprintf(stderr, "ERROR: Not a valid number \"%s\"\n", argv[1]); + return EXIT_FAILURE; + } + + if (lower_limit < 0) { + fprintf(stderr, "ERROR: Lower limit must be positive\n"); + return EXIT_FAILURE; + } + + rest = NULL; + upper_limit = strtol(argv[2], &rest, 10); + if (rest != NULL && *rest != '\0') { + fprintf(stderr, "ERROR: Not a valid number \"%s\"\n", argv[2]); + return EXIT_FAILURE; + } + + if (upper_limit < 0) { + fprintf(stderr, "ERROR: Upper limit must be positive\n"); + return EXIT_FAILURE; + } + + if (lower_limit >= upper_limit) { + fprintf(stderr, "ERROR: Upper limit must be higher than lower limit\n"); + return EXIT_FAILURE; + } + } else if (argc != 1) { + fprintf(stderr, "Error: Expected 0 or 2 arguments, got: %d\n", argc - 1); + return EXIT_FAILURE; + } + + int tentativas = 0; + int alvo = (rand() + lower_limit) % upper_limit; + + while (1) { + printf("Insert guess (e to exit): "); + char *user_input = NULL; + size_t user_input_alloc_size = 0; + ssize_t result = getline(&user_input, &user_input_alloc_size, stdin); + + if (result < 0) { + perror("ERROR"); + free(user_input); + return EXIT_FAILURE; + } + + if (user_input[result - 1] == '\n') { + user_input[result - 1] = '\0'; + result--; + } + + if (result == 1 && *user_input == 'e') { + break; + } + + char *rest = NULL; + int guess = strtol(user_input, &rest, 10); + if (rest != NULL && *rest != '\0') { + fprintf(stderr, "ERROR: Not a valid number \"%s\"\n", user_input); + continue; + } + + free(user_input); + tentativas++; + + if (guess == alvo) { + printf("Acertou!\n"); + break; + } else if (guess > alvo) { + printf("Mais baixo\n"); + } else { + printf("Mais alto\n"); + } + } + + printf("Usou %d tentativas\n", tentativas); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/args1.c b/2ano1/SO/aula05/args1.c new file mode 100644 index 0000000..984cb4d --- /dev/null +++ b/2ano1/SO/aula05/args1.c @@ -0,0 +1,12 @@ +#include +#include + +int main(int argc, char *argv[]) { + int i; + + for (i = 0; i < argc; i++) { + printf("Argument %02d: \"%s\"\n", i, argv[i]); + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/args1b.c b/2ano1/SO/aula05/args1b.c new file mode 100644 index 0000000..29b6022 --- /dev/null +++ b/2ano1/SO/aula05/args1b.c @@ -0,0 +1,17 @@ +#include +#include + +int main(int argc, char *argv[]) { + int i; + + if (argc != 3) { + fprintf(stderr, "ERROR: Expected 2 arguments got %d\n", argc - 1); + return EXIT_FAILURE; + } + + for (i = 0; i < argc; i++) { + printf("Argument %02d: \"%s\"\n", i, argv[i]); + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/args2.c b/2ano1/SO/aula05/args2.c new file mode 100644 index 0000000..f090b3c --- /dev/null +++ b/2ano1/SO/aula05/args2.c @@ -0,0 +1,30 @@ +#include +#include +#include + +int main(int argc, char **argv) +{ + int i, numChars; + char *username; + + username = getenv("USER"); + if(username != NULL) + { + printf("This program is being executed by %s\n", username); + } + else + { + printf("ERROR: USER not defined\n"); + return EXIT_FAILURE; + } + + numChars = 0; + for(i = 1 ; i < argc ; i++) + { + numChars += strlen(argv[i]); + } + + printf("All arguments have %d characters\n", numChars); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/args2b.c b/2ano1/SO/aula05/args2b.c new file mode 100644 index 0000000..e5b49d8 --- /dev/null +++ b/2ano1/SO/aula05/args2b.c @@ -0,0 +1,25 @@ +#include +#include +#include + +int main(int argc, char **argv) { + int i, numChars; + char *username; + + username = getenv("NEWUSER"); + if (username != NULL) { + printf("This program is being executed by %s\n", username); + } else { + printf("ERROR: USER not defined\n"); + return EXIT_FAILURE; + } + + numChars = 0; + for (i = 1; i < argc; i++) { + numChars += strlen(argv[i]); + } + + printf("All arguments have %d characters\n", numChars); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/calculadora.c b/2ano1/SO/aula05/calculadora.c new file mode 100644 index 0000000..de89817 --- /dev/null +++ b/2ano1/SO/aula05/calculadora.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + if (argc != 4) { + fprintf(stderr, "ERROR: Expected 3 arguments got %d\n", argc - 1); + return EXIT_FAILURE; + } + + const float left = atof(argv[1]); + const float right = atof(argv[3]); + + const char *op = argv[2]; + if (strlen(op) != 1) { + fprintf(stderr, "ERROR: Unknown operation \"%s\"\n", op); + return EXIT_FAILURE; + } + + float result; + + switch (*op) { + case '+': + result = left + right; + break; + case '-': + result = left - right; + break; + case 'x': + result = left * right; + break; + case '/': + result = left / right; + break; + case 'p': + result = pow(left, right); + break; + default: + fprintf(stderr, "ERROR: Unknown operation \"%s\"\n", op); + return EXIT_FAILURE; + } + + printf("%f %s %f = %f\n", left, op, right, result); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/calculadora_d.c b/2ano1/SO/aula05/calculadora_d.c new file mode 100644 index 0000000..76b4638 --- /dev/null +++ b/2ano1/SO/aula05/calculadora_d.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + if (argc != 4) { + fprintf(stderr, "ERROR: Expected 3 arguments got %d\n", argc - 1); + return EXIT_FAILURE; + } + + char *rest = NULL; + const float left = strtod(argv[1], &rest); + if (rest != NULL && strlen(rest) != 0) { + fprintf(stderr, "ERROR: Not a valid number \"%s\"\n", argv[1]); + return EXIT_FAILURE; + } + + rest = NULL; + const float right = strtod(argv[3], &rest); + if (rest != NULL && strlen(rest) != 0) { + fprintf(stderr, "ERROR: Not a valid number \"%s\"\n", argv[3]); + return EXIT_FAILURE; + } + + const char *op = argv[2]; + if (strlen(op) != 1) { + fprintf(stderr, "ERROR: Unknown operation \"%s\"\n", op); + return EXIT_FAILURE; + } + + float result; + + switch (*op) { + case '+': + result = left + right; + break; + case '-': + result = left - right; + break; + case 'x': + result = left * right; + break; + case '/': + result = left / right; + break; + case 'p': + result = pow(left, right); + break; + default: + fprintf(stderr, "ERROR: Unknown operation \"%s\"\n", op); + return EXIT_FAILURE; + } + + printf("%f %s %f = %f\n", left, op, right, result); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/joinWords.c b/2ano1/SO/aula05/joinWords.c new file mode 100644 index 0000000..15eff0c --- /dev/null +++ b/2ano1/SO/aula05/joinWords.c @@ -0,0 +1,35 @@ +#include +#include +#include + +int main(int argc, char **argv) { + int string_size = 1; + + for (int i = 1; i < argc; i++) { + string_size += strlen(argv[i]); + } + + string_size += argc - 2; + + // Plus one for null byte + char *result = (char *)malloc(string_size); + if (result == NULL) + return EXIT_FAILURE; + + *result = '\0'; + + for (int i = 1; i < argc; i++) { + size_t count = strlen(result); + if (i > 1) { + result[count] = ' '; + result[count + 1] = '\0'; + } + strcat(result, argv[i]); + } + + printf("Resultado: \"%s\"\n", result); + + free(result); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/joinWordsText.c b/2ano1/SO/aula05/joinWordsText.c new file mode 100644 index 0000000..f39421c --- /dev/null +++ b/2ano1/SO/aula05/joinWordsText.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) { + int string_size = 0; + + for (int i = 1; i < argc; i++) { + string_size += strlen(argv[i]); + } + + // Plus one for null byte + char *result = (char *)malloc(string_size + 1); + if (result == NULL) + return EXIT_FAILURE; + + *result = '\0'; + + for (int i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (isalpha(*arg)) + strcat(result, arg); + } + + printf("Resultado: \"%s\"\n", result); + + free(result); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula05/sortWords.c b/2ano1/SO/aula05/sortWords.c new file mode 100644 index 0000000..049ec94 --- /dev/null +++ b/2ano1/SO/aula05/sortWords.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +int cmp_string(const void *a, const void *b) { + fprintf(stderr, "%s %s %d\n", a, b, strcmp(a, b)); + return strcmp(a, b); +} + +int main(int argc, char **argv) { + int order = 1; + char *sort_order = getenv("USER"); + + if (sort_order != NULL) { + if (strcmp(sort_order, "crescente")) { + order = 1; + } else if (strcmp(sort_order, "decresecent")) { + order = -1; + } else { + fprintf(stderr, "Ordenação desconhecida \"%s\"\n", sort_order); + return EXIT_FAILURE; + } + } + + size_t sorted_size = 0; + char *sorted[argc]; + + for (int i = 1; i < argc; i++) { + if (isalpha(*argv[i])) + sorted[sorted_size++] = argv[i]; + } + + qsort(sorted, sorted_size, sizeof(sorted[0]), cmp_string); + + for (size_t i = 0; i < sorted_size; i++) { + printf("%s\n", sorted[i]); + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/command.log b/2ano1/SO/aula06/command.log new file mode 100644 index 0000000..a22953a --- /dev/null +++ b/2ano1/SO/aula06/command.log @@ -0,0 +1,3 @@ +15:06: whoami +15:06: ls +15:06: echo "bananas" | wc diff --git a/2ano1/SO/aula06/dirList.c b/2ano1/SO/aula06/dirList.c new file mode 100644 index 0000000..92ec2c5 --- /dev/null +++ b/2ano1/SO/aula06/dirList.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man opendir man readdir +*/ + +void listDir(char dirname[]) { + DIR *dp; + struct dirent *dent; + + dp = opendir(dirname); + if (dp == NULL) { + perror("Error opening directory"); + return; + } + + dent = readdir(dp); + while (dent != NULL) { + if (dent->d_name[0] != '.') /* do not list hidden dirs/files */ + { + struct stat path_stat; + if (stat(dent->d_name, &path_stat) != 0) { + perror("Error executing stat"); + return; + } + + char type = ' '; + if S_ISDIR (path_stat.st_mode) + type = 'd'; + + printf("%c %s/%s\n", type, dirname, dent->d_name); + } + + dent = readdir(dp); + } +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: %s base_directory\n", argv[0]); + return EXIT_FAILURE; + } + + listDir(argv[1]); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/dirList_l.c b/2ano1/SO/aula06/dirList_l.c new file mode 100644 index 0000000..fe441c2 --- /dev/null +++ b/2ano1/SO/aula06/dirList_l.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man opendir man readdir +*/ + +void listDir(char dirname[]) { + DIR *dp; + struct dirent *dent; + + dp = opendir(dirname); + if (dp == NULL) { + perror("Error opening directory"); + return; + } + + dent = readdir(dp); + while (dent != NULL) { + if (dent->d_name[0] != '.') /* do not list hidden dirs/files */ + { + struct stat path_stat; + if (stat(dent->d_name, &path_stat) != 0) { + perror("Error executing stat"); + return; + } + + char type = ' '; + if S_ISDIR (path_stat.st_mode) + type = 'd'; + + printf("%c %s/%s\n", type, dirname, dent->d_name); + + if S_ISDIR (path_stat.st_mode) { + // Size of the two plus null byte and slash + size_t child_dirname_size = strlen(dirname) + strlen(dent->d_name) + 2; + char *child_dirname = (char *)malloc(sizeof(char) * child_dirname_size); + if (child_dirname == NULL) { + perror("Error allocating memory"); + return; + } + + sprintf(child_dirname, "%s/%s", dirname, dent->d_name); + + listDir(child_dirname); + + free(child_dirname); + } + } + + dent = readdir(dp); + } +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: %s base_directory\n", argv[0]); + return EXIT_FAILURE; + } + + listDir(argv[1]); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/myActions.c b/2ano1/SO/aula06/myActions.c new file mode 100644 index 0000000..c4c249d --- /dev/null +++ b/2ano1/SO/aula06/myActions.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man system man date +*/ + +int main(void) { + char text[1024]; + + FILE *fd = fopen("command.log", "a"); + if (fd == NULL) { + perror("Error opening file!"); + return EXIT_FAILURE; + } + + do { + printf("Command: "); + scanf("%1023[^\n]%*c", text); + + const time_t now = time(NULL); + if (now == (time_t)(-1)) { + perror("Failed to get time!"); + return EXIT_SUCCESS; + } + const struct tm *local_time = localtime(&now); + if (local_time == NULL || (void *)local_time == (void *)&now) { + perror("Failed to get calendar time!"); + return EXIT_SUCCESS; + } + + /* system(const char *command) executes a command specified in command + by calling /bin/sh -c command, and returns after the command has been + completed. + */ + if (strcmp(text, "end")) { + printf("\n * Command to be executed: %s\n", text); + fprintf(fd, "%02d:%02d: %s\n", local_time->tm_hour, local_time->tm_min, + text); + printf("---------------------------------\n"); + system(text); + printf("---------------------------------\n"); + } + } while (strcmp(text, "end")); + + printf("-----------The End---------------\n"); + + fclose(fd); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/myCat.c b/2ano1/SO/aula06/myCat.c new file mode 100644 index 0000000..5b656e3 --- /dev/null +++ b/2ano1/SO/aula06/myCat.c @@ -0,0 +1,43 @@ +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man fopen man fgets +*/ + +#define LINEMAXSIZE 80 /* or other suitable maximum line size */ + +int main(int argc, char *argv[]) { + FILE *fp = NULL; + char line[LINEMAXSIZE]; + + /* Validate number of arguments */ + if (argc < 2) { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + for (int i = 1; i < argc; i++) { + const char *file_path = argv[i]; + + /* Open the file provided as argument */ + errno = 0; + fp = fopen(file_path, "r"); + if (fp == NULL) { + perror("Error opening file!"); + return EXIT_FAILURE; + } + + /* Read all the lines of the file */ + while (fgets(line, sizeof(line), fp) != NULL) { + /* not needed to add '\n' to printf because fgets will read + the '\n' that ends each line in the file */ + printf("-> %s", line); + } + + fclose(fp); + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/myCat_c.c b/2ano1/SO/aula06/myCat_c.c new file mode 100644 index 0000000..7ec4fea --- /dev/null +++ b/2ano1/SO/aula06/myCat_c.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man fopen man fgets +*/ + +#define LINEMAXSIZE 80 /* or other suitable maximum line size */ + +int main(int argc, char *argv[]) { + FILE *fp = NULL; + char line[LINEMAXSIZE]; + + /* Validate number of arguments */ + if (argc < 2) { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + for (int i = 1; i < argc; i++) { + const char *file_path = argv[i]; + + /* Open the file provided as argument */ + errno = 0; + fp = fopen(file_path, "r"); + if (fp == NULL) { + perror("Error opening file!"); + return EXIT_FAILURE; + } + + size_t line_number = 1; + /* Read all the lines of the file */ + while (fgets(line, sizeof(line), fp) != NULL) { + /* not needed to add '\n' to printf because fgets will read + the '\n' that ends each line in the file */ + printf("%lu -> %s", line_number++, line); + } + + fclose(fp); + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/myCat_d.c b/2ano1/SO/aula06/myCat_d.c new file mode 100644 index 0000000..ea4e868 --- /dev/null +++ b/2ano1/SO/aula06/myCat_d.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man fopen man fgets +*/ + +#define LINEMAXSIZE 80 /* or other suitable maximum line size */ + +int main(int argc, char *argv[]) { + FILE *fp = NULL; + char line[LINEMAXSIZE]; + + /* Validate number of arguments */ + if (argc < 2) { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + for (int i = 1; i < argc; i++) { + const char *file_path = argv[i]; + + /* Open the file provided as argument */ + errno = 0; + fp = fopen(file_path, "r"); + if (fp == NULL) { + perror("Error opening file!"); + return EXIT_FAILURE; + } + + size_t line_number = 1; + /* Read all the lines of the file */ + while (fgets(line, sizeof(line), fp) != NULL) { + /* not needed to add '\n' to printf because fgets will read + the '\n' that ends each line in the file */ + printf("%lu -> %s", line_number++, line); + + size_t bytes_read = strlen(line); + if (bytes_read == 0) + continue; + + while (line[bytes_read - 1] != '\n') { + if (fgets(line, sizeof(line), fp) == NULL) + break; + + printf("%s", line); + bytes_read = strlen(line); + if (bytes_read == 0) + break; + } + } + + fclose(fp); + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/sortNumbers_g.c b/2ano1/SO/aula06/sortNumbers_g.c new file mode 100644 index 0000000..8a5ad86 --- /dev/null +++ b/2ano1/SO/aula06/sortNumbers_g.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man qsort +*/ + +int compareInts(const void *px1, const void *px2) { + int x1 = *((int *)px1); + int x2 = *((int *)px2); + return (x1 < x2 ? -1 : x1 == x2 ? 0 : 1); +} + +int main(int argc, char *argv[]) { + size_t allocated = 2, numSize = 0; + int *numbers; + + /* Validate number of arguments */ + if (argc != 2) { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + /* Open the file provided as argument */ + errno = 0; + FILE *fp = fopen(argv[1], "r"); + if (fp == NULL) { + perror("Error opening file!"); + return EXIT_FAILURE; + } + + /* Memory allocation for all the numbers in the arguments */ + numbers = (int *)malloc(sizeof(int) * allocated); + if (numbers == NULL) { + perror("Error allocating memory!"); + return EXIT_FAILURE; + } + + numSize = 0; + while (1) { + if (numSize >= allocated) { + allocated *= 2; + fprintf(stderr, "Reallocing %lu numbers\n", allocated); + numbers = realloc(numbers, sizeof(int) * allocated); + if (numbers == NULL) { + perror("Error allocating memory!"); + return EXIT_FAILURE; + } + } + + if (fscanf(fp, "%d", &numbers[numSize]) != 1) + break; + + numSize++; + } + + /* void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void + *, const void *)); The qsort() function sorts an array with nmemb elements + of size size.*/ + qsort(numbers, numSize, sizeof(int), compareInts); + + /* Printing the sorted numbers */ + printf("Sorted numbers: \n"); + for (size_t i = 0; i < numSize; i++) { + printf("%d\n", numbers[i]); + } + + free(numbers); + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/sortNumbers_i.c b/2ano1/SO/aula06/sortNumbers_i.c new file mode 100644 index 0000000..0860947 --- /dev/null +++ b/2ano1/SO/aula06/sortNumbers_i.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man qsort +*/ + +#define LINEMAXSIZE 80 +#define MAXNUMBERS 100 + +int compareInts(const void *px1, const void *px2) { + int x1 = *((int *)px1); + int x2 = *((int *)px2); + return (x1 < x2 ? -1 : x1 == x2 ? 0 : 1); +} + +int main(int argc, char *argv[]) { + int i, numSize; + int *numbers; + char line[LINEMAXSIZE]; + + /* Validate number of arguments */ + if (argc != 2) { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + /* Open the file provided as argument */ + errno = 0; + FILE *fp = fopen(argv[1], "r"); + if (fp == NULL) { + perror("Error opening file!"); + return EXIT_FAILURE; + } + + /* Memory allocation for all the numbers in the arguments */ + numbers = (int *)malloc(sizeof(int) * MAXNUMBERS); + + numSize = 0; + while (fgets(line, sizeof(line), fp) != NULL) { + if (numSize >= MAXNUMBERS) { + fprintf(stderr, "File has more numbers than were allocated"); + return EXIT_FAILURE; + } + + size_t read_bytes = strlen(line); + if (read_bytes == 0) + continue; + + if (line[read_bytes - 1] == '\n') + line[read_bytes - 1] = '\0'; + + numbers[numSize++] = atoi(line); + } + + /* void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void + *, const void *)); The qsort() function sorts an array with nmemb elements + of size size.*/ + qsort(numbers, numSize, sizeof(int), compareInts); + + /* Printing the sorted numbers */ + printf("Sorted numbers: \n"); + for (i = 0; i < numSize; i++) { + printf("%d\n", numbers[i]); + } + + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula06/sortNumbers_ii.c b/2ano1/SO/aula06/sortNumbers_ii.c new file mode 100644 index 0000000..34705cb --- /dev/null +++ b/2ano1/SO/aula06/sortNumbers_ii.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +/* SUGESTÂO: utilize as páginas do manual para conhecer mais sobre as funções + usadas: man qsort +*/ + +#define MAXNUMBERS 100 + +int compareInts(const void *px1, const void *px2) { + int x1 = *((int *)px1); + int x2 = *((int *)px2); + return (x1 < x2 ? -1 : x1 == x2 ? 0 : 1); +} + +int main(int argc, char *argv[]) { + int i, numSize; + int *numbers; + + /* Validate number of arguments */ + if (argc != 2) { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + /* Open the file provided as argument */ + errno = 0; + FILE *fp = fopen(argv[1], "r"); + if (fp == NULL) { + perror("Error opening file!"); + return EXIT_FAILURE; + } + + /* Memory allocation for all the numbers in the arguments */ + numbers = (int *)malloc(sizeof(int) * MAXNUMBERS); + + numSize = 0; + while (1) { + if (numSize >= MAXNUMBERS) { + fprintf(stderr, "File has more numbers than were allocated"); + return EXIT_FAILURE; + } + + if (fscanf(fp, "%d", &numbers[numSize]) != 1) + break; + + numSize++; + } + + /* void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void + *, const void *)); The qsort() function sorts an array with nmemb elements + of size size.*/ + qsort(numbers, numSize, sizeof(int), compareInts); + + /* Printing the sorted numbers */ + printf("Sorted numbers: \n"); + for (i = 0; i < numSize; i++) { + printf("%d\n", numbers[i]); + } + + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula07/readPeople.c b/2ano1/SO/aula07/readPeople.c new file mode 100644 index 0000000..7142754 --- /dev/null +++ b/2ano1/SO/aula07/readPeople.c @@ -0,0 +1,47 @@ +#include +#include +#include + +typedef struct +{ + int age; + double height; + char name[64]; +} Person; + +void printPersonInfo(Person *p) +{ + printf("Person: %s, %d, %f\n", p->name, p->age, p->height); +} + +int main (int argc, char *argv[]) +{ + FILE *fp = NULL; + Person p; + + /* Validate number of arguments */ + if(argc != 2) + { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + /* Open the file provided as argument */ + errno = 0; + fp = fopen(argv[1], "rb"); + if(fp == NULL) + { + perror ("Error opening file!"); + return EXIT_FAILURE; + } + + /* read all the itens of the file */ + while(fread(&p, sizeof(Person), 1, fp) == 1) + { + printPersonInfo(&p); + } + + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula07/testLongOpt.c b/2ano1/SO/aula07/testLongOpt.c new file mode 100644 index 0000000..a00cfd1 --- /dev/null +++ b/2ano1/SO/aula07/testLongOpt.c @@ -0,0 +1,76 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int c; + int digit_optind = 0; + int option_index = 0; + struct option long_options[] = { + { "add", required_argument, 0, 0 }, + { "append", no_argument, 0, 0 }, + { "delete", required_argument, 0, 0 }, + {"verbose", no_argument, 0, 0 }, + { "create", required_argument, 0, 'c' }, + { "file", required_argument, 0, 0 }, + { 0, 0, 0, 0 } + }; + while ( (c = getopt_long(argc, argv, "abc:d:012", + long_options, &option_index) + ) != -1 + ) + { + int this_option_optind = optind ? optind : 1; + switch (c) + { + case 0: + printf("option %s", long_options[option_index].name); + if (optarg) + printf(" with arg %s", optarg); + printf("\n"); + break; + + case '0': + case '1': + case '2': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf("option %c\n", c); + break; + + case 'a': + printf("option a\n"); + break; + case 'b': + printf("option b\n"); + break; + + case 'c': + printf("option c with value '%s'\n", optarg); + break; + + case 'd': + printf("option d with value '%s'\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } + + exit(EXIT_SUCCESS); +} + diff --git a/2ano1/SO/aula07/testOpt.c b/2ano1/SO/aula07/testOpt.c new file mode 100644 index 0000000..28b54ed --- /dev/null +++ b/2ano1/SO/aula07/testOpt.c @@ -0,0 +1,61 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int flags, opt; + int nsecs, tfnd; + + nsecs = 0; + tfnd = 0; + flags = 0; + + /* The getopt() function parses the command-line arguments. Its arguments + argc and argv are the argument count and array as passed to the main() + function on program invocation. An element of argv that starts with + '-' (and is not exactly "-" or "--") is an option element. The charac‐ + ters of this element (aside from the initial '-') are option charac‐ + ters. If getopt() is called repeatedly, it returns successively each + of the option characters from each of the option elements. + + For more information check the man page (man 3 getopt) + */ + while ((opt = getopt(argc, argv, "nt:")) != -1) + { + switch (opt) + { + case 'n': + flags = 1; + break; + case 't': + nsecs = atoi(optarg); + tfnd = 1; + break; + /* If getopt() finds an option character in argv that was not included in + optstring, or if it detects a missing option argument, it returns '?' + */ + default: /* '?' */ + fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", + argv[0]); + exit(EXIT_FAILURE); + } + } + + printf("flags=%d; tfnd=%d; nsecs=%d; optind=%d\n", flags, tfnd, nsecs, optind); + + /* By default, getopt() permutes the contents of argv as it scans, so that + eventually all the nonoptions are at the end. + */ + if (optind >= argc) + { + fprintf(stderr, "Expected argument after options\n"); + return EXIT_FAILURE; + } + + printf("name argument = %s\n", argv[optind]); + + /* Other code omitted */ + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula07/writePeople.c b/2ano1/SO/aula07/writePeople.c new file mode 100644 index 0000000..4860584 --- /dev/null +++ b/2ano1/SO/aula07/writePeople.c @@ -0,0 +1,50 @@ +#include +#include +#include + +typedef struct +{ + int age; + double height; + char name[64]; +} Person; + +void printPersonInfo(Person *p) +{ + printf("Person: %s, %d, %f\n", p->name, p->age, p->height); +} + +int main (int argc, char *argv[]) +{ + FILE *fp = NULL; + int i; + Person p = {35, 1.65, "xpto"}; + + /* Validate number of arguments */ + if(argc != 2) + { + printf("USAGE: %s fileName\n", argv[0]); + return EXIT_FAILURE; + } + + /* Open the file provided as argument */ + errno = 0; + fp = fopen(argv[1], "wb"); + if(fp == NULL) + { + perror ("Error opening file!"); + return EXIT_FAILURE; + } + + /* Write 10 itens on a file */ + for(i = 0 ; i < 10 ; i++) + { + p.age = p.age+1; + p.height = p.height+0.03; + fwrite(&p, sizeof(Person), 1, fp); + } + + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/Makefile b/2ano1/SO/aula08/Makefile new file mode 100644 index 0000000..33532ab --- /dev/null +++ b/2ano1/SO/aula08/Makefile @@ -0,0 +1,22 @@ + +CC = gcc +CFLAGS = -Wall + +progs = fork1 fork2 child fork3 fork4 sig1 sig2 +objs = $(progs:%=%.o) + +.PHONY: all clean cleanall + +all: $(progs) + +$(progs): %: %.o + $(CC) -o $@ $< + +$(objs): %.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f *~ *.o + +cleanall: clean + rm -f $(progs) diff --git a/2ano1/SO/aula08/child.c b/2ano1/SO/aula08/child.c new file mode 100644 index 0000000..1f6a17d --- /dev/null +++ b/2ano1/SO/aula08/child.c @@ -0,0 +1,12 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + printf("Filho: PID = %d, PPID = %d\n", getpid(), getppid()); + sleep(3); + printf("Filho: PID = %d, PPID = %d\n", getpid(), getppid()); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/fork1.c b/2ano1/SO/aula08/fork1.c new file mode 100644 index 0000000..197811b --- /dev/null +++ b/2ano1/SO/aula08/fork1.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int ret; + + printf("Antes do fork: PID = %d, PPID = %d\n", getpid(), getppid()); + if ((ret = fork()) < 0) { + perror ("erro na duplicação do processo"); + return EXIT_FAILURE; + } + if (ret > 0) sleep (1); + printf("Quem sou eu?\nApós o fork: PID = %d, PPID = %d\n", getpid(), getppid()); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/fork2.c b/2ano1/SO/aula08/fork2.c new file mode 100644 index 0000000..1114dc4 --- /dev/null +++ b/2ano1/SO/aula08/fork2.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int ret; + + printf("Antes do fork: PID = %d, PPID = %d\n", getpid(), getppid()); + if ((ret = fork()) < 0) { + perror("erro na duplicação do processo"); + return EXIT_FAILURE; + } + if (ret > 0) sleep(1); + printf("Quem sou eu?\nApós o fork: PID = %d, PPID = %d, retorno do fork = %d\n", + getpid(), getppid(), ret); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/fork2t.c b/2ano1/SO/aula08/fork2t.c new file mode 100644 index 0000000..75d2aa2 --- /dev/null +++ b/2ano1/SO/aula08/fork2t.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + int ret; + + printf("Antes do fork: PID = %d, PPID = %d\n", getpid(), getppid()); + if ((ret = fork()) < 0) { + perror("erro na duplicação do processo"); + return EXIT_FAILURE; + } + if (ret > 0) + sleep(1); + printf( + "Quem sou eu?\nApós o fork: PID = %d, PPID = %d, retorno do fork = %d\n", + getpid(), getppid(), ret); + + if (ret > 0) + printf("PAI\n"); + else + printf("FILHO\n"); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/fork3.c b/2ano1/SO/aula08/fork3.c new file mode 100644 index 0000000..a96b00d --- /dev/null +++ b/2ano1/SO/aula08/fork3.c @@ -0,0 +1,26 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + printf("Pai (antes do fork): PID = %u, PPID = %u\n", getpid(), getppid()); + switch (fork()) + { + case -1: /* fork falhou */ + perror("Erro no fork\n"); + return EXIT_FAILURE; + case 0: /* processo filho */ + if (execl("./child", "./child", NULL) < 0) { + perror("erro no lancamento da aplicacao"); + return EXIT_FAILURE; + } + printf("Porque é que eu não apareço?\n"); + break; + default: /* processo pai */ + sleep(1); + printf("Pai (depois do fork): PID = %u, PPID = %u\n", getpid(), getppid()); + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/fork4.c b/2ano1/SO/aula08/fork4.c new file mode 100644 index 0000000..6f983f8 --- /dev/null +++ b/2ano1/SO/aula08/fork4.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int stat; + + printf("Pai (antes do fork): PID = %u, PPID = %u\n", getpid(), getppid()); + switch (fork()) + { + case -1: /* fork falhou */ + perror("Erro no fork\n"); + return EXIT_FAILURE; + case 0: /* processo filho */ + if (execl("./child", "./child", NULL) < 0) { + perror("erro no lancamento da aplicacao"); + return EXIT_FAILURE; + } + break; + default: /* processo pai */ + printf("Pai (depois do fork): PID = %u, PPID = %u\n", getpid(), getppid()); + if (wait(&stat) < 0) { + perror("erro na espera da terminação do processo-filho"); + return EXIT_FAILURE; + } + printf("Pai: o processo-filho terminou. "); + if (WIFEXITED(stat) != 0) { + printf("O seu status de saída foi %d.\n", WEXITSTATUS(stat)); + } + else { + printf("O processo filho terminou de forma anormal.\n"); + } + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/sig1.c b/2ano1/SO/aula08/sig1.c new file mode 100644 index 0000000..f1e1d0e --- /dev/null +++ b/2ano1/SO/aula08/sig1.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + unsigned int i; + + printf("PID = %u\n", getpid()); + i = 0; + while (i <= 10) { + printf("\r%08u ", i++); + fflush(stdout); + sleep(1); + } + printf("\n"); + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula08/sig2.c b/2ano1/SO/aula08/sig2.c new file mode 100644 index 0000000..b916433 --- /dev/null +++ b/2ano1/SO/aula08/sig2.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include + +#define NTIMES 50 + +static void Interrupt (int); + +int main(int argc, char *argv[]) +{ + struct sigaction sigact; + unsigned int i; + + /* altera a rotina de atendimento ao ^C */ + sigact.sa_handler = Interrupt; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + if (sigaction(SIGINT, &sigact, NULL) < 0) { + perror("Rotina de atendimento não instalada\n"); + return EXIT_FAILURE; + } + + /* contador */ + printf("PID = %u\n", getpid()); + i = 0; + while (i <= NTIMES) { + printf("\r%08u ", i++); + fflush(stdout); + sleep(1); + } + printf("\n"); + + return EXIT_SUCCESS; +} + +static void Interrupt (int signum) +{ + if (signum == SIGINT) { + printf("\nCalma, ainda não cheguei a %d!\n", NTIMES); + } + else { + printf("Foi recebido um sinal diferente de SIGINT!\n"); + exit(EXIT_FAILURE); + } +} diff --git a/2ano1/SO/aula08/sig3.c b/2ano1/SO/aula08/sig3.c new file mode 100644 index 0000000..2b763be --- /dev/null +++ b/2ano1/SO/aula08/sig3.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +#define NTIMES 50 + +static int sig_times = 0; + +static void Interrupt(int); + +int main(int argc, char *argv[]) { + struct sigaction sigact; + unsigned int i; + + /* altera a rotina de atendimento ao ^C */ + sigact.sa_handler = Interrupt; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + if (sigaction(SIGINT, &sigact, NULL) < 0) { + perror("Rotina de atendimento não instalada\n"); + return EXIT_FAILURE; + } + + /* contador */ + printf("PID = %u\n", getpid()); + i = 0; + while (i <= NTIMES) { + printf("\r%08u ", i++); + fflush(stdout); + sleep(1); + } + printf("\n"); + + return EXIT_SUCCESS; +} + +static void Interrupt(int signum) { + if (signum == SIGINT) { + printf("\nCalma, ainda não cheguei a %d!\n", NTIMES); + + if (++sig_times == 4) { + struct sigaction sigact; + sigact.sa_handler = SIG_DFL; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + if (sigaction(SIGINT, &sigact, NULL) < 0) { + perror("Rotina de atendimento não instalada\n"); + exit(EXIT_FAILURE); + } + } + } else { + printf("Foi recebido um sinal diferente de SIGINT!\n"); + exit(EXIT_FAILURE); + } +} diff --git a/2ano1/SO/aula09/incrementer/Makefile b/2ano1/SO/aula09/incrementer/Makefile new file mode 100644 index 0000000..9aee276 --- /dev/null +++ b/2ano1/SO/aula09/incrementer/Makefile @@ -0,0 +1,24 @@ +CC = gcc +CFLAGS = -Wall + +LK = gcc +LDFLAGS = -lpthread -lm + +.PHONY: clean cleanall + +objs = incMod.o incModSafe.o incrementer.o + +incrementer: incrementer.o incMod.o + $(LK) -o $@ $^ $(LDFLAGS) + +incrementerSafe:incrementer.o incModSafe.o + $(LK) -o $@ $^ $(LDFLAGS) + +$(objs): %.o: %.c incMod.h + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f *.o *~ + +cleanall: clean + rm -f incrementer incrementerSafe diff --git a/2ano1/SO/aula09/incrementer/incMod.c b/2ano1/SO/aula09/incrementer/incMod.c new file mode 100644 index 0000000..45a525d --- /dev/null +++ b/2ano1/SO/aula09/incrementer/incMod.c @@ -0,0 +1,64 @@ +/** + * A simple module (implementation file). + * + * (c) 2004 Artur Pereira + * + * A very simple module, with an internal data structure and 3 manipulation functions. + * The internal data structure is just a single integer variable. + * The 3 manipulation functions are meant to: + * - set the variable value; + * - get the variable value; + * - increment by one the variable value. + */ + +#include + +/* time delay length */ +#define BIG 5000 +#define SMALL 0 + +/* generate time delay */ +void delay (int nite) { + int i; + double b = 0.0; + double c = 0.0; + double PI = 3.141516; + + for (i = 0; i < nite; i++) { + b = cos (c + PI/4); + c = sqrt (fabs (b)); + } +} + +/* internal data structure */ +static int value = 0; + +/* set the variable value */ +void vSet (int new_value) +{ + value = new_value; +} + +/* get the variable value */ +int vGet (void) +{ + return value; +} + +/* increment the variable value */ +void vInc (void) +{ + int val; + + /* load locally the stored value */ + val = value; + + /* generate time delay 1 */ + delay (BIG); + + /* increment the local value and store it back */ + value = val + 1; + + /* generate time delay 2 */ + delay (BIG); +} diff --git a/2ano1/SO/aula09/incrementer/incMod.h b/2ano1/SO/aula09/incrementer/incMod.h new file mode 100644 index 0000000..1f5d3b9 --- /dev/null +++ b/2ano1/SO/aula09/incrementer/incMod.h @@ -0,0 +1,26 @@ +/** + * A simple module/monitor (interface file). + * + * (c) 2004 Artur Pereira + * + * A very simple module/monitor, with an internal data structure and 3 manipulation functions. + * The internal data structure is just a single integer variable. + * The 3 manipulation functions are meant to: + * - set the variable value; + * - get the variable value; + * - increment by one the variable value. + */ + +#ifndef INCMOD_H_ +#define INCMOD_H_ + +/* set the variable value */ +void vSet (int new_value); + +/* get the variable value */ +int vGet (void); + +/* increment the variable value */ +void vInc (void); + +#endif /* INCMOD_H_ */ diff --git a/2ano1/SO/aula09/incrementer/incModSafe.c b/2ano1/SO/aula09/incrementer/incModSafe.c new file mode 100644 index 0000000..6523db6 --- /dev/null +++ b/2ano1/SO/aula09/incrementer/incModSafe.c @@ -0,0 +1,126 @@ +/** + * A simple monitor (implementation file). + * + * (c) 2004 Artur Pereira + * + * A very simple monitor, with an internal data structure and 3 manipulation functions. + * The internal data structure is just a single integer variable. + * The 3 manipulation functions are meant to: + * - set the variable value; + * - get the variable value; + * - increment by one the variable value. + */ + +#include +#include +#include +#include +#include + +/* time delay length */ +#define BIG 5000 +#define SMALL 0 + +/* generate time delay */ +void delay (int nite) { + int i; + double b = 0.0; + double c = 0.0; + double PI = 3.141516; + + for (i = 0; i < nite; i++) { + b = cos (c + PI/4); + c = sqrt (fabs (b)); + } +} + +/* thread return status */ + +extern int status; + +/* internal data structure */ +static int value = 0; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +/* set the variable value */ +void vSet (int new_value) +{ + /* lock mutex */ + if ((status = pthread_mutex_lock (&mutex)) != 0) { /* enter monitor */ + errno = status; /* save error in errno */ + perror ("error on entering the monitor"); + status = EXIT_FAILURE; + pthread_exit (&status); + } + + value = new_value; + + /* unlock mutex */ + if ((status = pthread_mutex_unlock (&mutex)) != 0) { /* exit monitor */ + errno = status; /* save error in errno */ + perror ("error on exiting monitor"); + status = EXIT_FAILURE; + pthread_exit (&status); + } +} + +/* get the variable value */ +int vGet (void) +{ + /* lock mutex */ + if ((status = pthread_mutex_lock (&mutex)) != 0) { /* enter monitor */ + errno = status; /* save error in errno */ + perror ("error on entering the monitor"); + status = EXIT_FAILURE; + pthread_exit (&status); + } + + int val; + + val = value; + + /* unlock mutex */ + if ((status = pthread_mutex_unlock (&mutex)) != 0) { /* exit monitor */ + errno = status; /* save error in errno */ + perror ("error on exiting monitor"); + status = EXIT_FAILURE; + pthread_exit (&status); + } + + return val; +} + +/* increment the variable value */ +void vInc (void) +{ + int val; + + /* lock mutex */ + if ((status = pthread_mutex_lock (&mutex)) != 0) { /* enter monitor */ + errno = status; /* save error in errno */ + perror ("error on entering the monitor"); + status = EXIT_FAILURE; + pthread_exit (&status); + } + + /* load locally the stored value */ + val = value; + + /* generate time delay 1 */ + delay (BIG); + + /* increment the local value and store it back */ + value = val + 1; + + /* unlock mutex */ + if ((status = pthread_mutex_unlock (&mutex)) != 0) { /* exit monitor */ + errno = status; /* save error in errno */ + perror ("error on exiting monitor"); + status = EXIT_FAILURE; + pthread_exit (&status); + } + + /* generate time delay 2 */ + delay (BIG); + +} diff --git a/2ano1/SO/aula09/incrementer/incrementer.c b/2ano1/SO/aula09/incrementer/incrementer.c new file mode 100644 index 0000000..468805e --- /dev/null +++ b/2ano1/SO/aula09/incrementer/incrementer.c @@ -0,0 +1,117 @@ +/** + * Incrementing a common integer variable with / without synchronization. + * Thread implementation using primitives from the pthread library. + * + * Incrementing threads - inc = 0, 1, ... , N-1 + * + * (c) 2004 Artur Pereira + * + * + * Sintax: incrementer [options] + */ + +#include +#include +#include +#include +#include + +#include "incMod.h" + +/* thread return status */ +int status; + +#define USAGE "Synopsis: %s [options]\n"\ + "\t----------+--------------------------------------------\n"\ + "\t Option | Description \n"\ + "\t----------+--------------------------------------------\n"\ + "\t -i num | number of increments \n"\ + "\t -t num | number of 'threads' (<= 600) \n"\ + "\t -h | this help \n"\ + "\t----------+--------------------------------------------\n" + +/* allusion to internal function */ +static void *incrementer (void *arg); + +/* main thread: it starts the simulation and generates the incrementing threads + */ +int main (int argc, char *argv[]) +{ + int niter = 1000; /* number of iterations by default */ + int nthr = 1; /* number of threads by default */ + + /* command line processing */ + const char *optstr = "i:t:h"; /* allowed options */ + int option; /* parsed option */ + + do { + switch ((option = getopt (argc, argv, optstr))) + { + case 'i': niter = atoi (optarg); + break; + case 't': nthr = atoi (optarg); + if (nthr > 600) { + fprintf (stderr, "Too many threads!\n"); + fprintf (stderr, USAGE, basename (argv[0])); + return EXIT_FAILURE; + } + break; + case 'h': printf (USAGE, basename(argv[0])); + return EXIT_SUCCESS; + case -1: break; + default: fprintf (stderr, "Non valid option!\n"); + fprintf (stderr, USAGE, basename (argv[0])); + return EXIT_FAILURE; + } + } while (option >= 0); + + /* setting initial value of the common integer variable */ + vSet(0); + + /* launching the 'pthreads' */ + pthread_t thr[nthr]; /* ids of the incrementing threads */ + int i; /* counting variable */ + int *status_p; /* pointer to thread execution status */ + + printf ("Launching %d threads, each performing %d increments\n", nthr, niter); + for (i = 0; i < nthr; i++) { + if (pthread_create (thr+i, NULL, incrementer, &niter) != 0) { + fprintf (stderr, "thread %d\n", i); + perror ("error on launching the thread"); + return EXIT_FAILURE; + } + } + + /* wait for threads to conclude */ + for (i = 0; i < nthr; i++) { + if (pthread_join (thr[i], (void **) &status_p) != 0) { + fprintf (stderr, "thread %d\n", i); + perror ("error on waiting for a thread to conclude"); + return EXIT_FAILURE; + } + printf ("Thread %d has terminated: ", i); + printf ("its status was %d\n", *status_p); + } + + /* print variable value and quit */ + printf ("Final value = %d\n", vGet()); + + return EXIT_SUCCESS; +} + + +/* + * thread routine + */ +void *incrementer (void *arg) +{ + int i, n; + + n = *((int *) arg); + for (i = 0; i < n; i++) { + vInc (); + } + + status = EXIT_SUCCESS; + pthread_exit (&status); +} diff --git a/2ano1/SO/aula09/prodcon/Makefile b/2ano1/SO/aula09/prodcon/Makefile new file mode 100644 index 0000000..5f4f5d7 --- /dev/null +++ b/2ano1/SO/aula09/prodcon/Makefile @@ -0,0 +1,21 @@ +CC = gcc +CFLAGS = -Wall + +LK = gcc +LDFLAGS = -lpthread -lm + +.PHONY: clean cleanall + +objs = fifo.o prodcon.o + +prodcon: fifo.o prodcon.o + $(LK) -o $@ $^ $(LDFLAGS) + +$(objs): %.o: %.c fifo.h + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f *.o *~ + +cleanall: clean + rm -f prodcon diff --git a/2ano1/SO/aula09/prodcon/fifo.c b/2ano1/SO/aula09/prodcon/fifo.c new file mode 100644 index 0000000..00a01a8 --- /dev/null +++ b/2ano1/SO/aula09/prodcon/fifo.c @@ -0,0 +1,150 @@ +/** + * \file fifo.c (implementation file) + * + * \brief Problem name: Producers-Consumers. + * + * Synchronization based on monitors. + * Both threads and the monitor are implemented using the pthread library which enables the creation of a + * monitor of the Lampson / Redell type. + * + * Monitor FIFO. + * + * The following operations are defined: + * \li insertion of a value + * \li retrieval of a value. + */ + +#include +#include +#include +#include + +/** \brief internal storage size of FIFO memory */ +#define M 2 + +/** + * \brief Definition of FIFO memory data type. + */ +typedef struct + { /** \brief storage region for spectators/betters identification */ + unsigned int mem[M]; + /** \brief insertion pointer */ + unsigned int ii; + /** \brief retrieval pointer */ + unsigned int ri; + /** \brief flag signaling that FIFO is full */ + bool full; + } FIFO; + +/** \brief internal storage region of FIFO type */ +static FIFO f; + +/** \brief locking flag which warrants mutual exclusion inside the monitor */ +static pthread_mutex_t accessCR = PTHREAD_MUTEX_INITIALIZER; + +/** \brief FIFO is full synchronization point */ +static pthread_cond_t fifoFULL = PTHREAD_COND_INITIALIZER; + +/** \brief FIFO is empty synchronization point */ +static pthread_cond_t fifoEMPTY = PTHREAD_COND_INITIALIZER; + +/** \brief signalling flag which warrants internal data is initialized exactly once */ +static pthread_once_t init = PTHREAD_ONCE_INIT; + +/** + * \brief FIFO initialization (Internal monitor operation). + * + * FIFO will be empty after it. + * + * \param p_f pointer to the location where the FIFO is stored + */ + +static void fifoInit (void) +{ + f.ii = f.ri = 0; + f.full = false; +} + +/** + * \brief Insertion of a value into the FIFO. + * + * \param val value to be stored + * + * \return status of operation (0 - success; -1 - error) + */ + +int fifoIn (unsigned int val) +{ + int stat; /* status of operation */ + + if ((stat = pthread_mutex_lock (&accessCR)) != 0) { /* enter monitor */ + errno = stat; /* save error condition */ + return stat; + } + pthread_once (&init, fifoInit); /* internal data initialization */ + + while (f.full) { /* check if FIFO is full */ + if ((stat = pthread_cond_wait (&fifoFULL, &accessCR)) != 0) { /* wait for available space to store the value */ + errno = stat; /* save error condition */ + return stat; + } + } + + f.mem[f.ii] = val; /* store the value */ + f.ii = (f.ii + 1) % M; + f.full = (f.ii == f.ri); + + if ((stat = pthread_cond_signal (&fifoEMPTY)) != 0) { /* signal some consumer that a value is available */ + errno = stat; /* save error condition */ + return stat; + } + + if ((stat = pthread_mutex_unlock (&accessCR)) != 0) { /* exit monitor */ + errno = stat; /* save error condition */ + return stat; + } + + return 0; +} + +/** + * \brief Retrieval of a value from the FIFO. + * + * \param p_val pointer to the location where the retrieved value is to be stored + * + * \return status of operation (0 - success; -1 - error) + */ + +int fifoOut (unsigned int *p_val) +{ + int stat; /* status of operation */ + + if ((stat = pthread_mutex_lock (&accessCR)) != 0) { /* enter monitor */ + errno = stat; /* save error condition */ + return stat; + } + pthread_once (&init, fifoInit); /* internal data initialization */ + + while (!(f.full) && (f.ii == f.ri)) { /* check if FIFO is empty */ + if ((stat = pthread_cond_wait (&fifoEMPTY, &accessCR)) != 0) { /* wait for a value to be available */ + errno = stat; /* save error condition */ + return stat; + } + } + + *p_val = f.mem[f.ri]; /* retrieve a value */ + f.ri = (f.ri + 1) % M; + f.full = false; + + if ((stat = pthread_cond_signal (&fifoFULL)) != 0) { /* signal some producer that space is available */ + errno = stat; /* save error condition */ + return stat; + } + + if ((stat = pthread_mutex_unlock (&accessCR)) != 0) { /* exit monitor */ + errno = stat; /* save error condition */ + return stat; + } + + return 0; +} diff --git a/2ano1/SO/aula09/prodcon/fifo.h b/2ano1/SO/aula09/prodcon/fifo.h new file mode 100644 index 0000000..468e3a1 --- /dev/null +++ b/2ano1/SO/aula09/prodcon/fifo.h @@ -0,0 +1,40 @@ +/** + * \file fifo.h (interface file) + * + * \brief Problem name: Producers-Consumers. + * + * Synchronization based on monitors. + * Both threads and the monitor are implemented using the pthread library which enables the creation of a + * monitor of the Lampson / Redell type. + * + * Monitor FIFO. + * + * The following operations are defined: + * \li insertion of a value + * \li retrieval of a value. + */ + +#ifndef FIFO_H_ +#define FIFO_H_ + +/** + * \brief Insertion of a value into the FIFO. + * + * \param val value to be stored + * + * \return status of operation (0 - success; -1 - error) + */ + +extern int fifoIn (unsigned int val); + +/** + * \brief Retrieval of a value from the FIFO. + * + * \param p_val pointer to the location where the retrieved value is to be stored + * + * \return status of operation (0 - success; -1 - error) + */ + +extern int fifoOut (unsigned int *p_val); + +#endif /* FIFO_H_ */ diff --git a/2ano1/SO/aula09/prodcon/prodcon.c b/2ano1/SO/aula09/prodcon/prodcon.c new file mode 100644 index 0000000..ff58870 --- /dev/null +++ b/2ano1/SO/aula09/prodcon/prodcon.c @@ -0,0 +1,185 @@ +/** + * \file prodcon.c (implementation file) + * + * \brief Problem name: Producers-Consumers. + * + * Synchronization based on monitors. + * Both threads and the monitor are implemented using the pthread library which enables the creation of a + * monitor of the Lampson / Redell type. + * + * Generator thread of the intervening entities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fifo.h" + +#define USAGE "Synopsis: %s [options]\n"\ + "\t----------+--------------------------------------------\n"\ + "\t Option | Description \n"\ + "\t----------+--------------------------------------------\n"\ + "\t -i num | number of iterations (<= 100) \n"\ + "\t -t num | number of 'threads' (<= 300) \n"\ + "\t -h | this help \n"\ + "\t----------+--------------------------------------------\n" + +/* communication data structure with producer and consumer threads */ +typedef struct + { + int id; /* thread identification */ + int niter; /* number of iterations */ + } THREAD_PAR; + +/* allusion to internal function */ +static void *producer (void *arg); +static void *consumer (void *arg); + +/* producer and consumer thread return status pointer array */ +static int (*statusPO_p)[], + (*statusCO_p)[]; + +/* main thread: it starts the simulation and generates the producer and consumer threads + */ +int main (int argc, char *argv[]) +{ + int niter = 10; /* number of iterations by default */ + int nthr = 4; /* number of producer and consumer threads by default */ + + /* command line processing */ + const char *optstr = "i:t:h"; /* allowed options */ + int option; /* parsed option */ + + do { + switch ((option = getopt (argc, argv, optstr))) { + case 'i': niter = atoi (optarg); + if (niter > 100) { + fprintf (stderr, "Too many iterations!\n"); + fprintf (stderr, USAGE, basename (argv[0])); + return EXIT_FAILURE; + } + break; + case 't': nthr = atoi (optarg); + if (nthr > 300) { + fprintf (stderr, "Too many threads!\n"); + fprintf (stderr, USAGE, basename (argv[0])); + return EXIT_FAILURE; + } + break; + case 'h': printf (USAGE, basename(argv[0])); + return EXIT_SUCCESS; + case -1: break; + default: fprintf (stderr, "Non valid option!\n"); + fprintf (stderr, USAGE, basename (argv[0])); + return EXIT_FAILURE; + } + } while (option >= 0); + + /* launching the 'pthreads' */ + pthread_t thr[2*nthr]; /* identification of the producer and consumer threads */ + THREAD_PAR thrp[2*nthr]; /* parameter communication */ + int i; /* counting variable */ + int statusPO[nthr], /* producer return status array */ + statusCO[nthr]; /* consumer return status */ + int *status_p; /* pointer to thread execution status */ + + printf ("Launching %d consumer threads, each performing %d iterations\n", nthr, niter); + statusCO_p = &statusCO; + for (i = 0; i < nthr; i++) { + thrp[nthr+i].id = i; + thrp[nthr+i].niter = niter; + if (pthread_create (thr+nthr+i, NULL, consumer, &thrp[nthr+i]) != 0) { + fprintf (stderr, "consumer %d\n", i); + perror ("error on launching the consumer thread"); + return EXIT_FAILURE; + } + } + printf ("Launching %d producer threads, each performing %d iterations\n", nthr, niter); + statusPO_p = &statusPO; + for (i = 0; i < nthr; i++) { + thrp[i].id = i; + thrp[i].niter = niter; + if (pthread_create (thr+i, NULL, producer, &thrp[i]) != 0) { + fprintf (stderr, "producer %d\n", i); + perror ("error on launching the producer thread"); + return EXIT_FAILURE; + } + } + + /* wait for threads to conclude */ + for (i = 0; i < nthr; i++) { + if (pthread_join (thr[i], (void **) &status_p) != 0) { + fprintf (stderr, "producer %d\n", i); + perror ("error on waiting for a thread to conclude"); + return EXIT_FAILURE; + } + printf ("Producer thread %d has terminated: its status was %d\n", i, *status_p); + } + for (i = 0; i < nthr; i++) { + if (pthread_join (thr[nthr+i], (void **) &status_p) != 0) { + fprintf (stderr, "consumer %d\n", i); + perror ("error on waiting for a thread to conclude"); + return EXIT_FAILURE; + } + printf ("Consumer thread %d has terminated: its status was %d\n", i, *status_p); + } + + return EXIT_SUCCESS; +} + +/* + * producer thread + */ + +void *producer (void *val_p) +{ + int id = ((THREAD_PAR *) val_p)->id; /* thread identification */ + int niter = ((THREAD_PAR *) val_p)->niter; /* number of iterations */ + int i; /* counting variable */ + + srandom ((unsigned int) pthread_self ()); + for (i = 0; i < niter; i++) { + usleep ((unsigned int) floor (1 + 10000.0 * random () / RAND_MAX)); + if (((*statusPO_p)[id] = fifoIn (10000*id+i+1)) != 0) { + fprintf (stderr, "producer %d\n", id); + perror ("error on inserting a value into the FIFO"); + pthread_exit (&(*statusPO_p)[id]); + } + } + + (*statusPO_p)[id] = EXIT_SUCCESS; + pthread_exit (&(*statusPO_p)[id]); +} + +/* + * consumer thread + */ + +void *consumer (void *val_p) +{ + int id = ((THREAD_PAR *) val_p)->id; /* thread identification */ + int niter = ((THREAD_PAR *) val_p)->niter; /* number of iterations */ + unsigned int value; /* retrieved value */ + int i; /* counting variable */ + + srandom ((unsigned int) pthread_self ()); + for (i = 0; i < niter; i++) { + usleep ((unsigned int) floor (1 + 10000.0 * random () / RAND_MAX)); + if (((*statusCO_p)[id] = fifoOut (&value)) != 0) { + fprintf (stderr, "consumer %d\n", id); + perror ("error on retrieving a value from the FIFO"); + pthread_exit (&(*statusCO_p)[id]); + } + printf ("The value %u was produced by thread P%u and consumed by thread C%u!\n", + value%10000, value/10000, (unsigned int) id); + } + + (*statusCO_p)[id] = EXIT_SUCCESS; + pthread_exit (&(*statusCO_p)[id]); +} diff --git a/2ano1/SO/aula10/base/Makefile b/2ano1/SO/aula10/base/Makefile new file mode 100644 index 0000000..3c556c4 --- /dev/null +++ b/2ano1/SO/aula10/base/Makefile @@ -0,0 +1,26 @@ +CC = gcc + +CFLAGS = -Wall + +LDFLAGS = -lm + +.PHONY: all clean cleanall + +all: reg-cri + +reg-cri: sharedMemory.o reg-cri.o + gcc ${CFLAGS} -o $@ $^ ${LDFLAGS} + +reg-cri.o: sharedMemory.h + +reg-cri-correct: sharedMemory.o semaphore.o reg-cri-correct.o + gcc ${CFLAGS} -o $@ $^ ${LDFLAGS} + +reg-cri-correct.o: sharedMemory.h semaphore.h + +clean: + rm -f *.o *~ + +cleanall: clean + rm -f reg-cri + diff --git a/2ano1/SO/aula10/base/reg-cri-correct.c b/2ano1/SO/aula10/base/reg-cri-correct.c new file mode 100644 index 0000000..a9f7a34 --- /dev/null +++ b/2ano1/SO/aula10/base/reg-cri-correct.c @@ -0,0 +1,302 @@ +/** + * reg-cri + * + * Programa de ilustração da necessidade de controlo de + * acesso a regiões críticas, baseado numa proposta inicial + * do Pedro Mariano. + * + * Sintaxe: reg-cri [opcões] + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "semaphore.h" +#include "sharedMemory.h" + +#define SEMKEY 0x101 +#define SHMKEY 0x100 +#define NPROC 4 +#define BIG 1000 + +// clang-format off +/* mensagem de ajuda */ +#define USAGE "Sintaxe: %s [opções]\n"\ + "\t----------+--------------------------------------------\n"\ + "\t Opção | Descrição \n"\ + "\t----------+--------------------------------------------\n"\ + "\t -i num | lança quatro processos, cada um incrementando a variável residente em mem. part. num vezes\n"\ + "\t -c | cria uma região de memória partilhada onde é definida uma variável\n"\ + "\t -d | destroi a região de memória partilhada\n"\ + "\t -s num | inicializa a variável residente em memória partilhada\n"\ + "\t -p | imprime no 'stdout' o valor da variável\n"\ + "\t -h | esta ajuda \n"\ + "\t----------+--------------------------------------------\n" +// clang-format on + +static int set(int value); +static int iter(int value); +static int print(void); +static int create(void); +static int destroy(void); + +int main(int argc, char *argv[]) { + /* processamento da linha de comando */ + const char *optstr = "i:cds:ph"; + int option; + + do { + switch ((option = getopt(argc, argv, optstr))) { + case 'i': + return iter(atoi(optarg)); + case 's': + return set(atoi(optarg)); + case 'p': + return print(); + case 'c': + return create(); + case 'd': + return destroy(); + case 'h': + printf(USAGE, basename(argv[0])); + return EXIT_SUCCESS; + default: + fprintf(stderr, "Opção não válida\n"); + case -1: + fprintf(stderr, USAGE, basename(argv[0])); + return EXIT_FAILURE; + } + } while (option >= 0); + + return EXIT_SUCCESS; +} + +void delay(int nite) { + int k; + double b = 0.0; + double c = 0.0; + double PI = 3.141516; + + for (k = 0; k < nite; k++) { + b = cos(c + PI / 4); + c = sqrt(fabs(b)); + } +} + +static int create(void) { + /* cria a memória partilhada, falhando se já existir */ + if (shmemCreate(SHMKEY, sizeof(long)) == -1) { + perror("shmemCreate"); + return EXIT_FAILURE; + } + + int semid = semCreate(SEMKEY, 1); + if (semid == -1) { + perror("semCreate"); + return EXIT_FAILURE; + } + + if (semUp(semid, 1) == -1) { + perror("semUp"); + return EXIT_FAILURE; + } + + if (semSignal(semid) == -1) { + perror("semSignal"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int destroy(void) { + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect(SHMKEY); + if (shmid == -1) { + perror("shmemConnect"); + return EXIT_FAILURE; + } + + /* destroi-a */ + if (shmemDestroy(shmid) == -1) { + perror("shmemDestroy"); + return EXIT_FAILURE; + } + + /* ganha acesso ao semaforo */ + int semid = semConnect(SEMKEY); + if (semid == -1) { + perror("semConnect"); + return EXIT_FAILURE; + } + + if (semDestroy(semid) == -1) { + perror("semDestroy"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int iter(int niter) { + int i, j, auxcnt; + + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect(SHMKEY); + if (shmid == -1) { + perror("shmemConnect"); + return EXIT_FAILURE; + } + + /* anexa a memória partilhada ao espaço de endereçamento próprio */ + int *cntp; + if (shmemAttach(shmid, (void **)&cntp) == -1) { + perror("shmemAttach"); + return EXIT_FAILURE; + } + + /* ganha acesso ao semaforo */ + int semid = semConnect(SEMKEY); + if (semid == -1) { + perror("semConnect"); + return EXIT_FAILURE; + } + + /* lança processos incrementadores e espera pelo seu termo */ + for (i = 0; i < NPROC; i++) { + switch (fork()) { + case -1: + perror("fork"); + return EXIT_FAILURE; + + case 0: // processo incrementador + for (j = 0; j < niter; j++) { /* faz cópia do contador em mem. part. */ + if (semDown(semid, 1) == -1) { + perror("semDown"); + return EXIT_FAILURE; + } + + auxcnt = *cntp; + + /* generate a time delay */ + delay(BIG); + + /* incrementa a cópia e armazena-a em mem. part. */ + *cntp = auxcnt + 1; + + if (semUp(semid, 1) == -1) { + perror("semUp"); + return EXIT_FAILURE; + } + + /* generate a time delay */ + delay(BIG); + } + + /* desanexa a memória partilhada do espaço de endereçamento próprio */ + if (shmemDettach(cntp) == -1) { + perror("incrementador - shmemDettach"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + } + } + + /* espera pelos termo dos incrementadores e sai */ + for (i = 0; i < NPROC; i++) { + wait(NULL); + } + return EXIT_SUCCESS; +} + +static int set(int value) { + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect(SHMKEY); + if (shmid == -1) { + perror("shmemConnect"); + return EXIT_FAILURE; + } + + /* anexa a memória partilhada ao espaço de endereçamento próprio */ + int *cntp; + if (shmemAttach(shmid, (void **)&cntp) == -1) { + perror("shmemAttach"); + return EXIT_FAILURE; + } + + /* ganha acesso ao semaforo */ + int semid = semConnect(SEMKEY); + if (semid == -1) { + perror("semConnect"); + return EXIT_FAILURE; + } + + /* inicializa o contador em memória partilhada */ + if (semDown(semid, 1) == -1) { + perror("semDown"); + return EXIT_FAILURE; + } + *cntp = value; + if (semUp(semid, 1) == -1) { + perror("semUp"); + return EXIT_FAILURE; + } + + /* desanexa a memória partilhada do espaço de endereçamento próprio */ + if (shmemDettach(cntp) == -1) { + perror("incrementador - shmemDettach"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int print(void) { + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect(SHMKEY); + if (shmid == -1) { + perror("shmemConnect"); + return EXIT_FAILURE; + } + + /* anexa a memória partilhada ao espaço de endereçamento próprio */ + int *cntp; + if (shmemAttach(shmid, (void **)&cntp) == -1) { + perror("shmemAttach"); + return EXIT_FAILURE; + } + + /* ganha acesso ao semaforo */ + int semid = semConnect(SEMKEY); + if (semid == -1) { + perror("semConnect"); + return EXIT_FAILURE; + } + + /* imprime valor */ + if (semDown(semid, 1) == -1) { + perror("semDown"); + return EXIT_FAILURE; + } + printf("Value = %d\n", *cntp); + if (semUp(semid, 1) == -1) { + perror("semUp"); + return EXIT_FAILURE; + } + + /* desanexa a memória partilhada do espaço de endereçamento próprio */ + if (shmemDettach(cntp) == -1) { + perror("incrementador - shmemDettach"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula10/base/reg-cri.c b/2ano1/SO/aula10/base/reg-cri.c new file mode 100644 index 0000000..206d3ed --- /dev/null +++ b/2ano1/SO/aula10/base/reg-cri.c @@ -0,0 +1,227 @@ +/** + * reg-cri + * + * Programa de ilustração da necessidade de controlo de + * acesso a regiões críticas, baseado numa proposta inicial + * do Pedro Mariano. + * + * Sintaxe: reg-cri [opcões] + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sharedMemory.h" + +#define SHMKEY 0x100 +#define NPROC 4 +#define BIG 1000 + +/* mensagem de ajuda */ +#define USAGE "Sintaxe: %s [opções]\n"\ + "\t----------+--------------------------------------------\n"\ + "\t Opção | Descrição \n"\ + "\t----------+--------------------------------------------\n"\ + "\t -i num | lança quatro processos, cada um incrementando a variável residente em mem. part. num vezes\n"\ + "\t -c | cria uma região de memória partilhada onde é definida uma variável\n"\ + "\t -d | destroi a região de memória partilhada\n"\ + "\t -s num | inicializa a variável residente em memória partilhada\n"\ + "\t -p | imprime no 'stdout' o valor da variável\n"\ + "\t -h | esta ajuda \n"\ + "\t----------+--------------------------------------------\n" + +static int set(int value); +static int iter(int value); +static int print(void); +static int create(void); +static int destroy(void); + +int main (int argc, char *argv[]) +{ + /* processamento da linha de comando */ + const char *optstr = "i:cds:ph"; + int option; + + do { + switch ((option = getopt (argc, argv, optstr))) + { + case 'i': return iter (atoi (optarg)); + case 's': return set (atoi (optarg)); + case 'p': return print (); + case 'c': return create (); + case 'd': return destroy (); + case 'h': printf (USAGE, basename (argv[0])); + return EXIT_SUCCESS; + default: fprintf (stderr, "Opção não válida\n"); + case -1: fprintf (stderr, USAGE, basename (argv[0])); + return EXIT_FAILURE; + } + } while (option >= 0); + + return EXIT_SUCCESS; +} + +void delay(int nite) +{ + int k; + double b = 0.0; + double c = 0.0; + double PI = 3.141516; + + for (k = 0; k < nite; k++) + { + b = cos (c + PI/4); + c = sqrt (fabs (b)); + } +} + +static int create(void) +{ + /* cria a memória partilhada, falhando se já existir */ + if (shmemCreate (SHMKEY, sizeof (long)) == -1) { + perror ("shmemCreate"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +static int destroy(void) +{ + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect (SHMKEY); + if (shmid == -1) { + perror ("shmemConnect"); + return EXIT_FAILURE; + } + + /* destroi-a */ + if (shmemDestroy (shmid) == -1) { + perror ("shmemDestroy"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +static int iter(int niter) +{ + int i, j, auxcnt; + + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect (SHMKEY); + if (shmid == -1) { + perror ("shmemConnect"); + return EXIT_FAILURE; + } + + /* anexa a memória partilhada ao espaço de endereçamento próprio */ + int *cntp; + if (shmemAttach (shmid, (void **) &cntp) == -1) { + perror ("shmemAttach"); + return EXIT_FAILURE; + } + + /* lança processos incrementadores e espera pelo seu termo */ + for (i = 0; i < NPROC; i++) + { + switch (fork ()) + { + case -1: perror ("fork"); + return EXIT_FAILURE; + + case 0: // processo incrementador + for (j = 0; j < niter; j++) + { /* faz cópia do contador em mem. part. */ + auxcnt = *cntp; + + /* generate a time delay */ + delay (BIG); + + /* incrementa a cópia e armazena-a em mem. part. */ + *cntp = auxcnt + 1; + + /* generate a time delay */ + delay (BIG); + } + + /* desanexa a memória partilhada do espaço de endereçamento próprio */ + if (shmemDettach (cntp) == -1) { + perror ("incrementador - shmemDettach"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + } + } + + /* espera pelos termo dos incrementadores e sai */ + for (i = 0; i < NPROC; i++) { + wait(NULL); + } + return EXIT_SUCCESS; +} + +static int set(int value) +{ + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect (SHMKEY); + if (shmid == -1) + { + perror ("shmemConnect"); + return EXIT_FAILURE; + } + + /* anexa a memória partilhada ao espaço de endereçamento próprio */ + int *cntp; + if (shmemAttach (shmid, (void **) &cntp) == -1) { + perror ("shmemAttach"); + return EXIT_FAILURE; + } + + /* inicializa o contador em memória partilhada */ + *cntp = value; + + /* desanexa a memória partilhada do espaço de endereçamento próprio */ + if (shmemDettach (cntp) == -1) { + perror ("incrementador - shmemDettach"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int print(void) +{ + /* ganha acesso à memória partilhada */ + int shmid = shmemConnect (SHMKEY); + if (shmid == -1) { + perror ("shmemConnect"); + return EXIT_FAILURE; + } + + /* anexa a memória partilhada ao espaço de endereçamento próprio */ + int *cntp; + if (shmemAttach (shmid, (void **) &cntp) == -1) + { + perror ("shmemAttach"); + return EXIT_FAILURE; + } + + /* imprime valor */ + printf("Value = %d\n", *cntp); + + /* desanexa a memória partilhada do espaço de endereçamento próprio */ + if (shmemDettach (cntp) == -1) + { + perror ("incrementador - shmemDettach"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/2ano1/SO/aula10/base/semaphore.c b/2ano1/SO/aula10/base/semaphore.c new file mode 100644 index 0000000..29ee4a6 --- /dev/null +++ b/2ano1/SO/aula10/base/semaphore.c @@ -0,0 +1,139 @@ +/** + * \file semaphore.c (implementation file) + * + * \brief Semaphore management. + * + * Operations defined on semaphores: + * \li creation of a set of semaphores + * \li connection to a previously created set of semaphores + * \li destruction of a previously created set of semaphores + * \li signalling start of operations + * \li down of a semaphore within the set + * \li up of a semaphore within the set. + * + * \author António Rui Borges + */ + +#include +#include +#include +#include + +/** \brief access permission: user r-w */ +#define MASK 0600 + +/** + * \brief Creation of a set of semaphores. + * + * All semaphores in the set will be in set to red state upon creation. + * The function fails if there is already a semaphore set with a creation key equal to key. + * + * \param key creation key + * \param snum number of semaphores in the set (>= 1) + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semCreate (int key, unsigned int snum) +{ + return semget ((key_t) key, snum+1, MASK | IPC_CREAT | IPC_EXCL); +} + +/** + * \brief Connection to a previously created set of semaphores. + * + * The function fails if there is no semaphore set with a creation key equal to key. + * + * \param key creation key + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semConnect (int key) +{ + int semgid; /* semaphore set identifier */ + struct sembuf init[2] = {{ 0, -1, 0 }, {0, 1, 0}}; /* initialization operation */ + + if ((semgid = semget ((key_t) key, 1, MASK)) == -1) + return -1; + else if (semop (semgid, init, 2) == -1) + return -1; + else return semgid; +} + +/** + * \brief Destruction of a previously created set of semaphores. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semDestroy (int semgid) +{ + return semctl (semgid, 0, IPC_RMID, NULL); +} + +/** + * \brief Signalling start of operations upon initialization of shared data structures. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semSignal (int semgid) +{ + struct sembuf up = { 0, 1, 0 }; /* all around up operation */ + + return semop (semgid, &up, 1); +} + +/** + * \brief Down of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semDown (int semgid, unsigned int sindex) +{ + struct sembuf down = { 0, -1, 0 }; /* specific down operation */ + + down.sem_num = (unsigned short) sindex; + return semop (semgid, &down, 1); +} + +/** + * \brief Up of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semUp (int semgid, unsigned int sindex) +{ + struct sembuf up = { 0, 1, 0 }; /* specific up operation */ + + up.sem_num = (unsigned short) sindex; + + return semop (semgid, &up, 1); +} diff --git a/2ano1/SO/aula10/base/semaphore.h b/2ano1/SO/aula10/base/semaphore.h new file mode 100644 index 0000000..96c1f5f --- /dev/null +++ b/2ano1/SO/aula10/base/semaphore.h @@ -0,0 +1,102 @@ +/** + * \file semaphore.h (interface file) + * + * \brief Semaphore management. + * + * Operations defined on semaphores: + * \li creation of a set of semaphores + * \li connection to a previously created set of semaphores + * \li destruction of a previously created set of semaphores + * \li signalling start of operations + * \li down of a semaphore within the set + * \li up of a semaphore within the set. + * + * \author António Rui Borges + */ + +#ifndef SEMAPHORE_H_ +#define SEMAPHORE_H_ + +/** + * \brief Creation of a set of semaphores. + * + * All semaphores in the set will be in set to red state upon creation. + * The function fails if there is already a semaphore set with a creation key equal to key. + * + * \param key creation key + * \param snum number of semaphores in the set (>= 1) + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semCreate (int key, unsigned int snum); + +/** + * \brief Connection to a previously created set of semaphores. + * + * The function fails if there is no semaphore set with a creation key equal to key. + * + * \param key creation key + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semConnect (int key); + +/** + * \brief Destruction of a previously created set of semaphores. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semDestroy (int semgid); + +/** + * \brief Signalling start of operations upon initialization of shared data structures. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semSignal (int semgid); + +/** + * \brief Down of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semDown (int semgid, unsigned int sindex); + +/** + * \brief Up of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semUp (int semgid, unsigned int sindex); + +#endif /* SEMAPHORE_H_ */ diff --git a/2ano1/SO/aula10/base/sharedMemory.c b/2ano1/SO/aula10/base/sharedMemory.c new file mode 100644 index 0000000..e0c8171 --- /dev/null +++ b/2ano1/SO/aula10/base/sharedMemory.c @@ -0,0 +1,111 @@ +/** + * \file sharedMemory.c (implementation file) + * + * \brief Shared memory management. + * + * Operations defined on shared memory: + * \li creation of a new block + * \li connection to a previously created block + * \li destruction of a previously created block + * \li mapping of the block previously created on the process address space + * \li unmapping of the block off the process address space. + * + * \author António Rui Borges + */ + +#include +#include +#include + +/** \brief access permission: user r-w */ +#define MASK 0600 + +/** + * \brief Creation of a new block. + * + * The function fails if there is already a block of shared memory with a creation key equal to key. + * + * \param key creation key + * \param size block size (in bytes) + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemCreate (int key, unsigned int size) +{ + return shmget ((key_t) key, size, MASK | IPC_CREAT | IPC_EXCL); +} + +/** + * \brief Connection to a previously created block. + * + * The function fails if there is no block with a creation key equal to key. + * + * \param key creation key + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemConnect (int key) +{ + return shmget ((key_t) key, 1, MASK); +} + +/** + * \brief Destruction of a previously created block. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemDestroy (int shmid) +{ + return shmctl (shmid, IPC_RMID, (struct shmid_ds *) NULL); +} + +/** + * \brief Mapping of the block previously created on the process address space. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * \param pAttAdd pointer to the location where the local address of the attached block is stored + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemAttach (int shmid, void **pAttAdd) +{ + void *add; /* temporary pointer */ + + add = shmat (shmid, (char *) NULL, 0); + if (add != (void *) -1) { + *pAttAdd = (void *) add; + return 0; + } + else return 1; +} + +/** + * \brief Unmapping of the block off the process address space. + * + * The function fails if the pointer does not locate a region of the address space + * where a mapping took previously place. + * + * \param attAdd local address of the attached block + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemDettach (void *attAdd) +{ + return shmdt (attAdd); +} diff --git a/2ano1/SO/aula10/base/sharedMemory.h b/2ano1/SO/aula10/base/sharedMemory.h new file mode 100644 index 0000000..0fa2250 --- /dev/null +++ b/2ano1/SO/aula10/base/sharedMemory.h @@ -0,0 +1,87 @@ +/** + * \file sharedMemory.h (interface file) + * + * \brief Shared memory management. + * + * Operations defined on shared memory: + * \li creation of a new block + * \li connection to a previously created block + * \li destruction of a previously created block + * \li mapping of the block previously created on the process address space + * \li unmapping of the block off the process address space. + * + * \author António Rui Borges + */ + +#ifndef SHAREDMEMORY_H_ +#define SHAREDMEMORY_H_ + +/** + * \brief Creation of a new block. + * + * The function fails if there is already a block of shared memory with a creation key equal to key. + * + * \param key creation key + * \param size block size (in bytes) + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemCreate (int key, unsigned int size); + +/** + * \brief Connection to a previously created block. + * + * The function fails if there is no block with a creation key equal to key. + * + * \param key creation key + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemConnect (int key); + +/** + * \brief Destruction of a previously created block. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemDestroy (int shmid); + +/** + * \brief Mapping of the block previously created on the process address space. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * \param pAttAdd pointer to the location where the local address of the attached block is stored + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemAttach (int shmid, void **pAttAdd); + +/** + * \brief Unmapping of the block off the process address space. + * + * The function fails if the pointer does not locate a region of the address space + * where a mapping took previously place. + * + * \param attAdd local address of the attached block + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemDettach (void *attAdd); + +#endif /* SHAREDMEMORY_H_ */ diff --git a/2ano1/SO/aula10/servcli/Makefile b/2ano1/SO/aula10/servcli/Makefile new file mode 100644 index 0000000..ba21da1 --- /dev/null +++ b/2ano1/SO/aula10/servcli/Makefile @@ -0,0 +1,21 @@ +CC = gcc + +CFLAGS = -Wall + +LDFLAGS = -lm + +.PHONY: all clean cleanall + +all: server client + +comm-shm.o: comm.h semaphore.h sharedMemory.h + +server client: %: %.o sharedMemory.o semaphore.o comm-shm.o + gcc ${CFLAGS} -o $@ $? ${LDFLAGS} + +clean: + rm -f *.o *~ + +cleanall: clean + rm -f server client + diff --git a/2ano1/SO/aula10/servcli/client.c b/2ano1/SO/aula10/servcli/client.c new file mode 100644 index 0000000..8dbfc64 --- /dev/null +++ b/2ano1/SO/aula10/servcli/client.c @@ -0,0 +1,43 @@ +/** + * Nome : client.c + * Função : cliente do servidor conversor para maisculas + * Autores : Artur Pereira e José Luís Oliveira + * Email : {artur, jlo}@ua.pt + */ + +#include "comm.h" + +#include +#include +#include +#include + +int main(void) +{ + MESSAGE msg; + + /* abre o canal de comunicacao */ + cliOpenComm(); + + /* uso do serviço */ + while (1) { + /* pede expressao ao utilizador e constroi mensagem */ + printf("Mensagem a enviar: "); + fgets(msg.data, MSG_MAX, stdin); + msg.size = strlen(msg.data+1); + + /* envia mensagem */ + cliSend(&msg); + + /* aguarda e recolhe resposta */ + cliReceive(&msg); + + /* imprime mensagem recebida */ + printf("Mensagem recebida: %s\n", msg.data); + } + + /* fecha o canal de comunicacao */ + cliCloseComm(); + + return 0; +} diff --git a/2ano1/SO/aula10/servcli/comm-shm.c b/2ano1/SO/aula10/servcli/comm-shm.c new file mode 100644 index 0000000..c385296 --- /dev/null +++ b/2ano1/SO/aula10/servcli/comm-shm.c @@ -0,0 +1,204 @@ +/** + * Name : comm-shm.c + * Function : Implementation of comm functions using shared memory and semaphores. + * Author : Artur Pereira + */ + +#ifndef _SVID_SOURCE +#define _SVID_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "comm.h" +#include "sharedMemory.h" +#include "semaphore.h" + +#define THEKEY 1111UL + +enum {R = 1, S, A}; + +static int semid = -1; /* semaphore id */ +static int shmid = -1; /* shared memory id */ +static MESSAGE *buf = NULL; /* message buffer */ + +/* up operation on a semaphore */ +static void up(int semidx) +{ + if (semUp (semid, semidx) == -1) { + perror ("Fail doing an up to a semaphore"); + exit (EXIT_FAILURE); + } +} + +/* down operation on a semaphore */ +static void down (int semidx) +{ + if (semDown (semid, semidx) == -1) { + perror ("Fail doing a down to a semaphore"); + exit (EXIT_FAILURE); + } +} + + +/** Server side functions */ + +/* Open communication - server side */ +void servOpenComm(void) +{ + bool first = false; + + /* create semaphore agregate */ + if ((semid = semCreate (THEKEY, 3)) == -1) { + if (errno == EEXIST) { + if ((semid = semConnect (THEKEY)) == -1) { + perror("Fail connecting to semaphore agregate"); + exit(EXIT_FAILURE); + } + } + else { + perror("Fail creating semaphore agregate"); + exit(EXIT_FAILURE); + } + } + else first = true; + + /* create shared memory */ + if ((shmid = shmemCreate (THEKEY, sizeof (MESSAGE))) == -1) { + if (errno == EEXIST) { + if ((shmid = shmemConnect (THEKEY)) == -1) { + perror("Fail connecting to shared memory"); + exit(EXIT_FAILURE); + } + } + else { + perror("Fail creating shared memory"); + exit(EXIT_FAILURE); + } + } + + /* map shared memory into process memory space */ + if (shmemAttach (shmid, (void **) &buf) == -1) { + perror("Fail attaching to shared memory"); + exit(EXIT_FAILURE); + } + if (first) { + /* sinalização de início de operações */ + if (semSignal (semid) == -1) { + perror("Fail signaling start of operations"); + exit(EXIT_FAILURE); + } + + /* allow for a service request */ + up(R); + } +} + +/* Close communication - server side */ +void servCloseComm(void) +{ + /* detach shared memory from process memory space and destroy shared memory and semaphore agregate */ + if (shmemDettach (buf) == -1) + { perror("Fail detaching from shared memory"); + exit(EXIT_FAILURE); + } + if (shmemDestroy (shmid) == -1) + { perror ("Fail destroying shared memory"); + exit(EXIT_FAILURE); + } + if (semDestroy (semid) == -1) + { perror ("Fail destroying semaphore agregate"); + exit(EXIT_FAILURE); + } +} + +/* Receive message - server side */ +void servReceive(MESSAGE *msg) +{ + /* lock until a request is in buffer */ + down(S); + + /* get message */ + *msg = *buf; +} + +/* Send message - server side */ +void servSend(MESSAGE *msg) +{ + /* put message */ + *buf = *msg; + + /* the answer is ready */ + up(A); +} + + +/** Client side functions */ + +/* Open communication - client side */ +void cliOpenComm(void) +{ + /* connect to semaphore agregate */ + if ((semid = semConnect (THEKEY)) == -1) + { perror("Fail connecting semaphore agregate"); + exit(EXIT_FAILURE); + } + + /* connect to shared memory */ + if ((shmid = shmemConnect (THEKEY)) == -1) + { perror("Fail connecting to shared memory"); + exit(EXIT_FAILURE); + } + + /* map shared memory into process memory space */ + if (shmemAttach (shmid, (void **) &buf) == -1) + { perror("Fail attaching to shared memory"); + exit(EXIT_FAILURE); + } +} + +/* Close communication - client side */ +void cliCloseComm(void) +{ + /* detach shared memory from process memory space */ + if (shmemDettach (buf) == -1) + { perror("Fail detaching from shared memory"); + exit(EXIT_FAILURE); + } +} + +/* Send message - client side */ +void cliSend(MESSAGE *msg) +{ + /* lock until a service request is possible */ + down(R); + + /* put message */ + *buf = *msg; + + /* notify server */ + up(S); +} + +/* Receive message - client side */ +void cliReceive(MESSAGE *msg) +{ + /* lock until the answer is ready */ + down(A); + + /* get message */ + *msg = *buf; + + /* open access for a new request */ + up(R); +} diff --git a/2ano1/SO/aula10/servcli/comm.h b/2ano1/SO/aula10/servcli/comm.h new file mode 100644 index 0000000..8c7f9e0 --- /dev/null +++ b/2ano1/SO/aula10/servcli/comm.h @@ -0,0 +1,46 @@ +/** + * Name : comm.h + * Function : Prototype of comm functions for a client-server app. + * Author : Artur Pereira + */ + +#ifndef _COMM_H_ +#define _COMM_H_ + +#define MSG_MAX 256 /* tamanho máximo da mensagem */ + +/** + * message definition + */ + +typedef struct message +{ + unsigned int size; /* message size */ + char data[MSG_MAX]; /* message data */ +} MESSAGE; + +/* Open communication - server side */ +void servOpenComm(void); + +/* Close communication - server side */ +void servCloseComm(void); + +/* Send message - server side */ +void servSend(MESSAGE *m); + +/* Receive message - server side */ +void servReceive(MESSAGE *m); + +/* Open communication - client side */ +void cliOpenComm(void); + +/* Close communication - client side */ +void cliCloseComm(void); + +/* Send message - client side */ +void cliSend(MESSAGE *m); + +/* Receive message - client side */ +void cliReceive(MESSAGE *m); + +#endif diff --git a/2ano1/SO/aula10/servcli/semaphore.c b/2ano1/SO/aula10/servcli/semaphore.c new file mode 100644 index 0000000..29ee4a6 --- /dev/null +++ b/2ano1/SO/aula10/servcli/semaphore.c @@ -0,0 +1,139 @@ +/** + * \file semaphore.c (implementation file) + * + * \brief Semaphore management. + * + * Operations defined on semaphores: + * \li creation of a set of semaphores + * \li connection to a previously created set of semaphores + * \li destruction of a previously created set of semaphores + * \li signalling start of operations + * \li down of a semaphore within the set + * \li up of a semaphore within the set. + * + * \author António Rui Borges + */ + +#include +#include +#include +#include + +/** \brief access permission: user r-w */ +#define MASK 0600 + +/** + * \brief Creation of a set of semaphores. + * + * All semaphores in the set will be in set to red state upon creation. + * The function fails if there is already a semaphore set with a creation key equal to key. + * + * \param key creation key + * \param snum number of semaphores in the set (>= 1) + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semCreate (int key, unsigned int snum) +{ + return semget ((key_t) key, snum+1, MASK | IPC_CREAT | IPC_EXCL); +} + +/** + * \brief Connection to a previously created set of semaphores. + * + * The function fails if there is no semaphore set with a creation key equal to key. + * + * \param key creation key + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semConnect (int key) +{ + int semgid; /* semaphore set identifier */ + struct sembuf init[2] = {{ 0, -1, 0 }, {0, 1, 0}}; /* initialization operation */ + + if ((semgid = semget ((key_t) key, 1, MASK)) == -1) + return -1; + else if (semop (semgid, init, 2) == -1) + return -1; + else return semgid; +} + +/** + * \brief Destruction of a previously created set of semaphores. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semDestroy (int semgid) +{ + return semctl (semgid, 0, IPC_RMID, NULL); +} + +/** + * \brief Signalling start of operations upon initialization of shared data structures. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semSignal (int semgid) +{ + struct sembuf up = { 0, 1, 0 }; /* all around up operation */ + + return semop (semgid, &up, 1); +} + +/** + * \brief Down of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semDown (int semgid, unsigned int sindex) +{ + struct sembuf down = { 0, -1, 0 }; /* specific down operation */ + + down.sem_num = (unsigned short) sindex; + return semop (semgid, &down, 1); +} + +/** + * \brief Up of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int semUp (int semgid, unsigned int sindex) +{ + struct sembuf up = { 0, 1, 0 }; /* specific up operation */ + + up.sem_num = (unsigned short) sindex; + + return semop (semgid, &up, 1); +} diff --git a/2ano1/SO/aula10/servcli/semaphore.h b/2ano1/SO/aula10/servcli/semaphore.h new file mode 100644 index 0000000..96c1f5f --- /dev/null +++ b/2ano1/SO/aula10/servcli/semaphore.h @@ -0,0 +1,102 @@ +/** + * \file semaphore.h (interface file) + * + * \brief Semaphore management. + * + * Operations defined on semaphores: + * \li creation of a set of semaphores + * \li connection to a previously created set of semaphores + * \li destruction of a previously created set of semaphores + * \li signalling start of operations + * \li down of a semaphore within the set + * \li up of a semaphore within the set. + * + * \author António Rui Borges + */ + +#ifndef SEMAPHORE_H_ +#define SEMAPHORE_H_ + +/** + * \brief Creation of a set of semaphores. + * + * All semaphores in the set will be in set to red state upon creation. + * The function fails if there is already a semaphore set with a creation key equal to key. + * + * \param key creation key + * \param snum number of semaphores in the set (>= 1) + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semCreate (int key, unsigned int snum); + +/** + * \brief Connection to a previously created set of semaphores. + * + * The function fails if there is no semaphore set with a creation key equal to key. + * + * \param key creation key + * + * \return set identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semConnect (int key); + +/** + * \brief Destruction of a previously created set of semaphores. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semDestroy (int semgid); + +/** + * \brief Signalling start of operations upon initialization of shared data structures. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semSignal (int semgid); + +/** + * \brief Down of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semDown (int semgid, unsigned int sindex); + +/** + * \brief Up of a semaphore within the set. + * + * The function fails if there is no semaphore set with an identifier equal to semgid. + * + * \param semgid set identifier + * \param sindex semaphore location in the set (1 .. snum) + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int semUp (int semgid, unsigned int sindex); + +#endif /* SEMAPHORE_H_ */ diff --git a/2ano1/SO/aula10/servcli/server.c b/2ano1/SO/aula10/servcli/server.c new file mode 100644 index 0000000..4a95d9c --- /dev/null +++ b/2ano1/SO/aula10/servcli/server.c @@ -0,0 +1,42 @@ +/** + * Nome : server.c + * Função : servidor conversor de string para maisculas + * Autores : Artur Pereira e José Luís Oliveira + * Email : {artur, jlo}@ua.pt + */ + +#include "comm.h" + +#include +#include + +int main(void) +{ + MESSAGE msg; + int i; + int cnt = 0; + + /* abre o canal de comunicação */ + servOpenComm(); + + /* atendimento */ + while (1) { + /* le primeira mensagem da fila */ + servReceive(&msg); + + /* converte mensagem para maisculas */ + for (i = 0; i < msg.size; i++) + msg.data[i] = toupper(msg.data[i]); + + /* envia de volta a mensagem processada */ + printf("String %d ", ++cnt); fflush(stdout); + servSend(&msg); + printf("processado.\n"); + } + + /* fecha o canal de comunicacao */ + servCloseComm(); + + return 0; +} + diff --git a/2ano1/SO/aula10/servcli/sharedMemory.c b/2ano1/SO/aula10/servcli/sharedMemory.c new file mode 100644 index 0000000..e0c8171 --- /dev/null +++ b/2ano1/SO/aula10/servcli/sharedMemory.c @@ -0,0 +1,111 @@ +/** + * \file sharedMemory.c (implementation file) + * + * \brief Shared memory management. + * + * Operations defined on shared memory: + * \li creation of a new block + * \li connection to a previously created block + * \li destruction of a previously created block + * \li mapping of the block previously created on the process address space + * \li unmapping of the block off the process address space. + * + * \author António Rui Borges + */ + +#include +#include +#include + +/** \brief access permission: user r-w */ +#define MASK 0600 + +/** + * \brief Creation of a new block. + * + * The function fails if there is already a block of shared memory with a creation key equal to key. + * + * \param key creation key + * \param size block size (in bytes) + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemCreate (int key, unsigned int size) +{ + return shmget ((key_t) key, size, MASK | IPC_CREAT | IPC_EXCL); +} + +/** + * \brief Connection to a previously created block. + * + * The function fails if there is no block with a creation key equal to key. + * + * \param key creation key + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemConnect (int key) +{ + return shmget ((key_t) key, 1, MASK); +} + +/** + * \brief Destruction of a previously created block. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemDestroy (int shmid) +{ + return shmctl (shmid, IPC_RMID, (struct shmid_ds *) NULL); +} + +/** + * \brief Mapping of the block previously created on the process address space. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * \param pAttAdd pointer to the location where the local address of the attached block is stored + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemAttach (int shmid, void **pAttAdd) +{ + void *add; /* temporary pointer */ + + add = shmat (shmid, (char *) NULL, 0); + if (add != (void *) -1) { + *pAttAdd = (void *) add; + return 0; + } + else return 1; +} + +/** + * \brief Unmapping of the block off the process address space. + * + * The function fails if the pointer does not locate a region of the address space + * where a mapping took previously place. + * + * \param attAdd local address of the attached block + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +int shmemDettach (void *attAdd) +{ + return shmdt (attAdd); +} diff --git a/2ano1/SO/aula10/servcli/sharedMemory.h b/2ano1/SO/aula10/servcli/sharedMemory.h new file mode 100644 index 0000000..0fa2250 --- /dev/null +++ b/2ano1/SO/aula10/servcli/sharedMemory.h @@ -0,0 +1,87 @@ +/** + * \file sharedMemory.h (interface file) + * + * \brief Shared memory management. + * + * Operations defined on shared memory: + * \li creation of a new block + * \li connection to a previously created block + * \li destruction of a previously created block + * \li mapping of the block previously created on the process address space + * \li unmapping of the block off the process address space. + * + * \author António Rui Borges + */ + +#ifndef SHAREDMEMORY_H_ +#define SHAREDMEMORY_H_ + +/** + * \brief Creation of a new block. + * + * The function fails if there is already a block of shared memory with a creation key equal to key. + * + * \param key creation key + * \param size block size (in bytes) + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemCreate (int key, unsigned int size); + +/** + * \brief Connection to a previously created block. + * + * The function fails if there is no block with a creation key equal to key. + * + * \param key creation key + * + * \return block identifier, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemConnect (int key); + +/** + * \brief Destruction of a previously created block. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemDestroy (int shmid); + +/** + * \brief Mapping of the block previously created on the process address space. + * + * The function fails if there is no block with an identifier equal to shmid. + * + * \param shmid block identifier + * \param pAttAdd pointer to the location where the local address of the attached block is stored + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemAttach (int shmid, void **pAttAdd); + +/** + * \brief Unmapping of the block off the process address space. + * + * The function fails if the pointer does not locate a region of the address space + * where a mapping took previously place. + * + * \param attAdd local address of the attached block + * + * \return \c 0, upon success + * \return -\c 1, when an error occurs (the actual situation is reported in errno) + */ + +extern int shmemDettach (void *attAdd); + +#endif /* SHAREDMEMORY_H_ */ diff --git a/2ano1/SO/aula11/base/Makefile b/2ano1/SO/aula11/base/Makefile new file mode 100644 index 0000000..e208a98 --- /dev/null +++ b/2ano1/SO/aula11/base/Makefile @@ -0,0 +1,33 @@ +CC = gcc + +CFLAGS = -Wall + +LD = gcc + +LDFLAGS = -lm + +TARGETS = server client client2 + +.PHONY: all clean cleanall + +all: $(TARGETS) + +comm-msg.o: comm.h message.h + +message.o: message.h + +client.o: comm.h + +server.o: comm.h + +client2.o: comm.h + +$(TARGETS): %: %.o comm-msg.o message.o + $(LD) -o $@ $^ $(LDFLAGS) + +clean: + rm -f *.o *~ + +cleanall: clean + rm -f $(TARGETS) + diff --git a/2ano1/SO/aula11/base/client.c b/2ano1/SO/aula11/base/client.c new file mode 100644 index 0000000..81d1744 --- /dev/null +++ b/2ano1/SO/aula11/base/client.c @@ -0,0 +1,36 @@ +/** + * \brief the client + * \author Artur Pereira + */ + +#include "comm.h" + +#include +#include +#include + +int main(void) +{ + MESSAGE msg; + + /* opening the communication channel */ + cliOpenComm(); + + /* use the service */ + while(1) { + /* asking user for a message */ + printf("\n[client \'%d\'] Message to be sent: ", getpid()); + fgets(msg.data, MSG_MAX, stdin); + msg.size = strlen(msg.data)+1; + + /* sending messagee */ + cliSend(&msg); + + /* getting response */ + cliReceive(&msg); + + /* printing received message */ + printf("Message received: %s", msg.data); + } + return 0; +} diff --git a/2ano1/SO/aula11/base/client2.c b/2ano1/SO/aula11/base/client2.c new file mode 100644 index 0000000..aa4dbb5 --- /dev/null +++ b/2ano1/SO/aula11/base/client2.c @@ -0,0 +1,41 @@ +/** + * \brief the client + * \author Artur Pereira + */ + +#include "comm.h" + +#include +#include +#include + +int main(void) +{ + MESSAGE msg; + + /* opening the communication channel */ + cliOpenComm(); + + /* use the service */ + while(1) { + /* asking user for a message */ + printf("\n[client \'%d\'] Message to be sent: ", getpid()); + fgets(msg.data, MSG_MAX, stdin); + msg.size = strlen(msg.data)+1; + + /* sending messagee */ + cliSend(&msg); + + /* asking for authorization to get response */ + printf("\e[33mPress ENTER to get response\e[0m "); + scanf("%*[^\n]"); + scanf("%*c"); + + /* getting response */ + cliReceive(&msg); + + /* printing received message */ + printf("Message received: %s", msg.data); + } + return 0; +} diff --git a/2ano1/SO/aula11/base/comm-msg.c b/2ano1/SO/aula11/base/comm-msg.c new file mode 100644 index 0000000..4526a20 --- /dev/null +++ b/2ano1/SO/aula11/base/comm-msg.c @@ -0,0 +1,155 @@ +/** + * \brief Implementation of client-server comunication channel using unix message queues\ + * \author : Artur Pereira + */ + +#include "comm.h" +#include "message.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSG_KEY1 0x1111UL +#define MSG_KEY2 0x1112UL + +static struct cont +{ + long client; + MESSAGE msg; +} container; + +static int csQueue, /* client-server message queue */ + scQueue; /* server-client message queue */ + + +/* server side functions */ + +int servOpenComm(void) +{ + int side = 0; + + /* creating client-server message queue */ + if ((csQueue = msg_create(MSG_KEY1)) == -1) { + if (errno == EEXIST) { + if ((csQueue = msg_connect(MSG_KEY1)) == -1) { + perror("Fail creating client-server message queue"); + exit(EXIT_FAILURE); + } + side = 1; + } + else { + perror("Fail creating client-server message queue"); + exit(EXIT_FAILURE); + } + } + + /* creating server-client message queue */ + if ((scQueue = msg_create(MSG_KEY2)) == -1) { + if (errno == EEXIST) { + if ((scQueue = msg_connect(MSG_KEY2)) == -1) { + perror("Fail creating server-client message queue"); + exit(EXIT_FAILURE); + } + } + else { + perror("Fail creating server-client message queue"); + exit(EXIT_FAILURE); + } + } + + return side; +} + +void servReceive(MESSAGE *msg) +{ + /* get a message, any type */ + if (msg_receive(csQueue, &container, sizeof(MESSAGE), 0L) == -1) { + perror("Fail receiving message from client-server message queue"); + exit(EXIT_FAILURE); + } + *msg = container.msg; + printf("[Server \'%d\'] message received from client \'%ld\'.\n", getpid(), container.client); +} + +void servSend(MESSAGE *msg) +{ + /* send a message */ + container.msg = *msg; + if (msg_send_nb(scQueue, &container, sizeof(MESSAGE)) == -1) { + perror("Fail sending message to server-client message queue"); + exit(EXIT_FAILURE); + } + printf("[Server \'%d\'] message sent to client \'%ld\'.\n", getpid(), container.client); +} + +void servCloseComm(void) +{ + if (msg_destroy(csQueue) == -1) { + perror("Fail destroying client-server message queue"); + exit(EXIT_FAILURE); + } + if (msg_destroy(scQueue) == -1) { + perror("Fail destroying server-client message queue"); + exit(EXIT_FAILURE); + } +} + +/* client side functions */ + +void cliOpenComm(void) +{ + /* openning client-server message queue */ + if ((csQueue = msg_connect(MSG_KEY1)) == -1) { + perror("Fail accessing client-server message queue"); + exit(EXIT_FAILURE); + } + + /* openning server-client message queue */ + if ((scQueue = msg_connect(MSG_KEY2)) == -1) { + perror("Fail accessing server-client message queue"); + exit(EXIT_FAILURE); + } +} + + +void cliCloseComm(void) +{ + /* nothing to be done */ + return; +} + + +void cliSend(MESSAGE *msg) +{ + /* copy message into container */ + container.client = 1L; + container.msg = *msg; + + /* send message */ + if (msg_send_nb(csQueue, &container, sizeof(MESSAGE)) == -1) { + perror("Fail sending message to client-server message queue"); + exit(EXIT_FAILURE); + } + + printf("[Client \'%ld\'] message sent.\n", container.client); +} + +void cliReceive(MESSAGE *msg) +{ + /* get response message */ + if (msg_receive(scQueue, &container, sizeof(MESSAGE), 0L) == -1) { + perror("Fail receiving message from server-client message queue"); + exit(EXIT_FAILURE); + } + + /* copy message into caller area */ + *msg = container.msg; + + printf("[Client \'%ld\'] message received.\n", container.client); +} diff --git a/2ano1/SO/aula11/base/comm.h b/2ano1/SO/aula11/base/comm.h new file mode 100644 index 0000000..6f9b309 --- /dev/null +++ b/2ano1/SO/aula11/base/comm.h @@ -0,0 +1,52 @@ +/** \brief Client-server communication channel + * \author : Artur Pereira + */ +#ifndef _SO_IPC_COMM_H_ +#define _SO_IPC_COMM_H_ + +#define MSG_MAX 512 /* maximum size allowed for a message */ + +/* + * message definition + */ +typedef struct message +{ + unsigned int size; /* actual message size */ + char data[MSG_MAX]; /* message data */ +} MESSAGE; + + +/** \brief Open communication - server side + */ +int servOpenComm(void); + +/** \brief Close communication - server side + */ +void servCloseComm(void); + +/** \brief Send message - server side + */ +void servSend(MESSAGE *m); + +/** \brief Receive message - server side + */ +void servReceive(MESSAGE *m); + + +/** \brief Open communication - client side + */ +void cliOpenComm(void); + +/** \brief Close communication - client side + */ +void cliCloseComm(void); + +/** \brief Send message - client side + */ +void cliSend(MESSAGE *m); + +/** \brief Receive message - client side + */ +void cliReceive(MESSAGE *m); + +#endif diff --git a/2ano1/SO/aula11/base/message.c b/2ano1/SO/aula11/base/message.c new file mode 100644 index 0000000..7a2661d --- /dev/null +++ b/2ano1/SO/aula11/base/message.c @@ -0,0 +1,95 @@ +/* + * \brief message queue module (implementation) + * + * \details This module defines a set of operations to + * manage message queues. + * The following operations are defined: + * \li creation of a message queue + * \li connection to a previous created message queue + * \li destruction of message queue + * \li non blocking sending of a message + * \li blocking reception of a message + * \li non blocking reception of a message + */ + +#include +#include +#include +#include +#include + +#define MASK 0600 ///< creation permissions + +/* + * \brief creation of a message queue + * \param key the creation key + * \return the queue id on success; -1 on error, being errno set with the cause + */ +int msg_create (int key) +{ + return (msgget ((key_t) key, MASK | IPC_CREAT | IPC_EXCL)); +} + +/* + * \brief connection to a previous created message queue + * \param key the creation key + * \return the queue id on success; -1 on error, being errno set with the cause + */ +int msg_connect (int key) +{ + return (msgget ((key_t) key, MASK)); +} + +/* + * \brief destruction of message queue + * \param msgid queue id + * \return 0 on success; -1 on error, being errno set with the cause + */ +int msg_destroy (int msgid) +{ + return (msgctl (msgid, IPC_RMID, 0)); +} + +/* + * \brief non blocking sending of a message + * \param msgid queue id + * \param msg pointer to the message to be sent + * \param size size of message in bytes + * \return 0 on success; -1 on error, being errno set with the cause + */ +int msg_send_nb (int msgid, void *msg, int size) +{ + return (msgsnd (msgid, (struct msgbuf *) msg, size, 0)); +} + +/* + * \brief non blocking reception of a message + * \param msgid queue id + * \param msg pointer to the message buffer + * \param size size of message buffer in bytes + * \param dest destination id + * \param status pointer to success on repeption status + * \return 0 on success; -1 on error, being errno set with the cause + */ +int msg_receive_nb (int msgid, void *msg, int size, long dest, bool *msgrec) +{ + int stat; + + stat = msgrcv (msgid, (struct msgbuf *) msg, size, dest, IPC_NOWAIT); + *msgrec = (stat >= 0); + if ((stat >= 0) || ((stat == -1) && (errno == ENOMSG))) return (0); + else return (stat); +} + +/* + * \brief blocking reception of a message + * \param msgid queue id + * \param msg pointer to the message buffer + * \param size size of message buffer in bytes + * \param dest destination id + * \return 0 on success; -1 on error, being errno set with the cause + */ +int msg_receive (int msgid, void *msg, int size, long dest) +{ + return (msgrcv (msgid, (struct msgbuf *) msg, size, dest, 0)); +} diff --git a/2ano1/SO/aula11/base/message.h b/2ano1/SO/aula11/base/message.h new file mode 100644 index 0000000..c78ef41 --- /dev/null +++ b/2ano1/SO/aula11/base/message.h @@ -0,0 +1,72 @@ +/** + * \brief message queue module + * + * \details This module defines a set of operations to + * manage message queues. + * The following operations are defined: + * \li creation of a message queue + * \li connection to a previous created message queue + * \li destruction of message queue + * \li non blocking sending of a message + * \li blocking reception of a message + * \li non blocking reception of a message + */ + +#include + +/** + * \brief creation of a message queue + * \param key the creation key + * \return the queue id on success; -1 on error,, being errno set with the cause + */ +extern int msg_create (int key); + + +/** + * \brief connection to a previous created message queue + * \param key the creation key + * \return the queue id on success; -1 on error, being errno set with the cause + */ +extern int msg_connect (int key); + + +/** + * \brief destruction of message queue + * \param msgid queue id + * \return 0 on success; -1 on error, being errno set with the cause + */ +extern int msg_destroy (int msgid); + + +/** + * \brief non blocking sending of a message + * \param msgid queue id + * \param msg pointer to the message to be sent + * \param size size of message in bytes + * \return 0 on success; -1 on error, being errno set with the cause + */ +extern int msg_send_nb (int msgid, void * msg, int size); + + +/** + * \brief non blocking reception of a message + * \param msgid queue id + * \param msg pointer to the message buffer + * \param size size of message buffer in bytes + * \param rec receiver id + * \param status pointer to success on reception status + * \return 0 on success; -1 on error, being errno set with the cause + */ +extern int msg_receive_nb (int msgid, void* msg, int size, long rec, + bool* status); + + +/** + * \brief blocking reception of a message + * \param msgid queue id + * \param msg pointer to the message buffer + * \param size size of message buffer in bytes + * \param rec receiver id + * \return 0 on success; -1 on error, being errno set with the cause + */ +extern int msg_receive (int msgid, void* msg, int size, long rec); diff --git a/2ano1/SO/aula11/base/server.c b/2ano1/SO/aula11/base/server.c new file mode 100644 index 0000000..080f3fa --- /dev/null +++ b/2ano1/SO/aula11/base/server.c @@ -0,0 +1,36 @@ +/** + * \brief The server + * \details This server converts strings to upper case + * \autores : Artur Pereira e José Luís Oliveira + */ + +#include "comm.h" + +#include +#include +#include +#include + +int main(void) +{ + /* Creating communication channel */ + servOpenComm(); + + /* the service */ + MESSAGE msg; + while(1) { + /* getting first message from queue, blocking if necessary */ + servReceive(&msg); + + /* converting it to upper case */ + int i; + for (i=0; i