# Handle varying sizes of procfs buffers.

set test "PROCFS_BUFFER"
if {![installtest_p]} { untested $test; return }

proc proc_read_value { test path} {
    set value "<unknown>"
    if [catch {open $path RDONLY} channel] {
	fail "$test $channel"
    } else {
	set value [read -nonewline $channel]
	close $channel
	pass "$test read $value"
    }
    return $value
}

proc proc_write_value { test path value } {
    if [catch {open $path WRONLY} channel] {
	fail "$test $channel"
    } else {
	puts -nonewline $channel $value
	close $channel
	pass "$test wrote $value"
    }
}

set fullstring "1bcdefghijklmno2BCDEFGHIJKLMNO3qrstuvwxyz12344QRSTUVWXYZ12345bcdefghijklmno6BCDEFGHIJKLMNO7qrstuvwxyz12348QRSTUVWXYZ12340BCDEFGHIJKLMNO1qrstuvwxyz12342QRSTUVWXYZ1234"

proc proc_read_write_counted { test maxsize } {
    global fullstring
    set path "/proc/systemtap/$test/command"

    # Read the file
    set value [proc_read_value $test $path]

    set value2 [string range $fullstring 0 [expr $maxsize - 2]]
    if { $value == $value2 } {
	pass "$test received correct initial value maxsize: $maxsize"
    } else {
	fail "$test received incorrect initial value: $value ($value2)"
    }

    # Write a new value.
    proc_write_value $test $path $fullstring

    return 0;
}

# Expect 80 byte return from reading procfs file.
proc proc_read_write_80 {} {
    global test
    proc_read_write_counted $test 80
}

# Expect 64 byte return from reading procfs file.
proc proc_read_write_64 {} {
    global test
    proc_read_write_counted $test 64
}

set script1 {
    global values[10]
    global idx = 0

    probe procfs.read {
      try {
	$value = "1bcdefghijklmno"
	$value .= "2BCDEFGHIJKLMNO"
	$value .= "3qrstuvwxyz1234"
	$value .= "4QRSTUVWXYZ1234"
	$value .= "5bcdefghijklmno"
	$value .= "6BCDEFGHIJKLMNO"
	$value .= "7qrstuvwxyz1234"
	$value .= "8QRSTUVWXYZ1234"
	$value .= "9bcdefghijklmno"
	$value .= "0BCDEFGHIJKLMNO"
	$value .= "1qrstuvwxyz1234"
	$value .= "2QRSTUVWXYZ1234"
      } catch {
      }
    }
    probe procfs.write {
	values[idx] = $value
	idx++
    }

    probe begin {
        printf("systemtap starting probe\n")
    }
    probe end {
        printf("systemtap ending probe\n")
	for (i = 0; i < idx; i++) {
	    printf("value%d=%s\n", i, values[i])
	}
    }
}

# Output strings in 64 and 80 byte chunks.
set output_string_64 "value0=1bcdefghijklmno2BCDEFGHIJKLMNO3qrstuvwxyz12344QRSTUVWXYZ12345bc\r\nvalue1=defghijklmno6BCDEFGHIJKLMNO7qrstuvwxyz12348QRSTUVWXYZ12340BCDEF\r\nvalue2=GHIJKLMNO1qrstuvwxyz12342QRSTUVWXYZ1234\r\n"

set output_string_80 "value0=1bcdefghijklmno2BCDEFGHIJKLMNO3qrstuvwxyz12344QRSTUVWXYZ12345bcdefghijklmno6BCD\r\nvalue1=EFGHIJKLMNO7qrstuvwxyz12348QRSTUVWXYZ12340BCDEFGHIJKLMNO1qrstuvwxyz12342QRSTUVW\r\nvalue2=XYZ1234\r\n"

# By default, setting MAXSTRINGLEN should set the size of
# procfs read and write buffers.
set test "PROCFS_BUFFER1"
stap_run $test proc_read_write_80 $output_string_80 -DMAXSTRINGLEN=80 -e $script1 -m $test
exec /bin/rm -f ${test}.ko

# Try with MAXSTRINGLEN=80 and STP_PROCFS_BUFSIZE=64
set test "PROCFS_BUFFER2"
stap_run $test proc_read_write_64 $output_string_64 -DMAXSTRINGLEN=80 -DSTP_PROCFS_BUFSIZE=64 -e $script1 -m $test
exec /bin/rm -f ${test}.ko

# Try with MAXSTRINGLEN=64 and STP_PROCFS_BUFSIZE=80.  Note that in
# this case, even though the procfs buffer is 80 bytes in size, since
# strings can only hold 64 bytes, the expected output is the same as
# in the previous test.
set test "PROCFS_BUFFER3"
stap_run $test proc_read_write_80 $output_string_64 -DMAXSTRINGLEN=64 -DSTP_PROCFS_BUFSIZE=80 -e $script1 -m $test
exec /bin/rm -f ${test}.ko

