Tuesday, May 17, 2016

Leadership Styles: 'Do As I Say' vs. 'Show Me What You Can Do'

On occasion, as I was interviewing with one company or another, I would be asked a question such as, What kind of manager do you like to work for? or some derivative of that. I gave this question a good deal of thought, as I think it was just as important, if not more so for me to know, than the interviewer. This has has obvious implications for anyone in the workplace, and I thought I might devote some attention to it here.

I tend to file leaders into two groups*:

  • 'Do as I say' leaders
  • 'Show me what you can do' leaders

The 'do as I say' leader has knows what needs to be done, and how it needs to be done. He's been in the industry for a while, knows the office politics, and is adept at ensuring a smooth running machine.

The 'show me what you can do' leader may not have the in-depth domain knowledge to provide such tactile leadership. The best this leader can do is describe the desired outcome, and any possible constraints, and leave you to figure out the details.

Each style has its own advantages and disadvantages, but (as I'm sure you've guessed by now), I have a favorite. For employees who look to grow in their career, be it technically, or as future leaders, one of these will thrust you forward, the other will hold you back.

Three of my former managers, specifically come to mind in the 'do as I say' camp. Each was quick to tell me how I was not measuring up. Each also had an incredible fear of allowing mistakes to happen, or letting those mistakes get communicated out. Finally, I discovered another very interesting trend: under the guidance of each of these, I progressed little or not at all in my career. When you know all the answers, you don't have a need for ideas from those under you, and when employees can't innovate, they stagnate.

Another three of my former leaders fell into the 'show me what you can do' group. This kind of leader may not posses all of the the domain knowledge, but he recognizes that fact. She provides the goal and constraints, then leaves you to solve the problem. Of course, you're going to make a mistake, but this leader chooses to focus on what you do right, because this type of leader recognizes that people are motivated far more by the realization of their potential, than by the fear of reprimand. Under the three 'show me what you can do' leaders I worked for, I accomplished things that I never thought I could, and I was proud of my work. Were there mistakes? Absolutely. Some technical or logistical, some as a junior leader, but with faith and guidance, these leaders pushed me to learn from those mistakes and grow.

To the three 'show me what you can do' leaders, I am eternally grateful. I have learned much from you. To the other three, I learned some things from you, too.


* Certainly, this is a very simplistic delineation, and in no way fully reflective of all leadership styles; it's just an observation that came to me.

Saturday, May 7, 2016

A Template for Pointers in C

This is a small template file I wrote to refresh my memory on how we handle pointers in C. It is not by any means a tutorial. Rather, if I need to do some file I/O or pass pointers to strings around between functions, this is really just to remind me how it is done. It should compile just fine on any GNU Linux machine with gcc:

# gcc -o file-io file-io.c

So why include C source code in a blog for topics in system administration; isn't that really a developer's topic? Strictly speaking it is development. The reality, however is that in most organizations, the development staff tends to be focused upon development of systems that directly generate revenue. Developer salaries generally run higher on average, so the appropriate use of that resource is in generating revenue, not maintaining infrastructure (this is not to say that the developer function is more important than management of infrastructure; just more costly). So, when the system administrator needs to retrofit some behavior in the operating system, he or she needs to understand at least some C, or rely upon someone else to have already developed a solution/workaround. In addition, since this blog is really focused upon Open Source administration, and Linux, as well as other operating systems are heavy in C, you should not be surprised to see the occasional C programming entry here.

One of the things you might notice is that I've abstracted simple functions like fprintf() and getline(). I can't imagine any reason to do this in a real project; it amounts to just code bloat. The only reason I've done that is to show not only how to pass pointers into functions, but also how to manipulate the data they represent inside the function. I also go a little overboard with variable naming, and comments. That's really just a style thing for me. I like the code to be crystal clear, so I can spend all my cognitive capital thinking about the problem space, rather than code details.

On to the file-io.c code (or as I like to call it, 94 lines to pointer nirvana):

==BEGIN==
/* file-io.c
** Template for handling file I/O in C using pointers & functions.
*/

