Im using putty for a class assignment and I am getting a segmentation fault - putty

Write a C program that counts the number of non white-space characters in an input text file. Program takes as command argument(s) the name of the input file (and the output file with option -f). Based on the option flags, it displays the output on the standard output, or writes the output to an output file. (25 points)
The command format is as follows:
command -f inputfile outputfile
or,
command -s inputfile
-f indicates writing to an output file;
-s indicates displaying the output on the screen.
I am receiving the segmentation fault on the -s command
#include <stdio.h>
#define BLANK ' '
#define NEWLINE '\n'
int main(int argc, char *argv[])
{
FILE *infile;
char c;
int char_count=0;
FILE *outfile;
outfile = fopen(argv[3], "w");
//checks for the argc length to be within the correct perameteres
if ((argc < 3) || (argc > 4))
{
printf("Incorrect format, please try gain\n");
exit(1);
}
//checks the input file to see if it is empty
if ( (infile= fopen(argv[2], "r")) == NULL)
{
fprintf(stderr,"%s: cannot open %s \n", argv[0], argv[1]);
exit(1);
}
// count the number of charecters in infile
while ( (c = getc(infile)) != EOF)
if ((c != BLANK) && (c != NEWLINE) )
char_count++;
//checks to see if the command is -s or not, outputing the corrct message to the desired location
if (argv[1] == "-s")
{
printf("%d characters\n", char_count);
}
else
{
fprintf(outfile, "%s contains %d characters\n", argv[2], char_count);
}
return 0;
}

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BLANK ' '
#define NEWLINE '\n'
int main(int argc, char *argv[])
{
FILE *infile;
FILE *outfile;
char c;
int char_count=0;
//checks for the argc length to be within the correct perameteres
if ((argc < 3) || (argc > 4))
{
printf("Incorrect format, please try gain\n");
exit(1);
}
//checks if passed second argument is valid (-f or -s)
if (strcmp(argv[1], "-f") == 0) {
if (argc < 4) {
fprintf(stderr, "Please inform output file. Usage: -f inputfile outputfile");
exit(1);
}
outfile = fopen(argv[3], "w");
}
else if (strcmp(argv[1], "-s") != 0) {
fprintf(stderr, "Parameter not recognized: %s\n", argv[1]);
exit(1);
}
//checks the input file to see if it is empty
if ( (infile= fopen(argv[2], "r")) == NULL)
{
fprintf(stderr,"%s: cannot open %s \n", argv[0], argv[1]);
exit(1);
}
// count the number of charecters in infile
while ( (c = getc(infile)) != EOF)
if ((c != BLANK) && (c != NEWLINE) )
char_count++;
//checks to see if the command is -s or not, outputing the corrct message to the desired location
if (strcmp(argv[1], "-s") == 0)
{
printf("%d characters\n", char_count);
}
else
{
fprintf(outfile, "%s contains %d characters\n", argv[2], char_count);
printf("Result written to %s\n", argv[3]);
}
return 0;
}

Related

Error with fread() in c, not having expected outut