# script2 has a '.maxsize(80). override
set script2 {
    global values[10]
    global idx = 0

    probe procfs.read.maxsize(80) {
      try {
	$value = "1bcdefghijklmno"
	$value .= "2BCDEFGHIJKLMNO"
	$value .= "3qrstuvwxyz1234"
	$value .= "4QRSTUVWXYZ1234"
	$value .= "5bcdefghijklmno"
	$value .= "6BCDEFGHIJKLMNO"
	$value .= "7qrstuvwxyz1234"
	$value .= "8QRSTUVWXYZ1234"
	$value .= "9bcdefghijklmno"
	$value .= "0BCDEFGHIJKLMNO"
	$value .= "1qrstuvwxyz1234"
	$value .= "2QRSTUVWXYZ1234"
      } catch {
      }
    }
    probe procfs.write {
	values[idx] = $value
	idx++
    }

    probe begin {
        printf("systemtap starting probe\n")
    }
    probe end {
        printf("systemtap ending probe\n")
	for (i = 0; i < idx; i++) {
	    printf("value%d=%s\n", i, values[i])
	}
    }
}

# By default, setting MAXSTRINGLEN should set the size of
# procfs read and write buffers.  But script2 has a '.maxsize(80)'
# override.
set test "PROCFS_BUFFER4"
stap_run $test proc_read_write_80 $output_string_64 -DMAXSTRINGLEN=64 -e $script2 -m $test
exec /bin/rm -f ${test}.ko

# The script2 '.maxsize(80)' override should override even setting
# STP_PROCFS_BUFSIZE.
set test "PROCFS_BUFFER5"
stap_run $test proc_read_write_80 $output_string_64 -DMAXSTRINGLEN=64 -DSTP_PROCFS_BUFSIZE=80 -e $script2 -m $test
exec /bin/rm -f ${test}.ko

# script3 has a maxsize override and a default size file
set script3 {
    global values[10]
    global idx = 0

    probe procfs("default").read {
      try {
	$value = "1bcdefghijklmno"
	$value .= "2BCDEFGHIJKLMNO"
	$value .= "3qrstuvwxyz1234"
	$value .= "4QRSTUVWXYZ1234"
	$value .= "5bcdefghijklmno"
	$value .= "6BCDEFGHIJKLMNO"
	$value .= "7qrstuvwxyz1234"
	$value .= "8QRSTUVWXYZ1234"
	$value .= "9bcdefghijklmno"
	$value .= "0BCDEFGHIJKLMNO"
	$value .= "1qrstuvwxyz1234"
	$value .= "2QRSTUVWXYZ1234"
      } catch {
      }
    }
    probe procfs.read.maxsize(80) {
      try {
	$value = "1bcdefghijklmno"
	$value .= "2BCDEFGHIJKLMNO"
	$value .= "3qrstuvwxyz1234"
	$value .= "4QRSTUVWXYZ1234"
	$value .= "5bcdefghijklmno"
	$value .= "6BCDEFGHIJKLMNO"
	$value .= "7qrstuvwxyz1234"
	$value .= "8QRSTUVWXYZ1234"
	$value .= "9bcdefghijklmno"
	$value .= "0BCDEFGHIJKLMNO"
	$value .= "1qrstuvwxyz1234"
	$value .= "2QRSTUVWXYZ1234"
      } catch {
      }
    }
    probe procfs.write {
	values[idx] = $value
	idx++
    }

    probe begin {
        printf("systemtap starting probe\n")
    }
    probe end {
        printf("systemtap ending probe\n")
	for (i = 0; i < idx; i++) {
	    printf("value%d=%s\n", i, values[i])
	}
    }
}

proc proc_read_write_default_80 {} {
    global test
    global fullstring

    set path "/proc/systemtap/$test/default"
    set value2 [string range $fullstring 0 62]

    # Read the file
    set value [proc_read_value $test $path]
    if { $value == $value2 } {
	pass "$test received correct initial value"
    } else {
	fail "$test received incorrect initial value: $value ($value2)"
    }

    proc_read_write_counted $test 80
}

set test "PROCFS_BUFFER6"
stap_run $test proc_read_write_default_80 $output_string_64 -DMAXSTRINGLEN=64 -e $script3 -m $test
exec /bin/rm -f ${test}.ko

