This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
haas:spring2017:sysprog:projects:sci0 [2017/01/26 16:32] – [Squaring values ending with 5] wedge | haas:spring2017:sysprog:projects:sci0 [2017/02/14 17:00] (current) – [Submission] wedge | ||
---|---|---|---|
Line 31: | Line 31: | ||
</ | </ | ||
+ | ====Setting permissions==== | ||
+ | Although we've largely operated without direct attention to it, our data and our access to it very much depends upon the permissions set on them. | ||
+ | You cannot view any source code written without the read permission being set; you cannot save changes unless you have write permission enabled; and you cannot run your compiled programs if the execution permission was not applied. | ||
+ | |||
+ | Different operating systems and different filesystems manifest file permissions differently; | ||
+ | |||
+ | UNIX file permissions are represented as a 3-digit octal (base 8!) value, and each octal value can have the following values: | ||
+ | |||
+ | ^ value ^ description | ||
+ | | 4 | apply read permission to that particular mode | | ||
+ | | 2 | apply write permission to that particular mode | | ||
+ | | 1 | apply execute permission to that particular mode | | ||
+ | | 0 | apply no permissions to that particular mode | | ||
+ | |||
+ | Being an octal value, we can express results ranging from 0-7, and that is precisely how many variations we need to specify all the possible combinations here. | ||
+ | |||
+ | For example, if we wanted read (4) and write (2) permission, we'd add them together... 4+2 is 6; if we wanted read, write, AND execute: 4+2+1 = 7. | ||
+ | |||
+ | There are 3 ' | ||
+ | |||
+ | ^ tier ^ description | ||
+ | | user | permissions applied to the assigned owner of the file | | ||
+ | | group | permissions applied to the assigned group of the file | | ||
+ | | other | permissions applied to anyone else (the world) | ||
+ | |||
+ | More specifically: | ||
+ | |||
+ | ^ ^ user ^ group ^ other | | ||
+ | | read | 0400 | 0040 | 0004 | | ||
+ | | write | 0200 | 0020 | 0002 | | ||
+ | | execute | ||
+ | | none | 0000 | 0000 | 0000 | | ||
+ | |||
+ | To form the octal permission, we figure out what permissions to apply to the user (a combination of read, write, execute, or none), and then for the group, and finally for the world. That is the 3-digit octal value we need. | ||
+ | |||
+ | The problem is that the mode as specified on the command-line will be available as a string (argv[1], an array of characters), | ||
+ | |||
+ | Your program should expect data to be provided as follows: | ||
+ | |||
+ | * argv[0]: program name | ||
+ | * argv[1]: 3-digit permission (as a string) | ||
+ | * argv[2-n]: file to which we want to apply permissions | ||
+ | |||
+ | This can be done rather effectively using logic operations (almost crazy easily). | ||
+ | |||
+ | To get a better handle on this, you may run the following commands when logged into lab46: | ||
+ | |||
+ | <cli> | ||
+ | lab46:~$ ls -l /etc/motd /etc/shadow /bin/ls | ||
+ | -rwxr-xr-x 1 root root | ||
+ | -rw-r--r-- 1 root root 859 Mar 14 12:16 /etc/motd | ||
+ | -rw-r----- 1 root shadow 729 Oct 21 04:55 /etc/shadow | ||
+ | lab46: | ||
+ | </ | ||
+ | |||
+ | Ignoring the leading ' | ||
+ | |||
+ | **/ | ||
=====Program===== | =====Program===== | ||
- | It is your task to write the program that will use the above method | + | It is your task to write the program that will use the **chmod(2)** system call to provide 3- or 4-digit octal values to appropriately change |
Your program should: | Your program should: | ||
- | * prompt | + | * accept as command-line arguments: |
- | * input number as an unsigned short integer | + | * the 3- or 4-digit octal value |
+ | * the file(s) | ||
* perform the task (process) | * perform the task (process) | ||
- | * isolate one's digit mathematically, store in a variable (unsigned short int) | + | * as stated, you are not allowed to use any of the **strtol(3)** family |
- | | + | * This isn't to say you cannot use them; you may, you just cannot use them to do any of the conversion work (beyond ASCII to base 10). |
- | | + | * display |
- | * display | + | * if error or usage, make sure you return |
- | * display | + | |
- | * display the resulting number | + | |
- | * display | + | |
- | * because we have not officially learned how to do selection/ | + | |
- | =====Execution===== | + | |
- | < | + | =====FAQs/Hints===== |
- | lab46: | + | |
- | Enter value: 75 | + | |
- | 75 x 75 | + | |
- | lab46:~/src/ | + | |
- | </ | + | |
- | The execution of the program is short and simple- obtain the input, do the processing, produce the output, and then terminate. | + | ====0x0: Octal==== |
- | Note how the two " | + | > In argv[1] |
+ | > | ||
- | Similarly, here' | + | As **argv[1]** is an array of characters... if you give it 640, it'll actually be " |
- | < | + | ' |
- | lab46: | + | |
- | Enter value: 105 | + | |
- | 105 x 105 = 11025 | + | |
- | lab46: | + | |
- | </ | + | |
- | The ' | + | If you were to convert " |
- | If you'd like to verify successful output to STDOUT/ | + | If you pass that decimal 640 to the chmod() function, you'd end up with the sticky bit being set (T in other) along with user write, and NOTHING else. Not 0640 as we desire, but instead 01200. |
- | < | + | So, entering 640 on the command-line would not result in a direct conversion to octal 0640... some converting will be in order. |
- | lab46: | + | |
- | | + | |
- | lab46: | + | |
- | </ | + | |
- | What we are doing here is two-fold: | + | ====0x1: more octal==== |
+ | > Since octal values start with a leading zero, if I insert an ASCII ' | ||
+ | > | ||
- | * We are using command-line I/O redirection to redirect STDERR (which | + | That leading zero is only a convenience, implemented on a case by case basis. It would appear |
- | * We are " | + | |
- | Similarly, if we were to eliminate STDOUT entirely | + | <code c> |
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | int main(int argc, char **argv) | ||
+ | { | ||
+ | int result = atoi(argv[1]); | ||
+ | |||
+ | printf(" | ||
+ | |||
+ | // display the result in octal, decimal, and hex | ||
+ | printf(" | ||
+ | |||
+ | return(0); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | And look at the output: | ||
<cli> | <cli> | ||
- | lab46:~/ | + | lab46:~$ ./testatoi 640 |
- | Enter value: 75 | + | argv[1] is " |
- | 75 x 75 = lab46:~/src/ | + | result is 1200 in octal, 640 in decimal, and 280 in hexadecimal |
+ | lab46:~$ ./testatoi 0640 | ||
+ | argv[1] is " | ||
+ | result is 1200 in octal, 640 in decimal, and 280 in hexadecimal | ||
</ | </ | ||
- | What we are doing here: | + | As you can see, even if you had a 0640, the leading zero would be dropped in the conversion, because **atoi(3)** is apparently only cognizant of decimal values (and good, because that would have taken the fun out of this particular problem... you stand to learn some important things by working through this process). |
- | * We are using command-line I/O redirection to redirect STDOUT (which | + | And also, do you see that regardless of displaying it in octal, decimal, or hex, it is the same value? They' |
- | =====Verification===== | + | > Why doesn't adding the leading zero make it octal? |
- | One of the tests I will perform for output compliance of your code will involve comparing your program's output against a range of input values, to see if they all output in conformance with project specifications. | + | > |
- | I will make use of a checksum | + | The leading zero is a convenient way to identify an octal value. It is a means to mark one, but by no means a required form. That C and other facilities on the computer support a leading 0 for octal and a leading 0x for hex makes our lives easier, but only goes as far as support for such things has been implemented. |
- | You will need to run this from your sof0 project directory with a compiled and operational binary by the name of **sof0**. | + | We do the same in language. If I were to say the following value is in base 8: 72033 |
- | You can check your project | + | You would understand because I identified it as such... note the lack of the leading zero. If I wanted to be more brief, instead of saying "the following value is in base 8" I could just prefix a 0 on, because that shortcut is generally understood (within the context of assignable values in C syntax). But it is by no means the only way to do it. |
+ | |||
+ | ===atoi=== | ||
+ | And note, there is nothing magical about **atoi(3)**... it is just a function. It takes an array currently filled with ASCII-equivalents of single digit decimal numbers and coalesces those separate digits into one. We've played with things like this in our early labs this semester (there are advantages to having a number broken up into separate digits, there are also advantages to having a number combined as a single value). | ||
+ | |||
+ | The overall scope of this problem presents you with a desired-octal value currently represented as a string-- each ' | ||
+ | |||
+ | And as we know: 031 is not 31. 031 is 25. | ||
+ | |||
+ | So, if we read in 031 as a decimal 31 yet desire to then represent it as octal, we'd instead have 037. | ||
+ | |||
+ | ===the neatness of binary and octal (and hex)=== | ||
+ | There are certain advantages when working in similar bases that are all powers of two. Quite advantageous things. | ||
+ | |||
+ | That base 8 is one of those bases means this problem | ||
+ | |||
+ | That each octal digit represents three binary bits should be kept in mind. This problem entirely plays off how well binary values and octal values just sync up (because, well, they do). | ||
+ | |||
+ | We would experience similar neatness with decimal if we started playing with base 10, base 100, and base 1000 values (in such a case, decimal would be to base 100 and 1000 what binary is to bases 8 and 16). | ||
+ | |||
+ | ====0x2: when a number isn't a number but a representation of a number we'd like it to be==== | ||
+ | > Does **chmod(2)** have to be in octal or are there other ways that it can work. | ||
+ | |||
+ | No, you can think of it as being in binary, octal, decimal, or hex... or any base, really, so long as that value, when converted to octal, matches the desired permissions. | ||
+ | |||
+ | After all: | ||
+ | * 0640 in binary is: 000110100000 | ||
+ | * 0640 in hex is: 1A0 | ||
+ | * 0640 in decimal is: 416 | ||
+ | |||
+ | Once the number is in the variable, it can instantly and effortlessly be represented in base 8, 10, or 16. It can be thought of as any one of those, and it really doesn' | ||
+ | |||
+ | The only difference is when we choose to visualize them... when you SEE a number, it has to take a form (and abide by a base)... when you input a number, we apply the same notions. But once stored | ||
+ | |||
+ | The value provided on the command line has to conform with the octal permissions, | ||
+ | |||
+ | > Converting argv[1]' | ||
+ | |||
+ | The command-line " | ||
+ | |||
+ | So, if the first digit of argv[1] is a ' | ||
+ | |||
+ | |||
+ | =====Execution===== | ||
+ | |||
+ | If you run without proper arguments: | ||
<cli> | <cli> | ||
- | lab46: | + | lab46: |
+ | ./mychmod < | ||
+ | lab46: | ||
</ | </ | ||
- | If all aligns, you will see this: | + | Run with invalid mode: |
<cli> | <cli> | ||
- | ================================================== | + | lab46:~/ |
- | = CPROG sof0 project output validation tool = | + | ERROR: invalid mode |
- | ================================================== | + | |
- | sof0 checksum is: 822a47fb2a45845500b6c10878045bd5 | + | |
- | your checksum is: 822a47fb2a45845500b6c10878045bd5 | + | |
- | ================================================== | + | |
- | verification: | + | |
- | ================================================== | + | |
</ | </ | ||
- | If something is off, your checksum will not match the sof0 checksum, and verification will instead say " | + | Run with valid mode (success means you just get your prompt back): |
<cli> | <cli> | ||
- | ================================================== | + | lab46:~/ |
- | = CPROG sof0 project output validation tool = | + | lab46:~/ |
- | ================================================== | + | |
- | sof0 checksum is: 822a47fb2a45845500b6c10878045bd5 | + | |
- | your checksum is: 92af264c86823a61529948caaeac53e0 | + | |
- | ================================================== | + | |
- | verification: | + | |
- | ================================================== | + | |
</ | </ | ||
- | =====Questions / Food for Thought===== | ||
- | These are things I'd like you to contemplate, | ||
- | * Why/how does this trick work for 1-digit numbers? | ||
- | * Considering our 1-, 2-, and 3-digit domain restriction for this project, how many candidate values are there for input? | ||
- | * What is the smallest input value? | ||
- | * What is the largest input value? | ||
- | * How many input values are there that end in **5**? | ||
- | * What is the largest square that can be calculated given the project input restrictions? | ||
- | * How many digits is the largest square? | ||
- | * How can knowing how many digits the largest square is help you implement your solution? | ||
- | =====Submission===== | ||
- | To successfully complete this project, the following criteria must be met: | ||
- | * Code must compile cleanly (no warnings or errors) | + | =====Submission===== |
- | * Executed program must display a total of 2 lines, one for input, one for output. | + | |
- | * The computed number must be output to STDOUT | + | |
- | * Any supporting output must be output to STDERR | + | |
- | * Output is formatted in the manner in the sample above | + | |
- | * Output must be correct, and match the form given in the sample output above. | + | |
- | * Code must be nicely and consistently indented | + | |
- | * Code must implement solution using the mental math technique described above | + | |
- | * Code must be commented | + | |
- | * have a properly filled-out comment banner at the top | + | |
- | * have at least 20% of your program consist of **< | + | |
- | * Output Formatting (including spacing) of program must conform to the provided output (see above). | + | |
- | * Track/ | + | |
- | * 25% late penalty per day after deadline | + | |
- | * Program is submit in a C source file called **sof0.c** and compiles without warning, note, nor error with gcc on lab46. | + | |
- | * Submit a copy of your source code to me using the **submit** tool. | + | |
To submit this program to me using the **submit** tool, run the following command at your lab46 prompt: | To submit this program to me using the **submit** tool, run the following command at your lab46 prompt: | ||
<cli> | <cli> | ||
- | $ submit | + | $ submit |
- | Submitting | + | Submitting |
- | -> sof0.c(OK) | + | -> mychmod.c(OK) |
SUCCESSFULLY SUBMITTED | SUCCESSFULLY SUBMITTED | ||
Line 178: | Line 248: | ||
You should get some sort of confirmation indicating successful submission if all went according to plan. If not, check for typos and or locational mismatches. | You should get some sort of confirmation indicating successful submission if all went according to plan. If not, check for typos and or locational mismatches. | ||
- | I'll be looking for the following: | ||
- | |||
- | < | ||
- | 52: | ||
- | *: | ||
- | *:sof0:data stored and calculated in correct and separate variables [4/4] | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *:sof0:no negative compiler messages for sof0.c [4/4] | ||
- | </ |