I'm making a checksum algorithm for one of my classes, I want to read two binary files and run them through a checksum algorithm. The checksum algorithm works (I've tried inputting what I want into the terminal and it works) but I can't get my fread() to work. I've tried printing the outputs and they print the correct stuff, but then a bunch of other random numbers and letters at the end.
Here is my code:
int main(int argc, char *argv[])
{
FILE *ptr1;
FILE *ptr2;
ptr1 = fopen("test1.bin","rb");
ptr2 = fopen("test2.bin","rb");
char file1[sizeof(ptr1)], file2[sizeof(ptr2)];
char sum[sizeof(ptr1)], comp[sizeof(ptr1)];
fread(file1,sizeof(file1),1,ptr1);
fread(file2,sizeof(file2),1,ptr2);
fclose(ptr1);
fclose(ptr2);
/* char file1[20], file2[20];
char sum[20], comp[20];
printf("enter 1\n");
scanf("%s",&file1);
printf("enter 2\n");
scanf("%s",&file2);*/
if(strlen(file1)==strlen(file2)) {
char next='0';
int length = strlen(file1);
for(int i=length-1;i>=0;i--)
{
if(file1[i]=='0' && file2[i]=='0' && next=='0')
{
sum[i]='0';
next='0';
}
else if(file1[i]=='0' && file2[i]=='0' && next=='1')
{
sum[i]='1';
next='0';
}
else if(file1[i]=='0' && file2[i]=='1' && next=='0')
{
sum[i]='1';
next='0';
}
else if(file1[i]=='0' && file2[i]=='1' && next=='1')
{
sum[i]='0';
next='1';
}
else if(file1[i]=='1' && file2[i]=='0' && next=='0')
{
sum[i]='1';
next='0';
}
else if(file1[i]=='1' && file2[i]=='0' && next=='1')
{
sum[i]='0';
next='1';
}
else if(file1[i]=='1' && file2[i]=='1' && next=='0')
{
sum[i]='0';
next='1';
}
else if(file1[i]=='1' && file2[i]=='1' && next=='1')
{
sum[i]='1';
next='1';
}
else
break;
}
for (int i=0;i<length;i++)
{
if(sum[i]=='0')
comp[i]='1';
else
comp[i]='0';
}
if(next=='1')
next='0';
else
next='1';
printf("\nChecksum=%c%s",next, comp);
}
else {
printf("\nInput Lengths do not match");
}
}
test1.bin and test2.bin are two files that contain 8 bytes of binary. I've tried using
printf("this is file 1 %s\n", file1)
printf("this is file 2 %s\n", file2)
to help debug and it outputs
this is file 1 01001001dL
this is file 2 01001000P5L
What is my error here? I'm not great at C so I'm sure its something simple.
You allocate sizeof(ptr1) bytes for file1, but that means the size of the type FILE*, which is likely to be 4. If you know your file contains exactly 8 bytes, do write 8 there.

Building simple unix shell problems

I am new with unix and I've got an assignemnt on college to build a simple shell in c with built in cd and kill command..
This is my code which is not working..tbh I dont understand it the best so Im not suprised it is not working.. can you help me with it? Also have no idea how I would implement kill command. thank you!
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024
const int ARGSIZE = 20;
void execute(char*args[])
{
int pid, status;
pid = fork();
if(pid<0)
{
perror("Error forking!");
}
else if(pid > 0)
{
while(wait(&status) != pid)
continue;
}
else if(pid == 0)
{
if (execvp(args[0], args) == -1)
{
perror("Error");
}
}
}
void cd(char*directory)
{
int ret = 0;
if(directory == '\0')
directory = getenv("HOME");
ret = chdir(directory);
if(ret != 0)
fprintf(stderr,"Failed to enter directory: %s\n",directory);
else
printf("%s\n",directory);
}
int main()
{
char line[BUF_SIZE];
char *args[ARGSIZE];
int argIndex = 0;
while(1){
printf("> ");
fgets(line, BUF_SIZE, stdin);
char *token;
token = strtok(line," ");
while(token!=NULL)
{
args[argIndex]=token;
token = strtok(NULL," ");
argIndex++;
}
args[argIndex]=NULL;
if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
break;
if(line== "\n")
printf("> ");
else if ((strcmp(args[0], "cd") == 0))
cd(args[1]);
else
execute(args);
}
return 0;
}
You were on the right track. There were a few subtle issues where you were not accounting for the trailing '\n' that would remain in line as the last character following whatever was entered at the prompt. Including " \n" in the delimiters used to tokenize the input with strtok will remove it, allowing valid strcmp comparisons with the final token (e.g. that is why quit and exit would not quit the application).
Other than than, there were several additional things you could do a little different/better, you could handle directories entered as e.g. '~/somedir', and similar additional checks that could be employed. I have notated most below as comments to the code.
Look over the changes below and let me know if you have any questions. There are always additional checks that can be added, etc.., but on balance your approach to the problem was pretty good. (note: some of the changes made were non-substantive, e.g. "shell> " as the prompt, instead of "> ". Just handle any of those as you wish.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
enum {ARGSIZE = 20, BUF_SIZE = 1024};
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1) {
argIndex = 0; /* reinitialize variables */
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> "); /* prompt */
if (fgets (line, BUF_SIZE, stdin) == NULL) {
printf ("EOF received\n");
return 0;
}
if (*line == '\n') /* Enter alone */
continue;
token = strtok (line, " \n"); /* add \n to delimiters */
while (token != NULL) {
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex) continue; /* validate at least 1 arg */
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
/* handle 'cd' or 'kill' separately */
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0)) {
if (args[1]) killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0) {
perror ("Error forking!");
return;
}
else if (pid > 0) {
while (wait (&status) != pid)
continue;
}
else if (pid == 0) {
if (execvp (args[0], args) == -1) {
perror ("Error");
}
_exit (EXIT_FAILURE);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory) { /* handle 'cd' */
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~') { /* handle cd ~/stuff */
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory)) /* handle given directory */
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1) {
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
// return kill (pid, sig);
return 0;
}
Sample Usage/Output
$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
killing pid '18004' with signal '15'
shell>
shell> quit