/*--------------------------- includes -------------------------------*/
#include <stdio.h>
#include <stdlib.h>
/*---------------------------- defines -------------------------------*/
#define MODE_APPEND "a"
#define MODE_READONLY "r"
#define MODE_READWRITE "rw"

/*---------------------- function prototypes -------------------------*/
int iWriteLineToFile(FILE *, char *);
int iReadLineFromFile(char **line, size_t *n, FILE *stream);
void vOpenFile(FILE **fp, const char *filename, char *mode);
void vCloseFile(FILE *fp, const char *filename);

/*--------------------------------------------------------------------*/
/*---------------------------- main() --------------------------------*/
/*--------------------------------------------------------------------*/
int main(void)
{
    /* Declare & initialize our variables */
    char *sLine;                     /* any line of text */
    size_t iLength = NULL;           /* size of buffer allocated */
    FILE *fpOut;                     /* output file pointer */
    FILE *fpIn;                      /* input file pointer */
    int iInRetVal = 0;               /* return value of writes */
    int iOutRetVal = 0;              /* return value of writes */
    const char *sOutFile = "";       /* name of the file to write to */
    const char *sInFile = "";        /* name of the file to read from */

    sOutFile = "./output.txt";
    sInFile = "./input.txt";

    vOpenFile(&fpIn, sInFile, MODE_READONLY);
    vOpenFile(&fpOut, sOutFile, MODE_APPEND);
    
    iInRetVal = iReadLineFromFile(&sLine, &iLength, fpIn);
    iOutRetVal = iWriteLineToFile(fpOut, sLine);
    free(sLine); //good boys & girls clean up after themselves...
    
    vCloseFile(fpOut, sOutFile);
    vCloseFile(fpIn, sInFile);

    return iInRetVal + iOutRetVal;
}

/*--------------------------------------------------------------------*/
/*---------------------- iWriteLineToFile() --------------------------*/
/*--------------------------------------------------------------------*/
int iWriteLineToFile(FILE *fpOut, char *sLine)
{
    if(fprintf(fpOut, "%s", sLine) < 0)
        return(EXIT_FAILURE);
    else
        return(EXIT_SUCCESS);
}

/*--------------------------------------------------------------------*/
/*---------------------- iReadLineFromFile() -------------------------*/
/*--------------------------------------------------------------------*/
int iReadLineFromFile(char **sLine, size_t *iN, FILE *fpIn)
{
    if(getline(sLine, iN, fpIn) < 0)
        return(EXIT_FAILURE);
    else
        return(EXIT_SUCCESS);
}
 


/*--------------------------------------------------------------------*/
/*------------------------- vOpenFile() ------------------------------*/
/*--------------------------------------------------------------------*/
void vOpenFile(FILE **fp, const char *sFilename, char *cMode)
{
    if((*fp = fopen(sFilename, cMode)) == NULL)
    {
        fprintf(stderr, "Failure opening %s\n", sFilename);
        exit(EXIT_FAILURE);
    }
}

/*--------------------------------------------------------------------*/
/*------------------------- vCloseFile() -----------------------------*/
/*--------------------------------------------------------------------*/
void vCloseFile(FILE *fp, const char *sFilename)
{
    if (fclose(fp) == -1)
    {
        fprintf(stderr, "Failure closign %s\n",sFilename);
        exit(EXIT_FAILURE);
    }
}
==END==

This code is free to use for any purpose, and without consent. Enjoy!

Update 2/8/2017: Updated iReadLineFromFile to return either EXIT_SUCCESS or EXIT_FAILURE, rather than the count of characters read. This makes the final return code from the application 0 upon success.

Moved Music Posts

I've separated out my posts on musical projects to their own blog. You can now find them at Rich's Adventures in Music.

Thursday, May 5, 2016

Creating a Documentation RPM

OVERVIEW


Not too long ago, I had to learn how to build RPM files. It turns out, there is excellent documentation out there on building RPMs that include compiling source code as part of the build process. If you need something simpler, for example, an RPM that does nothing but installs some static documents (or really any files, for that matter), it's not quite as well documented. In this post, I'll show you how to build an RPM that does nothing more than install files (i.e., where no ./configure;make... is required). Useful for documentation, or where an installer is provided, rather than an .rpm file.

