• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Learning Unix as I do homework

NintendoMan07

Smash Journeyman
Joined
Jul 23, 2008
Messages
251
Location
Dallas: The Land that Killed Me
Well, it's fun until all the problems become too troublesome to fix by the due time.

Anyway, one of my shell scripts is supposed to send something as "an email to the user". Well, the thing is, I'm naturally assuming this is referring to using the USER variable, but when I run it and check my mail... I get nothing. And even worse, I tried sending a few emails to myself but still the same thing: nothing.

Is this part of Unix or just my stupidity?

BTW, I'm running the script in Bash on my college's Unix server, if that helps anything.
 

AltF4

BRoomer
BRoomer
Joined
Dec 13, 2005
Messages
5,042
Location
2.412 – 2.462 GHz
I've never sent mail from BASH before, but here's something I found with a quick google search. Maybe it'll help.

#!/bin/bash
# script to send simple email
# email subject
SUBJECT="SET-EMAIL-SUBJECT"
# Email To ?
EMAIL="admin@somewhere.com"
# Email text/message
EMAILMESSAGE="/tmp/emailmessage.txt"
echo "This is an email message test"> $EMAILMESSAGE
echo "This is email text" >>$EMAILMESSAGE
# send an email using /bin/mail
/bin/mail -s "$SUBJECT" "$EMAIL" < $EMAILMESSAGE
 

NintendoMan07

Smash Journeyman
Joined
Jul 23, 2008
Messages
251
Location
Dallas: The Land that Killed Me
Sorry for the late response, but I've figured out what it is: evidently my Unix mail is directly forwarded to my school's email address, hence why there's no mail when I run mailx.

Thanks for the response though.

I feel kinda silly right now.
 

NintendoMan07

Smash Journeyman
Joined
Jul 23, 2008
Messages
251
Location
Dallas: The Land that Killed Me
I apologize for the double-post, but I'm now tackling a Unix assignment that's got a mix of C programming in it. And... I know nothing about C.

One of the first things I've run into is that one or more of the given problems require command line arguments.

I noticed that my Unix book, when command line arguments are required, employs the following method header:

int main(int argc, char **argv);

And from my best guess, argc should be the number of arguments (including the executing file) and argv is the array storing each argument?

And yes, I realize from the frequent number of topics I've created that I'm totally unorganized as of now.

EDIT: The very first problem has me locating all instance of a character in a file and replacing it with another. I'm completely lost on this.
 

Kirby King

Master Lameoid
Premium
BRoomer
Joined
Feb 8, 2002
Messages
7,577
Location
Being a good little conformist
Right, that's basically it.

Are you really not expected to know any C at all? Seems surprising that they'd just be expecting you to go implement stuff in C without having really broached simple things like this. I mean, have you learned what a pointer is, for example?
 

NintendoMan07

Smash Journeyman
Joined
Jul 23, 2008
Messages
251
Location
Dallas: The Land that Killed Me
Right, that's basically it.

Are you really not expected to know any C at all? Seems surprising that they'd just be expecting you to go implement stuff in C without having really broached simple things like this. I mean, have you learned what a pointer is, for example?
To be fair, the class prerequisites mentioned having some knowledge of C, yet our instructor mentioned that if we went through our college's programming classes (which mainly teach Java), that we would get a bit of a crash course during one of the lectures. I was there the day he did that crash course, but the discussion was far too rushed for much of it to sink in.

I'm currently trying to rely on Google to help me out a bit with this, but trying to start from the middle with something like this isn't exactly the best way to go, I guess.

Anyway, there was a bit of discussion on pointers on that class day, and I can at least identify the syntax, but in terms of usage, I'm a bit lost.
 

Big Sean

Smash Journeyman
Joined
Jun 3, 2003
Messages
484
Location
Berkeley
note that argc also includes the name of the function you called. So like if you function was called with:

$ ./thing you me
argc would be 3 and argv[0] would be "thing"

that's screwed me up more than a couple of times.
 

NintendoMan07

Smash Journeyman
Joined
Jul 23, 2008
Messages
251
Location
Dallas: The Land that Killed Me
It's the last set of homework problems, yay. But I'm still as stuck as I was before.

"1. Write a program that creates a pipe and forks a child. The program should accept a single argument and pass it across the pipe to the child. The child should read the pipe and print what it receives. The child should have its own code and not call an exec function. Since the child won't know how many bytes are being sent, it should keep reading until there are no more bytes. The child should call _exit(0) and the parent should wait on the child and print its exit status. Name the program send.c.


2. Write a program that performs an ls -l on the filename given as the program's first argument and pipes the listing to the grep command where grep is looking for directories in the listing. Fork a child process to run the ls -l. Let the parent run grep. Use execvp for both parent and child. Name the program dirs.c.


3. Write a program that prints the numbers from 1 to 25, sleeping one second after each number. If signal SIGUSR1 arrives, it should print the total so far, sleep 3 seconds, and resume printing numbers. Name the program sig.c."

Here's where I stand on each of these:

1. I'm kinda stuck on two points:

a. How do get the number of bytes in the single argument that you're passing into the pipe?
b. How exactly do the exit and wait system calls work in this situation? An example in the textbook declares an integer named status, yet assigns nothing to it. Later in the example, the wait system call refers to the address of the status variable out of nowhere. Is status predefined in a library or something? I apologize if I'm butchering programming terms but here's what I'm seeing:

Code:
#include <stdio.h>
#include <wait.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
int status;
...
(rest of the code; no action is taken on status)
...
wait(&status);
}
2. I think I've got this one. I know that my prof hinted at basically modifying the existing examples that he pulled from the textbook, which I THINK I've got covered here.

3. I haven't started on yet. I'll probably place #1 on hold just to try this one out.
 

Kirby King

Master Lameoid
Premium
BRoomer
Joined
Feb 8, 2002
Messages
7,577
Location
Being a good little conformist
1a: check out the man page for fread. I think that'll answer your question.

1b: this is a common way for functions to effectively return multiple values. The caller to wait() creates the int status in order to allocate the integer on the stack. Then it passes the address of that variable to wait() itself, but then wait() returns a process id (not used in the example you gave) and updates the status variable via the pointer you passed it. So you create the actual variable in the caller, and then somewhere in wait() you would have
Code:
*status = 0;
or whatever the status was. (And by "would" I mean you would if wait() were implemented solely as a user-level function, since the OS has to do some funny stuff to actually update memory in your user-level program. But if you wanted to write user-level functions in your own programs that achieved a similar effect, i.e. return multiple values, you would use this sort of approach.) The effect is that after you've called wait, the status you wanted is now actually in the variable "status" without you having to do anything else, and you can refer to/use it like any other variable.
 

NintendoMan07

Smash Journeyman
Joined
Jul 23, 2008
Messages
251
Location
Dallas: The Land that Killed Me
1a: check out the man page for fread. I think that'll answer your question.

1b: this is a common way for functions to effectively return multiple values. The caller to wait() creates the int status in order to allocate the integer on the stack. Then it passes the address of that variable to wait() itself, but then wait() returns a process id (not used in the example you gave) and updates the status variable via the pointer you passed it. So you create the actual variable in the caller, and then somewhere in wait() you would have
Code:
*status = 0;
or whatever the status was. (And by "would" I mean you would if wait() were implemented solely as a user-level function, since the OS has to do some funny stuff to actually update memory in your user-level program. But if you wanted to write user-level functions in your own programs that achieved a similar effect, i.e. return multiple values, you would use this sort of approach.) The effect is that after you've called wait, the status you wanted is now actually in the variable "status" without you having to do anything else, and you can refer to/use it like any other variable.
To elaborate on my problem: here's my current code (not working) for the problem:

Code:
/*
Considering how unfamiliar with comments in C I am,
I'm just taking a shot in the dark and hoping this is
how it works. This code is adapted from the textbook
"Your Unix: The Ultimate Guide, 2nd Edition" by Sumitabha Das.
*/

#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	int n, status, fd[2];
	char buf[100];

	if(argc != 2)
	{
		printf("Usage: %s argument1\n", argv[0]);
	}	

	if (pipe(fd) < 0)
	{
		write(STDERR_FILENO, "Pipe failed\n", 12);
		exit(1);
	}

	switch(fork())
	{
		case -1: 
		write(STDERR_FILENO, "Fork failed\n", 12);
		exit(2);

		case 0: 
		close(fd[1]);
		while((n = read(fd[0], buf, 100)) > 0); 
			write(STDOUT_FILENO, buf, n);
		_exit(0);

		default:
		close(fd[0]);
		write(fd[1], argv[1], x);
		wait(&status);
		printf("Exit status: %d\n", WEXITSTATUS(status));
	}
	
	exit(0);
}
Considering how I might be getting a bit close to breaking Global Rules in posting this stuff already, I'll just say that the original example this is adapted from DOES close the read file descriptor in the parent (the default section), and also closes the write file descriptor in the child (the case 0 section). I'm trying to stick to the example as close as I can, considering it's one of the few things I understand.

So what I'm wondering is:

a. Considering how the read file descriptor is closed in the parent, how would I be able be able to determine the size of the given argument (read or fread wouldn't work in this situation, right?)? Would I have to remove the close statement to make this work at all, and if so, how would this affect the pipe?

b. I'm not exactly sure if I implemented the exit and wait commands correctly, since I once again referred to the book for that implementation. Looking at KK's explanation of this though, I guess this would work?

For reference, here's the actual assignment:

1. Write a program that creates a pipe and forks a child. The program should accept a single argument and pass it across the pipe to the child. The child should read the pipe and print what it receives. The child should have its own code and not call an exec function. Since the child won't know how many bytes are being sent, it should keep reading until there are no more bytes. The child should call _exit(0) and the parent should wait on the child and print its exit status. Name the program send.c.
I apologize for bringing up the same issues again, but I now see where there's some complications. Thanks so much for the help, guys. =D
 

Kirby King

Master Lameoid
Premium
BRoomer
Joined
Feb 8, 2002
Messages
7,577
Location
Being a good little conformist
a. I've never actually dealt with pipe() before, but the thing about a fork is that you're creating two copies of the same process, and in doing so you're creating additional references to those fds. So when you close the read fd in the parent that doesn't affect the read fd in the child, and vice versa with the write fds.

b. As far as I can tell it looks fine. When I said "in wait() you'd have ____" I didn't mean you should literally have that line in your code--I was just explaining how you would hypothetically implement your own function that had the same effect wait() does with the pointer you pass it. Implementing is not quite the same thing as using. :p

In terms of errors, a few things: first, there's a variable "x" that you never ever define. Next, you're missing some #includes at the top of that file--the man pages for exit() and wait() should tell you what you need to #include. Also, there's a big difference between
Code:
while(...);
     // do stuff
and
Code:
while(...)
{
    // do stuff
}
 
Top Bottom