Using libssh library, I have a trouble with ssh_scp_read function

Now I'm trying to download file from server (Linux) to my host (windows).
It looks working well (other functions) but when I'm trying to read file from server. Data in the file is not proper.
for example)
server text file:
A
B
C
D
E
Reading file and saving to buffer:
A
B
C
I checked small size text file. It was working well. However now I'm in trouble because text file is bigger than before.
Here is my code.
int scp_receive(ssh_session session)
{
ssh_scp scp;
int rc;
int size, mode;
char *filename;
char *buffer;
int fd;
scp = ssh_scp_new(session, SSH_SCP_READ, "/home/abc/27");
if (scp == NULL)
{
fprintf(stderr, "Error allocating scp session: %s\n",
ssh_get_error(session)); return SSH_ERROR;
}
rc = ssh_scp_init(scp);
if (rc != SSH_OK)
{
fprintf(stderr, "Error initializing scp session: %s\n",ssh_get_error(session));
ssh_scp_free(scp);
return rc;
}
rc = ssh_scp_pull_request(scp);
if (rc != SSH_SCP_REQUEST_NEWFILE)
{
fprintf(stderr, "Error receiving information about file: %s\n",ssh_get_error(session));
return SSH_ERROR;
}
size = ssh_scp_request_get_size(scp);
std::cout << "size is:" << size << std::endl;
filename = strdup(ssh_scp_request_get_filename(scp));
mode = ssh_scp_request_get_permissions(scp);
printf("Receiving file %s, size %d, permisssions 0%o\n", filename, size, mode);
free(filename);
buffer = (char *)malloc(sizeof(char)*size);
if (buffer == NULL)
{
fprintf(stderr, "Memory allocation error\n");
return SSH_ERROR;
}
ssh_scp_accept_request(scp);
rc = ssh_scp_read(scp, buffer, sizeof(char)*size);
if(rc == SSH_ERROR)
{
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(session));
free(buffer);
return rc;
}
std::cout << buffer << std::endl;
printf("Done\n");
//write(fd, buffer, size);
char path[30];
sprintf(path, "C:/Check/%s", filename);
if (access(path, F_OK) != 0) {
//TODO: file
remove(path);
}
if(0 < (fd=open(path, O_RDWR | O_CREAT | O_TRUNC, mode)))
{
write(fd, buffer, sizeof(char)*size);
close(fd);
}
else
{
std::cerr << "failed to open" << std::endl;
}
free(buffer);
//rc = ssh_scp_pull_request(scp);
//if(rc != SSH_SCP_REQUEST_EOF)
//{
// fprintf(stderr, "Unexpected request: %s\n",ssh_get_error(session));
// return SSH_ERROR;
//}
ssh_scp_close(scp);
ssh_scp_free(scp);
return SSH_OK;
}
The issue here is with the libssh read function. It only reads a max of 65536 bytes at once. It won't read anything large than that block size.
If you take a look at the libssh SCP read function here: http://xtalopt.openmolecules.net/wiki/index.fcgi/browser/src/libssh/scp.c?rev=2b0288492ad2481ee8bdbb8c1f9d5c453a044eee
You will see the size is limited to 65536.
SOLUTION
In your application, you should attempt to read multiple smaller chunks of memory till you finish reading the large text file. And since you have the size of the large text file, this can be done easily via a loop.
I know this is a late answer, but hope this can help someone else having this issue.

dup2 blocking printf, but not fprintf?

