CSCI2467 – Lecture 18. Shell Lab: Intro + Trace 01
Video Title: CSCI2467 – Lecture 18. Shell Lab: Intro + Trace 01
Ted Holmberg: Okay, welcome to the class. This is gonna be a video recording. Considering that this is a Halloween week. And I don’t suppose that you all wanna be spending Halloween evening inside of lecture. So we will do a entirely video recorded lecture. So in this lecture I want to introduce the new lab that we’re gonna explore.
We’re gonna move on to the shell lab where we’re gonna write our own unix shell. And so I’m gonna spend this lecture to really kind of motivate and preface the idea Ted Holmberg: on how we’re going to to do this. Excuse me, just a moment. Ted Holmberg: 37.
Ted Holmberg: How’s your heck out. Unplugged. Okay. Ted Holmberg: so this is, I think, one of the most quintessential labs that we’ll cover over the semester, and it’ll probably be
Ted Holmberg: We’ll probably go over a couple semesters of of working through it and kind of defining it. And of course this lab, like the other labs, is going to be group based team based. So
Ted Holmberg: try to work in groups. Talk about issues you might have. We’ll talk more about that in this upcoming slides.
Ted Holmberg: Okay, so let’s just do an introduction to our Sis shell lab. So the purposes of this assignment is for you to gain a hands-on understanding of how unix shells function and also to implement a basic shell program which we’ll call TSH. Tish, just effectively meaning tiny shell and C that can execute commands, handle process, control, and manage jobs so as opposed to
Ted Holmberg: boring you with the contents of the book, I’m going to depend on you to read the book to facilitate your ability to go ahead and do this lab, and we’ll kind of walk through this lab and in our lecture time. So the big key concepts that are going to be important, that we’re going to cover
Ted Holmberg: that are again in the book. But we’ll kind of briefly discuss some slides that you’ll need to know to be effective at this lab. The shell lab are gonna be processes. So processes are an instance of a program and execution. It’s the basic unit of computation in our unix environment.
Ted Holmberg: Of course, the purpose of a process is, it allows us to separate the execution of different programs and provide a concurrent execution. Other key concepts. The concept of forking or fork. So a system call is the fork system calls used to create a new process, which is then called a child process that runs concurrently with the process that made the fork which we will then call the parent process.
Ted Holmberg: So an example of how we might make a fork is we can make a system call fork. And that’s gonna create a process. It’s gonna return to us a process. Id and so the importance of forking is, it’s going to be critical for creating new processes in a shell.
Ted Holmberg: And so this is this is a concept that’s really gonna be what this this lab targets. So let’s move on to the concept of these parent and child processes. The relationship here is that when we have a new process, it’s created with fork. The original process is the parent, the new processes, the child. And then you have the ability to communicate. Typically a parent child can communicate through pipes and signals.
Ted Holmberg: So signalling will define that as a way to deliver asynchronous notifications to a process in order to evoke event driven actions right? Because we don’t know how long ahead of time the child processes are gonna take to run. There’s needs to be a way to update the parent process to know. Oh, I’m done working. And then these are just some common signals. We have the aliases here, and we’ll cover them more as we go deeper into this slide deck and then we have
Ted Holmberg: how we might use these signals is in the the kill method or function that we’re looking at here, where you can pass a process. Id and a particular type of signal on this particular signal will then send an interrupt signal and actually kill that particular process.
Ted Holmberg: And then you have I/O redirection, which is another important concept. This allows us to alter the standard input output flow of our program. Of course, the purpose of this is allows a program to read input from a file or send output to a file
Ted Holmberg: instead of to the terminal. And so these are very useful for taking what would normally be terminal display messages, or input that you’re you’re pulling through from your keyboard and redirecting it to an input to an input follow or an output file so that you can use it to diff against, or you can use it to go and automate the task of providing an input into your application.
Ted Holmberg: Of course, we’re gonna be writing our shell code inside of the C programming language. And of course, the C language is pretty much embrace that system level programming due to its close to hardware abstraction and our ability to have both that high level capability of modeling, and then that ability to drop into that that lower level
Ted Holmberg: methodology of building our our assembly code, or how we could reverse engineer and see how our Assembly code can then, effectively get
Ted Holmberg: compiled down into. And then our code structures. So you’ll be writing the C functions that handle various shell functionalities. But you’re gonna be giving boilerplate code. And we’re gonna take a look at what that boiler play code is in just a moment. So in terms of sections for reference in this particular slide deck section 3 is gonna provide some more background information on how shells work and what they do and the common shell functionalities that you’re gonna be concerned about. And then, section 4,
Ted Holmberg: we’ll talk about the details of the specific text to be implemented. The lab assignment, including being able to parse our commands, create processes and implement job controls. Now, you’re gonna have some helper functions that are gonna be pre implemented for you. There’s gonna be some stuff functions that you’re gonna have to go ahead and implement throughout the lab. That’s my intent to go ahead and do kind of a walkthrough of this process. So you have some kind of guide to follow along.
Ted Holmberg: So in terms of the logistics of the shell lab. Ted Holmberg: as I stated earlier, we’re going to do a collaborative approach. Ted Holmberg: And so
Ted Holmberg: what that’s really going to mean is this is going to be a collaborative project where I want the students to work in groups of your own making.
Ted Holmberg: To encourage collaboration and to allow you to collectively problem solve on these issues. So you’re not stuck, having to figure out all on your own. And so, despite the collaborative nature that I really want you to abide by, I also
Ted Holmberg: feel that it’s each of your responsibilities to understand the entire project. So as you work in a group, I don’t want one person to carry or just share code. You set up group discussions to ensure that each member is capable of explaining and implementing every part of the shelf
Ted Holmberg: that way. Everyone comes away with the same sets of knowledge is now one of the most critical
Ted Holmberg: tools for this project is, gonna be your textbook that you have a computer systems, a programmers perspective. So definitely use that book. In fact, you might have to look up in certain chapters that book which I’ll go ahead and give you reference to in a moment
Ted Holmberg: on how to actually solve these, the book examples will actually show you how to solve some of these problems in addition to what we’ll cover in some of these slide decks. And so when you do use the book which everyone should do, go ahead and cite where in the book, when you find your solution, you have sourced it from, and then, in terms of submissions, we’ll cover this a little bit more in detail in the future. But I’ll just add iterate that even though this is a group project. Each student has to submit their own
Ted Holmberg: work, their their own code. C code file to auto lab because everyone obviously gets individually graded Ted Holmberg: and that gets tracked through auto lab. Ted Holmberg: Okay? So
Ted Holmberg: a few more things that we should kind of emphasize before moving over. There are going to be trace examples, and we’ll see more of this when we actually kind of download the files and examine them. But these trace examples are, gonna provide what must be executed. And you should understand
Ted Holmberg: what’s happening. With these trace examples, each of the trace examples. These are the things that are worth the individual points that culminate into the total amounts of points that you get, that you end up coming away with for this. So
Ted Holmberg: for this lab, so each student obviously should be able to demonstrate how each trace example executes and interacts with their implementation like. So you should feel confident that you can go from trace one all the way through. Trace 16 and understand what your shell needs to do to pass those tests, and we’ll talk more about that when we’ll come to the verifying your shell implementation.
Ted Holmberg: And one way to do this is just to kind of sync up and constantly be in communication with your team dissect the trace examples, talk about them, and show what parts of the shell kind of match up to what that task is. Now there is a single deadline. So I’m mainly gonna use the Pdf documentation as well. The Pdf. Documentation state some things that I’m not going to take into account
Ted Holmberg: like I do want. Group based projects. I’m also only gonna have a singular deadline for this project where you you don’t get like deduced points for not meeting the first deadline but because there is a single deadline definitely manage your time. Make sure you do your regular check-ins with your group. Make sure that you’re making progress cause. This is probably one of the largest labs that we have inside this class
Ted Holmberg: and course. Each group member should be able to Ted Holmberg: participate in that. Ted Holmberg: Okay, so let’s see here.
Ted Holmberg: So in order to go ahead and start your shell lab journey, the first thing you need to do is the initial setup. And so you can go to auto lab to initially get your shell lab dash handout dot tar file. And I was having some issues getting this uploaded on auto lab. So it might actually be sh lab
Ted Holmberg: or shell lab, dash, dash, handout, tar.
Ted Holmberg: So just keep that in mind when you follow the instructions to be able to go ahead and download and and go ahead and untar it. But of course, the process by which you will untar. This is gonna be very similar to what we’ve done in our other labs. And, in fact, I’ll take a moment here to go over and do this process. So I’m gonna jump to my applications. Gonna go to the Internet here, gonna go to my chromium browser.
Ted Holmberg: I’m gonna Ted Holmberg: I’m already in auto lab. But here I’ll even type out and go to auto lab. So it brings me to the home screen. Here I’m gonna scroll down to. I can either go to Shell Lab and I’ll just do that shell lab here
Ted Holmberg: and then inside of Shell Lab. I have this ability to get this handout. So I’m going to go ahead and request that handout. And there it is. And notice, yeah, there’s the the 2 underscores on this particular one kind of did something goofy there. Ted Holmberg: Okay, so let me
Ted Holmberg: close out of this. Ted Holmberg: And so I’m gonna go to my downloads folder here. Ted Holmberg: And so inside of my downloads folder is going to be
Ted Holmberg: my the lab. So here I’ll go into 2467. I made a shell lab Directory already. There’s nothing in there, so I’ll just go ahead and move that in here, and this will be my workspace, and I’ll go ahead and untar that, and I’ll be very bad and just use the Gui
Ted Holmberg: instead of the command line, because, it’s much more interesting on a on a video.
Ted Holmberg: Okay, there we go. Okay. So now let’s open up our to our terminal. And so now, if I go and ls. I’m gonna see all these files in there and effects, if I open it to here. We can see also a graphical depiction of all this
Ted Holmberg: excellent. Okay? So that’s how you’re going to get all your starter files.
Ted Holmberg: Okay. So eventually, we’re also going to go ahead and run, make inside of this directory to make some of the utility applications that’s gonna allow us to be able to test our shell out. We will look at that in just a few moments, and, in fact, let’s see what the readme document on here says
Ted Holmberg: so I’ll we have. Let’s do this cat grade main. I don’t know. Ted Holmberg: Read me. and there we go. We have
Ted Holmberg: the readme on the shell lab, all the files and the description of what each of the files are. So we can say, we have a Mag file which is, gonna compile your shell program and run the test. We have this, read me, file, which is what we’re reading. We have the th the the tiny shell
Ted Holmberg: code, which is a boilerplate code. This is gonna be the shell program that you’re gonna write and have to hand in is what you’re gonna get. Get a grade on. You’re gonna have a tiny shell reference. So this is a binary file. You don’t have the source code, for this is a binary file that’s given to you that will execute inside of this systems lab environment. And so you can actually compare the output from the reference shell
Ted Holmberg: to the code that you go ahead and produce. And so the way you get points is that your code? Your tiny shell, has to have all the same outputs and behaviors as the reference. Tiny shell.
Ted Holmberg: Okay? So the remaining files are gonna be used to test your shell. So we have our shell driver, dot perl script. This is going to do all the trace driven shell drivers. So when we look at what these traces are, we’re gonna understand how what gets fed into them. What is our test harness is this application here? And we will actually be able to, alias, use an alias inside of our make to be able to use that quite easily.
Ted Holmberg: We have some text files which effectively gonna be our test configuration files which are gonna feed instructions to our our shell driver script, and so we’ll take a look at that in a moment, too. We have our tshell out, which is the example output of the reference shell on all of the 15 traces
Ted Holmberg: we have, then some little C utility programs are going to be called, buy our trace files in order to perform the testing. So we have, like my spin, which takes an argument and and spends for N number of seconds we have my split, which forks a child that spins for N number of seconds. We have my stop, which spends for N seconds and sends a
Ted Holmberg: a signal Ted Holmberg: to to itself. And then we’ll have my Ted Holmberg: and sort for enter all that spins for 10 s and sends a signal Ted Holmberg: to itself. In this case it’s the stop signal. In the other case it’s an interrupt signal.
Ted Holmberg: Okay? So with that said. let’s talk a little bit about understanding what is a unix shell. Let’s kind of give a motivation and a preface to this. What is this? Show? Well, unix shell is an interactive command line interpreter
Ted Holmberg: that acts as an interface between the user and the operating system.
Ted Holmberg: So its function is, it allows us to interpret commands entered by the user. That’s us and run programs accordingly, and of course shells. But we’ll look at this in a moment. But shells have built-in commands, but they also have the ability to launch external applications or programs as well.
Ted Holmberg: So
Ted Holmberg: let’s go deeper into this and talk a little bit about a command line interface. Whenever we talk about a command line. We’re talking about a sequence of Ascii tax words effectively. as input by the user which the cell reads or parses into standard. Input so that’s our standard. And it typically consists of common commands followed by arguments.
Ted Holmberg: And so your arguments will usually be like, have some kind of symbol to to state that as an argument like a dash, and then a particular letter, or it could even be a full word, and usually all of the
Ted Holmberg: The tokens inside of our command line is delimited with white space. So commands typically start with the program name or a building command for the shell, followed by the arguments that modify the behavior of that particular command, or that program that you’re looking to launch from your shell.
Ted Holmberg: So the built in commands versus executable programs. So it’s kind of take just a moment just to to pay
Ted Holmberg: respect to that our built in commands would be, say, for instance, like the command jobs are executed directly within the shell itself quits another one. If that’s gonna be the first one that we’re going to implement that we’re gonna actually implement that one inside of this this lecture today. Other commands specify the path to an executable which tells the shell where to go to
Ted Holmberg: get the application, then to launch it, creating a new process. Ted Holmberg: So let’s talk about jobs and process groups. A job is a set of processes that are started by a single command line and can be controlled together
Ted Holmberg: so jobs can be run in the foreground where the shell waits for the job to finish before taking another next command, or it can also run in the background where the share shell immediately returns to the prompt. After starting the job, and that prompt runs in the background, and we are not delayed. So let’s talk a little bit more about foreground versus background jobs. So foreground job by def is the one that is usually used by default. A command
Ted Holmberg: commands run in the background by default.
Ted Holmberg: That’s a really word, assented. Sorry. But it just means that the shell waits for the job to finish before accepting any new input whereas background jobs, we can make a job background by pending an Ampersand to our command line when we run it, and that’ll make it a background job, and then allows the shell to accept new commands immediately without having to wait for that job to complete. So just to give you an instance of what that looks like
Ted Holmberg: foreground versus background. I have this instance where we’re calling Ls kind of list, all of your directories.
Ted Holmberg: And so we we have our command. We have our argument. That’s gonna modify the behavior on our command, the dash, l, and the dash d and notice, since we do not go ahead and follow it up with a with an ampersand that’s gonna run the foreground. So we’re gonna have to wait for it to produce a result before we can do anything else, whereas the second variant all the same command, we just have the addition of the Ampersand which now runs it in the background.
Ted Holmberg: So let’s talk a little bit about job control. So Job control refers to the ability to move jobs between the background and foreground and to change their states. Now, typically, you have the states of a running job, a stop job and a terminated job commands for job control include dg, to continue a job in the background and fg, to move a job to the foreground, so you can. You can move them back and forth as necessary.
Ted Holmberg: Let’s talk a little bit about the signals. Signals are a form of software interrupts. And when I say, software interrupts, what I really mean to intend to say is, it’s a form of an inner process communication, so that one process can effectively talk to another process within our shell. To send a process to perform some kind of specific action
Ted Holmberg: so these actions are then encoded inside of these signals. So like we said, we had segant, which is an interrupt signal typically that can be sent. If we do that control C combo on our keyboard, and so that can terminate the foreground job. We also have the
Ted Holmberg: the Sig Tstp, which is a stop signal, typically sent when we do control, Z is press and that stops the foreground job until it’s continued with a Sig count or Sig continue continue signal. Ted Holmberg: Let’s talk a little bit about the process group work around.
Ted Holmberg: So when a shell script runs, it’s part of the foreground process group. Any child process created inherits this group by default. So if you want to prevent a signal from affecting both the shell and it’s child processes incorrectly, a child process should change its process or group using a set
Ted Holmberg: PG, id, so pg, short for process group, so set process group id, and then you can pass it. These parameters. Okay? So some critical concepts to highlight for you, the shell’s ability to control jobs is crucial for multitasking and managing multiple processes efficiently and understanding the signals and their default actions is pretty vital for writing robust shell programs and handle your user interrupts gracefully.
Ted Holmberg: Okay, so let’s give specifications on what you’re actually gonna be doing
Ted Holmberg: for tiny shell. So we will have a prompt string. And so the shell prompts should display a effectively a message, tiny shell, and then it’s waiting for you, the user to supply it with a a string of tokens that it can parse and then do something in response to that to signal redness for the user.
Ted Holmberg: Okay, so once we get past. Ted Holmberg: so once we get to the point where you’ve we’re able to prompt the the tiny shell. Then you have your command line interpretation where commands entered by the user consists of a program name, or a built-in command.
Ted Holmberg: followed by arguments separated by spaces. And if, if the inner command is not a built in, then our tiny cell should treat it as a path to an executable and run it as a new process termed a job.
Ted Holmberg: And then we should also support input output directions. So our tiny shell must allow redirection of program output using the greater than less than symbols where the the greater than is for redirection on input, and the less than is for redirection on output. Just some use cases which you’ve probably already seen, either throughout this semester on prior classes, on how we use redirects on at the command line up.
Ted Holmberg: Okay, so more information about the specifications for our tiny shell. We need to be able to also support job control signals. So if you do control C, it should send an interrupt signal to terminate the current foreground job, and if you hit control Z. It should send a stop signal to stop the current foreground job until it’s continued with a continue signal.
Ted Holmberg: So it should support also your background versus foreground jobs. So if a command ends with an Ampersand, your tiny cell should execute it as a background job along the prompt to return immediately without the Ampersand. The job is run by default in the foreground, so the shelf would then wait for its completion before returning to the prompt.
Ted Holmberg: We have to support job identification jobs can be identified by a process Id, which we’ll call a pid or a job Id, which we’ll call a jid within our tiny shell jids. Ted Holmberg: Our job ids are denoted with a percent sign on the command line.
Ted Holmberg: So, for instance, percent 5 would represent a jig, 5 built in commands that we will have to have support in our tiny shell is going to be quit which allows us to exit the shell the jobs command. That’s gonna list, all of our background jobs, the bg, and then a job id, which continues a stop job in the background, or the FFG. Job, which moves the job to the foreground and continues, if it if it stop.
Ted Holmberg: we’re going to have to be able to handle weeping zombie processes, so our tiny shell must handle terminated jobs that have not been waited on by the parent Ted Holmberg: known as zombies. It should print a message. If a job terminates unexpectedly, due to an uncaught signal.
Ted Holmberg: We need to have the following function implementation. So these functions are stubs inside of our tiny shell. But they’re not actually have any meaningful behaviors defined, or or really co-described to them. So you’ll have the eval function which is responsible for parsing and executing your command line. You’ll have a built in
Ted Holmberg: command or a Cmd function which is gonna handle our built in command, or that that do things with our shell such as quit, or the fg, or the bg, or the jobs functions or or built in commands that we talked about earlier. We’ll have the Do bg, fg. Function which implements the functionality of Bg and Fg commands, and then wait. Fg, which ensures that the shell waits for the foreground job to complete
Ted Holmberg: before moving on to the next task by printing out the next prompt Ted Holmberg: message.
Ted Holmberg: and then also, we’re gonna be responsible for ensuring that there are signal handlers. So you’re gonna have your sig child handler, which deals with Terminator. Stop, child, processes. You’ll have your signal interrupt handler which handles your sig in signals, and you’ll have your sig stop handler, which handles your stop signal events.
Ted Holmberg: So as you’re implementing this.
Ted Holmberg: how are you gonna validate your tiny shell. How do you know if you’ve implemented it right? Well, you’re gonna have tools available for testing? That’s why we have so much files as part of this starter set. So for you, the tools for testing is you’ll have a reference solution, which is our tiny shell ref.
Ted Holmberg: Is it going to be a Linux executable. That acts as the reference behavior for your show.
Ted Holmberg: So you’re not giving the source code to this. But you are getting a executable that you can launch from the command line, and you can feed it. The instructions. You can even run the the tester harness on this and send traces to that, and we’ll actually look at that over the course of this particular lecture.
Ted Holmberg: You’ll also have the shell driver script. That’s the Sdriver pl, that’s a perl script a program that runs your shell with specified inputs and checks for the correct output. Ted Holmberg: So you’ll use the shell driver. So the shell driver runs.
Ted Holmberg: our tiny shell could also run our our tiny shell reference as a child process. And it’s gonna sync commands and signals based off with the trace file. It’s going to capture the output from our shell then, and allow you to compare it against expected results.
Ted Holmberg: So these trace files are what we’re really gonna use to evaluate and validate and verify your tiny shells. So the trace files provide predetermined sets of inputs and outputs for testing your shell, and the lower number traces are simpler, while obviously the higher number traces are going to be much more complex.
Ted Holmberg: So Ted Holmberg: let’s talk about the testing procedure for being able to actually test your tiny shell while you’re implementing it. You’re gonna want to run yourself using the trace file using a command line such as so we’re launching from the command line. The
Ted Holmberg: S. Driver, the shell driver script. Ted Holmberg: and we’re gonna give it a a particular trace file that you want to evaluate. So you put dash, t, and then trace in this instance. That would be the first trace file. Ted Holmberg: and then you want to give it the the arguments
Ted Holmberg: on being able to go ahead, and what you’re launching. So in this instance, we want the shell that we’re launching to be our tiny shell, whereas if we wanted to compare to the reference shell, we would give it the reference shell. So notice this part in both these instances on whether we’re running the test script to the the test partners on our own implementation versus the reference implementations. The same
Ted Holmberg: right? It’s just this argument on whether it is our tiny shell versus the tiny shell references. What’s gonna change? And then this latter part the dash a. And then inside of the string dash, P is going to emit the prompts. So we don’t see that when it goes and runs the testing.
Ted Holmberg: so we just get the the output. Now, there’s a much easier way than to run our our test procedures than having this big, long command Ted Holmberg: that launches again the application and the series of of
Ted Holmberg: inputs that you’re gonna require for to launch. We have these aliases where you just do make. And then Ted Holmberg: if it’s trace one you want, then test 0 one test 0 2 test 0 3, and that’ll automatically.
Ted Holmberg: effectively, effectively. Alias, this line to run the test on, trace one, or trace 2 or trace rate on your tiny shell. And if you make our task, or for reference, test 0 1 0, 2, or whatever trace number you’re actually on. That’ll go ahead and run that test harness on the reference again. What we’re gonna see is that you want your
Ted Holmberg: output to match the output from the reference. That’s what’s actually going to initiate your points.
Ted Holmberg: So your shells output should match the reference solution. With the exceptional process. Ids, right? Those are always gonna differ because those are gonna be unique. So your auto lab will grade your. And so you’re gonna supply. You’re gonna submit your tiny shell dot C file. That’s the one that you’re gonna be encoding. And
Ted Holmberg: and you’ll you’ll get points based off of the Max number of trace fires. So this says it’s 20 trace files, but I have to double, check and verify if 20 is the actual number. But just know you get 2 points per trace. 5
Ted Holmberg: that that is there, and then your full number of points is whatever the maximum number of trace files are. Ted Holmberg: Now, if you want to check the deference Ted Holmberg: to compare your output with the reference, we can go ahead and just do a diff
Ted Holmberg: command inside of our standard shell the shell that you’re going to be using on your tiny shell, and you can call that make. Say, for instance, this is on, make test. O, so 0 7. So this would be, trace 7 on your own implementation for tiny shell. This would compare it to the output
Ted Holmberg: from the make on the. So what we’re doing is we’re doing a redirect. So the parentheses prioritizes this operation. So it’s going to wait for this to resolve to Ted Holmberg: get the output
Ted Holmberg: the standard out, and then that standard out will then be redirected into the diff application. This utility application inside of our shell. And so this takes 2 parameters where it’s normally 2 text files that is comparing the dip between. Well, this will generate effectively to
Ted Holmberg: text files, redirect them all. The output actually from our standard Admin source standard in here onto our desk so that we can then go ahead and look at the discrepancies without actually having to save the output into files to do the default.
Ted Holmberg: And then another alternative way that you can go ahead and check is just to run this script. Check tiny shell script. It’s a python script, and that will do a preliminary check on all your tasks, and will notify you of any failures, and gives you what your score will be, it’ll actually give you the culmination, the summation of all possible points you can get.
Ted Holmberg: Of course, once you’re ready to submit, you do have to submit your tiny shell code onto auto lab. And that’s where you will get your official grading. So everything up to that point is just allows you to evaluate, to see what where you’re at in terms of your own grading.
Ted Holmberg: and just some tips for effective testing, always at your work after making any changes and utilize the reference solution from the tiny shell reference just to clarify any uncertainties you might have.
Ted Holmberg: But you’re given all the tools you need to test. Now let’s give you some hints and tips that’ll be
Ted Holmberg: that will help you along this journey of implementing a shell. So first of all recommended reading actually should be required. Reading this lab heavily pulls from chapter 8 of the textbook, so learn that chapter very well
Ted Holmberg: exceptional control flow. Read it closely for examples and concepts on control flow in unix systems. And while you can use code excerpts from the textbooks, please make sure to cite and explain them inside of your source code. So to guarantee that you have a strong understanding of what’s happening so that you’re not just copying pasting code. But you’re getting an appreciation of how shells are actually implemented
Ted Holmberg: now, for in terms of implementing shelf features, I/O redirections and signal handling. So we’ll talk more about that, obviously in in class.
Ted Holmberg: and we’ll try to do a walkthrough to try to show you how to do some of these traces. So that is what my goal is for these next remaining lectures until we get to the end of this lab, and the Trans files are also going to be a very critical asset to you. You’ll you’ll use those as your step-by-step guide to ensure that your sales output matches the reference
Ted Holmberg: starting with trace one and moving until you run out of trace files, because then you’ve accumulated all your points. Then Ted Holmberg: on just some important functions you should be aware of would be like, wait, pid. Ted Holmberg: the the kill function, the fork function, the Ted Holmberg: EXEC, VEV,
Ted Holmberg: the set, pg, id, and the same prog mask functions are all gonna be ones that Ted Holmberg: are free. They’re given to you. They’re ones that you can call from the system. But they’re going to be crucial for your shells functionality, and
Ted Holmberg: when it comes to options with weight. Pid, you might want to look at these particular options as well.
Ted Holmberg: so the W. Untraced and the W. No hang options are going to be ones that you want to look into, and we’ll talk more about that as we get deeper and deeper into this particular lab.
Ted Holmberg: Now, in terms of signal handlers, you want to ensure that you send signals like Sig int. And Sig data. Stop Ted Holmberg: to the entire foreground process
Ted Holmberg: group with the correct syntax using the kill function. Consider how you divide responsibilities between your wait fg, and your signal child handler functions to possibly use a busy loop and a single call to a pid.
Ted Holmberg: So in terms of just some hints for your process groups. You set pg, id, like we said earlier, just to place a child process in its own process group, preventing it from being interrupted by signals, I mean for the shell, and ensure that the child unblocks the Sig child signal before executing new program to prevent any kind of race conditions
Ted Holmberg: do debug with the debugger? Right? So if, for instance, you encounter a segmentation fault, the debugger can help identify the exact line of C code that causes the issue. If you run your shell with the debugger, input commands that cause the crash. You can use the debugger to to examine that.
Ted Holmberg: And just some practical examples. You know, debugging examples. We’ll look at inside these lectures and just the signal handling
Ted Holmberg: in terms of how you will be scored. It’s just 2 points per trace file. II think some of the trace files were actually eliminated. I think maybe the the oh, and we’ll see when this is submitted.
Ted Holmberg: But I don’t think that there’s actually 20 trace files total. So let’s just be the sum of however many trace files there are.
Ted Holmberg: But do comment your code, because that’s really gonna be the more interesting thing, especially since we’re gonna be stepping through a lot of this lab inside of our lecture time. So I just wanna ensure that everyone has strong understandings as to what’s being implemented inside your tiny shell.
Ted Holmberg: And of course you can also test with auto lab simply by submitting it and waiting for it to run its score. I might take a few minutes to do that, and then it’ll go ahead and give you the response. And just like all the other labs, you can spend multiple times and check your result, and you’ll get whatever the most recent submission value is as your score. And of course you can always just run that check
Te tiny shell python script, because that’s effectively what’s going to be running in auto lab as well. That’s what’s going to be evaluating to see and give you and grant you your points for this lab. Ted Holmberg: Okay? So let’s talk a little bit more about the tiny shell reference.
Ted Holmberg: Code that we’re gonna give to you the application we’re gonna give to you. So the TSTS. H. Raf
Ted Holmberg: is gonna act as your benchmark to show the expected outcomes when executing commands in our unix shell. So we’re gonna utilize our tiny shell left to validate the accuracy of our own shell implementation by comparing the behaviors.
Ted Holmberg: So here, why don’t we go ahead and take a look at this? So let me jump over here and let’s clear
Ted Holmberg: this terminal here. Okay, so again, when I look at this, I see. Oh, yeah, look at this. I have a couple of executable files. I have lots of text files. We’re going to kind of examine a couple of these. The
Ted Holmberg: one executable, viable, executable file is my tiny shell, Raf.
Ted Holmberg: And, as I said before, I don’t have the source code for that. But I can. I can. I can launch that. And so I’m gonna launch that and play around to get an idea of what my shell should be capable of. Then I have my testing applications. So my shell driver application is gonna be what allows me to go ahead and kind of launch using all of these traces, and these are the traces out. We do. I see all 20 of these traces.
Ted Holmberg: So then we we will have 20 traces that you have to get through. Each is worth 2 points. So the slide is worth 40 points total. and then we also have our
Ted Holmberg: our check tiny shell here as well, which will run and do an accumulation of all the possible points that you have for all 20 of your traces.
Ted Holmberg: Okay. So if I want to start my tiny shell right. This is going to be the command I can use to launch it from my command line. So let’s go ahead and do that.
Ted Holmberg: Let’s kind of let’s clear first. and let’s do launch. Okay. So once we launch notice, we’re given the the prompt TSH. To say, Hey, I’m aware I’m alert. And I was waiting for the user to supply a command. Ted Holmberg: blind Ted Holmberg: string effectively to to the system standard, input
Ted Holmberg: so that it can parse it and do something interesting. So now, one thing to keep in mind is that it’s not gonna use relative path to give complete path to some of the applications you want to run. So say, for instance, if we want to run the Ls application, the command line utility. We would have to go ahead and give it the full path. So slash, bin slash ls.
Ted Holmberg: and there we go. We could see I can go ahead and evaluate and Ted Holmberg: get all of the files and directories inside my current directory.
Ted Holmberg: I should also be able to do that with any kind of additional augmentation parameters, such as being able to try to include permissions or ownership or timestamp. So I should be able to parse that right? So let’s do this again. So Ben
Ted Holmberg: Ls dash L, and there we go. We could see we get same output in our tiny shell application that we should get from our bash shell or Z shell, or whatever you might be using.
Ted Holmberg: We should be able to check the process status. So this is gonna show. The current process is running in the system. Let’s take a look at this. Ted Holmberg: Here. We can see our processes right now. All the processes we have are PPS.
Ted Holmberg: Our tiny shell reference and bash. and
Ted Holmberg: we can also go ahead and do a background execution. And here we can call the the sleep application is gonna put the sleep command to run the background for 3 s. So this is a numerical number of seconds of time. We will sleep. And we’re gonna put that in the if if we do that as a background, notice what’s gonna happen.
Ted Holmberg: Actually, let’s do it like this. Ted Holmberg: Let’s do this first Ted Holmberg: notice here. If we do that. We waited 3 s Ted Holmberg: before I was able to feed another command into my shell. So here, let’s do this
Ted Holmberg: with our Ampersand, which is going to make this a background process. And you’re going to see very instantly. Ted Holmberg: It’s reporting, oh. Ted Holmberg: this is in the background, and we can see I could have instantly started typing a new command to put into my show right away.
Ted Holmberg: And then we can also just take a look at jobs as well. Ted Holmberg: and we can see jobs. Let’s do this again. Ted Holmberg: Then sleep Ted Holmberg: 3 Ted Holmberg: Ampersand oops Ted Holmberg: to back. Okay, Ampersand.
Ted Holmberg: and then let’s see, let’s do jobs. And we can see Ted Holmberg: if we do that quick enough that we still have that one job that’s currently running. And just gonna give me job, Id and process id. And
Ted Holmberg: now it’s complete. And what the job actually is. So now, it’s not showing up any longer. Ted Holmberg: Okay. So we looked a little bit about our tiny shell, a reference shell, right? So this is the behavior that our shell should have when we’re done implementing it
Ted Holmberg: on again. We’re gonna test it. Using all these trace applications, we also have to be able to quit out of it. Ted Holmberg: And we don’t even have quick implemented in our our initial version of our tiny shell.
Ted Holmberg: So there’s a lot that’s gonna have to be done in here. Let me just clear my terminal from my bash shell here.
Ted Holmberg: Okay? So in order to build our initial code base, what we’re gonna want us to do is we’re gonna start with the command, make to compile all the provided boilerplate code. And this, and we’ll create the executable files for the source code which will be used to test our shelf. So this will allow us to actually build our tiny shell, which won’t be able to do much as we’ll see it’s gonna build an application. A simple program called Myspin.
Ted Holmberg: which allows us to effectively just spend for some user specified amount of time and number of seconds. Effectively, I have my split, which is, gonna be a program that folks a child that spends for some N number of seconds. I have my stop, which is, gonna be a program to stop itself for debugging purposes, and my int which generates and interrupts my read, which is, gonna be a program to test shell reading. So these are all gonna be the Quintins central
Ted Holmberg: little utility applications that our tester is going to invoke from our cell to try to evaluate this behavior. Ted Holmberg: to be able to launch background and foreground and be able to wait and be able. Just see how effectively Ted Holmberg: everything is implemented for being able to manage these processes.
Ted Holmberg: So how are we going to use it? These are compiled applications will serve as our test cases to validate our
Ted Holmberg: shells. Functionalities such as our job control and our signal handling. And they’re gonna simulate various behaviors of programs that your shell will be able to handle correctly. And, in fact, that’s how you’re gonna be able to get your points. So just some demonstrations of how we might be able to actually use these applications like we can use these applications. They’re not specific to our tiny shell. We can use them from our bash shell or a Z shell as well.
Ted Holmberg: So let’s take a look at that, for instance, let’s just skip over here, and I have to make them haven’t made anything yet. Right? So if I just go make. The first thing that’s gonna do is we should go ahead and make all of these applications. And once I have these applications, I should be able to launch them just like any other kind of command line utility. So my spin. And then I give it some number of seconds, and we can see, we’re gonna have to wait 3 s, and now we’re back
Ted Holmberg: and we have what? What was the other one was my was it split? I believe it was my split, and I could do say, for instance, 3 s, and we could see that looks very similar to what I just did. But actually, it’s launching a child process.
Ted Holmberg: So if I wanted to like really take a look at that, let’s actually launch into Ted Holmberg: and also let me Ted Holmberg: me see here. Ted Holmberg: should be able to. Yep launch all of these applications from our tiny shell, just like our
Ted Holmberg: just like from our bash shell. Right? That’s one of the points of building our own shell. Ted Holmberg: And let’s do this one
Ted Holmberg: perfect. So we can see we’re launching these little applications in our tiny shell. And actually, why don’t we launch some of our other applications just to observe what some of the background execution job controls look like from our. So here, we’re recording the foreground, I mean, in the background launch my split. So let’s do this. And when we do that, we’re gonna look at both jobs and our our programs status
Ted Holmberg: 1010, Ted Holmberg: okay? And one that in the background. And let’s look at jobs. And let’s look at the program status. Ted Holmberg: And so here, what you can find interesting is that
Ted Holmberg: we have the job that we’re running and notice in our program status because of how my split works is it creates? From the parent. It creates a child process. So now it actually, we have 2 different process ids, right? One for the parent one for the child that exists.
Ted Holmberg: So these are all gonna be the interesting things we get to learn about as we develop our tiny shell.
Ted Holmberg: And of course there’s other things we can do, like, learn, learn how to sleep, and reap a zombie processes or set something to complete. We will play around with that as we continue moving forward. This is kind of an illustration of how these these utility applications are gonna be used by our tiny shell, and how they’re even accessible from just our standard shell that we’re using. Okay, let’s take a look at some of the boilerplate code for our tiny shell before we start. Kind of
Ted Holmberg: trying to examine this. I’m gonna show you highlights on the slide. But then we’ll just open up a source code file and look at it.
Ted Holmberg: So one important thing, I want you to look at inside of the source code that I’m gonna highlight here is struck. We have a struck a job structure that is, gonna have the the pid and the jid for a job as well as its current state.
Ted Holmberg: whether it’s a background or foreground, or whether it’s stopped Ted Holmberg: as well as the command line. Any argument for what? That that that job is. So this is effectively the data that’s carried for each job.
Ted Holmberg: The stub functions that we will be responsible for having to complete. To get this lab
Ted Holmberg: done are, gonna be these. And I think we’ve already mentioned these prior. But they should even have a comment in there that says, here are the functions that you will implement. That’s the Eval, the built in Cmd, the do. Bg, fg, the do redirect, the wait fg, and then we also have our signal handlers. Right, our trial signal handler, our stop signal handler and our interop signal handler.
Ted Holmberg: and also one thing inside of our main loop. Our main loop’s gonna be quite big, and if we go down to the thing we really want to be evaluating the thing that allows us to constantly feed and new instructions to our our shell is going to be what’s called or referred to as the revel which is going to be a read evaluate process loop.
Ted Holmberg: So let’s kinda let’s kind of break this down a little bit. We can see there’s a loop structure with this while loop. It’s it’s looped on one, because it just keeps working indefinitely every time it’s it’s there’s
Ted Holmberg: the the amount of instructions you should be able to feed to. Your rebel to your shell should be an unlimited amount number until you’re ready to quit. Ted Holmberg: So we’re just going to loop indefinitely. And then what we have here is we’re going to parse
Ted Holmberg: the we’re gonna read Ted Holmberg: the the string, the command line that’s given to us from the user. We’re gonna evaluate that string. So we’re gonna parse it and see what are the instructions built in command, or is it a external application we’re trying to launch?
Ted Holmberg: And then we’re going to process whatever we evaluated. And once we’re done processing it, then we’re ready to read the next instruction from the user. So that’s what’s referred to as Rep, and you’ll see that’s what’s given to us. Actually, inside of our T shell code. Ted Holmberg: our tiny shell.
Ted Holmberg: Okay. And this is a good opportunity actually, just to go and take a look at that. So let me go over here and let’s take a look at our T shell. So again, we have all of this code that we’re start with. Let’s take a look at our C code. Now, look, I already have an executable. I can. I can show you what happens when I launch my executable, but we’ll see.
Ted Holmberg: So we saw how, with Ted Holmberg: we’ll we’ll look at this and more in just a moment, but we could see I can launch. Let me quit. I’m already in my reference. Okay, so quit out of my reference. Ted Holmberg: We actually have something we can launch right?
Ted Holmberg: The problem is, we can’t even quit out of it. Look if I hit quit. That’s actually the first thing we have to do Ted Holmberg: we. Well, let me try to control. C, well, remember, control. C, that’s an interrupt that doesn’t work, either.
Ted Holmberg: Pull Z. No, that doesn’t work. Yeah. Let’s do this. let’s go to open tab by. Ted Holmberg: yeah, just close that terminal. Yeah. So you can see, we have very stubbed out implementation that offers almost no default. Ted Holmberg: user interactions. We’re gonna really have to implement all those out.
Ted Holmberg: But with that said, Let’s take a look at the code that we do have. So we can take and examine it.
Ted Holmberg: And so this should have the highlights that I showed you earlier, but feel free to look through this code yourself, to get a good, strong understanding. You could see the headers that were including Ted Holmberg: here. You can see.
Ted Holmberg: What we’re defining as our constants in terms of the maximum number of arguments on a command line, the maximum line size for command line, the maximum number of jobs at any point, and then, finally, the maximum number of job Ids that we can have.
Ted Holmberg: Okay, we have some job states here. Right? So fg. Ted Holmberg: is our foreground job undefined is 0. Bg, is a background job. And St. Is a stop job. So we have some constants that defined our job save.
Ted Holmberg: And then here we can see some of the global variables that we’ll have access to in all of our functions. Ted Holmberg: And we have this structure as well, which is our job structure which I highlighted and showed to you. And then we kind of broke this down.
Ted Holmberg: We have our function prototypes. So again, this is what I showed in the earlier slide. These are going to be all the functions that we’re going to be responsible for having to implement.
Ted Holmberg: And then here, we’re gonna have a collection of our function prototypes. This is gonna be a list of functions that we are given that we can call upon that are fully implemented. So we won’t have to make any changes to any of these here. So please read through these. See if you can’t learn what these do, as we’ll make use of these inside of the functions that we do have to implement.
Ted Holmberg: Then after that, you’ll see we have our main function. Ted Holmberg: which is going to have some various
Ted Holmberg: checks that it can do. It’s going to parse the command line. It’s going to install the signal handlers for us. It’s going to. And then here, this is the this is the part. This is the actual rebel part. This is going to execute the shells. Read Eval Loop.
Ted Holmberg: where Eval is going to be one of those functions that we’re going to be really responsible for implementing ourselves.
Ted Holmberg: And then you can see there’s gonna be lots of comments that are. Gonna tell you what are going to be necessary for some of these functions. But you see, for instance, with Eval, it’s just a blank function at the moment. It’s just a return. Ted Holmberg: You can see here for
Ted Holmberg: parse line, for instance, parse line is a function that’s given to us that should parse the line. So we have a very deep implementation for that already. But understand what it returns back and why it returns that. And then we have built in command function that takes in
Ted Holmberg: the Appointer Ted Holmberg: of our arguments. An array of arguments Ted Holmberg: have strings Ted Holmberg: or character pointers. But right now it doesn’t have any implementation just returns back 0 because it returns back an integer. So that’s just a subbed implementation.
Ted Holmberg: Yeah? And you could see it’s just gonna be Ted Holmberg: a collection of all the functions that are declared as the ones you have to have implemented. There’s almost no functionality. There. That’s that’s what the responsibility of the lab is going to be all about.
Ted Holmberg: Okay. So let’s talk about our objective, then, so your tiny shell should aim to emulate the reference shell, as I said earlier, so to ensure the consistency and reliability and performance and output. Ted Holmberg: So like a strategy is, do incremental testing utilize the 16 is actually 20.
Ted Holmberg: There’s actually Ted Holmberg: utilize the Ted Holmberg: 20 provided trace files sequentially to rigorously test and validate the functionalities of your shell against the reference shell. And again, a reference shell is the THTS. H. Raf.
Ted Holmberg: and so some guidelines just for testing. Start with your basic trace files. Compare with the reference file, and just, you know, consistently try to slowly improve
Ted Holmberg: check for insights check for abnormal behaviors. We already stated what the purpose of the shell driver script is is to execute your shell program as a child process, since those commands and signals based on the trace file and the captures and displays the trials which is your tiny shell standard input and standard error.
Ted Holmberg: And so your trace file format is going to consist of lines that are commands or comments so blank and comment. Lines starting with hashtag are ignored or echoed. So those it doesn’t try to evaluate. Driver commands
Ted Holmberg: for the testing, hardness for the perl script for the S. Driver. The shell driver are not passed to the child where shell a shell commands are passed to the child through standard in. Ted Holmberg: So there’s certain key words that are designed to provide behavior to the S. Driver application.
Ted Holmberg: And there’s certain keywords that’ll be inside the trace file that’s fed to your tiny shell, and your tiny shell is going to try to produce some text-based response to that command.
Ted Holmberg: So just so, you know what the key driver commands are that are going to be in these trace files that don’t go to the shell directly, but kind of alter or change the behavior of the driver script. We’re gonna be Tstp, that’s gonna send a a stop signal to the child.
Ted Holmberg: int, which is, gonna send a interrupt signal to the child. Quit, which is going to send a quick signal to the child kill, which is going to send a kill signal to the child close, which is gonna close the writer and sends an end to file to the child wait, which is, waits for the child to terminate
Ted Holmberg: and then sleep. N, which is gonna pause for N number of seconds. Ted Holmberg: So if we wanted to look at what this actually looked like. And actually, why don’t we just say oops. Ted Holmberg: I mean.
Ted Holmberg: So let me close this. And actually let’s look at. We can actually Ted Holmberg: open this up. This is a Ted Holmberg: this is a pearl script. Ted Holmberg: and you can see we have some comments in here.
Ted Holmberg: and the comments give us all these same instructions on how this works and what it does. Now, we we really don’t care about parsing through the actual contents of that. Once we know what the header comment states in terms of what are the commands?
Ted Holmberg: What are the driver statements that the S. Driver uses, and what are the commands that our shell is going to use. We can start looking at.
Ted Holmberg: We can look at some of these trace files. So let’s do that. The trace files are gonna actually act as as a way as a mechanism of of testing our shell. So it’s feeds the instructions to the tester to a a, a effectively like a unit test of sorts.
Ted Holmberg: So here we could see the all lower case in this instance. Quit is going to instruct Ted Holmberg: your Ted Holmberg: tiny shell to quit out.
Ted Holmberg: And so remember, we just tried to do tiny shell like. But let’s do that again. Gonna regret this. But our tiny shell is currently, if we try to feed it, that string.
Ted Holmberg: right? It’s not going to do anything. It’s just going into move on and say, Okay, what else do you want to do? It’s going to read? It’s not evaluating. It’s not processing that request.
Ted Holmberg: I mean, rather because I was able to submit it. And then it just prompted me again. So we really just have a a prompt loop going right now. So we’re gonna we’re gonna have to go ahead and implement the evaluate and process portion of our rebel loop
Ted Holmberg: so clearly. When we go to zoom, trace one, we could say, it’s not going to do it. But we’re going to test this out in just a moment. Ted Holmberg: Ju, just just to prove this, just and we’ll actually work through this first solution.
Ted Holmberg: So let me go ahead and Ted Holmberg: To this, let’s go here. So open a new close. This process. Close that terminal. Okay, yeah. yeah. Just talking our application at the moment. I can’t do anything about it.
Ted Holmberg: Okay, so this is just gives you an illustration of what these traces look like and and and clearly as we, that was the first one. And just to give you more preference before we move on any in complexity, you could just see.
Ted Holmberg: these race files are gonna get more and more complex instructions. So we can see the next one is gonna Ted Holmberg: invoke the Ls
Ted Holmberg: utility application to list. The contents of the directory. Then it’s going to sleep for a second and call it again, and it’s going to sleep for a second and call it again. So it’s going to run a foreground job several times.
Ted Holmberg: And then if I wanted to see, the idea is that we slowly implement our tiny shell. So we get past. Trace one. Then we could work on. Trace 2. Then once we’re done, trace 2, we can learn. We can look at trace 3, which gives us a description what it does. Remember anything in the hashtags or ignored. But what’s fed to our te tiny shell is gonna be everything that’s on the upper case so we could actually launch into our own tiny shelf. We wanted to and try to type in these commands.
You can launch into the tiny shell reference and actually see what happens. So actually, let’s do that just to show you. Ted Holmberg: Here, I’m gonna do my tiny shell reference and say, oh, go ahead, and I’ll launch my spin. Ted Holmberg: one as a background application, and then go ahead and do
Ted Holmberg: oops. Ted Holmberg: There we go, and then do that. Ted Holmberg: so if mine is my typo, you could see it should be able to Ted Holmberg: do both those things.
Ted Holmberg: and if it does it successfully, that produces the same output from our reference. Shell your shell. Then you get credit for that.
Ted Holmberg: Okay, so let’s talk about how we can actually run those tests. So we saw how I could manually kinda type in those instructions. But let’s actually use the test hardness and the easier way to use the test. Harness, as I said before, was to use like these, alias instructions where we just make
Ted Holmberg: our test. 0 one, which is going to be for the tray. 0 one text file. commands, and it’ll go ahead and spit out the output as generated from our reference. Tiny shell. So let’s try that. Make
Ted Holmberg: our test. 0 one up 0 one. So that’s reference. Test 0 one. And we can see, oh, yeah, what we’re gonna get is it’s launching that much more complex
Ted Holmberg: perl script with all of the modifiers that are required to run it the way we expect. But then the output we’re going to then generate is going to be. Oh, all the comments get displayed, and that’s it, because the only thing this does is it quits. What if we try to run this
Ted Holmberg: on our current tiny shell that we’ve done no implementation on whatsoever. And we could actually see if we try to do that. And if I just hit hit the make test 0 one. I ping indefinitely cause we’ve never. We’ve never implemented that quick
Ted Holmberg: so you could say it’s just waiting for that process to terminate. But we’ve never implemented that quit. So I’m actually gonna have to hit a control C on side of my on side of my test Ted Holmberg: application, which is going to bail me out.
Ted Holmberg: So what we can do now, if I wanted to is I can start to Ted Holmberg: explore this space using the debugger. Ted Holmberg: So if I wanted to use the debugger, though what I should do is I should go ahead, and
Ted Holmberg: when I make my file I should use this dash. G, did I think I Ted Holmberg: tonight, yeah, here we go. Ted Holmberg: Give rationale as to why I want to do this.
Ted Holmberg: but this will make it much easier. In fact, let’s do that really quick to see what happens before we even start implementing anything. Ted Holmberg: And so Ted Holmberg: so let’s do. Gcc.
Ted Holmberg: dash, G, this is going to be able to allow us to have much more verbose debugging opportunities with my debugger. And then I’m going to do. What is this? This is my. Ted Holmberg: this is going to be my tiny shell that we’re going to do.
Ted Holmberg: And then we want the output application name to be TSH. Ted Holmberg: And then bam. Okay. So now that we have that, let’s call. Dbg. Ted Holmberg: no. let’s call Ted Holmberg: chile being Ted Holmberg: on our ta our tiny shell.
Ted Holmberg: Okay, so we will do that. Now let’s set a breakpoint for Eval. We know that’s one of the things that has to be implemented doesn’t do anything. We looked at it. It’s empty. So that’s why we’re not evaluating any commands. So let’s break on the instance of Eval.
Ted Holmberg: Okay, so we created a break point. Let’s go ahead and tell it to run. And let’s give it. Okay, let’s give it something like quick, for instance. Ted Holmberg: and if I do that we can see inside of this breakpoint inside of my command line. So when Eval is called.
Ted Holmberg: we’re inside of Eval, right? So an email is called, Yeah, main Eval, that’s our break point. We just have that return statement. But we could see we have this command line.
Ted Holmberg: which is effectively quit with newline character, so we can see that quit the string of quit is being sent. In fact, let’s see this. Let’s Ted Holmberg: let us do this. Let us Ted Holmberg: run again. and let’s do a more complicated one. Let’s suppose we did like Ben
Ted Holmberg: Lass, dash, l dash. Ted Holmberg: Okay? Ted Holmberg: And we can say, yeah. So the entire string, no matter what is there, is currently being sent into our eval method. We’re just not doing anything with it.
Ted Holmberg: So we now know where we need to go to start parsing our our line. So let’s go ahead. And just at least, for now quit out of this player out of this. Okay? Ted Holmberg: So here.
Ted Holmberg: obviously, what we’d want to do is use some helper functions to be able to parse this this string for us right? And as we know, there’s some strings that’s already given to us. Ted Holmberg: so say, for instance. Ted Holmberg: we have. Well, we’re gonna want to
Ted Holmberg: implement our eval, we’re gonna want to implement our our built in command. So let’s Ted Holmberg: let’s look at this. So one of the functions that we know that we can access and let’s open up our T. Shell C code here Ted Holmberg: is gonna be this one.
Ted Holmberg: It’s gonna be this one. So, or let’s look at our our C code here and let’s see some of the helper functions that we think might be interesting. Ted Holmberg: Let’s see. Ted Holmberg: that was our end of our list. Other helper routines. Ted Holmberg: Let’s do this.
Ted Holmberg: See if there’s one that parses. So here are our helper functions. One of the first helper functions is a pars line function that we can say takes in a command line from the user. It’s going to take in a character pointer of a arguments array.
Ted Holmberg: So let’s go here and see if we can’t.
Ted Holmberg: So here we have. So we can read the description. It’s gonna parse the command line and build the Arg V. Array. The characters enclosed in single quotes are treated as a single argument. That’s good. So what we have right? And we’re gonna return. True, if the user has requested a background job and false, if the user has requested a foreground job.
Ted Holmberg: So this is something we should keep in mind where we’re turning back an int. And this int is going to be effectively. Let’s say one
Ted Holmberg: on the end, because because it’s effectively a bullying result. So say, for instance, one, if it’s a background job or nonzero value for background job and a 0 for a Ted Holmberg: if it’s a a forward job.
Ted Holmberg: But this is already implemented. So we should make use of this to parse our string.
Ted Holmberg: Okay, so the idea on what we’re gonna do. And let’s actually open up our code again. Let’s go. I shouldn’t have closed it. So there’s there’s 2 functions that we’re really probably gonna have to make use of for this first phase, cause we could see right now. Actually, I didn’t show this either.
Ted Holmberg: So I showed how the test output was different. But let’s look at the alternative way that we could test as well. Let’s look at check Ted Holmberg: tiny shell dot pie. Ted Holmberg: because I’ll be using this a lot. When we initially launch this. Ted Holmberg: it’s launching, it’s launching.
Ted Holmberg: and it might just be hung, cause we can’t even quit out of it. Ted Holmberg: Well, let’s house this one later. Yeah, look at this, this one’s causing all sorts of issues. So we’ll take a look at this one in just a bit. Let’s let’s finish implementing this first, this first
Ted Holmberg: test. Ted Holmberg: Okay? So let’s go to our rebel and see what’s happening with our rebel. And then kind of just drill down with everything. Ted Holmberg: So we’re gonna go to our main function. We’re gonna go to where?
Ted Holmberg: Yeah, we’re doing that. Okay, so here, this is where we start executing the shells. Read, evaluate loop. and then what we’re doing here is. Ted Holmberg: let’s let’s look at this. We are going to go ahead and read the command line.
Ted Holmberg: Then we’re going to evaluate the command line. And so notice we’re making a call to Eval here. That’s what we’re looking at before. If we go ahead Ted Holmberg: and jump over to Eval. Ted Holmberg: We can see it doesn’t actually have anything.
Ted Holmberg: So let’s start to define the behavior for a vow that we expect it to have. Ted Holmberg: So the first thing we’re gonna want to do is we’re gonna want to create a argument array Ted Holmberg: that will hold the command line arguments once they’ve been parsed.
Ted Holmberg: And so remember that Max Args
Ted Holmberg: was a predefined constant that specifies the maximum number of arguments that your shelf can handle. So we’re going to want to implement something like this initially, some local variable to handle the parsing, to capture the parsing of our of our arguments. So let’s go ahead and define that. So inside of here.
Ted Holmberg: let’s do character pointer. Ted Holmberg: R and B. Ted Holmberg: And as we said, Here we are going to define it the size of our Max Arcs. Ted Holmberg: Okay? So now that we’ve done that, the next thing we’re going to do is we’re going to create a variable
Ted Holmberg: that’s going to hold the integer results from when we try to parse a line indicating whether a process should be run in the background or foreground. Remember one of the things that parse line does is it checks to see it checks for us
Ted Holmberg: if it’s going to be a background or foreground and tells us one or 0 right? Nonzero value or 0 if it’s supposed to be a a foreground. Ted Holmberg: So let’s hold something. Ted Holmberg: Let’s create something just to store that.
Ted Holmberg: Now. The next thing I’m gonna do is actually assign to Bg
Ted Holmberg: the results from parse line which is made for us. Remember, parse line requires 2 arguments. The command line, which, when we did a breakpoint on Eval, we saw we already get into Eval right? But then we created the Arg V, and we’re gonna send a reference to Arg. V to parse so it can populate it for us
Ted Holmberg: and actually fill our command line arguments. Ted Holmberg: So here, let’s do. Bg, is equal to
Ted Holmberg: parse line. And so inside of Pars line I’m going to send it the command line that sent to us from Eval, and I’m going to send it a reference to our rb. that so that it can populate. Rv. Based off of the contents and command line.
Ted Holmberg: Excellent. And then the last thing we’re gonna have to do
Ted Holmberg: at for this particular function is we’re actually going to want to invoke the built in command. Rv, remember, there’s some built in commands that we’re gonna care about? Did we talk about what the built in commands are? There’s gonna be like a built in command to the shelves quit. Obviously, that’s the first one we’re trying to do. Other built in commands would be jobs
Ted Holmberg: which we haven’t implemented yet. Another some other built in commands would be fg, or bg, if you recall, yeah, we had a slide that discussed that. So we would want to go ahead and have our command line arguments and then send that to our built in command.
Ted Holmberg: which I think actually returns back something as well. We’re going to ignore what it turns back so. But the the built in command. We’ll we’ll look at it. It stuffed out. It doesn’t do anything yet.
Ted Holmberg: but what you traditionally do with it is it’s called with the argument list that we generate from parsing online. And then that functions gonna check to see if the command is a built in shell command like quit or jobs, or whatever, and if it does, it’s gonna execute it.
Ted Holmberg: And it’ll handle it. And if it isn’t, it’s going to return back so that we can bypass, and then, like effectively fork to create a child process so that we can call whatever non-built in command. We want the shell to go ahead and execute if it wants to launch some utility application and run that, then return back to the rebel loop.
Ted Holmberg: So that’s the general idea so built in does return back some status that’s gonna affect future implementations. But we’re gonna ignore that for now. And we’ll just add in the return data as we actually need it for quitting, we’re just gonna quit out. So it’s gonna not be very meaningful. But we are gonna have to invoke this. And it is something that’s built in. Right? If I go back up, let’s let’s do this really quick.
Ted Holmberg: Before I even implement it. Let’s do control F built in. Ted Holmberg: Yeah, we could see, I have this built in
Ted Holmberg: function right here. It just it just doesn’t. It just returns 0 cause it returns an end. But if the user has tied to built in command, we execute it immediately. So we’re gonna have to implement this and we’re getting our argument fee, not gonna implement it yet, though, because I’ll I’ll do the breakpoint on it right. But we can say, we do. This is gonna be the next thing. But let’s do some debugging. First, let me finish out. I know that I need to. And in fact.
Ted Holmberg: the other. Let me me do this
Ted Holmberg: because we see this is the stubbed out implementation. But if we go to where the prototypes are all defined at, we’re like, Oh, yeah, look, that’s also the next function under Eval, that’s listed under here functions. You will implement. And you kind of see that these functions are defined almost in a way that we can kinda easily and nicely read through
What we’ll have to do. Ted Holmberg: and again learn the helper routines that we’ll rely on. Ted Holmberg: Okay. So let’s go back down over to our eval then. So let’s jump to Eval. Ted Holmberg: And inside of Eval. What I’m going to do is we will call that Ted Holmberg: built in
Ted Holmberg: Cmd, I’m sorry built in Cmd. Ted Holmberg: And we will pass it in. Ted Holmberg: I believe, is what it is that we’re going to need to do so once we do that. That’s gonna be the Ted Holmberg: basic implementation for just evaluating Ted Holmberg: a
Ted Holmberg: prompt right? So we’re gonna create an array that can hold up to the maximum number of arguments. We’re gonna create a variable that holds whatever the integer value that represents a background versus foreground results. We’re gonna call this helper function pars line passing in the command line, and this empty argument array.
Ted Holmberg: and that’s going to populate that for us. We’re and then we’re going to. So send that in to our built-in command function which we have not implemented yet. Ted Holmberg: But now what we can do is, oh, don’t want to do
Ted Holmberg: Let me get rid of that. So what I do want to do at this moment is save, let’s save that.
Ted Holmberg: And now let’s try testing this again. So here, what I can do is let’s recompile. And again, I want to compile. So to get the debugger, the the with a dash G, that’s gonna give me the additional debugger support
Ted Holmberg: some some additional text, and then I can go ahead and I can go ahead and let’s run our debugger. Let’s create a break now, instead of breaking on Eval. Ted Holmberg: I could still break on email. And I will. Let’s break on Eval. But I can also break on
Ted Holmberg: built in Ted Holmberg: command. Right? Let’s do that. Okay, now. But I, yeah. Ted Holmberg: And now let’s go ahead and just run it. Ted Holmberg: Okay. So I run. It’s gonna ask for something. Suppose I want to hit something like, Ted Holmberg: let’s do something more complex. I’ll ask
Ted Holmberg: L. Dash a let’s hit enter. Ted Holmberg: The reason why I want to try to. Ted Holmberg: Okay. So let’s let’s let’s step through this. So let’s do next instruction. So notice another nice thing about what I get when I use the dash. Gee is, I’m actually seeing Ted Holmberg: the
Ted Holmberg: instruction I’m currently executing, not in assembly instructions, but actually inside of c instructions which makes it very nice to kind of
Ted Holmberg: read through. So here, let me go to that. I’m just gonna hit next. And now I’m at parse line. Okay. So at this point I’m parsing line. I’m I’m I.
Ted Holmberg: I’m giving it my arg. V. I’m going to go down to the next instruction onto built in command. So here, now, what I want to do is I want to print Ted Holmberg: R to V,
Ted Holmberg: and we can actually inspect them inside of our debugger, a debugger. The contents of my local variable. So I can see. Yeah, look, we’ve successfully parsed the Ls. Ted Holmberg: And now let me print out
Ted Holmberg: Rv at index one, and that’s my dash l nice. And then finally, let me do Argv Ted Holmberg: at index 2, and that’s a and then finally let me do a print of card V at Ted Holmberg: index 3.
Ted Holmberg: And we could say, Nope, that’s my null character which represents that this is the end of the array. Ted Holmberg: So yeah, let’s let’s actually run this again. Ted Holmberg: and let’s actually this time typing quick.
Ted Holmberg: And so now, if I print my help, let me go to next. So let’s walk down this. I’m currently inside of Eval. So here I am now at Ted Holmberg: the so let’s say, now
Ted Holmberg: I’m at the command line. I’m defining the. And then we’re going to be built in perfect. So now let me print Ted Holmberg: arg. V. 0, and we can say, Yes, I do have my quit, and then I’m then off I do my print are the one
Ted Holmberg: that’s going to be my middle symbol. Perfect. Okay? So yeah, we can see we’re properly parsing the command lines into tokens.
Ted Holmberg: And each of these tokens are effectively inside of our Rv array. And then we’re gonna jump. Actually, let me go down to next then. And so that’s going to bring me to Ted Holmberg: the built in command. But remember, my built in command is nothing at this point
Ted Holmberg: we just need. We’re getting a reference to the Argv array getting passed into it. Okay? So the next thing we need to do now that we see we have examined, we’ve used the debugger to kind of see how code is flowing from our main function to our eval function. Now into our built in command function, we need to do something in response to this Arg. V. Array to make a decision on exiting out our application. If
Ted Holmberg: the command was to quit right. That’s the first thing we have to implement. So what are we going to do inside of Ted Holmberg: what are we gonna do inside of our fells in
Ted Holmberg: command? Well, let’s do the following, the first thing we’re going to do is we’re going to go ahead and we’re gonna grab, quit is so for the quick keyword
Ted Holmberg: or for any of the built in functions. In fact, they don’t take any arguments, so we only care about the first element inside of our argument. V. Our Argv array. So we’re gonna grab that first element and save it to a variable. So let’s do that. Let’s go to built in command. So let’s let’s quit out of this.
Ted Holmberg: Just clear out of this. Okay, perfect. Now let’s go to here. And actually, let’s go to our. Ted Holmberg: Let’s go to our built in Ted Holmberg: perfect.
Ted Holmberg: And so I’m going to jump here. And right now we have no implementation. So the first thing we’re going to do here is we’re going to create Ted Holmberg: character pointer. And we’re going to want to effectively grab our command.
Ted Holmberg: And that’s just going to be the very first element of our Argv array Ted Holmberg: so that we can inspect that and do a comparison on it.
Ted Holmberg: Okay? So that’s gonna be a pointer declared to the first element of Rd, then we’re gonna want to do a string comparison. So we’re gonna want to compare our string, the command that we have to the word the literal string quit. And so remember, since these are
Ted Holmberg: effectively, non primitive data types, right? Since strings are more complex, we have the string comparator function, we can call. And so, if 2 strings have no differences between them, if they are exactly the same, it returns back a value of 0. So we’ll check to see if the result of a string compare between our command and quit.
Ted Holmberg: String is 0, and if it is, then we’re going to do something in response to that. So let’s go ahead and type that up. Ted Holmberg: So let’s jump here. Ted Holmberg: So if inside of here oops. we do a string compare.
Ted Holmberg: And inside of our string. Compare, we’re going to compare our Ted Holmberg: command, the the string argument, the first element from our. So our arguments array to the string level of quit, and we want to see if Ted Holmberg: that is equal to 0. And if it is
Ted Holmberg: okay, so if it is, then we want to do something in response to that. Ted Holmberg: And so what we’re gonna want to do in response is, we’re gonna want to go ahead and exit
Ted Holmberg: using the standard library which is available to us, and this will just exit our application right? So we wanna exit. We want to call the exit function, which will terminate the calling process. And just just Ted Holmberg: to make our our application stop.
Ted Holmberg: and it’ll it’ll give it with the status of 0, which is fine. This was what we wanted. We requested an exit. So it’s a a 0 value is apt for the exit status code here.
Ted Holmberg: Okay? And I. And that’s it. That’s that’s so. So we get the argument array. We grab the first element we compare to see if it’s quit. If it is, then we’re gonna exit. But save that. Ted Holmberg: and then let’s see what happens. Ted Holmberg: So let’s close this.
Ted Holmberg: So now, at this point, I feel like this should work. I can throw it in the debugger, or I can just use the testers that I did. So. The first thing I’m going to do is I’m going to do the the make test 0 1
Ted Holmberg: and try that. And now oh, you know what I need to do. I need to compile my code much. It should do that. Ted Holmberg: Okay, let’s clear this. Okay, let’s see here.
Ted Holmberg: Yeah, okay. So I compiled my code after updating it. And now, after compiling my code, I can go ahead and then make that that first test case and notice
Ted Holmberg: so long. And after I make my changes, I wanna always recompile after recompiling, I could say, Yeah, I’m getting the same output as if I were to do an art test. In fact, if I wanted to do a comparison cross comparison, I could do diff, if you remember. So here I can do diff. We’re gonna send the output from our test. 0 one. Send the output from test 0 one. And the only difference here
Ted Holmberg: me should be. Oh, I gotta do make sorry. Ted Holmberg: Make our test and make Ted Holmberg: test perfect. We can see they’re exactly the same, except just these initial calls to our driver script.
Ted Holmberg: which is fine because one of our drivers one of those scripts is touching our Tsh Raf. Ted Holmberg: our tiny shell reference where it’s it’s doing ours. And, in fact, another way, if you might recall, is, I actually can validate. I can. Ted Holmberg: I can use the check.
Ted Holmberg: tiny shell, the Tish pi, so let’s let’s take a look at that. Ted Holmberg: And here, look at this. I got 2 points on trace one.
Ted Holmberg: so I and then now, all of a sudden. I’m not getting any points on anything else here. It’s causing all sorts of chaos, 0 points and lots of errors and whatnot. But you could see, I already initially saw. I got the 2 points.
Ted Holmberg: or at first one, which means I successful, which means I can even do this if I wanted to slow this into the gdb. Ted Holmberg: let’s do our tiny shell. We could just run our tiny shell. One nice thing about launching
Ted Holmberg: our timing shells. If we mess it up, we can always just exit out without having to do anything inside of our actual Ted Holmberg: our outer shell, our terminal. So here we can try doing quit.
Ted Holmberg: And we say, Oh, yeah, it it quit like normal. It worked the way we want it.
Ted Holmberg: And now I can go ahead and quit out of here, and we’ll launch it. We can launch it this way, too. I’ll just launch it right from the command line until it quits. And we say, Yeah, quit out. It works exactly as our reference cell in that regard is right. This wants the reference cell type and quit. Let me see? Yeah, we got the same behavior. So that’s trace one. So we just walk through, trace one and the very first introducing this.
Ted Holmberg: And so we saw how we could test and evaluate the results of trace one using the def, we saw how we can chat to see how many points we’ve accumulated using the python script. So the next thing we would do is move to trace 2, which we will talk about next time. I’ve used up all my time for today to introduce this concept. But if I wanted to see what I had to do and trace to.
Ted Holmberg: just to motivate where we would go next is, I would Capt. Ted Holmberg: Trace 2 dot, CXT. And then you could see the instructions that are gonna be given to the test harness, anyway. Thank you for spending the time watching this lecture. Today I will see you all next lecture.
Ted Holmberg: Have a great day. and have a happy Halloween.
Video Keywords: Shell Programming, [vid_tags]
-
Sale!
Wireless WIFI Repeater Extender Amplifier Booster 300Mbps
$29.99$14.99 Add to cartWireless WIFI Repeater Extender Amplifier Booster 300Mbps
Categories: Electronics, Wi-Fi Router, Wireless Wi-Fi Extender Tags: 300Mbps, 802.11N, Amplifier, Booster, Extender, mobile wi-fi booster, Remote, WIFI, Wireless, Wireless WIFI, Wireless WIFI Repeater, Wireless WIFI Repeater Extender, Wireless WIFI Repeater Extender Amplifier, Wireless WIFI Repeater Extender Amplifier Booster, Wireless WIFI Repeater Extender Amplifier Booster 300Mbps$29.99$14.99 -
Sale!
Full RGB Light Design Gaming Headset Headphones with Mic
$24.99$14.99 Add to cartFull RGB Light Design Gaming Headset Headphones with Mic
Categories: Electronics, Gaming, Gaming Headsets Tags: Design, Full, Full RGB Light Design Gaming Headset, Full RGB Light Design Gaming Headset Headphones, Full RGB Light Design Gaming Headset Headphones with Mic, Gamer, Gaming, Gaming Headset Headphones, gaming headset wireless, Headphone, Headphones, Headset, Light, Mic, Package, RGB$24.99$14.99 -
Sale!
Wireless BlueTooth Multi-Device Keyboard Mouse Combo
$39.99$19.99 Add to cartWireless BlueTooth Multi-Device Keyboard Mouse Combo
Categories: Electronics, Gaming, Gaming Keyboards, Keyboard Mouse Combos Tags: Combo, Keyboard, keyboard mouse combos, Mouse, MultiDevice, Set, WireKeyboard Mouse Combo, Wireless, Wireless BlueTooth Keyboard Mouse Combo, Wireless BlueTooth Keyboard Mouse Combos, Wireless BlueTooth Multi-Device Keyboard Mouse Combo, Wireless BlueTooth Multi-Device Keyboard Mouse Combos$39.99$19.99 -
Sale!
High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
$199.99$139.99 Add to cartHigh Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
Categories: Gaming, Gaming Chairs Tags: Adjustable, Chair, computer chairs, Desk, Executive, Gaming, Girl, Headrest, High, High Back Leather Executive Adjustable Swivel Gaming Chair, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar, High Back Leather Executive Adjustable Swivel Gaming Chairs, Leather, Lumbar, Office, Racing, Swivel$199.99$139.99 -
Sale!
Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
$29.99$19.99 Select optionsProfessional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
SKU: N/A Categories: Electronics, Gaming, Gaming Headsets Tags: Cancelling, Gaming, Gaming Headphones with Noise Cancelling Microphone, gaming headset, Headphones, Headset, LED, Light, Mic, Microphone, Noise, Professional, Professional LED Light Wired Gaming Headphones, Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone, Wired, Wired Gaming Headphones, Wired Gaming Headphones with Noise Cancelling Microphone$29.99$19.99 -
Sale!
Gaming Desk with LED Lights USB Power Outlets and Charging Ports
$349.99$249.99 Select optionsGaming Desk with LED Lights USB Power Outlets and Charging Ports
SKU: N/A Categories: Computer Desk, Gaming, Gaming Desk Tags: and Charging Ports, Charging, Desk, Desks, Gaming, gaming desk with led lights, Gaming Desks with LED Lights, Home, LED, Lights, Monitor, Office, Outlets, Port, Power, Room, Stand, USB, USB Power Outlets, White, Workstation$349.99$249.99 -
Sale!
Wired Mixed Backlit Anti-Ghosting Gaming Keyboard
$99.99$79.99 Add to cartWired Mixed Backlit Anti-Ghosting Gaming Keyboard
Categories: Electronics, Gaming, Gaming Keyboards Tags: Antighosting, Backlit, Blue, brown, Gaming, Gaming Keyboard, gaming keyboards, gaming keyboards and mouse, Keyboard, Laptop, Switch, Wired, Wired Mixed Backlit Anti-Ghosting Gaming Keyboard, Wired Mixed Backlit Anti-Ghosting Gaming Keyboards, Wired Mixed Backlit Gaming Keyboard$99.99$79.99 -
Sale!
Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
$119.99$59.99 Add to cartWireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
Categories: Electronics, Gaming, Gaming Headsets Tags: 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, ANC, Audio, Bluetooth, Cancellation, Ear, Earphone, gaming headset, Headphones, Headset, Hi-Res Over the Ear Headphones Headset, HiRes, Noise, Wireless, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Headphones, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headsets$119.99$59.99 -
Sale!
Wired Sports Gaming Headset Earbuds with Microphone
$19.99$9.99 Select optionsWired Sports Gaming Headset Earbuds with Microphone
SKU: N/A Categories: Gaming, Gaming Headsets Tags: Accessories, Earbud, Earphone, Earphones, Gaming, gaming headset with microphone, Headphones, Headset, IOS, Microphone, Sports, Wired, Wired Sports Gaming Headset Earbuds, Wired Sports Gaming Headset Earbuds with Microphone, Wired Sports Headset Earbuds$19.99$9.99 -
Sale!
150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
$49.99$29.99 Add to cart150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
Categories: Charging Stations, Electronics Tags: 150W, 150W Charging Station, 150W Universal Multi USB Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Stations, 150W Universal Multi USB MAX Charging Station, 16 Port MAX Charging Station, 3.5A, Charger, Charging, Fast, laptop charging stations, Max, Multi, Port, Stand, Station, Universal, USB$49.99$29.99