Environment: RHEL/CentOS/Scientific 6, rpmbuild 4.8.0.
Assumptions: I assume you have a good understanding of what RPMs are, how they are used, and can navigate around Linux with some level of comfort (or at the very least, your hunger for learning outweighs your pain threshold).
       

CREATE THE BUILD DIRECTORY LAYOUT


No difference here; this is the same as if you're doing any other RPM file.

# mkdir ~/rpmbuild

# for DIR in BUILD BUILDROOT RPMS SOURCES SPECS SRPMS; \
do mkdir ~/rpmbuild/${DIR};done

BUILD THE SOURCES DIRECTORY


Create a directory structure in SOURCES that mimics the actual directory structure where
files will get dropped. For example, if placing documentation for package foo-1.2.3 in
/usr/share/doc, create the directories:

# mkdir -p ~/rpmbuild/SOURCES/usr/share/doc/foo-1.2.3

Drop any files (or tree) into this directory, exactly as it will appear in the actual
file system. Next create a tarball for the source in the SOURCES/ directory:

# tar -czvf foo-1.2.3.tar.gz usr/

The file name above (foo-1.2.3.tar.gz) will be used in the SPEC file below for the Source0 value. Assuming the directory structure looks like:

SOURCES/
  usr/
    share/
      doc/
        foo-1.2.3/
          dir1/
            file1
            file2
          dir2/
            dir2.1/
              file4
            file3

BUILDING THE SPEC FILE


Once your directory structure is built, the files are in place, and you've created your source file tarball, you can start building a SPEC file. This really is the magic sauce in the project. Here is a sample that uses the example directory structure above. I've added a few comments that explain what happens along the way.

Name:      <package name w/o version #s. Ex: unixODBC-doc>
Version:   <full version (maj.min.patch)
Release:   <release # - 0 if none; required>
Source0:   <filename of source file in rpmbuild/SOURCES/>
Packager:  Firstname Lastname <me@my-address.com>
Summary:   <short pkg description>
License:   <license type>
Group:     <group under which this pkg falls - see rpm.org for groups>
BuildArch: <architecture: noarch, i386, i686, x86_64, ...>

%description
<long, multiline description>

%prep
# creating the package directory name

%setup -c -n %{name}-%{version}

%build
# Leave %build empty.

%install
# Drop SOURCES files into the BUILDROOT directory to prepare for packaging

test -d ${RPM_BUILD_ROOT} && rm -rf ${RPM_BUILD_ROOT}
/bin/mkdir -p ${RPM_BUILD_ROOT}
cp -rp ${RPM_BUILD_DIR}/%{name}-%{version}/* ${RPM_BUILD_ROOT}/

%clean

%post
# Place any commands to be run after the files are installed here. These
# are just shell commands - no #!/bin/sh is required.

%preun

%files
# Tell rpmbuild which files to install (or uninstall)
# defattr are default attributes/ownerships. "-" = same as source file.
# %attr entries override defattr.
%defattr(-,root,root)
%attr(0644, root, root) /usr/share/doc/foo-1.2.3/dir1/file1
%attr(0644, root, root) /usr/share/doc/foo-1.2.3/dir1/file2
%attr(0644, root, root) /usr/share/doc/foo-1.2.3/dir2/file3
%attr(0644, root, root) /usr/share/doc/foo-1.2.3/dir2/dir2.1/file4

# Tell rpmbuild which directories are owned by this package

%dir /usr/share/doc/foo-1.2.3/dir1
%dir /usr/share/doc/foo-1.2.3/dir2
%dir /usr/share/doc/foo-1.2.3/dir2.1

# ChangeLog. Most recent entry at the top. The format is rather strict.
# An example appears below.

%changelog
* <3-char-Day> <3-char-Month> <Dayofmonth> <year> <firstname> <lastname> <me@my-address.com>
- Description of first change/update/modification
- Description of second change/update/modification
* Thu Apr 23 2016 Richard Lohman rlohman@example.com
- Added man pages.

BUILDING THE RPM


Beyond that, the remainder of the process is identical to any other RPM build, so no need to replicate the wealth of documentation out there.

RESOURCES