so, I have an assignment for my Operating Systems class wherein i am to create a ring of processes connected with pipes in order to pass messages between them. i found some example code which i was looking to adapt (or at least understand) for my needs. the example code (slightly modified) is:
/* Program 4.1 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/* Sample C program for generating a unidirectional ring of processes.Invoke this program
with a command-line arg ument indicating the number of processes on the ring. Communication
is done via pipes that connect the standard output of a process to the standard input of
its successor on the ring. After the ring is created, each process identifies itself with
its process ID and the process ID of its parent. Each process then exits. */
void main(int argc, char *argv[ ])
{
int master_pid = getpid();
printf("master pid: %i\n", master_pid);
int i; /* number of this process (starting with 1) */
int childpid; /* indicates process should spawn another */
int nprocs; /* total number of processes in ring */
int fd[2]; /* file descriptors returned by pipe */
int error; /* return value from dup2 call */
/* check command line for a valid number of processes to generate */
if ( (argc != 2) || ((nprocs = atoi (argv[1])) <= 0) ) {
fprintf (stderr, "Usage: %s nprocs\n", argv[0]);
exit(1);
}
/* connect std input to std output via a pipe */
if (pipe (fd) == -1) {
perror("Could not create pipe");
exit(1);
}
printf("%s\n", "test");
//this section is blocking printf()?
if ((dup2(fd[0], STDIN_FILENO) == -1) ||
(dup2(fd[1], STDOUT_FILENO) == -1)) {
perror("Could not dup pipes");
exit(1);
}
printf("%s\n", "test");
if ((close(fd[0]) == -1) || (close(fd[1]) == -1)) {
perror("Could not close extra descriptors");
exit(1);
}
/* create the remaining processes with their connecting pipes */
for (i = 1; i < nprocs; i++) {
if (pipe (fd) == -1) {
fprintf(stderr,"Could not create pipe %d: %s\n",
i, strerror(errno));
exit(1);
}
if ((childpid = fork()) == -1) {
fprintf(stderr, "Could not create child %d: %s\n",
i, strerror(errno));
exit(1);
}
if (childpid > 0) /* for parent process, reassign stdout */
error = dup2(fd[1], STDOUT_FILENO);
else
error = dup2(fd[0], STDIN_FILENO);
if (error == -1) {
fprintf(stderr, "Could not dup pipes for iteration %d: %s\n",
i, strerror(errno));
exit(1);
}
if ((close(fd[0]) == -1) || (close(fd[1]) == -1)) {
fprintf(stderr, "Could not close extra descriptors %d: %s\n",
i, strerror(errno));
exit(1);
}
if (childpid)
break;
}
/* say hello to the world */
fprintf(stderr,"This is process %d with ID %d and parent id %d\n",
i, (int)getpid(), (int)getppid());
wait(1);
exit (0);
} /* end of main program here */
which outputs:
master pid: 30593
test
This is process 1 with ID 30593 and parent id 30286
This is process 2 with ID 30594 and parent id 30593
when i give is 2 as argv[1]
so, I'm wondering, why would the dup2 section prevent the printf() from executing? if i cant even print something, i'm not sure if i could even pass the message correctly. also, why would the fprintf() already there work, but not one that i would put there?
edit: i would take this to my professor/TA, but theyre both out of town and will be unreachable between now and the deadline...
printf prints to stdout, which is file descriptor 1 (or equivalently STDOUT_FILENO). dup2(3) is duplicating the pipe's file descriptor on top of the current stdout, which has the side effect of closing the current stdout. So, when you try to printf after calling that particular dup2, you're really printing the data into the pipe you just created, which doesn't go to your terminal output.
fprintf(stderr, ...) still works because that prints to stderr, not stdout, and the stderr file descriptor (2, or equivalently STDERR_FILENO) does not change during the program, so it continues to print out to the terminal.
printf() does not send data to path 0, it sends buffered data using stdout. It would seem that when you disrupt path 0 by dup2'ing something to it, you're disrupting stdout in the process.
From the man page on dup2: dup2() makes newfd be the copy of oldfd, closing newfd first if necessary. Thus when you call dup2(fd[0], STDIN_FILENO) you are breaking stdout.
You state that fprintf() is working but printf() is not... what path are you using for fprintf()? If you're using stderr then it makes perfect sense that it would continue to work, since you haven't done anything with that path.

GNUPG how to encrypt file without it's original extension in the name?