set script4 {
    global large_strings[10]

    # Put more data than we can really handle into $value
    probe procfs.read.maxsize(2048) {
      try {
	$value = large_strings[0]
	for (i = 1; i < 10; i+=1) {
	    $value .= large_strings[i]
	}
      } catch {
      }
    }

    probe begin {
	# build up several maximum length strings
	max = 512
	for (i = 0; i < max/64; i+=1) {
	    for (j = 0; j < 10; j++) {
		if (i < (max/64 - 1)) {
		    large_strings[j] .= sprintf("%3d:12345678901234567890123456789012345678901234567890123456789\n",
						i + (j * (max/64)))
		}
		else {
		    large_strings[j] .= sprintf("%3d:1234567890123456789012345678901234567890123456789012345678\n",
						i + (j * (max/64)))
		}
	    }
	}
        printf("systemtap starting probe\n")
    }
    probe end {
        printf("systemtap ending probe\n")
    }
}

proc proc_read_big {} {
    global test
    global test_string

    set path "/proc/systemtap/$test/command"

    # Read the file
    set value [proc_read_value $test $path]

    # set value2 [string range $fullstring 0 [expr $maxsize - 2]]
    if { $value == $test_string } {
	pass "$test received correct initial value"
    } else {
	fail "$test received incorrect initial value: $value ($test_string)"
    }
    return 0;
}

set test_string \
"  0:12345678901234567890123456789012345678901234567890123456789
  1:12345678901234567890123456789012345678901234567890123456789
  2:12345678901234567890123456789012345678901234567890123456789
  3:12345678901234567890123456789012345678901234567890123456789
  4:12345678901234567890123456789012345678901234567890123456789
  5:12345678901234567890123456789012345678901234567890123456789
  6:12345678901234567890123456789012345678901234567890123456789
  7:1234567890123456789012345678901234567890123456789012345678
  8:12345678901234567890123456789012345678901234567890123456789
  9:12345678901234567890123456789012345678901234567890123456789
 10:12345678901234567890123456789012345678901234567890123456789
 11:12345678901234567890123456789012345678901234567890123456789
 12:12345678901234567890123456789012345678901234567890123456789
 13:12345678901234567890123456789012345678901234567890123456789
 14:12345678901234567890123456789012345678901234567890123456789
 15:1234567890123456789012345678901234567890123456789012345678
 16:12345678901234567890123456789012345678901234567890123456789
 17:12345678901234567890123456789012345678901234567890123456789
 18:12345678901234567890123456789012345678901234567890123456789
 19:12345678901234567890123456789012345678901234567890123456789
 20:12345678901234567890123456789012345678901234567890123456789
 21:12345678901234567890123456789012345678901234567890123456789
 22:12345678901234567890123456789012345678901234567890123456789
 23:1234567890123456789012345678901234567890123456789012345678
 24:12345678901234567890123456789012345678901234567890123456789
 25:12345678901234567890123456789012345678901234567890123456789
 26:12345678901234567890123456789012345678901234567890123456789
 27:12345678901234567890123456789012345678901234567890123456789
 28:12345678901234567890123456789012345678901234567890123456789
 29:12345678901234567890123456789012345678901234567890123456789
 30:12345678901234567890123456789012345678901234567890123456789
 31:1234567890123456789012345678901234567890123456789012345678
 32"

# Test outputting 2K worth of data in one shot.
set test "PROCFS_BUFFER7"
stap_run $test proc_read_big "" -DMAXSTRINGLEN=512 -e $script4 -m $test
exec /bin/rm -f ${test}.ko

# Expect 72 byte return from reading procfs file.
proc proc_read_write_72 {} {
    global test
    proc_read_write_counted $test 72
}

set script5 {
    global error

    probe procfs.read {
      try {
	$value = "1bcdefghijklmno"
	$value .= "2BCDEFGHIJKLMNO"
	$value .= "3qrstuvwxyz1234"
	$value .= "4QRSTUVWXYZ1234"
	$value .= "5bcdefghijk"
      } catch (err) {
        error = err
      }
    }
    probe procfs.write {
      next
    }

    probe begin {
        printf("systemtap starting probe\n")
    }
    probe end {
        printf("systemtap ending probe\n")
        println(error)
    }
}

set overflow_string "buffer size exceeded, consider .maxsize\\(72\\).\r\n"

# Buffer too small
set test "PROCFS_BUFFER8"
stap_run $test proc_read_write_64 $overflow_string -DSTP_PROCFS_BUFSIZE=64 -e $script5 -m $test
exec /bin/rm -f ${test}.ko

# Buffer is exactly large enough to hold contents
set test "PROCFS_BUFFER9"
stap_run $test proc_read_write_72 "\r\n" -DSTP_PROCFS_BUFSIZE=72 -e $script5 -m $test
exec /bin/rm -f ${test}.ko