I need to automatically encrypt file e.g. myfile.xls to myfile.gpg.
Now when I'm trying to encrypt it automatically or with GNU privacy assistent, the encrypted file is myfile.xls.gpg. When I delete that .xls, it has no extension after decrypting.
Thank you.
That gpgencrypt.c option looks like far too much effort.
To encrypt do this:
gpg -er $recipient_id -o myfile.gpg myfile.xls
To decrypt and restore the original filename do this:
gpg --use-embedded-filename -d myfile.gpg
That name has been encrypted and is stored with the encrypted data. That flag tells GPG to use the original filename instead of creating a new filename based on the name of the encrypted file.
This could be done easily with a simple C app that controls the output. The below file can do what you are looking for, you just need to compile it (linked against libgpgme) and then pass it the input file, the desired output file and the key-ids to use for encryption.
To compile using gcc, simply save the code below as gpgencrypt.c, and compile with gcc gpgencrypt.c -lgpgme -o gpgencrypt. (you need libgpgme installed)
The invocation syntax is gpgencrypt <input file> <output file> <encrypt to>. i.e. gpgencrypt myfile.xls myfile.gpg 01234567 12345678
file: gpgencrypt.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <gpgme.h>
#define fail_if_err(err) \
do { \
if (err) { \
fprintf (stderr, "%s:%d: %s: %s\n", \
__FILE__, __LINE__, gpgme_strsource (err), \
gpgme_strerror (err)); \
exit (1); \
} \
} \
while (0)
typedef char * string;
void gpgEncrypt(const char *fileToEncrypt, const char *outputFileName,
char *encryptTo[],
int encryptToLength) {
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_data_t in, out;
gpgme_encrypt_result_t enc_result;
FILE *outputFile;
gpgme_key_t keys[encryptToLength];
int nrecipients = 0;
int BUF_SIZE = 512;
char buf[BUF_SIZE + 1];
int ret;
/* Begin setup of GPGME */
gpgme_check_version (NULL);
setlocale (LC_ALL, "");
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
#ifndef HAVE_W32_SYSTEM
gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
#endif
/* End setup of GPGME */
// Create the GPGME Context
err = gpgme_new (&ctx);
// Error handling
fail_if_err (err);
// Set the context to textmode
gpgme_set_textmode (ctx, 1);
// Enable ASCII armor on the context
gpgme_set_armor (ctx, 1);
// Create a data object pointing to the input file
err = gpgme_data_new_from_file (&in, fileToEncrypt, 1);
// Error handling
fail_if_err (err);
// Create a data object pointing to the out buffer
err = gpgme_data_new (&out);
// Error handling
fail_if_err (err);
// Retrieve the keys used to encrypt to
for (nrecipients=0; nrecipients < encryptToLength; nrecipients++) {
printf("Retrieving key: %s, %i of %i\n", encryptTo[nrecipients], nrecipients, encryptToLength);
err = gpgme_get_key (ctx, encryptTo[nrecipients], &keys[nrecipients], 0);
if(err != GPG_ERR_NO_ERROR)
printf("error");
}
// NULL terminate the key array
keys[nrecipients] = NULL;
// Encrypt the contents of "in" using the defined mode and place it into "out"
err = gpgme_op_encrypt (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
// Error handling
fail_if_err (err);
// Retrieve the encrypt result from the context
enc_result = gpgme_op_encrypt_result (ctx);
// Check for invalid recipients
if (enc_result->invalid_recipients) {
fail_if_err (err);
}
// Open the output file
outputFile = fopen (outputFileName, "w+");
// Rewind the "out" data object
ret = gpgme_data_seek (out, 0, SEEK_SET);
// Error handling
if (ret)
fail_if_err (gpgme_err_code_from_errno (errno));
// Read the contents of "out" and place it into buf
while ((ret = gpgme_data_read (out, buf, BUF_SIZE)) > 0) {
// Write the contents of "buf" to "outputFile"
fwrite (buf, ret, 1, outputFile);
}
// Error handling
if (ret < 0)
fail_if_err (gpgme_err_code_from_errno (errno));
// Close "outputFile"
fclose(outputFile);
// Unreference the key objects
for (nrecipients=0; nrecipients < sizeof(&keys) / sizeof(int) + 1; nrecipients++) {
if (keys[nrecipients]) {
printf ("Releasing key: %s\n", keys[nrecipients]->subkeys->fpr);
gpgme_key_unref (keys[nrecipients]);
}
}
// Release the "in" data object
gpgme_data_release (in);
// Release the "out" data object
gpgme_data_release (out);
// Release the context
gpgme_release (ctx);
}
int
main (int argc, char **argv) {
if (argc < 4) {
printf ("Usage: gpgencrypt <input file> <output file> <encrypt to>\n");
exit (1);
}
int pos, n;
string encryptToList[argc - 4];
printf ("Encrypting %s and placing the result into %s\n",
argv[1], argv[2]);
for (pos=3; pos < argc; pos++) {
encryptToList[n] = argv[pos];
n++;
}
gpgEncrypt (argv[1], argv[2], encryptToList, argc - 3);
return 0;
}

Resources